采用redis+ThreadLocal获取全局的登录用户信息(一)
生活随笔
收集整理的這篇文章主要介紹了
采用redis+ThreadLocal获取全局的登录用户信息(一)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1.首先進行登錄操作,代碼已經假設你從數據庫拿到了用戶信息保存在變量userinfo中,將token返回給瀏覽器保存,并將token和userinfo保存在redis中。
@Resourceprivate RedisTemplate redisTemplate;@RequestMapping("/login")public R token(HttpServletRequest request, HttpServletResponse response) {//假設此時已經從數據庫獲取到用戶信息在userinfoString token = UUID.randomUUID().toString();Cookie cookie=new Cookie("tokenUser",token);cookie.setMaxAge(60 * 60 * 24 * 7);//有效期設為7天cookie.setPath("/");//設置路徑response.addCookie(cookie);//響應回游覽器RedisCache redis=new RedisCache(redisTemplate);redis.set(token,userinfo,60 * 60 * 24 * 7);//有效期設為7天return R.ok(userinfo,"登錄成功");}2.新建一個類型,這個是全局線程。當用戶信息經過token驗證從redis拿出來之后要保存在這個里面,想用的時候從這個里面拿取就行了。
public class UserThreadLocal {private static ThreadLocal<User> userThread =new ThreadLocal<User>();public static void set(User user){userThread.set(user);}public static User get(){return userThread.get();}//防止內存泄漏public static void remove(){userThread.remove();} }3.新建一個攔截器,業務邏輯是 獲取瀏覽器token,再從redis獲取userinfo,將userinfo保存在UserThreadLocal線程中。
@Configuration public class LoginInterceptor implements HandlerInterceptor {@Resourceprivate RedisTemplate redisTemplate;@Autowiredprivate static ObjectMapper objectMapper = new ObjectMapper();//在執行COntroller方法之前執行/*** boolean 表示是否放行* true:放行 用戶可以跳轉頁面* false:攔截 之后給定重定向路徑** 業務邏輯:* 1.判斷用戶客戶端是否有Cookie/token數據* 如果用戶沒有token則重定向到用戶登陸頁面* 2.如果用戶token中有數據,則從redis緩存中獲取數據* 如果redis中數據為null,則重定向到用戶登陸頁面* 3.如果reids中有數據,則放行請求.*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {String token = "";//獲取Cookie數據Cookie[] cookies = request.getCookies();for (Cookie cookie : cookies) {if("tokenUser".equals(cookie.getName())){token = cookie.getValue();break;}}//判斷Cookie是否為nullif(!StringUtils.isEmpty(token)){System.out.println(token);//檢測緩存中是否有該數據RedisCache redis=new RedisCache(redisTemplate);Object userinfo= redis.get(token);System.out.println(userinfo);if(!StringUtils.isEmpty(userinfo)){//將userJSON轉化為User對象User user= (User) userinfo;UserThreadLocal.set(user);//用戶已經登陸 放行請求return true;}}//表示用戶沒有登陸response.sendRedirect("/login.html");return false;}//執行完業務邏輯后攔截@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {// TODO Auto-generated method stub}//返回頁面之前攔截@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {//將ThreadLocal數據清空UserThreadLocal.remove();}}3.新建一個攔截器配置類,設置要訪問攔截器的路徑,開放登錄接口和靜態資源接口,其他都配置成要訪問攔截器
@Configuration public class InterceptorConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry){//添加對用戶未登錄的攔截器,并添加排除項registry.addInterceptor(loginInterceptor).addPathPatterns("/**")//攔截所有.excludePathPatterns("/js/**","/dist/images/**")//排除樣式、腳本、圖片等資源文件.excludePathPatterns("/login")//排除登錄.excludePathPatterns("/","/index");} }4.獲取用戶信息。
@RequestMapping("/getuserinfo")public R getuserinfo() {User user = UserThreadLocal.get();System.out.println(user);return R.ok(user,"獲取用戶信息成功");}?問:ThreadLocal如何確保每次都能取到對應的信息?
?答:每次執行請求時攔截器將用戶信息保存在ThreadLocal中,ThreadLocal每次調用set時是一個獨立的線程,當另一個用戶調用ThreadLocal的set時方法?時,就會新建另一個線程,線程之間互不影響,當對應線程在調用get時候,就會請求到set時候的信息。
?問:怎么保證線程過多內存不會溢出呢?
?答:在攔截器的afterCompletion方法中添加ThreadLocal線程刪除方法,這樣每次請求結束后會將ThreadLocal線程中的數據刪除,這樣保證了線程不會太多,內存不會溢出。
總結
以上是生活随笔為你收集整理的采用redis+ThreadLocal获取全局的登录用户信息(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 炉石传说希尔瓦娜斯怎么获得
- 下一篇: 吃鸡摇车什么意思