JSP+Servlet + Tomcat实现用户登录(五)使用listener实现在线(游客)人数统计【JavaWeb、无数据库】
1.创建一个监听类,添加注解
添加@WebListener
用于声明类为监听器,至少一个下方接口
- ServletContextListener
- ServletContextAttributeListener
- ServletRequestListener
- ServletRequestAttributeListener
- HttpSessionListener
- HttpSessionAttributeListener
下面是@WebListener的属性列表。
Name | Type | Required | Description |
---|---|---|---|
value | String | Optional | Description of the listener. |
实现HttpSessionListener
接口
HttpSessionListener:用于监听HttpSession域中对象的创建和销毁
为什么选择监听Session就可以实现监听在线人数呢?
我们知道在servlet中有以下三个对象可以监听
request
——ServletRequestListenersession
——HttpSessionListenerservletContext
——ServletContextListenerrequest会对所有请求进行监听,但是无法区分用户,因此无法做到对在线人数的监听
servlet 仅仅只会服务器的开启和关闭进行监听,无法做到对用户的监听
因此就只剩下
session
了在服务器第一次接受一个用户请求就会为分配一个sessionId,在
有效期结束
或者用户主动关闭一段时间
,session就会被销毁(session默认有效时间30分钟)
实现ServletContextListener接口
我们需要在servlet创建时,将在线人数的变量设置进入servlet
的上下文中
2.实现接口方法
ctrl
+o
对接口中的方法进行实现
这里可以不实现
contextDestroyed
方法
package com.example.Login;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class OnlineCount implements HttpSessionListener, ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
}
@Override
public void sessionCreated(HttpSessionEvent se) {
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
}
}
3.处理servlet创建逻辑
我们需要在servlet服务器开启后,对变量进行赋值初始化
- 获取servlet上下文
- 定义表示变量的名字——不可更改
- 设置初始值(0)
public final static String cntName = "onlineCnt";
@Override
public void contextInitialized(ServletContextEvent sce) {
context = sce.getServletContext();
context.setAttribute(cntName,0);
}
4.处理创建session逻辑
首先获取此时servlet上下文对象
获取session数目
判断是否存在
- 存在——自增
- 不存在——赋值为1
并将值设置进入servlet上下文中
@Override
public void sessionCreated(HttpSessionEvent se) {
// 获取上下文对象
ServletContext context = se.getServletContext();
// 获取sessionId
String sessionId = se.getSession().getId();
// 获取session数目
Integer count = (Integer) context.getAttribute(sessionId);
context.setAttribute(cntName , ++count);
}
5.处理销毁session逻辑
与创建session逻辑基本一致,只需对count减少即可
@Override
public void sessionDestroyed(HttpSessionEvent se) {
// 获取上下文对象
ServletContext context = se.getServletContext();
// 获取session数目
Integer count = (Integer) context.getAttribute(cntName);
context.setAttribute(cntName , --count);
}
6.优化代码,封装逻辑
我们发现创建和销毁session的步骤基本一致
- 获取session数目
所以,可对这两者进行逻辑封装
公有变量 + 方法
公有变量
private ServletContext context;
private Integer count;
获取方法
// 获取session数目
private void getSessionCount(){
count = (Integer) context.getAttribute(cntName);
}
7.显示人数
在index.jsp
中显示在线人数
<p>
<span>在线人数:</span>
<span>${onlineCnt}</span>
</p>
这里的
onlineCnt
与类中的cntName相对应
阶段成果
问题解决
为什么会开始就会出现两次呢?
我是通过内置tomcat运行的,默认的配置就是idea会代替我们打开浏览器
在idea打开页面时,也会与页面建立起一个session
解决办法
勾选掉After launch
然后,手动打开网址即可
OK,完整的登录功能就已经完成了
但是,其实这样对在线人数的监听是不精准的,因为我们打开不同的页面登录不同的账号也会算作一个不同的人,准确来说监听的是游客人数
若需要精细的对真实的用户进行监听登录,则可能需要创建多个用户进行实现
阶段代码
OnlineCount
package com.example.Login;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class OnlineCount implements HttpSessionListener, ServletContextListener {
public final static String cntName = "onlineCnt";
private ServletContext context;
private Integer count;
// 获取session数目
private void getSessionCount(){
count = (Integer) context.getAttribute(cntName);
}
@Override
public void contextInitialized(ServletContextEvent sce) {
context = sce.getServletContext();
context.setAttribute(cntName,0);
}
@Override
public void sessionCreated(HttpSessionEvent se) {
this.getSessionCount();
context.setAttribute(cntName , ++count);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
this.getSessionCount();
context.setAttribute(cntName , --count);
}
}
index.jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>登录成功</title>
</head>
<body>
<h1>
Welcome,
<span style="color: green">
${sessionScope.userName}
</span>
<p>
<span>在线人数:</span>
<span>${onlineCnt}</span>
</p>
</h1>
<form action="logout">
<input type="submit" value="退出登录" />
</form>
</body>
</html>