单点登录Redis存储Session及SessionId问题说明与集群实战-2
生活随笔
收集整理的這篇文章主要介紹了
单点登录Redis存储Session及SessionId问题说明与集群实战-2
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
我們要寫什么呢,我們要在服務端寫一個cookie,而這個cookie呢,是寫在客戶端上的,那他寫的就是登陸時候的,sessionId,非常簡單,我們開始寫一下,首先新建一個類,我們就在util里面創建,這個類呢,就叫CookieUtil,首先聲明兩個String類型的常量,這是final的,COOKIE_DOMAIN,先寫一個空字符串放著,然后我們再寫一個,COOKIE_NAME,cookie的名字,這些名字是我們服務端要送到,客戶端瀏覽器上的,這個名字我們就叫mmall_login_cookie,其實這里要說一下,我們寫在happymall,這個domain下面之后呢,那user.happymall,還有www.happymall,還有后續訂單服務化之后,order.mall,這里面的cookie都是可以看到的,也就是把我們的cookie,寫在一個domain,大一點的domain,寫在一級域名下的,那我們也可以寫在二級域名下,例如我們寫在abc.happymall.com,這么一個二級域名下,三級域名比如3.abc.happymall.com,能夠讀到abc.happymall的cookie,那kk.happymall和abc并行的域名,它是讀不到abc.happymall.com下的cookie的,我們先寫在一級域名下,那很簡單,我們現在封裝一個方法,那我們寫cookie的時候,肯定要放到response里邊,我們把HttpServetResponse拿過來,response,第二個就是寫我們的value,那我們稱之為token,也就是JSESSIONID,那怎么寫呢,在new Cookie的時候,要寫他的name和value,name就是cookie_name,那他的value就是token,很簡單的一個構造器,然后我們set他的domain,上面聲明了這個常量,我們還要set他的path,然后我們還要設置一個maxage,這個是什么呢,cookie的有效期,如果我們寫-1的話,就代表永久的,那這個單位是秒,這里面還有一個注釋,如果這個maxage不設置的話,那cookie就不會寫入硬盤,而是寫在內存,只在當前頁面有效,也就是我們設置這個之后,才會存在硬盤當中,包括我們關閉瀏覽器等等,重啟電腦cookie都存在,那因為它是秒,我們設置他的有效期為一年,60這是一分鐘,60秒就是一分鐘,現在再乘以60代表1小時,然后24代表一天,乘以365,這個就設置一年的有效期,就用我們前面講的slfj,log.info,write cookiename,占位,write cookievalue,占位,后面寫上直接沖ck里面讀,那這個path也說一下,這個設置代表在根目錄,直接斜杠,如果我設置一個path為test,那么就是說只有test目錄下,或者test子目錄頁面,才能獲取到這個cookie,那我們就把它放到根目錄下,然后response.addCookie,把這個ck放進來,寫入cookie,那么一口氣封裝完,再寫一個讀取cookie,那我們在登陸的時候,寫入了cookie,寫入了mmall_login_cookie,那我們在獲取user的時候,我們就要讀取這個cookie,拿到當時登陸時候,存的JSESSIONID,這個就是一個string了,因為要讀,readLoginToken
private final static String COOKIE_DOMAIN = ".happymmall.com";private final static String COOKIE_NAME = "mmall_login_token";public static void writeLoginToken(HttpServletResponse response,String token){Cookie ck = new Cookie(COOKIE_NAME,token);ck.setDomain(COOKIE_DOMAIN);ck.setPath("/");//代表設置在根目錄ck.setHttpOnly(true);//單位是秒。//如果這個maxage不設置的話,cookie就不會寫入硬盤,而是寫在內存。只在當前頁面有效。ck.setMaxAge(60 * 60 * 24 * 365);//如果是-1,代表永久log.info("write cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());response.addCookie(ck);}
我們肯定是從request里面拿,request.getCookies,它是一個返回cookie數組的方法,這里有一個判斷,如果不為空的話就給他做一個遍歷,做each遍歷,然后打印他的cookie,我們讀取到之后要做一個判斷了,這里說一下StringUtils的這個equal方法,里面做了空判斷,比較好用一些
/*** <p>Compares two Strings, returning <code>true</code> if they are equal.</p>** <p><code>null</code>s are handled without exceptions. Two <code>null</code>* references are considered to be equal. The comparison is case sensitive.</p>** <pre>* StringUtils.equals(null, null) = true* StringUtils.equals(null, "abc") = false* StringUtils.equals("abc", null) = false* StringUtils.equals("abc", "abc") = true* StringUtils.equals("abc", "ABC") = false* </pre>** @see java.lang.String#equals(Object)* @param str1 the first String, may be null* @param str2 the second String, may be null* @return <code>true</code> if the Strings are equal, case sensitive, or* both <code>null</code>*/public static boolean equals(String str1, String str2) {return str1 == null ? str2 == null : str1.equals(str2);}
這個方法已經封裝好了,并不會包空指針異常,就是沒有讀到我們想要的login cookie,那這個方法就實現了
public static String readLoginToken(HttpServletRequest request){Cookie[] cks = request.getCookies();if(cks != null){for(Cookie ck : cks){log.info("read cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());if(StringUtils.equals(ck.getName(),COOKIE_NAME)){log.info("return cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());return ck.getValue();}}}return null;}
注銷登錄就要把這個cookie刪除,同樣的他不需要返回值,delLoginToken,刪除我既要讀,也要寫,那這里面就要講一下,怎么刪除cookie,那把request和response都拿過來,讀從request里面讀,寫從response里面寫,Cookie數組,如果不等于空,遍歷它,重要的在這里,如果我們把maxage設置為0的話,代表刪除此cookie,那刪除就通過把有效期設置成0,就代表刪除了這個cookie,然后打個log,然后response.addCookie,也就是我們add一個有效期為0的cookie,放到response里邊,然后返回給瀏覽器,瀏覽器就會把這個cookie刪除掉,有效期是0,直接結束這個方法,不再執行循環,那現在我們看一下
public static void delLoginToken(HttpServletRequest request,HttpServletResponse response){Cookie[] cks = request.getCookies();if(cks != null){for(Cookie ck : cks){if(StringUtils.equals(ck.getName(),COOKIE_NAME)){ck.setDomain(COOKIE_DOMAIN);ck.setPath("/");ck.setMaxAge(0);//設置成0,代表刪除此cookie。log.info("del cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());response.addCookie(ck);return;}}}}
讀刪除都寫完了,那我們debug來測試一下,還是來到UserController里面,我們在這里面直接調用,把response傳進去,所以在我們login參數里面,就要加response,然后response放到這里面,那么value就是session的id,為了調試,一起領著大家一起看,現在我們調用一下讀取readCookie,把request放到里邊,直接進行一個測試,然后我們還要刪除掉他,刪除它我們直接調用,把request和response都放到這里,實際上我們只要調用write就可以了,加到這里是為了一起測試,因為我們還有一個tomcat2
/*** 用戶登錄* @param username* @param password* @param session* @return*/@RequestMapping(value = "login.do",method = RequestMethod.POST)@ResponseBodypublic ServerResponse<User> login(String username, String password, HttpSession session, HttpServletResponse httpServletResponse){ServerResponse<User> response = iUserService.login(username,password);if(response.isSuccess()){// session.setAttribute(Const.CURRENT_USER,response.getData());CookieUtil.writeLoginToken(httpServletResponse,session.getId());RedisShardedPoolUtil.setEx(session.getId(), JsonUtil.obj2String(response.getData()),Const.RedisCacheExtime.REDIS_SESSION_EXTIME);}return response;}@RequestMapping(value = "logout.do",method = RequestMethod.POST)@ResponseBodypublic ServerResponse<String> logout(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse){String loginToken = CookieUtil.readLoginToken(httpServletRequest);CookieUtil.delLoginToken(httpServletRequest,httpServletResponse);RedisShardedPoolUtil.del(loginToken);// session.removeAttribute(Const.CURRENT_USER);return ServerResponse.createBySuccess();}
?
總結
以上是生活随笔為你收集整理的单点登录Redis存储Session及SessionId问题说明与集群实战-2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 单点登录Redis存储Session及S
- 下一篇: 单点登录Redis存储Session及S