1 分析问题
对token的解析当初在拦截器中已经写过。期待的是在拦截器里写了,在其他地方就不写了,应该去复用拦截器里面得到的结果
2 解决方式-ThreadLocal
2.1提供线程局部变量
- 用来存取数据: set()/get()
- 使用ThreadLocal存储的数据, 线程安全
2.2过程图解
2.3代码实现
工具类
package com.aaa.utils; import java.util.HashMap; import java.util.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(); } }
拦截器
package com.aaa.interceptors; import com.aaa.pojo.Result; //统一返回结果 import com.aaa.utils.JwtUtil;//token令牌 import com.aaa.utils.ThreadLocalUtil;//线程 import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import java.util.Map; @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); }
3 小结
- 用来存取数据: set()/get()
- 使用ThreadLocal存储的数据, 线程安全
- 用完记得调用remove方法释放