1. 程式人生 > >javaweb查詢所有登入的使用者,判斷是否線上

javaweb查詢所有登入的使用者,判斷是否線上

場景描述

專案中需要獲取所有線上的使用者,當用戶登入時,就記錄住線上狀態,當退出時或一定時間中無操作(超時)時,就記錄離線狀態

設想辦法

眾所周知,當用戶登入後,會把登入資訊放入session中,既然session中存有登入資訊,那麼是否可以在session中查詢使用者,session中有的就是線上使用者呢?顯然這是不行的,首先,要了解什麼是session。

session是一個容器,也是一個會話,當有請求到伺服器時,伺服器就產生一個session,會有一個唯一標識sessionId,session物件是一個使用者全域性變數,也可以看作一個私有的,在整個會話期間一直都有效(瀏覽器不關閉,當然及時關閉了也不會立馬清除),當然如果一直無操作的話,也會超時失效,預設應該是半個小時,這個可以自己設定。由於session是在伺服器上的私有空間,因此是不能訪問別人的session資訊的。因此不能根據session來判斷是否線上。

1.資料庫儲存登入狀態

當用戶登入時可以把狀態設定1(線上),退出時設定0(離線),看著感覺是可行的,但感覺設計上不是很好。

2.放在伺服器的公共物件中

放在共享的空間,每個使用者都能訪問或共享的物件中

解決辦法

根據上面分析session之所以不能滿足需求,就是因為它是私有的,使用者之間不能共享,那麼問題就簡單了,如果有一個公共的,使用者可以共享的物件,那麼把登入的使用者放進去,豈不是可以判斷出線上的使用者?
一個web伺服器啟動時,會自動的建立一個application物件,直到web服務停止,在整個伺服器的生命週期中,所有的使用者都公用這個application物件,它是公共的,因此可以拿來存放共享的資料,那麼問題就簡單了,當用戶登入時,不僅把登入資訊放進session,同時也把使用者放進application中,當用戶退出或者超時時,也就是session銷燬時,把使用者從application中移除,那麼就可以在application中一直都儲存登入的使用者,當查詢線上使用者時,只需要把application中的資料取出來即可。

程式碼分享

核心就是寫一個監聽器,實現HttpSessionListenerServletContextListener,在伺服器啟動初始化ServletContext時,往application中放一個set的空集合(存使用者帳號,不會有重複資料),當每一次使用者進行登入時取出application中的set,把帳號儲存set中,再放入application中


import java.util.HashSet;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent
; import javax.servlet.ServletContextListener; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class LoginListener implements HttpSessionListener,ServletContextListener{ private ServletContext application = null; public void contextDestroyed(ServletContextEvent sce) { System.out.println("context destory"); } public void contextInitialized(ServletContextEvent sce) { System.out.println("context init"); application = sce.getServletContext(); Set<String> onlineUserSet = new HashSet<String>(); application.setAttribute("onlineUserSet", onlineUserSet); } public void sessionCreated(HttpSessionEvent se) { System.out.println("session create"); } public void sessionDestroyed(HttpSessionEvent se) { HttpSession session = se.getSession(); Set<String> onlineUserSet = (Set<String>)application.getAttribute("onlineUserSet"); String username = (String)session.getAttribute("username"); onlineUserSet.remove(username); application.setAttribute("onlineUserSet", onlineUserSet); onlineUserSet = (Set<String>)application.getAttribute("onlineUserSet"); System.out.println(onlineUserSet.toString()); System.out.println(username + "超時退出"); System.out.println("session destory"); } }

登入時程式碼

    HttpServletRequest request = ServletActionContext.getRequest();
    HttpSession session = request.getSession();
    session.setMaxInactiveInterval(60);
    ServletContext application = session.getServletContext();
    Set<String> onlineUserSet = new HashSet<String>();
    session.setAttribute("username", name);
    onlineUserSet = (Set)application.getAttribute("onlineUserSet");
    onlineUserSet.add(name);
    application.setAttribute("onlineUserList", onlineUserSet);
    onlineUserSet = (Set)application.getAttribute("onlineUserSet");

Mark

Mark1——2017-01-25

工作上實際並不是按照上面的方法解決的

專案裡用的redis,把登陸使用者資訊存在redis中,每隔一段時間刪除,前端登陸成功後向後臺傳送請求,每隔一段時間請求一次,重新把當前登入使用者寫入redis,這樣保證登陸使用者一直存在redis中