網上看了很多方法,個人也看了,自己也總結了幾個比較常用的:
前提都是用session監聽器,對session的創建與銷毀進行監聽
一、在用戶登錄時保存該用戶的狀態有這幾種保存方式:
1、保存到內存中(application ,servletcontext ,個人也是推薦這種方式)
2、保存狀態到數據庫,至於具體的怎么保存你可以隨意返回,如:0,1兩種狀態
3、保存到文件中,對文件的讀寫
以上是登錄用戶的狀態,這對於大家來說都沒有什么問題。
二、 這時如果同一用戶登錄了,你可以在登錄成功后(保存信息之前)進入到上面的狀態 中進行匹配判斷,如果存在就提醒此用戶你的賬號已登錄。
三、關鍵在於該用戶的銷毀
invliate(),調用這個方法,通過Session的監聽器,進行對當前用戶的刪除。
Session過期,也會調用Session監聽器。
討論最多的就是在比如用戶沒有自己去注銷session.invalidate()方法,而是直接關閉了 瀏覽器,這時怎么辦?(瀏覽器關閉半個小時候,默認注銷session,監聽器這時才調用sessionDestroyed方法)。
首先要明確的一點,用戶關閉瀏覽器,服務器端是無法得知的(因為web客戶瀏覽器與服務器之間是無狀態的),網上也有一些解決方案,比如通過js來判斷用戶是否關閉了瀏覽器,是的次方法可行,但是如果用戶操作時,打開了多個窗口呢,這里也有方法:
1、一個方法還是比較好的,通過cokkie保存當前用戶開了的頁面數,如果頁數為一的話,就可以觸發js的注銷Session了。
2、先把Session的生命期設置的短一點,用類似ajax這種異步請求方式周期不斷的去請求后台,這樣可以保證當前的這個Session有效,如果用戶退出后,該Session也會很快的過期。
上面的兩種方式都有些缺陷,如:
1、用戶刪除cokkie的話,就無法判斷准確,這種可能應該不多吧(在訪問當前網站時)
2、有延遲,服務器壓力相對來說比較大
還有一種方式與上面的思考角度不一樣(當然也要看需求了),如果有用戶登錄時,就注銷之前已登錄的同一用戶。
實現方式與上面應該是差不多的,唯一不同之處在於,不用去刻意的想辦法讓用戶退出了(注銷Session)。
四、雖然像百度,CSDN等這些網站都沒有這樣做,當然也沒有必要這要這樣做。
但是在我們做企業內部應用的時候有時候可能會要求我們這樣做(同一賬號在統一時間只能在一個登錄),下面是個例子
我們先定義兩個Map對象需要用到,存放用戶與HttpSession的關系和sessionId與用戶的關系。用來記錄當前登錄的用戶是否登錄和當前session是否已經綁定了登錄用戶。
-
- public static final Map<String, HttpSession> USER_SESSION=new HashMap<String, HttpSession>();
-
- public static final Map<String, String> SESSIONID_USER=new HashMap<String, String>();
然后我們需要實現HttpSessionListener接口監聽,主要是監聽session的銷毀事件。
- public void sessionDestroyed(HttpSessionEvent se) {
- String sessionId=se.getSession().getId();
-
-
- USER_SESSION.remove(SESSIONID_USER.remove(sessionId));
- }
接下來是關鍵,處理登錄用戶的唯一。
當用戶登錄進來的時候我們先把當前HttpSession綁定的用戶和用戶綁定的HttpSession關系刪除。
再次我們刪除當前登錄的用戶綁定的HttpSession關系,如果當前用戶已經登錄刪除session和用戶的關系、刪除session中用戶的信息、設置說明用戶被擠下線了。
- public static void userLoginHandle(HttpServletRequest request){
-
- String userName=request.getParameter("userName");
-
- String sessionId=request.getSession().getId();
-
- USER_SESSION.remove(SESSIONID_USER.remove(sessionId));
-
-
- HttpSession session=USER_SESSION.remove(userName);
- if(session!=null){
- SESSIONID_USER.remove(session.getId());
- session.removeAttribute("userName");
- session.setAttribute("userMsg", "您的賬號已經在另一處登錄了,你被迫下線!");
- }
- }
用戶登錄的請求處理。先判斷用戶輸入的登錄信息是否合法,在判斷用戶輸入的信息是否正確(登錄是否成功),成功則調用單用戶登錄的處理方法,把當前登錄的用戶和當前session關聯,session中保持當前登錄用戶的信息
一個Java交流平台分享給你們,讓你在實踐中積累經驗掌握原理。如果你想拿高薪,想突破瓶頸,想跟別人競爭能取得優勢的,想進BAT但是有擔心面試不過的,可以加Java學習交流群:318261748
-
- protected void service(HttpServletRequest request,
- HttpServletResponse response) throws ServletException, IOException {
- String userName=request.getParameter("userName");
- String password=request.getParameter("password");
-
- if(userName!=null&&!"".equals(userName.trim())){
-
- if(login(userName, password)){
- HttpSession session=request.getSession();
-
- userLoginHandle(request);
-
- USER_SESSION.put(userName.trim(), session);
-
- SESSIONID_USER.put(session.getId(), userName);
-
- session.setAttribute("userName", userName);
- session.removeAttribute("userMsg");
- }
- }
- response.sendRedirect("index.jsp");
- }
-
- private boolean login(String userName,String password){
-
- return true;
- }
對於,同一時間同一賬戶可以在兩處乃至三處登錄的處理類似上面的處理流程,可以建個隊列來實現先進先出。