SpringBoot 拦截器妙用你真的了解吗

关于springboot拦截器很多朋友掌握的不是多好,今天抽空给大家普及下这方面的知识,SpringBoot 拦截器妙用,让你一个人开发整个系统的鉴权模块,快来跟小编一起学习下吧

handlerinterceptor 详解

handlerinterceptor 允许定制 handler 处理器执行链的工作流接口。我们可以自定义拦截器用于拦截 handlers 处理器(你可以理解为 controller 层的接口),从而可以添加一些共同的重复性的处理行为(例如接口鉴权,接口日志记录,性能监控等),而不用修改一个 handler 的实现。

注意,此基于 SpringBoot 2.3.12.RELEASE 版本讲解。

handlerinterceptor 接口只有三个认空实现方法,在低版本中这三个方法不是方法,而是抽象方法

public interface handlerinterceptor { default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } }

这三个方法的执行顺序图如下:

preHandle

preHandle 前置处理,拦截一个处理器(handler)的执行,preHandle 方法会在 HandlerMapping 确定一个适当的处理器对象之后,但在 HandlerAdapter 调用处理器之前被调用。可以简单理解为 controller 接口被调用之前执行。

Intercepter 是链式的,就是一个接着一个执行。如果此方法返回 true,则会执行下一个拦截器或者直接执行处理器。如果此方法返回 false 或者抛出异常则终止执行链,也不再调用处理器。

注意,此方法如果不返回 true,那么 postHandle 和 afterCompletion 不会被执行。

那这个方法有什么用呢?其实可以做一些接口被调用前的预处理,例如用户权限校验。

package com.chenpi; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.handlerinterceptor; /** * @Description 用户权限验证拦截 * @Author 陈皮 * @Date 2021/6/27 * @Version 1.0 */ @Component public class UserPermissionInterceptor implements handlerinterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; // 获取用户权限校验注解 UserAuthenticate userAuthenticate = handlerMethod.getmethod().getAnnotation(UserAuthenticate.class); if (null == userAuthenticate) { userAuthenticate = handlerMethod.getmethod().getDeclaringClass() .getAnnotation(UserAuthenticate.class); } if (userAuthenticate != null && userAuthenticate.permission()) { // 验证用户信息 UserContext userContext = userContextManager.getUserContext(request); if (null == userContext) { return false; } } } return true; } }

postHandle

postHandle 后置处理,会在 HandlerAdapter 调用处理器之后,但在 dispatcherServlet 渲染视图之前被调用。可以在此对 ModelAndView 做一些额外的处理。可以简单理解为 controller 接口被调用后执行

注意,此方法在执行链中的执行顺序是倒着执行的,即先声明的拦截后执行

afterCompletion

afterCompletion 完成之后,在请求处理完之后被执行,也就是渲染完视图之后。一般用于做一些资源的清理工作,配合 preHandle 计算接口执行时间等。

注意,和 postHandle 一样,此方法在执行链中的执行顺序也是倒着执行的,即先声明的拦截后执行

@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) { // 请求完后,清除当前线程的用户信息 UserContextHolder.removeUserContext(); }

注册拦截

注意,我们自定义拦截器要通过 WebMvcConfigurer 的实现类进行注册,才能生效。

package com.yzj.ehr.common.config; import com.yzj.ehr.common.context.UserContextResolver; import org.springframework.stereotype.Component; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.yzj.ehr.common.interceptor.UserPermissionInterceptor; /** * @Description 注册拦截器 * @Author 陈皮 * @Date 2021/6/27 * @Version 1.0 */ @Component public class WebAppConfigurer implements WebMvcConfigurer { private UserPermissionInterceptor userPermissionInterceptor; public WebAppConfigurer(final UserPermissionInterceptor userPermissionInterceptor) { this.userPermissionInterceptor = userPermissionInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { // 匹配所有接口,排除/base/test接口 registry.addInterceptor(userPermissionInterceptor).addpathPatterns("/**") .excludePathPatterns("/base/test"); } }

相关文章

Java中的String是不可变对象 在面向对象及函数编程语言中,不...
String, StringBuffer 和 StringBuilder 可变性 String不可变...
序列化:把对象转换为字节序列的过程称为对象的序列化. 反序...
先说结论,是对象!可以继续往下看 数组是不是对象 什么是对...
为什么浮点数 float 或 double 运算的时候会有精度丢失的风险...
面试题引入 这里引申出一个经典问题,看下面代码 Integer a ...