1. 程式人生 > >java web 監聽系統線上使用者人數(tomcat session的建立時機)

java web 監聽系統線上使用者人數(tomcat session的建立時機)

 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

。查了程式碼看到專案中在登入頁面時有呼叫getSession()做一些邏輯,所以只要進入登入頁面,即便使用者還沒有登入,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();

以上,完