ThreadLocal工具类,线程本地变量

时间:2024-7-22    作者:老大夫    分类: 工具类


拦截器解析token后直接存储在线程本地变量当中,之后的controller,Service,Mapper都可以直接获取用户信息了

  • 编写ThreadLocal工具类

    理论上我们可以在Controller方法中,使用@RequestHeader获取JWT,然后在进行解析,如下

    @Operation(summary = "获取登陆用户个人信息")
    @GetMapping("info")
    public Result<SystemUserInfoVo> info(@RequestHeader("access-token") String token) {
      Claims claims = JwtUtil.parseToken(token);
      Long userId = claims.get("userId", Long.class);
      SystemUserInfoVo userInfo = service.getLoginUserInfo(userId);
      return Result.ok(userInfo);
    }

    上述代码的逻辑没有任何问题,但是这样做,JWT会被重复解析两次(一次在拦截器中,一次在该方法中)。为避免重复解析,通常会在拦截器将Token解析完毕后,将结果保存至ThreadLocal中,这样一来,我们便可以在整个请求的处理流程中进行访问了。

    ThreadLocal概述

    ThreadLocal的主要作用是为每个使用它的线程提供一个独立的变量副本,使每个线程都可以操作自己的变量,而不会互相干扰,其用法如下图所示。

    common模块中创建com.atguigu.lease.common.login.LoginUserHolder工具类

    public class LoginUserHolder {
      public static ThreadLocal<LoginUser> threadLocal = new ThreadLocal<>();
    
      public static void setLoginUser(LoginUser loginUser) {
          threadLocal.set(loginUser);
      }
    
      public static LoginUser getLoginUser() {
          return threadLocal.get();
      }
    
      public static void clear() {
          threadLocal.remove();
      }
    }

    同时在common模块中创建com.atguigu.lease.common.login.LoginUser

    @Data
    @AllArgsConstructor
    public class LoginUser {
    
      private Long userId;
      private String username;
    }
  • 修改AuthenticationInterceptor拦截器

    @Component
    public class AuthenticationInterceptor implements HandlerInterceptor {
    
      @Override
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
          String token = request.getHeader("access-token");
    
          Claims claims = JwtUtil.parseToken(token);
          Long userId = claims.get("userId", Long.class);
          String username = claims.get("username", String.class);
          LoginUserHolder.setLoginUser(new LoginUser(userId, username));
    
          return true;
    
      }
    
      @Override
      public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
          LoginUserHolder.clear();
      }
    }
  • 编写Controller层逻辑

    LoginController中增加如下内容

    @Operation(summary = "获取登陆用户个人信息")
    @GetMapping("info")
    public Result<SystemUserInfoVo> info() {
      SystemUserInfoVo userInfo = service.getLoginUserInfo(LoginUserHolder.getLoginUser().getUserId());
      return Result.ok(userInfo);
    }
  • 编写Service层逻辑

    LoginService中增加如下内容

    @Override
    public SystemUserInfoVo getLoginUserInfo(Long userId) {
      SystemUser systemUser = systemUserMapper.selectById(userId);
      SystemUserInfoVo systemUserInfoVo = new SystemUserInfoVo();
      systemUserInfoVo.setName(systemUser.getName());
      systemUserInfoVo.setAvatarUrl(systemUser.getAvatarUrl());
      return systemUserInfoVo;
    }


扫描二维码,在手机上阅读

推荐阅读: