在统计在线人数的时候,分为两种情况的统计,一种是统计访问该网站的人数(不登录),另外一种就是登录的人数。
首先在容器启动时,我们可以声明一个ServletContext对象,并通过setAttribute方法初始化访问人数为0,
第一种情况下,每当有浏览器访问网站的时候就会创建一个session,并调用HttpSessionListener的sessionCreated的方法对访问人数增一,在会话消亡时调用HttpSessionListener的sessionDestroyed来对访问人数减一,但是问题来了,我们可以知道会话的消亡只能通过两种方式,一种是等待其消亡时间到,另外一种就是使用session.invalidate()来手动使其消亡,而关闭浏览器并不能使session消亡,所以在关闭浏览器后,消亡时间前,是不会执行sessionDestroyed方法。后来想到用js来触发关闭浏览器的事件再交由servlet处理,然而,我们无法再前端区分用户是刷新还是关闭浏览器,所以还是无法完成我们的目标,只能借助session的超时来处理,但无法做到十分实时,只能将超时时间设置的短一些,同时使用空请求一直保持与后台交互。
第二种情况下,每当有用户登录,session就会添加一个键值对,可以利用HttpSessionAttributeListener的attributeAdded方法来对用户在线人数增一,在退出账户时调用attributeRemoved方法,但是如果用户直接浏览器退出,则仍然无法调用该方法,解决方法同上。
package Listener; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; import javax.servlet.http.*; @WebListener public class ListenerDemo implements ServletContextListener, HttpSessionListener, HttpSessionAttributeListener { // Public constructor is required by servlet spec public ListenerDemo() { } // ------------------------------------------------------- // ServletContextListener implementation // ------------------------------------------------------- public void contextInitialized(ServletContextEvent sce) { /* This method is called when the servlet context is initialized(when the Web application is deployed). You can initialize servlet context related data here. */ ServletContext application = sce.getServletContext(); application.setAttribute("onlineCount", 0); application.setAttribute("userCount", 0); System.out.println((int)application.getAttribute("onlineCount")); } public void contextDestroyed(ServletContextEvent sce) { /* This method is invoked when the Servlet Context (the Web application) is undeployed or Application Server shuts down. */ } // ------------------------------------------------------- // HttpSessionListener implementation // ------------------------------------------------------- public void sessionCreated(HttpSessionEvent se) { /* Session is created. */ ServletContext application = se.getSession().getServletContext(); int count = (int)application.getAttribute("onlineCount"); ++count; System.out.println(count); //如果不让IDEA自动打开浏览器,此处的在线人数正常 application.setAttribute("onlineCount", count); } public void sessionDestroyed(HttpSessionEvent se) { /* Session is destroyed. */ //之所以关闭浏览器人数未减少,是由于关闭浏览器后session是没有消亡,故不会执行此方法,只能通过设置消亡时长或手动,解决问题:利用js捕获关闭浏览器的事件才触发 System.out.println("消亡"); ServletContext application = se.getSession().getServletContext(); int count = (int)application.getAttribute("onlineCount"); --count; application.setAttribute("onlineCount", count); } // ------------------------------------------------------- // HttpSessionAttributeListener implementation // ------------------------------------------------------- public void attributeAdded(HttpSessionBindingEvent sbe) { /* This method is called when an attribute is added to a session. */ if(sbe.getName().equals("username")) { ServletContext application = sbe.getSession().getServletContext(); int count = (int)application.getAttribute("userCount"); ++count; application.setAttribute("userCount", count); } } public void attributeRemoved(HttpSessionBindingEvent sbe) { /* This method is called when an attribute is removed from a session. */ //用户退出减一 } public void attributeReplaced(HttpSessionBindingEvent sbe) { /* This method is invoked when an attibute is replaced in a session. */ } }
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <error-page> <error-code>404</error-code> <location>/error.jsp</location> </error-page> <session-config> <session-timeout>30</session-timeout> <!--设置会话存活时间为30分钟 --> </session-config> </web-app>