目录
- 一.拦截器
- 1.1 介绍
- 1.2 拦截器的使用
- 1.3 拦截器的执行流程
- 1.4 适配器模式
- 二.统一数据返回格式
- 2.1 介绍
- 2.2 统一数据返回格式的使用
- 2.3 优点
- 三.统一异常处理
- 3.1 介绍
- 3.2 统一异常处理的使用
一.拦截器
1.1 介绍
拦截器是Spring框架提供的核心功能之一,主要用于拦截用户的请求,根据业务需要执行预先设定的代码,可以在用户的请求响应前后执行,也可以在用户请求前阻止其执行
1.2 拦截器的使用
拦截器的使用步骤分为两步:定义拦截器和注册配置拦截器
- 定义拦截器
preHandle()
方法:目标方法执行前
执行,返回true则继续执行后续操作,返回false则中端后续操作postHandle()
方法:目标方法执行后
执行afterCompletion()
方法:视图渲染完毕后执行,最后执行(不常用)
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Component
public class LoginInterceptor implements HandlerInterceptor {/*** 在目标方法前执行* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 具体代码实现}/*** 在目标方法执行后执行* @param request* @param response* @param handler* @param modelAndView* @throws Exception*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {// 具体代码实现}/*** 视图渲染完毕后执行(最后执行)* @param request* @param response* @param handler* @param ex* @throws Exception*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 具体代码实现}
}
- 注册配置拦截器
addPathPatterns()
方法:对指定请求进行拦截excludePathPatterns()
方法:对指定请求不进行拦截- 拦截路径:
/*
表示拦截一级路径
,如/user,/book,不能拦截多级路径,如/user/login,/**
表示拦截任意级路径
(即一级或多级路径),同理/user/*
表示拦截/user路径下的一级路径,/user/**
表示拦截/user下的任意级路径
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Component
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/user/**");}
}
1.3 拦截器的执行流程
- 添加拦截器方法后,执行Controller的方法之前,请求会先被拦截器拦截住,执行
preHandle()
方法,如果返回true则放行本次操作,继续访问controller层的方法,如果返回false则不会放行,即不会执行controller层的方法 - Controller层的方法执行完毕后,再回来执行
postHandle()
这个方法以及afterCompletion()
方法,执行完毕之后,最终给浏览器相应数据
1.4 适配器模式
适配器模式
,也叫包装器模式
,指将一个类的接口转换成符合需求的另一个接口,简单来说就是目标类不能直接使用,需要通过一个新的类进行包装
,从而适配调用方的调用,把两个不兼容
的接口通过一定的方式转变为兼容
。在日常生活中,适配器模式也是非常常见,比如转换插头,网络转接头等。在适配器模式中,分别有四类角色:
- Target:目标接口(可以是抽象类或接口)
- Adaptee:适配者,与Target不兼容
- Adapter:适配器类,适配器模式的核心,通过继承或引用适配者的对象,把适配者转为目标接口
- client:需要使用适配器的对象
// 适配器模式的简单举例
// slf4j提供了一系列用于打印日志的Api,底层调用log4j或logback来打印日志,调用者只需调用slf4j的Api就可以打印日志
//目标接口Target
public interface Slf4jApi {void log(String message);
}//适配者Adaptee
public class Log4j {void log4jLog(String message){System.out.println("log4j:" + message);}
}//适配器类Adapter
public class Slf4jLog4jAdapter implements Slf4jApi{private Log4j log4j;public Slf4jLog4jAdapter(Log4j log4j){this.log4j = log4j;}@Overridepublic void log(String message) {log4j.log4jLog(message);}
}//使用适配器的对象client
public class client {public static void main(String[] args) {Slf4jApi slf4jApi = new Slf4jLog4jAdapter(new Log4j());slf4jApi.log("日志打印");}
}
二.统一数据返回格式
2.1 介绍
在实际的业务环境中,如果后端每一个接口返回的数据格式都大不相同,那么在前端处理起来会变得非常麻烦,因而需要对数据返回格式进行统一的处理,方便前端人员对相关数据的获取,Spring提供了使用@ControllerAdvice
注解和ResponseBodyAdvice
来返回统一数据格式
2.2 统一数据返回格式的使用
supports()
方法:判断是否要执行beforeBodyWrite
方法,为true则执行,为false则不执行,通过该方法可以选择哪些类或者哪些方法的response要进行处理,其他的不进行处理beforeBodyWrite()
方法:对response方法进行具体操作处理
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {return body; //返回值可以自己定义实现}
}
2.3 优点
- 方便前端人员更好接收和解析后端数据接口返回的数据
- 降低前端人员和后端人员的沟通成本,确定好返回数据的具体格式即可
- 有利于项目统一数据的维护和修改
- 有利于后端技术部门的统一规范的标准制定,不会出现乱七八糟的返回内容
三.统一异常处理
3.1 介绍
在日常写代码过程中,有的程序会因为某些原因抛出异常,而这些异常一般都是利用try,catch的方式处理异常或者throw,throws的方式抛出异常不管,如果每一个可能抛出异常的地方都要编写重复的代码,处理起来可能相对比较麻烦,这时如果不想过多的自己去处理各种异常编写重复的代码,统一异常处理就变得很重要,很便捷。在Spring中,可以集中定义全局异常处理器类,使用@ControllerAdvice
注解和@ExceptionHandler
注解统一捕获和处理所有 Controller 中可能抛出的异常
3.2 统一异常处理的使用
以下只是对统一异常处理的简单示例,通常可以在统一数据返回结果添加异常信息的对应属性,将全局捕获的异常设置到异常信息属性中,更好观察后端的具体返回结果。统一异常捕获的匹配顺序为当前类以及其子类向上依次匹配
,所以抛出的空指针异常等会先被针对这些异常进行处理的handler捕获,而不会先被处理异常类Exception的handler捕获。针对不同的异常类型,可以运用不同的处理方式。
注:如果返回的数据是json数据
,那么需要添加注解@ResponseBody
,或者把@ControllerAdvice
换为@RestControllerAdvice
(综合了@ResponseBody和@ControllerAdvice)
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;@ControllerAdvice
@Slf4j
public class ExceptionAdvice {@ExceptionHandlerpublic String handler(Exception e){log.error("发生异常:", e);// 返回值可以设置到统一数据返回结果的异常信息属性中return e.getMessage();}// 可以针对不同异常进行特殊的处理@ExceptionHandlerpublic String handler(NullPointerException e){log.error("发生空指针异常:", e);return e.getMessage();}}