============= 后端_线程存储 ============= 1 线程局部存储 ____________ |线程局部存储| ----------------> 线程一 ____________ |线程局部存储| ----------------> 线程二 ____________ |线程局部存储| ----------------> 线程三 - 每个线程都拥有各自独立的局部存储空间 - 每个线程都只能访问自己的局部存储空间 - 通过线程局部存储实现线程间的数据隔离 - 线程局部存储中的数据只能手动方式删除 2 用户信息放哪好? ... public class LoginInterceptor implements HandlerInterceptor { ... /** * 前置拦截处理 * 在执行控制器方法之前执行 * 登录验证 */ @Override public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ... // 若根据令牌找不到用户,即令牌有误 User user = loginService.findUserByToken(token); if (user == null) { ... } ... // 将User对象放在某个地方,便于控制器从中获得用户信息 return true; // 验证通过,允许访问 } ... } 从登录拦截器的实现可以看到,有关登录用户的信息已经从缓存中获得。 若访问被允许,后续的控制器方法如何能更方便地获取到这些用户信息? 3 在线程局部存储中存放用户信息 /ysdblog-api/src/main/java/com/weihome/ysdblog/utils/UserThreadLocal.java: public class UserThreadLocal { private UserThreadLocal() {} // 禁止外部实例化 private static final ThreadLocal LOCAL = new ThreadLocal(); public static void put(User user) { LOCAL.set(user); } public static User get() { return LOCAL.get(); } public static void remove() { LOCAL.remove(); } } 4 登录拦截器 /ysdblog-api/src/main/java/com/weihome/ysdblog/handler/LoginInterceptor.java: ... public class LoginInterceptor implements HandlerInterceptor { ... /** * 前置拦截处理 * 在执行控制器方法之前执行 * 登录验证 */ @Override public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ... // 若根据令牌找不到用户,即令牌有误 User user = loginService.findUserByToken(token); if (user == null) { ... } // 将用户信息放到线程局部存储中 UserThreadLocal.put(user); return true; // 验证通过,允许访问 } /** * 完成拦截处理 * 在被拦截控制器方法执行完成后执行 * 删除线程局部存储中的数据 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 删除线程局部存储中的数据,避免内存泄漏 UserThreadLocal.remove(); } ... } 5 测试控制器 /ysdblog-api/src/main/java/com/weihome/ysdblog/controller/TestController.java: @RestController @RequestMapping("test") public class TestController { @RequestMapping public Result test() { return Result.success(UserThreadLocal.get()); } } 6 运行测试 Postman GET localhost:8888/test Headers Authorization: eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NDk1ODQyMjcsInVzZXJJZCI6MTUwOTM2MzE2Mjc2MjE4Njc1NCwiaWF0IjoxNjQ4Njk1MTk1fQ.cHFM0rmfQvr6frtWJaC1citGTESGt0b25FOBNwPgdlY ------------------------------------------------------- { "success": true, "code": 200, "msg": "success", "data": { "id": 1509363162762186754, "account": "user_f", "admin": 0, "avatar": "/static/img/logo.b3a48c0.png", "createDate": 20220331105315, "deleted": 0, "email": "", "lastLogin": 20220331105315, "mobilePhoneNumber": "", "nickname": "nickname_f", "password": "01bec61b2f05979aed0c4935bd8c7653", "salt": "", "status": "" } }