ThreadLocal存放用户信息(springboot)

场景:

接手一个项目,用户信息是用Feign调用用户中心获取,方法之间相互调用使用用户信息很麻烦(1,通过接口传参,2,再次调用Feign)。所以使用ThreadLocal存放用户信息

1,定义用户实体:

@ApiModel("登录用户信息")
@Data
public class FeginUser implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "用户ID")
    private String id;
    @ApiModelProperty(value = "用户名")
    private String name;
   
    @ApiModelProperty(value = "密码")
    @JsonIgnore
    private String upass;
}

2,定义工具类操作ThreadLocal(存放,获取,删除用户信息)

  public class ThreadLocalUtil {

        /**
         * 保存用户对象的ThreadLocal  在拦截器操作 添加、删除相关用户数据
         */
        private static final ThreadLocal<FeginUser> userThreadLocal = new ThreadLocal<FeginUser>();

        /**
         * 添加当前登录用户方法  在拦截器方法执行前调用设置获取用户
         * @param user
         */
        public static void addCurrentUser(FeginUser user){
            userThreadLocal.set(user);
        }

        /**
         * 获取当前登录用户方法
         */
        public static FeginUser getCurrentUser(){
            return userThreadLocal.get();
        }


        /**
         * 删除当前登录用户方法  在拦截器方法执行后 移除当前用户对象
         */
        public static void remove(){
            userThreadLocal.remove();
        }
    }

3,拦截器:1,访问接口时将用户信息放入ThreadLocal,2,访问结束时候删除ThreadLocal中信息(线程放入线程池并不一定会销毁)

@Component
@Slf4j
public class UserInfoInterceptor implements HandlerInterceptor  {

    @Autowired
    private UserInfoUtil userInfoUtil;

    /**
     * 请求执行前执行的,将用户信息放入ThreadLocal
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        FeginUser user;
        try{
             user = userInfoUtil.getUser();
        }catch (CustomException e){
            log.info("***************************用户未登录, ThreadLocal无信息***************************");
            return true;
        }
        if (null!=user) {
            log.info("***************************用户已登录,用户信息放入ThreadLocal***************************");
            ThreadLocalUtil.addCurrentUser(user);
            return true;
        }
        log.info("***************************用户未登录, ThreadLocal无信息***************************");
        return true;
    }

    /**
     * 接口访问结束后,从ThreadLocal中删除用户信息
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("***************************接口调用结束, 从ThreadLocal删除用户信息***************************");
        ThreadLocalUtil.remove();
    }

4,配置拦截器。

@Configuration
@ComponentScan
public class MyAppConfigurer extends WebMvcConfigurationSupport {

    @Autowired
    private UserInfoInterceptor userInfoInterceptor;

    /**
     * 拦截器,将用户信息放入threadLocal
     *
     * @param registry
     */
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(this.userInfoInterceptor).addPathPatterns("/**");
        super.addInterceptors(registry);
    }

}

5,定义用户信息具体操作接口:

为了类实现接口后直接使用(不定义为基础类,是因为类单继承)

public interface IBaseUserInfo {
    default Boolean isLogin() {
        return ThreadLocalUtil.getCurrentUser() != null;
    }

    default FeginUser getUser() {
        return ThreadLocalUtil.getCurrentUser();
    }

    default String getUserId() {
        if (ThreadLocalUtil.getCurrentUser() != null) {
            return ThreadLocalUtil.getCurrentUser().getId();
        }
        return null;
    }

}

6,使用:(代码中第二种使用方法,不需要定义接口)

@Service
public class ApplylServiceImpl implements IBaseUserInfo {
    

    public void applyUserInfo() {
        /**
         * 1,实现接口后,直接使用
         */
        FeginUser user1 = getUser();
        /**
         * 2,不实现接口,调用ThreadLocalUtil
         */
        FeginUser user2 = ThreadLocalUtil.getCurrentUser();
    }

}
  • 12
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
在Spring Boot中使用ThreadLocal存放请求的header信息可以通过以下步骤来实现: 1. 创建一个自定义的拦截器(Interceptor),用于在每个请求进入控制器方法之前进行拦截和处理。 2. 在拦截器中,使用ThreadLocal类来存储请求的header信息ThreadLocal是一个线程局部变量,它可以确保每个线程都有自己独立的副本。这样就可以确保在处理请求的同时,不会出现线程安全问题。 下面是一个简单的示例代码: ```java public class HeaderInterceptor extends HandlerInterceptorAdapter { private static final ThreadLocal<Map<String, String>> headerThreadLocal = new ThreadLocal<>(); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Map<String, String> headers = new HashMap<>(); // 将请求的header信息存储ThreadLocal中 Enumeration<String> headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); String headerValue = request.getHeader(headerName); headers.put(headerName, headerValue); } headerThreadLocal.set(headers); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 请求处理完成后,清除ThreadLocal中的数据,避免内存泄漏 headerThreadLocal.remove(); } public static Map<String, String> getHeaders() { return headerThreadLocal.get(); } } ``` 3. 在Spring Boot的配置类中注册拦截器: ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new HeaderInterceptor()); } } ``` 4. 在控制器中可以通过调用HeaderInterceptor的getHeaders方法来获取当前请求的header信息: ```java @RestController public class MyController { @GetMapping("/myEndpoint") public String myEndpoint() { Map<String, String> headers = HeaderInterceptor.getHeaders(); // 使用获取到的header信息进行处理 // ... return "Response"; } } ``` 这样,你就可以在Spring Boot中使用ThreadLocal存放请求的header信息了。每个请求都会有自己独立的header信息,不会相互干扰。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值