美文网首页
SpringBoot实战—ThreadLocal获取当前用户信息

SpringBoot实战—ThreadLocal获取当前用户信息

作者: 遇见编程 | 来源:发表于2024-07-08 09:24 被阅读0次

    介绍:

    ThreadLocal 并不是一个Thread,而是Thread的局部变量。
    ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。

    常用方法:

    • public void set(T value) 设置当前线程的线程局部变量的值
    • public T get() 返回当前线程所对应的线程局部变量的值
    • public void remove() 移除当前线程的线程局部变量
    public class BaseContext {
    
        public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
    
        public static void setCurrentId(Long id) {
            threadLocal.set(id);
        }
    
        public static Long getCurrentId() {
            return threadLocal.get();
        }
    
        public static void removeCurrentId() {
            threadLocal.remove();
        }
    
    }
    

    在拦截器中解析出当前登录员工id,并放入线程局部变量中:

    /**
     * jwt令牌校验的拦截器
     */
    @Component
    @Slf4j
    public class JwtTokenAdminInterceptor implements HandlerInterceptor {
    
        @Autowired
        private JwtProperties jwtProperties;
    
        /**
         * 校验jwt
         *
         * @param request
         * @param response
         * @param handler
         * @return
         * @throws Exception
         */
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            //判断当前拦截到的是Controller的方法还是其他资源
            if (!(handler instanceof HandlerMethod)) {
                //当前拦截到的不是动态方法,直接放行
                return true;
            }
    
            //1、从请求头中获取令牌
            String token = request.getHeader(jwtProperties.getAdminTokenName());
    
            //2、校验令牌
            try {
                log.info("jwt校验:{}", token);
                Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
                Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
                log.info("当前员工id:{}", empId);
                /////将用户id存储到ThreadLocal////////
                BaseContext.setCurrentId(empId);
                ////////////////////////////////////
                //3、通过,放行
                return true;
            } catch (Exception ex) {
                //4、不通过,响应401状态码
                response.setStatus(401);
                return false;
            }
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            //清空ThreadLocal中的数据
            BaseContext.removeCurrentId();
        }
    
    }
    
    @Configuration
    @Slf4j
    public class WebMvcConfiguration extends WebMvcConfigurationSupport {
    
        @Autowired
        private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;
    
        @Autowired
        private JwtTokenUserInterceptor jwtTokenUserInterceptor;
    
        /**
         * 注册自定义拦截器
         *
         * @param registry
         */
        protected void addInterceptors(InterceptorRegistry registry) {
            log.info("开始注册自定义拦截器...");
            registry.addInterceptor(jwtTokenAdminInterceptor)
                    .addPathPatterns("/admin/**")
                    .excludePathPatterns("/admin/employee/login");
    
            registry.addInterceptor(jwtTokenUserInterceptor)
                    .addPathPatterns("/user/**")
                    .excludePathPatterns("/user/user/login")
                    .excludePathPatterns("/user/shop/status");
        }
    }
    

    在Service中获取线程局部变量中的值:

        /**
         * 新增员工
         *
         * @param employeeDTO
         */
        public void save(EmployeeDTO employeeDTO) {
            //.............................
    
            //设置当前记录创建人id和修改人id
            employee.setCreateUser(BaseContext.getCurrentId());
            employee.setUpdateUser(BaseContext.getCurrentId());
    
            employeeMapper.insert(employee);
        }
    

    使用map

    /**
     * ThreadLocal 工具类
     */
    @SuppressWarnings("all")
    public class ThreadLocalUtil {
        //提供ThreadLocal对象,
        private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();
     
        //根据键获取值
        public static <T> T get(){
            return (T) THREAD_LOCAL.get();
        }
        
        //存储键值对
        public static void set(Object value){
            THREAD_LOCAL.set(value);
        }
     
     
        //清除ThreadLocal 防止内存泄漏
        public static void remove(){
            THREAD_LOCAL.remove();
        }
    }
    
    
    @Component
    public class LoginInterceptor implements HandlerInterceptor {
        @Autowired
        private StringRedisTemplate stringRedisTemplate;
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            //令牌验证
            String token = request.getHeader("Authorization");
            //验证token
            try {
               
                Map<String, Object> claims = JwtUtil.parseToken(token);
     
                //把业务数据存储到ThreadLocal中
                ThreadLocalUtil.set(claims);
                //放行
                return true;
            } catch (Exception e) {
                //http响应状态码为401
                response.setStatus(401);
                //不放行
                return false;
            }
        }
     
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            //清空ThreadLocal中的数据
            ThreadLocalUtil.remove();
        }
    }
    
    @GetMapping("/userInfo")
        public Result<User> userInfo(/*@RequestHeader(name = "Authorization") String token*/) {
            //根据用户名查询用户
           /* Map<String, Object> map = JwtUtil.parseToken(token);
            String username = (String) map.get("username");*/
            Map<String, Object> map = ThreadLocalUtil.get();
            String username = (String) map.get("username");
            User user = userService.findByUserName(username);
            return Result.success(user);
        }
    

    ThreadLocal:

    • 用来存取数据: set()/get()
    • 使用ThreadLocal存储的数据, 线程安全
    • 用完记得调用remove方法释放

    相关文章

      网友评论

          本文标题:SpringBoot实战—ThreadLocal获取当前用户信息

          本文链接:https://www.haomeiwen.com/subject/dwpwcjtx.html