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


	com.demo.web.UserSessionListener

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();

以上,完

你可能感兴趣的:(Java,web)