springMVC自定义拦截器、ThreadLocal

    技术2022-07-12  82

    SpringMVC执行流程

    用户发起请求到dispatchServletdispatchServlet根据请求路径到HandleMapping(映射器)中查询具体的handler(处理器)handlerMapping返回handleExecutionchain(具体的handler和拦截器集合)dispatchServlet根据handler的实现方式调用对应的handlerAdapter(适配器)handlerAdapter调用具体的handler(处理业务逻辑)handler返回处理结果(modelandview:数据模型和视图名称)给handlerAdapter返回modelandview给dispatchservletdispatchservlert根据视图名称到viewresolver(视图解析器)返回具体的视图给dispatcherservlet渲染视图返回渲染后的视图给dispatcherservletdispatcherservlet响应用户请求

    自定义拦截器

    此拦截器的功能为:拦截用户请求,从请求中获取cookie中的token,对token进行解析,获取token中用户的信息,对获得的信息通过ThreadLocal进行传递,保证线程安全,并在拦截器的后置处理中释放线程

    1.编写拦截器类,继承HandlerInterceptorAdapter类,重写preHandle(),并加入到Spring容器中

    @Component public class LoginInterceptor extends HandlerInterceptorAdapter { private static final ThreadLocal<UserInfo> THREAD_LOCAL = new ThreadLocal<>(); @Autowired private JwtProperties jwtProperties; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 获取cookie信息 String token = CookieUtils.getCookieValue(request, jwtProperties.getCookieName()); String userKey = CookieUtils.getCookieValue(request, jwtProperties.getUserKeyName()); // 如果都为空,设置userKey。 if (StringUtils.isBlank(token) && StringUtils.isBlank(userKey)){ userKey = UUID.randomUUID().toString(); CookieUtils.setCookie(request, response, jwtProperties.getUserKeyName(), userKey, jwtProperties.getExpire()); } // 不管有没有登录都要设置userKey UserInfo userInfo = new UserInfo(); userInfo.setUserKey(userKey); // token不为空,解析token if (StringUtils.isNotBlank(token)){ Map<String, Object> map = JwtUtils.getInfoFromToken(token, jwtProperties.getPublicKey()); if (!CollectionUtils.isEmpty(map)) { userInfo.setId(new Long(map.get("id").toString())); } } // 保存到threadlocal THREAD_LOCAL.set(userInfo); // 如果token不为空, return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { THREAD_LOCAL.remove(); } //对外提供静态方法,获取ThreadLocal public static UserInfo getUserInfo(){ return THREAD_LOCAL.get(); } }

    注意:

    这里我们使用了ThreadLocal来存储查询到的用户信息,线程内共享,对外提供get方法,因此请求到达Controller后可以共享User并且对外提供了静态的方法:getUserInfo()来获取User信息在完成逻辑任务后,要进行释放,否则会内存泄漏

    2.配置拦截器

    @Configuration public class MvcConfig implements WebMvcConfigurer { @Autowired private LoginInterceptor loginInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor).addPathPatterns("/**"); } }
    Processed: 0.009, SQL: 9