利用ThreadLocal实现不同方法的值获取

本文探讨了在用户登录后如何利用拦截器将token存储在浏览器本地,并在每次请求时通过ThreadLocal在服务端方便地获取token。通过创建拦截器拦截请求,将token存入ThreadLocal中,使得在服务层可以便捷地访问。然而,当业务方法在不同线程中执行时,ThreadLocal可能无法跨线程获取token,这在多线程环境下需要注意。
摘要由CSDN通过智能技术生成

假设有这么个需求,用户登录系统以后,将用户的token存入浏览器的本地存储,每次发送请求时将用户token携带上,方便后台控制层或业务层获取,那么此时可以有什么解决方案?

  • 利用拦截器获取请求头中的token,然后将token存入请求域中,然后将这个request传入controller,controller再传给service,其实这里也不用再将token存入请求域,我们可以直接将这个request传入service,这样看起来也确实可以,但是假如业务方法很多,每个方法都需要token,难道还需要每个方法都要传递request对象?

  • 利用拦截器获取请求头中token,将token存入ThreadLocal中,然后将这个ThreadLocal封装成一个工具类。这样在每个同步方法中都可以获取ThreadLocal中的值。只要是在一个线程里,就可以获取到。

拦截器类:

package com.example.appauth.interceptors;

import com.example.appauth.utils.ThreadLocalUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;

@Component
public class TokenInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String s = UUID.randomUUID().toString();
        System.out.println("interceptor:" + s);
        ThreadLocalUtils.setToken(s);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    //在方法执行完成移除token
    	ThreadLocalUtils.removeToken(s);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}

utils工具类

package com.example.appauth.utils;

public class ThreadLocalUtils {

    private static ThreadLocal<String> tokenThreadLocal = new ThreadLocal<>();

    public static void setToken(String token){
        tokenThreadLocal.set(token);
    }

    public static String getToken(){
        return tokenThreadLocal.get();
    }
  public static void removeToken(){
         if(tokenThreadLocal.get() != null){
			tokenThreadLocal.remove()
		}
    }

}

controller

    @GetMapping("tokentest")
    public R tokentest(){
        System.out.println("controller:" + ThreadLocalUtils.getToken());
        userService.saveUser();
        return R.success();
    }

service

    @Override
    public void saveUser() {
        String token = ThreadLocalUtils.getToken();
        System.out.println("service:" + token);
    }

启动访问测试

在这里插入图片描述
如果我们将service中的方法写在另一个线程中

    @Override
    public void saveUser() {
       new Thread(()->{
           String token = ThreadLocalUtils.getToken();
           System.out.println("service:" + token);
       }).start();
    }

再测试

在这里插入图片描述
此时由于不在一个线程中,便无法获取。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值