目录
1、使用 HttpSessionListener 和 HttpSessionAttributeListener 实现
2、使用 HttpSessionBindingListener 实现
本节我们利用 Servlet 监听器接口,完成一个统计网站在线人数的案例。当一个用户登录后,显示欢迎信息,同时显示出当前在线人数和用户名单。当用户退出登录或 Session 过期时,从在线用户名单中删除该用户,同时将在线人数减 1。
本案例可以通过如下 2 种方案实现:
- 使用 HttpSessionListener 和 HttpSessionAttributeListener 实现;
- 使用 HttpSessionBindingListener 实现。
1、使用 HttpSessionListener 和 HttpSessionAttributeListener 实现
创建 login.html,代码如下。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/web/LoginServlet" method="GET">
<table border="1" width="50%">
<tr>
<td colspan="2" align="center">欢迎登录 LoginServlet !</td>
</tr>
<tr>
<td>账号</td>
<td><input type="text" name="username" /></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提交" />
</td>
</tr>
</table>
</form>
</body>
</html>
创建名称为 LoginServlet 的 Servlet 类,代码如下。
package swadian.servlet.listener;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
/**
* @author swadian
* @date 2022/2/14
* @Version 1.0
*/
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@SuppressWarnings("unchecked")
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
//设置页面输出格式
response.setContentType("text/html;charset=UTF-8");
//修改request缓冲区的字符集为UTF-8
request.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
//获取表单数据
String username = request.getParameter("username");
//查看当前会话是否已有账号登录
String logined = (String) request.getSession().getAttribute("username");
//当前会话已有账号登录
if ("".equals(username) || username == null) {
System.out.println("非法操作,您没有输入用户名");
response.sendRedirect("/web/login.html");
} else {
if (!"".equals(logined) && logined != null) {
System.out.println("您已经登录,重复登录无效,请先退出当前账号重新登录!");
writer.write("<h1>LoginServlet 提醒您!</h1>"
+ "<h3>您好,您已经登录了账户:" + logined + "</h3>"
+ "如要登录其他账号,请先退出当前账号重新登录!");
} else {// 将当前账号加入会话中
request.getSession().setAttribute("username", username);
writer.write("<h1>LoginServlet</h1>"
+ "<h3>" + username + ":欢迎您的到来!</h3>");
}
// 从上下文中获取已经登录账号的集合
List<String> onLineUserList = (List<String>) request.getServletContext().getAttribute("onLineUserList");
if (onLineUserList != null) {
// 向页面输出结果
writer.write(
"<h3> 当前在线人数为:" + onLineUserList.size() + "</h3>" + "<table border=\"1\" width=\"50%\">");
for (int i = 0; i < onLineUserList.size(); i++) {
writer.write("<tr>\r\n" + "<td align=\"center\">" + onLineUserList.get(i) + " </td>\r\n" + "</tr>");
}
}
writer.write("</table><br/>" + "<a href=\"/web/LogoutServlet\">退出登录</a>");
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
doGet(request, response);
}
}
当有对象添加到session中时,session.setAttribute("object",other) 触发 attributeAdded 事件,当该对象从 session 移除时,session.removeAttribute("object") 触发 attriubteRemoved 事件,当该属性的值发生变化时, session.replaceAttribute("object",another) 触发 attributeRepalced 事件。
注意:只要有对象保存到 session 中或从 session 中移除或改变属性的值都会触发相应事件,不论该对象是否实现了 AttributeListener。
创建名称为 MySessionListener 的监听器类,代码如下。
package swadian.servlet.listener;
import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.util.ArrayList;
import java.util.List;
/**
* @author swadian
* @date 2022/2/15
* @Version 1.0
* @Description 监听器
*/
@WebListener
public class MySessionListener implements HttpSessionListener, HttpSessionAttributeListener {
@SuppressWarnings("unchecked")
@Override//向Session添加属性时立即执行:LoginServlet->MySessionListener->LoginServlet
public void attributeAdded(HttpSessionBindingEvent se) {
System.out.println("HttpSessionAttributeListener****attributeAdded()方法开始工作*******************");
//从上下文中获取已经登录账号的集合
List<String> onLineUserList = (List<String>) se.getSession().getServletContext().getAttribute("onLineUserList");
//在上下文中没有登陆用户
if (onLineUserList == null || onLineUserList.size() == 0) {
onLineUserList = new ArrayList<String>();
}
String username = (String) se.getSession().getAttribute("username");
//向已登录集合中添加当前账号
onLineUserList.add(username);
System.out.println("用户:" + username + " 成功加入在线用户列表");
for (int i = 0; i < onLineUserList.size(); i++) {
System.out.println(onLineUserList.get(i));
}
se.getSession().getServletContext().setAttribute("onLineUserList", onLineUserList);
}
@SuppressWarnings("unchecked")//Session销毁时执行
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
ServletContext application = session.getServletContext();
List<String> onlineUserList = (List<String>) application.getAttribute("onLineUserList");
// 取得登录的用户名
String username = (String) session.getAttribute("username");
if (!"".equals(username) && username != null && onlineUserList != null && onlineUserList.size() > 0) {
// 从在线列表中删除用户名
onlineUserList.remove(username);
System.out.println(username + "已经退出!");
System.out.println("当前在线人数为:" + onlineUserList.size());
} else {
System.out.println("会话已经销毁!");
}
}
@Override
public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
}
@Override
public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
}
public MySessionListener() {
}
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
}
}
创建名称为 LogoutServlet 的 Servlet 类,代码如下。
package swadian.servlet.listener;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author swadian
* @date 2022/2/15
* @Version 1.0
*/
@WebServlet("/LogoutServlet")
public class LogoutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//退出登录操作,将此次session进行销毁
//触发HttpSessionListener监听器的sessionDestroyed方法
request.getSession().invalidate();
//跳转回登录页面
response.sendRedirect("/web/login.html");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
启动 Tomcat,在谷歌浏览器地址栏输入“http://localhost:8080/web/login.html”,访问 login.html,结果如下图。
输入账号信息后,点击提交,结果如下图。// 登陆前已经使用其他浏览器登录了一个账号
在相同的浏览器,再次登录susan账号,点击提交,结果如下图。
2、使用 HttpSessionBindingListener 实现
// 登录页 login.html 保持不变
创建名称为 MyBindingListener 的监听器类,代码如下。
package swadian.servlet.listener_servlet;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import java.util.ArrayList;
import java.util.List;
/**
* @author swadian
* @date 2022/2/17
* @Version 1.0
*/
public class MyBindingListener implements HttpSessionBindingListener {
private String username;
public MyBindingListener(String username) {
super();
this.username = username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public MyBindingListener() {
}
@SuppressWarnings("unchecked")
public void valueBound(HttpSessionBindingEvent event) {
HttpSession session = event.getSession();
ServletContext application = session.getServletContext();
// 把用户名放入在线列表
List<String> onlineUserList = (List) application.getAttribute("onlineUserList");
// 第一次使用前,需要初始化
if (onlineUserList == null) {
onlineUserList = new ArrayList<String>();
}
onlineUserList.add(this.username);
application.setAttribute("onlineUserList", onlineUserList);
System.out.println("*******用户:" + this.username + " 已经成功加入在线用户列表");
}
@SuppressWarnings("unchecked")
public void valueUnbound(HttpSessionBindingEvent event) {
HttpSession session = event.getSession();
ServletContext application = session.getServletContext();
// 从在线列表中删除用户名
List<String> onlineUserList = (List<String>) application.getAttribute("onlineUserList");
onlineUserList.remove(this.getUsername());
application.setAttribute("onlineUserList", onlineUserList);
System.out.println(this.username + "退出。");
System.out.println("当前在线人数:" + onlineUserList.size());
}
}
创建名称为 LoginServlet 的 Servlet 类,代码如下。
// HttpSessionBindingListener 方式有代码入侵,需要使用 new MyBindingListener(username)
注意:只有当该监听器(MyBindingListener)保存到 session 中或从 session 移除时才会触发事件,其他没有实现该listener对象保存到session时不会触发该事件。
package swadian.servlet.listener_servlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
/**
* @author swadian
* @date 2022/2/17
* @Version 1.0
*/
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@SuppressWarnings("unchecked")
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
//设置页面输出格式
response.setContentType("text/html;charset=UTF-8");
request.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
//获取表单数据->乱码处理
String username = request.getParameter("username");
username = new String(username.getBytes("ISO-8859-1"), "utf-8");
//查看当前会话是否已有账号登录
MyBindingListener loginedDemo = (MyBindingListener) request.getSession().getAttribute("onlineUserBindingListener");
//当前会话已有账号登录
if ("".equals(username) || username == null) {
System.out.println("非法操作,您没有输入用户名");
response.sendRedirect("/web/login.html");
} else {
if (loginedDemo != null) {
String logined = loginedDemo.getUsername();
System.out.println("您已经登录,重复登录无效,请先退出当前账号重新登录!");
writer.write("<h1>LoginServlet 提醒您 !</h1>"
+ "<h3>您好,您已经登录了账户:" + logined + "</h3>"
+ "如要登录其他账号,请先退出当前账号重新登录!");
// 登陆页面为填写内容
} else {
//将当前账号加入会话中
request.getSession().setAttribute("onlineUserBindingListener", new MyBindingListener(username));
writer.write("<h1>LoginServlet 欢迎您!</h1>"
+ "<h3>" + username + ": 欢迎您的到来</h3>");
}
//向页面输出结果
//从上下文中获取已经登录账号的集合
List<String> onLineUserList = (List<String>) request.getServletContext().getAttribute("onlineUserList");
System.out.println("当前在线用户为:");
if (onLineUserList != null) {
for (int i = 0; i < onLineUserList.size(); i++) {
System.out.println(onLineUserList.get(i));
}
}
System.out.println("********************************");
writer.write("<h1> 当前在线人数为:" + onLineUserList.size() + "</h1>"
+ "<table border=\"1\" width=\"50%\">");
for (int i = 0; i < onLineUserList.size(); i++) {
writer.write("<tr>\r\n" +
"<td align=\"center\">" + onLineUserList.get(i) + " </td>\r\n" +
"</tr>");
}
writer.write("</table><br/>"
+ "<a href=\"/web/LogoutServlet\">退出登录</a>");
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
doGet(request, response);
}
}
创建名称为 LogoutServlet 的 Servlet 类,代码如下。
package swadian.servlet.listener_servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author swadian
* @date 2022/2/17
* @Version 1.0
*/
@WebServlet("/LogoutServlet")
public class LogoutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//退出登录操作,将此次session进行销毁
//触发HttpSessionListener监听器的sessionDestroyed方法
request.getSession().invalidate();
//跳转回登录页面
response.sendRedirect("/web/login.html");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
启动 Tomcat,在谷歌浏览器地址栏输入“http://localhost:8080/web/login.html”,访问 login.html,结果如下图。
输入账号信息后,点击提交,结果如下图。
HttpSessionBindingListener和HttpSessionAttributeListener区别
HttpSessionBindingListener和HttpSessionAttributeListener区别_fjkxyl的博客-CSDN博客