JavaWeb Listener
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页面查看结果。
没有高深的知识,没有进阶的技巧,万丈高楼平地起~!