SpringBoot 统⼀功能处理
1. 拦截器
拦截器是Spring框架提供的核⼼功能之⼀,主要⽤来拦截⽤⼾的请求,在指定⽅法前后,根据业务需要执⾏预先设定的代码。
也就是说,允许开发⼈员提前预定义⼀些逻辑,在⽤⼾的请求响应前后执⾏,在拦截器当中,开发⼈员可以在应⽤程序中做⼀些通⽤性的操作,⽐如通过拦截器来拦截前端发来的请求,判Session中是否有登录⽤⼾的信息,如果有就可以放⾏,如果没有就进⾏拦截。
拦截器的使⽤
定义拦截器
⾃定义拦截器:实现HandlerInterceptor接⼝,并重写其所有⽅法
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("LoginInterceptor⽬标⽅法执⾏前执⾏..");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("LoginInterceptor目标方法后执行..");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info("LoginInterceptors视图结束后执行,最后执行..");}
}
- preHandle()⽅法:⽬标⽅法执⾏前执⾏. 返回true:继续执⾏后续操作;返回false:中断后续操作.
- postHandle()⽅法:⽬标⽅法执⾏后执⾏
- afterCompletion()⽅法:视图渲染完毕后执⾏,最后执⾏(后端开发现在⼏乎不涉及视图
注册配置拦截器:实现WebMvcConfigurer接⼝,并重写addInterceptors⽅法
@Configuration
public class WebConfig implements WebMvcConfigurer {//⾃定义的拦截器对象@Autowiredprivate LoginInterceptor loginInterceptor;//注册⾃定义拦截器对象@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns("/book/**")//设置拦截器拦截的请求路径 }
}
启动服务
可以看到preHandle⽅法执⾏之后就放⾏了,开始执⾏⽬标⽅法,⽬标⽅法执⾏完成之后执⾏ postHandle和afterCompletion⽅法,此时拦截器是运行通过的,如果把返回值改为False。
可以看到拦截器拦截成功,目标方法未执行。
拦截路径
我们在注册配置拦截器的时候,通过 addPathPatterns() ⽅法指定要拦截哪些请求。也可以通过 excludePathPatterns() 指定不拦截哪些请求.
拦截路径对比表
拦截路径 | 含义 | 匹配示例 | 不匹配示例 |
---|---|---|---|
/* | 匹配一级路径,不包含子路径 | /user , /book , /login | /user/login , /book/addBook |
/** | 匹配任意级路径,包括子目录 | /user , /user/login , /book/addBook/1 | 无 |
/book/* | 匹配 /book 下一级路径 | /book/addBook , /book/delete | /book , /book/addBook/1 |
/book/** | 匹配 /book 下任意级路径 | /book , /book/addBook , /book/update/2 | /user/login |
代码示例
比如我们希望对除登录接口外的所有接口有效
registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/user/login");
拦截器执⾏流程
登录校验
根据自己的实际项目做出响应调整
定义拦截器
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("LoginInterceptor⽬标⽅法执⾏前执⾏..");HttpSession session = request.getSession(false);//如果成功获取session代表登录成功,则返回trueif (session != null &&session.getAttribute(Constants.SESSION_USER_KEY) != null) {return true;}response.setStatus(401);return false;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("LoginInterceptor目标方法后执行..");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info("LoginInterceptors视图结束后执行,最后执行..");}
}
注册配置拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns("/book/**").excludePathPatterns("/**/*.js").excludePathPatterns("/**/*.css").excludePathPatterns("/**/*.png").excludePathPatterns("/**/*.html");;}
}
2.适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,用于将不兼容的接口转换为客户端期望的接口。通过引入一个中间层(适配器类),解决因接口不匹配而无法协作的问题。
适配器模式的结构
- 目标接口(Target):客户端期望的接口。
- 被适配者(Adaptee):需要被适配的现有类或接口。
- 适配器(Adapter):实现目标接口并包装被适配者,完成接口转换。
代码示例
// 目标接口
interface Target {void request();
}// 被适配者
class Adaptee {void specificRequest() {System.out.println("Adaptee's specific request");}
}// 适配器
class Adapter implements Target {private Adaptee adaptee;public Adapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {adaptee.specificRequest();}
}// 客户端调用
public class Client {public static void main(String[] args) {Adaptee adaptee = new Adaptee();Target target = new Adapter(adaptee);target.request(); // 输出: Adaptee's specific request}
}
适用场景
- 需要复用现有类,但其接口与系统不兼容时。
- 希望统一多个类的接口,避免直接修改原有代码。
- 需要为多个子类提供统一接口,但无法修改父类。
优缺点
优点:
- 解耦客户端与被适配者,提高代码复用性。
- 符合开闭原则,新增适配器无需修改原有代码。
缺点:
- 过度使用会增加系统复杂性(如多层适配)。
- 类适配器需通过继承实现,可能破坏封装性。
3. 统⼀数据返回格式
统一的数据返回格式能够提升前后端协作效率,方便客户端处理数据。
添加类 ResponseAdvice ,实现ResponseBodyAdvice 接⼝,并在类上添加@ControllerAdvice 注解
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {@Autowiredprivate static ObjectMapper mapper = new ObjectMapper();@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@SneakyThrows //简化异常处理@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {if(body instanceof String){return mapper.writeValueAsString(Result.success(body));}// 如果已经是 Result 类型,不再重复包装if (body instanceof Result) {return body;}return Result.success(body);}
}
4. 统⼀异常处理
@ControllerAdvice
@ResponseBody
public class ErrorAdvice {@ExceptionHandlerpublic Object handler(Exception e){return Result.fail(e.getMessage());}@ExceptionHandlerpublic Object handler(NullPointerException e){return Result.fail("发生空指针异常" + e.getMessage());}