1. 程式人生 > >統計線上使用者數以及同賬號登入踢出另一使用者

統計線上使用者數以及同賬號登入踢出另一使用者

寫一個session屬性監聽器:定義兩個map,一個存session,以使用者編號為key;一個存使用者資訊,也以使用者編號為key.map的個數就是線上使用者數.每個使用者登入時,先檢查map中是否存在,如果不存在,就新增到map裡面去,如果存在,就通過使用者編號找對應session使其失效.再將當前登入使用者資訊寫入到map裡面.

package com.sunshine.monitor.comm.filter;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

import com.sunshine.monitor.system.manager.bean.SysUser;

/**
 * session屬性監聽,用於統計線上使用者數,同一賬戶登入踢出線上使用者
 * 對於直接關閉瀏覽器的操作等待session失效之後,才能做到清除.
 * @date 2016-6-1
 * @author licheng 
 *
 */
public class SessionListener implements HttpSessionAttributeListener{

	/**
	 * 定義監聽的session屬性名
	 */
	public final static String LISTENER_NAME = "_login";	
	public final static String LISTENER_COUNT = "_count";
	
	/**
	 * 定義儲存客戶登入使用者的集合
	 */
	private static Map<String, SysUser> users = new HashMap<String, SysUser>();
	
	/**
	 * 定義儲存客戶登入session的集合
	 */
	private static Map<String, HttpSession> sessions = new HashMap<String, HttpSession>();
	
	/**
	 * 定義儲存線上使用者數的集合
	 */
	private static Map<String, Integer> counts = new HashMap<String, Integer>();
	
	/**
	 * 加入session時的監聽方法
	 * 
	 * @param HttpSessionBindingEvent
	 * 				session事件
	 */
	public void attributeAdded(HttpSessionBindingEvent sbe) {
		if(LISTENER_NAME.equals(sbe.getName())){
			SysUser s = (SysUser) sbe.getValue();
			if(users.containsKey(s.getYhdh())) {
				HttpSession session = sessions.get(s.getYhdh());
				session.removeAttribute(LISTENER_NAME);
				session.invalidate();
			} 
			sessions.put(s.getYhdh(), sbe.getSession());
			users.put(s.getYhdh(), s);
		}
		Integer count = users.size();
		counts.put(LISTENER_COUNT, count);
	}
	
	/**
	 * session失效時的監聽方法
	 * 
	 * @param HttpSessionBindingEvent
	 * 				session事件
	 */
	public void attributeRemoved(HttpSessionBindingEvent sbe) {
		if(LISTENER_NAME.equals(sbe.getName())){
			// 從session集合中減去一個
			SysUser s = (SysUser) sbe.getValue();
			sessions.remove(s.getYhdh());
			users.remove(s.getYhdh());
			counts.put(LISTENER_COUNT, users.size());
		}
	}
	
	/**
	 * session覆蓋時的監聽方法
	 * 
	 * @param HttpSessionBindingEvent
	 * 				session事件
	 */
	public void attributeReplaced(HttpSessionBindingEvent sbe) {
		
	}
	
	public static Map<String, SysUser> getUsers() {
		return users;
	}
	
	public static Map<String, HttpSession> getSessions() {
		return sessions;
	}
	
	public static Map<String, Integer> getCounts() {
		return counts;
	}
	
}

監聽器寫好之後要在web.xml裡面配置一下.
  <listener>
    <listener-class>com.sunshine.monitor.comm.filter.SessionListener</listener-class>
  </listener>

如何使用呢,使用者登入時給session設定一個數據,獲取線上使用者數

		request.getSession().setAttribute(SessionListener.LISTENER_NAME, s);
		application.setAttribute("online", SessionListener.getCounts().get(SessionListener.LISTENER_COUNT));

頁面上的線上人數這樣獲取:

<c:out value="${online}"></c:out>

登出時,這樣寫:

	/**
	 * 登出移除sesson,從設定application的onlines屬性
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping
	public ModelAndView logout(HttpServletRequest request,
			HttpServletResponse response){
		ModelAndView mv = new ModelAndView(forwardLoginPath);
		HttpSession session = request.getSession();
		session.removeAttribute(SessionListener.LISTENER_NAME);
		session.invalidate();
		session.getServletContext().setAttribute("online", SessionListener.getCounts().get(SessionListener.LISTENER_COUNT));
		return mv;
	}

如果使用者非法退出,如直接關閉瀏覽器,關閉視窗等.這時session並不會立即失效.我嘗試過使用js監聽視窗關閉操作,然後移除session.可是這段js只適用於ie8及以下.最終放棄,只能等待session失效.session的失效時常是在web.xml裡面設定的.

session失效時,也是會觸發屬性移除時間的.