一、监听器简介
监听器就是一个Java程序,功能是监听另一个java对象变化(方法调用、属性变更)。
二、实现:
写一个类实现响应的接口
注册监听器利用web.xml或注解
8个监听器,分为了3种:
- 用来监听三大作用域的创建和销毁的监听器(除了page域)
A. ServletContextListener 用来监听ServletContext对象创建和销毁的监听器
创建:服务器启动,web应用加载后立即创建代表当前web应用的ServletContext对象
销毁:服务器关闭或web应用被移除出容器时,随着web应用的销毁而销毁
实现接口:
/**
*使用注解配置监听
*用来监听 servletCcontext创建和销毁
*/
@WebListener
public class TestListener implements ServletContextListener {
public TestListener() {
}
/**
* 销毁
*/
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("servletContext 被销毁了"+arg0.getServletContext());
}
/**
* 初始化
*/
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("servletContext 被创建出来了"+arg0.getServletContext().getContextPath());
}
}
注册 在web.xml 配置
<listener>
<listener-class> com.neuedu.Listener.TestListener</listener-class>
</listener>
B. HttpSessionListener 用来监听HttpSession对象创建和销毁的监听器
创建:第一次调用request.getSession方法时创建代表当前会话的session对象 。
销毁:超过30分钟没人用销毁(可以在web.xml通过session-timeout标签修改时间)/调用invalidate方法自杀/服务器非正常关闭时随着web应用的销毁而销毁,如果服务器是正常关闭会被钝化起来。
示例:
@WebListener
public class Test implements HttpSessionListener {
public Test() {
}
public void sessionCreated(HttpSessionEvent arg0) {
System.out.println("Session创建");
}
public void sessionDestroyed(HttpSessionEvent arg0) {
System.out.println("Session销毁");
}
}
当服务器正常关闭时,还存活着的session会随着服务器的关闭被以文件的形式存储在tomcat的work目录下,这个过程叫做session的钝化 。
当服务器再次正常开启时,服务器会找到之前的SESSIONS.ser文件从中恢复之前保存起来的session对象这个过程叫做session的活化 。
想要随着Session被钝化活化的对象(一般是bean)它的类必须实现Serializable接口。
示例:
编写实体类:
/**
*
* @类名: Users
* @描述: 必须实现序列化接口
*/
public class Users implements HttpSessionActivationListener, Serializable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Users() {
}
@Override
public void sessionDidActivate(HttpSessionEvent arg0) {
System.out.println(arg0.getSession().getId()+"被活化");
}
@Override
public void sessionWillPassivate(HttpSessionEvent arg0) {
System.out.println(arg0.getSession().getId()+"被钝化");
}
}
在Server.xml中配置:
<Context docBase="webweb" path="/webweb" reloadable="true"
source="org.eclipse.jst.jee.server:webweb">
<Manager className="org.apache.catalina.session.PersistentManager"
saveOnRestart="true" maxActiveSessions="1">
<Store className="org.apache.catalina.session.FileStore"
directory="d:/a">
</Store>
</Manager>
</Context>
className 不能变
saveOnRestart ="true" 能够进行存储
maxActiveSessions="n" n为最大的session数量
directory为存储路径
测试:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Users users = new Users();
HttpSession session=request.getSession();
session.setAttribute("users",users);
}


C. ServletRequestListener 用来监听ServletRequest对象创建和销毁的监听
创建:请求开始创建代表请求的request对象
销毁:请求结束时代表请求的request对象销毁
1) 用来监听三大作用域中属性变化的监听器
ServletContextAttributeListener
/**
*
*ServletContext属性监听
*/
@WebListener
public class TestAttrListener implements ServletContextAttributeListener {
public TestAttrListener() {
}
/**
* 添加属性
*/
public void attributeAdded(ServletContextAttributeEvent arg0) {
System.out.println("属性被加入到了域中" + arg0.getName() + ":" + arg0.getValue());
}
/**
* 移除属性
*/
public void attributeRemoved(ServletContextAttributeEvent arg0) {
System.out.println("属性被移除出了域中" + arg0.getName() + ":" + arg0.getValue());
}
/**
* 替换属性
*/
public void attributeReplaced(ServletContextAttributeEvent arg0) {
System.out.println("属性被替换在域中" + arg0.getName() + ":" + arg0.getValue() + ":"
+ arg0.getServletContext().getAttribute(arg0.getName()));
}
}
其中setvlet中代码核心为:
设置与改变属性
this.getServletContext().setAttribute("age", 23);
this.getServletContext().setAttribute("age", 24);
this.getServletContext().removeAttribute("age");
//下面这两个方法 和上面的类似
HttpSessionAttributeListener
ServletRequestAttributeListener
2) 使javabean自己感知自己在Session中状态变化的监听器,这两个监听器很特殊,不需要自己去写类实现也不需要在web.xml中注册,只要使javabean实现这个接口就能起作用
javabean 在session有下面这四种状态变化,两个监听器
1.HttpSessionBindingListener
javabean被绑定到session中
sessionDidActive(HttpSessionBindingEvent event)
javabean被移除绑定从session中
valueUnbound(HttpSessionBindingEvent event)方法
2.HttpSessionActivationListener
javabean随着session被钝化
sessionWillPassivate(HttpSessionBindingEvent event)
javabean随着session被活化
sessionDidActive(HttpSessionBindingEvent event)
三、在线人数统计
管理session,如果session销毁了就减少,如果登陆用户了就新增一个,但是如果是用户非法退出,如:未注销,关闭浏览器等,这个用户的session是管理不到的,可以使用HttpSessionListener接口或HttpSessionBindingListener接口来实现,通过监听session的新建和销毁来控制
- 登陆页面login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>登录</title>
</head>
<body>
<form action="LoginServlet" method="post">
用户名:
<input type="text" name="username" /> <br />
<input type="submit" value="登录" />
</form>
</body>
</html>
- 点击登陆后跳转的LoginServlet.java
/**
* 登录与注销Servlet
*/
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public LoginServlet() {
super();
}
/**
* 注销
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
// 取得登录的用户名
String username = (String) session.getAttribute("username");
// 销毁session
session.invalidate();
ServletContext application = request.getServletContext();
// 从在线列表中删除用户名
List onlineUserList = (List) application.getAttribute("onlineUserList");
onlineUserList.remove(username);
// 成功
response.sendRedirect("index.jsp");
}
/**
* 登录
*
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
// 取得登录的用户名
String username = request.getParameter("username");
// 把用户名保存进session
HttpSession session = request.getSession();
session.setAttribute("username", username);
//把用户名放入在线列表
ServletContext application = request.getServletContext();
List onlineUserList = (List)
application.getAttribute("onlineUserList");
// 第一次使用前,需要初始化
if (onlineUserList == null) {
onlineUserList = new ArrayList();
application.setAttribute("onlineUserList", onlineUserList);
}
onlineUserList.add(username);
// 成功
response.sendRedirect("index.jsp");
}
}
- 登录成功页面
<%@ page language="java" import="java.util.List" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>在线用户</title>
</head>
<body>
<h3>
您好:${username} [<a href="LoginServlet">注销</a>]
</h3>
当前在线用户:
<table>
<%
List onlineUserList = (List) application.getAttribute("onlineUserList");
for (int i = 0; i < onlineUserList.size(); i++) {
String onlineUsername = (String) onlineUserList.get(i);
%>
<tr>
<td><%=onlineUsername%></td>
</tr>
<%
}
%>
</table>
</body>
</html>
登陆成功跳转到显示页面result.jsp
点击注销页面logout.jsp页面
- 开始新建监听器
1、HttpSessionListener
添加类OnlineUserListener,继承HttpSessionListener,HttpSessionListener中有两个方法
sessionCreated(HttpSessionEvent event)与sessionDestroyed
(HttpSessionEvent event),前者是监听session的新建,后者是监听session的销毁。
/**
* 注解配置监听器
*/
@WebListener
public class OnlineUserListener implements HttpSessionListener {
public OnlineUserListener() {
}
public void sessionCreated(HttpSessionEvent arg0) {
System.out.println("新建session:" + arg0.getSession().getId());
}
public void sessionDestroyed(HttpSessionEvent arg0) {
HttpSession session = arg0.getSession();
ServletContext application = session.getServletContext();
// 取得登录的用户名
String username = (String) session.getAttribute("username");
// 从在线列表中删除用户名
List onlineUserList = (List) application.getAttribute("onlineUserList");
onlineUserList.remove(username);
System.out.println(username + "已经退出!");
}
}
web.xml配置:
<listener>
<listener-class>com.test.OnlineUserListener</listener-class>
</listener>
一旦监听器发现调用了sessionDestoryed方法就会把其用户从在线人数中delete,在下面两种情况下会发生sessionDestoryed事件:
a.执行session.invalidate()方法时
logout.jsp中调用了 session.invalidate()方法
b.session会话超时
session的默认超时事件是30分钟,30分钟后自动销毁session
- HttpSessionBindingListener
HttpSessionBindingListener虽然叫做监听器,但使用方法与HttpSessionListener完全不同。我们实际看一下它是如何使用的。新建类OnlineUserBindingListener,实现HttpSessionBindingListener接口,构造方法传入username参数,HttpSessionBindingListener内有两个方法valueBound
(HttpSessionBindingEvent event)和valueUnbound(HttpSessionBindingEvent event),前者为数据绑定,后者为取消绑定所谓对session进行数据绑定,就是调用session.setAttribute()把HttpSessionBindingListener保存进session中。 - 修改LoginServlet.java
request.setCharacterEncoding("UTF-8");
// 取得登录的用户名
String username = request.getParameter("username");
HttpSession session = request.getSession();
// 把用户名放入在线列表
session.setAttribute("onlineUserBindingListener", new OnlineUserBindingListener(username));
// 成功
response.sendRedirect("index.jsp");
这就是HttpSessionBindingListener和HttpSessionListener之间的最大区别:HttpSessionListener只需要设置到web.xml中就可以监听整个应用中的所有session。
HttpSessionBindingListener必须实例化后放入某一个session中,才可以进行监听。
从监听范围上比较,HttpSessionListener设置一次就可以监听所有session,HttpSessionBindingListener通常都是一对一的。
正是这种区别成就了HttpSessionBindingListener的优势,我们可以让每个listener对应一个username,这样就不需要每次再去session中读取username,进一步可以将所有操作在线列表的代码都移入listener,更容易维护。
- HttpSessionBindingListener实现:
/**
* 配置监听器
*/
@WebListener
public class OnlineUserBindingListener implements HttpSessionBindingListener {
String username;
public OnlineUserBindingListener(String username) {
this.username=username;
}
public OnlineUserBindingListener() {
}
/**
* 数据绑定
*/
public void valueBound(HttpSessionBindingEvent arg0) {
HttpSession session = arg0.getSession();
ServletContext application = session.getServletContext();
// 把用户名放入在线列表
List onlineUserList = (List) application.getAttribute("onlineUserList");
// 第一次使用前,需要初始化
if (onlineUserList == null) {
onlineUserList = new ArrayList();
application.setAttribute("onlineUserList", onlineUserList);
}
onlineUserList.add(this.username);
}
/**
* 解除绑定
*/
public void valueUnbound(HttpSessionBindingEvent arg0) {
HttpSession session = arg0.getSession();
ServletContext application = session.getServletContext();
// 从在线列表中删除用户名
List onlineUserList = (List) application.getAttribute("onlineUserList");
onlineUserList.remove(this.username);
System.out.println(this.username + "退出。");
}
}
- 这里可以直接使用listener的username操作在线列表,不必再去担心session中是否存在username。
valueUnbound的触发条件是以下三种情况:
a.执行session.invalidate()时。
b.session超时,自动销毁时。
c.执行session.setAttribute("onlineUserListener", "其他对象");
或session.removeAttribute("onlineUserListener");
将listener从session中删除时。
因此,只要不将listener从session中删除,就可以监听到session的销毁。