场景

在程序中我们经常使用Threadlocal记录本次请求的用户信息,通过从请求的request中获取token值,获取到用户详情设置到Threadlocal。

Interceptor拦截器

拦截器(Interceptor)同 Filter 过滤器一样,它俩都是面向切面编程——AOP 的具体实现(AOP切面编程只是一种编程思想而已) 你可以使用 Interceptor 来执行某些任务,例如在 Controller 处理请求之前编写日志,添加或更新配置… 在 Spring中,当请求发送到 Controller 时,在被Controller处理之前,它必须经过 Interceptors(0或多个) Spring Interceptor是一个非常类似于Servlet Filter 的概念

Interceptor作用 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算 PV(Page View)等; 权限检查:如登录检测,进入处理器检测是否登录; 性能监控:通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间。(反向代理,如 Apache 也可以自动记录) 通用行为:读取 Cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取 Locale、Theme 信息等,只要是多个处理器都需要的即可使用拦截器实现。 自定义 Interceptor 如果你需要自定义 Interceptor 的话必须实现 org.springframework.web.servlet.HandlerInterceptor接口或继承 org.springframework.web.servlet.handler.HandlerInterceptorAdapter类,并且需要重写下面下面 3 个方法:

preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) 方法在请求处理之前被调用。该方法在 Interceptor 类中最先执行,用来进行一些前置初始化操作或是对当前请求做预处理,也可以进行一些判断来决定请求是否要继续进行下去。该方法的返回至是Boolean类型,当它返回false时,表示请求结束,后续的Interceptor和Controller都不会再执行;当它返回为true时会继续调用下一个Interceptor的preHandle方法,如果已经是最后一个Interceptor的时候就会调用当前请求的Controller方法。 postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 方法在当前请求处理完成之后,也就是Controller方法调用之后执行,但是它会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView对象进行操作。 afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法需要在当前对应的Interceptor类的postHandler方法返回值为true时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。此方法主要用来进行资源清理。

创建拦截器

public class AuthInterceptor implements HandlerInterceptor {

    @Autowired
    RedisClient redisClient;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
        String token = request.getHeader("token");
        String userInfoJson = redisClient.get("User:token:" + token);
        UserInfo userInfo = JSON.parseObject(userInfoJson, UserInfo.class);
        AuthContextUtil.setUserInfo(userInfo);
        return true;
    }
}

创建配置类配置拦截器

public class InterceptorConfig implements WebMvcConfigurer {

    @Autowired
    AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加拦截器并配置拦截地址
        registry.addInterceptor(authInterceptor).addPathPatterns("/api/**");
    }
}

自定义注解导入拦截器和拦截器配置类

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(value = { AuthInterceptor.class, InterceptorConfig.class })
public @interface EnableAuthInterceptor {
}