java web 監聽系統線上使用者人數(tomcat session的建立時機)
阿新 • • 發佈:2019-01-26
spring mvc架構,tomcat執行的web專案,需要統計系統線上使用者人數。在網上找的資料,很多都是使用HttpSessionListener監聽session的建立和銷燬來實現,session建立則人數+1,session銷燬則人數-1,人數存放在ServletContext中。但是我在使用的時候發現,使用者主動退出系統(退出函式中銷燬session),線上使用者數不會改變,只有等session超時自動過期線上使用者數才會減少。跟蹤程式碼發現,使用者主動退出系統,session銷燬,但是使用者主動退出系統後重定向到登入頁面,session會再次建立(線上使用者數-1又+1=不變)。意思就是說只要到了登入頁面,不管有沒有登入成功,都會建立一個session。難道tomcat在應用被訪問時就建立session麼?再查資料以後發現,原來tomcat並不是應用被訪問就建立session,竟然也不是在動態存放內容到session中時建立,而是在呼叫getSession()方法時,如果session存在就訪問存在的session,如果不存在就建立session並返回剛建立的session
結論:如果能夠確保session銷燬後不會再使用getSession()做邏輯,那麼可以使用HttpSessionListener來統計線上使用者數,否則,線上人數+1的邏輯不能在監聽到session建立事件時就做,可以在使用者登入成功後的方法中做。程式碼如下:
web.xml
<listener> <listener-class>com.demo.web.UserSessionListener</listener-class> </listener>
UserSessionListener
package com.demo.web; import javax.servlet.http.HttpSessionListener; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; /** * 監聽使用者session以獲取線上使用者數 * * */ public class UserSessionListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent event) { /** * 人數的加法不寫在這裡,寫在使用者登入成功後 * */ /*System.out.println("建立了"); HttpSession session = event.getSession();// 獲得Session物件 // 通過Session獲得servletcontext物件 ServletContext servletContext = session.getServletContext(); Object object = servletContext.getAttribute("curUserNum"); if (object == null) { servletContext.setAttribute("curUserNum", 1); } else { int num =(int)object; servletContext.setAttribute("curUserNum", num + 1); }*/ } @Override public void sessionDestroyed(HttpSessionEvent event) { //System.out.println("銷燬了"); HttpSession session = event.getSession();// 獲得Session物件 ServletContext servletContext = session.getServletContext(); /** * 1.獲取num值 * 2.減1 * 3.存入servletcontext * */ Object object = servletContext.getAttribute("curUserNum"); if (object != null){ int num = (int) object; servletContext.setAttribute("curUserNum", num - 1); } } }
使用者登入成功後的LoginServlet,人數增加部分:
//藉助ServletContext實現,避免發生:
//使用者未正常登出退出系統而是關閉頁面或回到登入頁(session未銷燬未過期)再次登入系統,使用者人數重複增加的問題
ServletContext sc = getServletContext();
//在ServletContext中獲取上一次存入的該使用者session資訊
HttpSession oldSession = (HttpSession) sc.getAttribute(id);
//以下程式碼中的session為使用者登入成功,把使用者資訊引數都放入到session後的session物件
if (oldSession != null) { //上次放入的該使用者資訊不為空,即表示該使用者上次登入的session還未過期
if (oldSession != session) {
try {
oldSession.invalidate();//銷燬
} catch (Throwable e) {
}
//把新的session放入到ServletContext中,鍵值為使用者ID或能標識使用者唯一性的引數
sc.setAttribute(id, session);
}
} else{ //使用者上次登入的session已經過期或使用者是首次登入
sc.setAttribute(id, session); //把該使用者session放入ServletContext
/**
* 線上使用者數+1
*/
Object object = sc.getAttribute("curUserNum");
if (object == null) {
sc.setAttribute("curUserNum", 1);
} else {
int num =(int)object;
sc.setAttribute("curUserNum", num + 1);
}
}
在系統登出的LoginoutServlet中,要新增session銷燬操作。以及,remove掉ServletContext中登入使用者的session
getServletContext().removeAttribute(Integer.toString(CurUser.getId()));
httpRequest.getSession().invalidate();
以上,完