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) 
The request is about to go out of scope of the web application.

void

requestInitialized(ServletRequestEvent sre) 
The request is about to come into scope of the web application.

  • ServletRequestAttributeListener

Method Summary

void

attributeAdded(ServletRequestAttributeEvent srae) 
Notification that a new attribute was added to the servlet request.

void

attributeRemoved(ServletRequestAttributeEvent srae) 
Notification that an existing attribute has been removed from the servlet request.

void

attributeReplaced(ServletRequestAttributeEvent srae) 
Notification that an attribute was replaced on the servlet request.

  • HttpSessionListener

Method Summary

void

sessionCreated(HttpSessionEvent se) 
Notification that a session was created.

void

sessionDestroyed(HttpSessionEvent se) 
Notification that a session is about to be invalidated.

  • HttpSessionAttributeListener

Method Summary

void

attributeAdded(HttpSessionBindingEvent se) 
Notification that an attribute has been added to a session.

void

attributeRemoved(HttpSessionBindingEvent se) 
Notification that an attribute has been removed from a session.

void

attributeReplaced(HttpSessionBindingEvent se) 
Notification that an attribute has been replaced in a session.

  • ServletContextListener

Method Summary

void

contextDestroyed(ServletContextEvent sce) 
Notification that the servlet context is about to be shut down.

void

contextInitialized(ServletContextEvent sce) 
Notification that the web application initialization process is starting.

  • ServletContextAttributeListener

Method Summary

void

attributeAdded(ServletContextAttributeEvent scab) 
Notification that a new attribute was added to the servlet context.

void

attributeRemoved(ServletContextAttributeEvent scab) 
Notification that an existing attribute has been removed from the servlet context.

void

attributeReplaced(ServletContextAttributeEvent scab) 
Notification that an attribute on the servlet context has been replaced.

  • HttpSessionBindingListener

Method Summary

void

valueBound(HttpSessionBindingEvent event) 
Notifies the object that it is being bound to a session and identifies the session.

void

valueUnbound(HttpSessionBindingEvent event) 
Notifies the object that it is being unbound from a session and identifies the session.

  • HttpSessionActivationListener

Method Summary

void

sessionDidActivate(HttpSessionEvent se) 
Notification that the session has just been activated.

void

sessionWillPassivate(HttpSessionEvent se) 
Notification that the session is about to be passivated.

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页面查看结果。
04-25 05:51