1. 监听器概述
1.1. 什么是监听器
做过Swing或者AWT图像界面Java程序开发的话,应该对Listener与Event非常熟悉。Swing或者AWT中通过Listener与Event来处理事件,如鼠标事件、键盘事件等。先实现一个Listener接口,然后通过addListener()方法把Listener绑定到某个控件上,单机按钮时就会调用Listener的相应方法,并传回一个Event对象。
Java Web程序也一样,使用Listener与Event完成相应事件的处理。使用Listener不需要关注该类事件是怎样触发的或者怎么调用相应的Listener,只要记住该类事件触发时一定会调用相应的Listener。遵循Servlet规范的服务器完成了相应的工作。开发者只要在Listener里编写相关代码就OK了。
1.2. 八大监听器
Java Web一共提供了八个监听器供使用,分别用于监听Request、Session和ServletContext等的创建与销毁、属性变化。这八个监听器分别如下:
- ServletRequestListner
Method Summary | |
void | requestDestroyed(ServletRequestEvent sre) |
void | requestInitialized(ServletRequestEvent sre) |
- ServletRequestAttributeListener
Method Summary | |
void | attributeAdded(ServletRequestAttributeEvent srae) |
void | attributeRemoved(ServletRequestAttributeEvent srae) |
void | attributeReplaced(ServletRequestAttributeEvent srae) |
- HttpSessionListener
Method Summary | |
void | sessionCreated(HttpSessionEvent se) |
void | sessionDestroyed(HttpSessionEvent se) |
- HttpSessionAttributeListener
Method Summary | |
void | attributeAdded(HttpSessionBindingEvent se) |
void | attributeRemoved(HttpSessionBindingEvent se) |
void | attributeReplaced(HttpSessionBindingEvent se) |
- ServletContextListener
Method Summary | |
void | contextDestroyed(ServletContextEvent sce) |
void | contextInitialized(ServletContextEvent sce) |
- ServletContextAttributeListener
Method Summary | |
void | attributeAdded(ServletContextAttributeEvent scab) |
void | attributeRemoved(ServletContextAttributeEvent scab) |
void | attributeReplaced(ServletContextAttributeEvent scab) |
- HttpSessionBindingListener
Method Summary | |
void | valueBound(HttpSessionBindingEvent event) |
void | valueUnbound(HttpSessionBindingEvent event) |
- HttpSessionActivationListener
Method Summary | |
void | sessionDidActivate(HttpSessionEvent se) |
void | sessionWillPassivate(HttpSessionEvent se) |
1.3. 自定义监听器
如果要自定义一个监听器的话,需要如下几步:
- 创建一个自定义监听器类,并实现上述八个监听器中的一个或多个。
- 配置Web工程的web.xml文件,格式如下:
<listener>
<listener-class>自定义监听器的完整路径</listener-class>
</listener>
2. 创建销毁监听器
2.1. ServletRequestListener
ServletRequestListener用于监听Request的创建与销毁。用户每次请求Request都会执行requestInitialized()方法,Request处理完毕自动销毁前执行requestDestroyed()方法。
需要注意的是如果一个页面内含有多个图片等元素,则请求一次页面可能会触发多次Request事件。
2.2. HttpSessionListener
HttpSessionListener用于监听Session的创建与销毁。创建Session时执行sessionCreated()方法,销毁Session或Session超时时执行sessionDestroyed()方法。该Listener可用于收集在线者信息。
2.3. ServletContextListener
ServletContextListener用于监听ServletContext的创建与销毁。服务器启动或者部署Web应用程序时执行contextInitialized()方法,服务器关闭或关闭Web应用程序时执行contextDestroyed()方法。该Listener可用于启动时获取web.xml文件中配置的初始化参数。
2.4. 监听Request、Session及ServletContext
编写一个监听器,分别实现ServletRequestListener、HttpSessionListener和ServletContextListener,并重写上述三个接口提供的方法。
- 编写一个自定义监听器。
public class ListenerTest implements ServletRequestListener, HttpSessionListener, ServletContextListener {
/**
* requestInitialized()用于监听Request对象的创建.
* * 该方法在Request对象创建后被调用.
*/
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("客户端向服务器端发送了一次请求......");
}
/**
* requestDestroyed()用于监听Request对象的销毁.
* * 该方法在Request对象销毁前被调用.
*/
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("客户端的请求结束了......");
}
/**
* sessionCreated()用于监听Session对象的创建.
* * 该方法在Session对象创建后被调用.
*/
public void sessionCreated(HttpSessionEvent se) {
System.out.println("新创建了一个session......");
}
/**
* sessionDestroyed()用于监听Session对象的销毁.
* * 该方法在Session对象销毁前被调用.
*/
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("销毁了一个session......");
}
/**
* contextInitialized()用于监听ServletContext对象的创建.
* * 该方法在ServletContext对象创建后被调用.
*/
public void contextInitialized(ServletContextEvent sce) {
System.out.println("Web应用即将启动......");
}
/**
* contextDestroyed()用于监听ServletContext对象的销毁.
* * 该方法在ServletContext对象销毁前被调用.
*/
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("Web应用即将关闭......");
}
}
- 在web.xml文件中配置自定义监听器。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<listener>
<listener-class>app.java.listener.ListenerTest</listener-class>
</listener>
</web-app>
3. 属性操作监听器
3.1. ServletRequestAttributeListener
ServletRequestAttributeListener用于监听Request对象添加、更新和移除属性。Request添加属性时执行requestAdded()方法,Request对象更新属性时执行requestReplaced()方法,Request对象移除属性时执行requestRemoved()方法。
3.2. HttpSessionAttributeListener
HttpSessionAttributeListener用于监听Session对象添加、更新和移除属性。Session添加属性时执行sessionAdded()方法,Session对象更新属性时执行sessionReplaced()方法,Session对象移除属性时执行sessionRemoved()方法。
3.3. ServletContextAttributeListener
ServletContextAttributeListener用于监听ServletContext对象添加、更新和移除属性。ServletContext添加属性时执行contextAdded()方法,ServletContext对象更新属性时执行contextReplaced()方法,Session对象移除属性时执行contextRemoved()方法。
3.4. 监听ServletRequestAttributeListener、HttpSessionAttributeListener及ServletContextAttributeListener
编写一个监听器,分别实现ServletRequestAttributeListener、HttpSessionAttributeListener和ServletContextAttributeListener,并重写上述三个接口提供的方法。
- 编写一个自定义监听器。
public class AttributeListenerTest implements ServletRequestAttributeListener, HttpSessionAttributeListener, ServletContextAttributeListener {
/**
* attributeAdded(ServletRequestAttributeEvent srae)用于监听Request对象添加属性.
* * 该方法在Request对象添加属性后被调用.
*/
public void attributeAdded(ServletRequestAttributeEvent srae) {
System.out.println("成功向Request对象添加了一个属性......");
}
/**
* attributeRemoved(ServletRequestAttributeEvent srae)用于监听Request对象删除属性.
* * 该方法在Request对象删除属性前被调用.
*/
public void attributeRemoved(ServletRequestAttributeEvent srae) {
System.out.println("成功向Request对象删除了一个属性......");
}
/**
* attributeReplaced(ServletRequestAttributeEvent srae)用于监听Request对象更新属性.
* * 该方法在Request对象更新属性前被调用.
*/
public void attributeReplaced(ServletRequestAttributeEvent srae) {
System.out.println("成功向Request对象更新了一个属性......");
}
/**
* attributeAdded(HttpSessionBindingEvent se)用于监听Session对象添加属性.
* * 该方法在Session对象添加属性后被调用.
*/
public void attributeAdded(HttpSessionBindingEvent se) {
System.out.println("成功向Session对象添加了一个属性......");
}
/**
* attributeRemoved(HttpSessionBindingEvent se)用于监听Session对象删除属性.
* * 该方法在Session对象删除属性前被调用.
*/
public void attributeRemoved(HttpSessionBindingEvent se) {
System.out.println("成功向Session对象删除了一个属性......");
}
/**
* attributeReplaced(HttpSessionBindingEvent se)用于监听Session对象更新属性.
* * 该方法在Session对象更新属性前被调用.
*/
public void attributeReplaced(HttpSessionBindingEvent se) {
System.out.println("成功向Session对象更新了一个属性......");
}
/**
* attributeAdded(ServletContextAttributeEvent scab)用于监听ServletContex对象添加属性.
* * 该方法在ServletContex对象添加属性后被调用.
*/
public void attributeAdded(ServletContextAttributeEvent scab) {
System.out.println("成功向ServletContex对象添加了一个属性......");
}
/**
* attributeRemoved(ServletContextAttributeEvent scab)用于监听ServletContex对象删除属性.
* * 该方法在ServletContex对象删除属性前被调用.
*/
public void attributeRemoved(ServletContextAttributeEvent scab) {
System.out.println("成功向ServletContex对象删除了一个属性......");
}
/**
* attributeReplaced(ServletContextAttributeEvent scab)用于监听ServletContex对象更新属性.
* * 该方法在ServletContex对象更新属性前被调用.
*/
public void attributeReplaced(ServletContextAttributeEvent scab) {
System.out.println("成功向ServletContex对象更新了一个属性......");
}
}
- 在web.xml文件中配置自定义监听器。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<listener>
<listener-class>app.java.listener.AttributeListenerTest</listener-class>
</listener>
</web-app>
4. Session绑定监听器
4.1. JavaBean感知监听
HttpSessionBindingListener用于当JavaBean对象被放到Session里时执行valueBound()方法,当JavaBean对象从Session移除时执行valueUnBound()方法。JavaBean必须实现该Listener接口。
- 创建一个JavaBean,实现HttpSessionBindingListener接口。
public class User implements HttpSessionBindingListener {
private String name;
private int age;
private String job;
public User(String name, int age, String job) {
this.name = name;
this.age = age;
this.job = job;
}
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 String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + ", job=" + job + "]";
}
/**
* valueBound()将该JavaBean对象放置到Session时被调用.
*/
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("该JavaBean被添加到session中......");
}
/**
* valueUnbound()将该JavaBean对象从Session移除时被调用.
*/
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("该JavaBean从session中被移除......");
}
}
- 创建一个Servlet用于将JavaBean对象放置到Session和从Session移除。
public class BeanServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
session.setAttribute("user", new User("zhangwuji", 18, "jiaozhu"));
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
session.removeAttribute("user");
}
}
使用HttpSessionBindingListener监听器时,不需要配置web.xml文件。
5. Session钝化与活化
5.1. Session序列化
所谓Session序列化就是指当Tomcat服务器关闭时Session会被保存到本地硬盘中,当Tomcat服务器启动时Session会从本地硬盘读取到内存中的过程。
- 创建一个Servlet用于向Session中存放数据内容。
public class SetSessionServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
session.setAttribute("name", "zhangwuji");
System.out.println("成功向session存储了数据......");
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
- 创建一个Servlet用于从Session中读取存放的数据内容。
public class GetSessionServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
String name = (String) session.getAttribute("name");
System.out.println("session中存储的数据内容为: "+name+"......");
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
- 发布Web工程到Tomcat服务器,并启动Tomcat服务器。访问向Session存储数据的Servlet。
- 关闭Tomcat服务器,查看${CATALINA_HOME}\work\Catalina\localhost\Web工程名目录。
- 重新启动Tomcat服务器,访问从Session读取存储数据的Servlet。
当Tomcat服务器被重新启动读取Session内容之后,序列化到本地硬盘中的Session文件会自动销毁。
如果想要关闭Session的序列化,可以修改Tomcat安装目录中conf目录的context.xml文件。具体内容如下:
<Manager pathname=""/>
5.2. Session钝化与活化
当Session长时间不被使用时(没有超时),将Session里的内容保存到本地硬盘中,这个过程叫做钝化。当Session重新被使用时,将保存到本地硬盘中的Session里的内容重新读取,这个过程叫做活化。
- 创建一个Servlet用于向Session中存放数据内容。
public class SetSessionServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
session.setAttribute("name", "zhangwuji");
System.out.println("成功向session存储了数据......");
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
- 创建一个Servlet用于从Session中读取存放的数据内容。
public class GetSessionServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
String name = (String) session.getAttribute("name");
System.out.println("session中存储的数据内容为: "+name+"......");
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
- 修改Tomcat安装目录/conf目录/ Catalina目录/ localhost目录中,创建一个名为Web工程名的xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- maxIdleSwap:指定多长时间后Session会被钝化.(单位为分钟) -->
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1" >
<!--
directory:指定钝化文件的保存目录.
钝化文件保存路径:${CATALINA_HOME}\work\Catalina\localhost\Web工程名\${sessionid}.session
-->
<Store className="org.apache.catalina.session.FileStore" directory="mysession" />
</Manager>
</Context>
钝化文件在重新被使用时,不会自动销毁。
6. 监听器案例
6.1. 统计在线人数
利用Java Web的监听器技术,实现在线人数统计的案例,具体实现步骤如下:
- 创建一个监听器,实现ServletContextListener接口,用于初始化在线人数为0。
public class OnLineCountServletContextListener implements
ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
// 通过 事件对象,获得事件源ServletContext
ServletContext servletContext = sce.getServletContext();
// 只会执行一次
servletContext.setAttribute("onlinecount", 0);
}
public void contextDestroyed(ServletContextEvent sce) {}
}
- 创建一个监听器,实现HttpSessionListener接口,用于统计在线人数。
public class OnLineCountHttpSessionListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent se) {
// 获得ServletContext
ServletContext servletContext = se.getSession().getServletContext();
// 获得原来在线人数
int onlinecount = (Integer) servletContext.getAttribute("onlinecount");
System.out.println(se.getSession().getId() + "在线了...");
servletContext.setAttribute("onlinecount", onlinecount + 1);
}
public void sessionDestroyed(HttpSessionEvent se) {
// 获得ServletContext
ServletContext servletContext = se.getSession().getServletContext();
// 获得原来在线人数
int onlinecount = (Integer) servletContext.getAttribute("onlinecount");
System.out.println(se.getSession().getId() + "离线了...");
servletContext.setAttribute("onlinecount", onlinecount - 1);
}
}
- 配置Web工程的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<listener>
<listener-class>app.java.demo.OnLineCountServletContextListener</listener-class>
</listener>
<listener>
<listener-class>app.java.demo.OnLineCountHttpSessionListener</listener-class>
</listener>
</web-app>
- 创建一个JSP页面用于显示在线人数。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>在线人数统计案例</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<h1>在线人数:${applicationScope.onlinecount }</h1>
</body>
</html>
- 发布Web工程到Tomcat服务器,并启动Tomcat服务器。访问对应的JSP页面查看结果。