HttpSessionListener与HttpSessionAttributeListener应用实例教程



HttpSessionListener与HttpSessionAttributeListener应用实例教程。使用HttpSessionListener和HttpSessionAttributeListener(1)

HttpSessionListener用于监听用户session的创建和销毁,实现该接口的监听器需要实现如下两个方法。

sessionCreated(HttpSessionEvent se):用户与服务器的会话开始、创建时时触发该方法。

sessionDestroyed(HttpSessionEvent se):用户与服务器的会话断开、销毁时触发该方法。

HttpSessionAttributeListener则用于监听HttpSession(session)范围内属性的变化,实现该接口的监听器需要实现attributeAdded、attributeRemoved、attributeReplaced三个方法。由此可见,HttpSessionAttributeListener与ServletContextAttributeListener的作用相似,都用于监听属性的改变,只是HttpSessionAttributeListener监听session范围内属性的改变,而ServletContextAttributeListener监听的是application范围内属性的改变。

http://book.51cto.com/art/201104/253576.htm

实现HttpSessionListener接口的监听器可以监听每个用户会话的开始和断开,因此应用可以通过该监听器监听系统的在线用户。

下面是该监听器的实现类。

程序清单:codes\02\2.13\listenerTest\WEB-INF\src\lee\OnlineListener.java

    1. @WebListener
    2. public class OnlineListener
    3.     implements HttpSessionListener
    4. {
    5.     //当用户与服务器之间开始session时触发该方法
    6.     public void sessionCreated(HttpSessionEvent se)
    7.     {
    8.         HttpSession sesession = se.getSession();
    9.         ServletContext application = session.getServletContext();
    10.         //获取session ID
    11.         String sessionsessionId = session.getId();
    12.         //如果是一次新的会话
    13.         if (session.isNew())
    14.         {
    15.             String user = (String)session.getAttribute(“user”);

上面的监听器实现类实现了HttpSessionListener接口,该监听器可用于监听用户与服务器之间session的开始、关闭,当用户与服务器之间的session开始时,如果该session是一次新的session,程序就将当前用户的session ID、用户名存入application范围的Map中;当用户与服务器之间的session关闭时,程序从application范围的Map中删除该用户的信息。通过上面的方式,application范围内的Map就记录了当前应用的所有在线用户。

显示在线用户的页面代码很简单,只要迭代输出application范围的Map即可,如以下代码所示。

程序清单:codes\02\2.13\listenerTest\online.jsp

  1. <%@ page contentType=”text/html; charset=GBK”
    language=”java” errorPage=”" %>
  2. <%@ page import=”java.util.*” %>
  3. <!DOCTYPE html PUBLIC ”-//W3C//DTD XHTML 1.0 Transitional//EN”
  4.     ”http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
  5. <html xmlns=”http://www.w3.org/1999/xhtml”>
  6. <head>
  7.     <title> 用户在线信息 </title>
  8. </head>
  9. <body>
  10. 在线用户:
  11. <table width=”400″ border=”1″>
  12. <%
  13. Map<String , String> online = (Map<String , String>)application

2.13.5  使用HttpSessionListener和HttpSessionAttributeListener(2)

笔者在本机启动三个不同的浏览器来模拟三个用户访问该应用,访问online.jsp页面将可看到如图2.42所示页面。

需要指出的是:采用HttpSessionListener监听用户在线信息比较”粗糙”,只能监听到有多少人在线,每个用户的session ID等基本信息。如果应用需要监听到每个用户停留在哪个页面、本次在线的停留时间、用户的访问IP等信息,则应该考虑定时检查HttpServletRequest来实现。

通过检查HttpServletRequest的做法可以更精确地监控在线用户的状态,这种做法的思路是:

定义一个ServletRequestListener,这个监听器负责监听每个用户请求,当用户请求到达时,系统将用户请求的session ID、用户名、用户IP、正在访问的资源、访问时间记录下来。


启动一条后台线程,这条后台线程每隔一段时间检查上面的每条在线记录,如果某条在线记录的访问时间与当前时间相差超过了指定值,将这条在线记录删除即可。这条后台线程应随着Web应用的启动而启动,可考虑使用ServletContextListener来完成。

下面先定义一个ServletRequestListener,它负责监听每次用户请求:每次用户请求到达时,如果是新的用户会话,将相关信息插入数据表;如果是老的用户会话,则更新数据表中已有的在线记录。

程序清单:codes\02\2.13\ online\WEB-INF\src\lee\RequestListener.java

  1. @WebListener
  2. public class RequestListener
  3.     implements ServletRequestListener
  4. {
  5.     //当用户请求到达、被初始化时触发该方法
  6.     public void requestInitialized(ServletRequestEvent sre)
  7.     {
  8.         HttpServletRequest request =
    (HttpServletRequest)sre.getServletRequest();
  9.         HttpSession session = request.getSession();
  10.         //获取session ID
  11.         String sessionsessionId = session.getId();
  12.         //获取访问的IP和正在访问的页面
  13.         String ip = request.getRemoteAddr();
  14.         String page = request.getRequestURI();
  15.         String user = (String)session.getAttribute(“user”);
  16.         //未登录用户当游客处理
  17.         user = (user == null) ? ”游客” : user;
  18.         try
  19.         {
  20.             DbDao dd = new DbDao(“com.mysql.jdbc.Driver”
  21.                 , ”jdbc:mysql://localhost:3306/online_inf”

上面的程序中粗体字代码控制用户会话是新的session,还是已有的session,新的session将插入数据表;旧的session将更新数据表中对应的记录。

接下来定义一个ServletContextListener,它负责启动一条后台线程,这条后台线程将会定期检查在线记录,并删除那些长时间没有重新请求过的记录。该Listerner代码如下。

程序清单:codes\02\2.13\ online\WEB-INF\src\lee\OnlineListener.java

  1. @WebListener
  2. public class OnlineListener
  3.     implements ServletContextListener
  4. {
  5.     //超过该时间(10分钟)没有访问本站即认为用户已经离线
  6.     public final int MAX_MILLIS = 10 * 60 * 1000;
  7.     //应用启动时触发该方法
  8.     public void contextInitialized(ServletContextEvent sce)
  9.     {
  10.         //每5秒检查一次
  11.         new javax.swing.Timer(1000 * 5 , new ActionListener()
  12.         {
  13.             public void actionPerformed(ActionEvent e)
  14.             {
  15.                 try
  16.                 {
  17.                     DbDao dd = new DbDao(“com.mysql.jdbc.Driver”
  18.                         , ”jdbc:mysql://localhost:3306/online_inf”
  19.                         , ”root”
  20.                         , ”32147″);
  21.                     ResultSet rs = dd.query
    (“select * from online_inf” , false);
  22.                     StringBuffer beRemove = new StringBuffer(“(“);
  23.                     while(rs.next())
  24.                     {
  25.                         //如果距离上次访问时间超过了指定时间
  26.                         if ((System.currentTimeMillis() - rs.getLong(5))
  27.                             > MAX_MILLIS)
  28.                         {
  29.                             //将需要被删除的session ID添加进来
  30.                             beRemove.append(“‘”);
  31.                             beRemove.append(rs.getString(1));
  32.                             beRemove.append(“‘ , ”);
  33.                         }
  34.                     }
  35.                     //有需要删除的记录
  36.                     if (beRemove.length() > 3)
  37.                     {
  38.                         beRemove.setLength(beRemove.length() - 3);
  39.                         beRemove.append(“)”);
  40.                         //删除所有”超过指定时间未重新请求的记录”
  41.                         dd.modify(“delete
    from online_inf where session_id in ”
  42.                             + beRemove.toString());
  43.                     }
  44.                     dd.closeConn();
  45.                 }
  46.                 catch (Exception ex)
  47.                 {
  48.                     ex.printStackTrace();
  49.                 }
  50.             }
  51.         }).start();
  52.     }
  53.     public void contextDestroyed(ServletContextEvent sce)

  使用ServletRequestListener和ServletRequestAttributeListener

ServletRequestListener用于监听用户请求的到达,实现该接口的监听器需要实现如下两个方法。

requestInitialized(ServletRequestEvent sre):用户请求到底、被初始化时触发该方法。

requestDestroyed(ServletRequestEvent sre):用户请求结束、被销毁时触发该方法。
ServletRequestAttributeListener则用于监听ServletRequest(request)范围内属性的变化,实现该接口的监听器需要实现attributeAdded、attributeRemoved、attributeReplaced三个方法。由此可见,ServletRequestAttributeListener与ServletContextAttributeListener的作用相似,都用于监听属性的改变,只是ServletRequestAttributeListener监听request范围内属性的改变,而ServletContextAttributeListener监听的是application范围内属性的改变。

需要指出的是,应用程序完全可以采用一个监听器类来监听多种事件,只要让该监听器实现类同时实现多个监听器接口即可,如以下代码所示。

程序清单:codes\02\2.13\listenerTest\WEB-INF\src\lee\RequestListener.java

 

  1. @WebListener
  2. public class RequestListener
  3.     implements ServletRequestListener ,
    ServletRequestAttributeListener
  4. {
  5.     //当用户请求到达、被初始化时触发该方法
  6.     public void requestInitialized(ServletRequestEvent sre)
  7.     {
  8.         HttpServletRequest request =
    (HttpServletRequest)sre.getServletRequest();
  9.         System.out.println(“—-发向” + request.getRequestURI()
  10.             + ”请求被初始化—-”);
  11.     }
  12.     //当用户请求结束、被销毁时触发该方法
  13.     public void requestDestroyed(ServletRequestEvent sre)
  14.     {
  15.         HttpServletRequest request =
    (HttpServletRequest)sre.getServletRequest();
  16.         System.out.println(“—-发向” + request.getRequestURI()
  17.             + ”请求被销毁—-”);
  18.     }
  19.     //当程序向request范围添加属性时触发该方法
  20.     public void attributeAdded(ServletRequestAttributeEvent event)
  21.     {
  22.         ServletRequest request = event.getServletRequest();
  23.         //获取添加的属性名和属性值
  24.         String name = event.getName();
  25.         Object value = event.getValue();
  26.         System.out.println(request + ”范围内添加了名为”
  27.             + name + ”,值为” + value + ”的属性!”);
  28.     }
  29.     //当程序从request范围删除属性时触发该方法
  30.     public void attributeRemoved(ServletRequestAttributeEvent event)
  31.     {
  32.         ServletRequest request = event.getServletRequest();
  33.         //获取被删除的属性名和属性值
  34.         String name = event.getName();
  35.         Object value = event.getValue();
  36.         System.out.println(request + ”范围内名为”
  37.             + name + ”,值为” + value + ”的属性被删除了!”);
  38.     }
  39.     //当request范围的属性被替换时触发该方法
  40.     public void attributeReplaced(ServletRequestAttributeEvent event)
  41.     {
  42.         ServletRequest request = event.getServletRequest();
  43.         //获取被替换的属性名和属性值

上面的监听器实现类同时实现了ServletRequestListener接口和ServletRequestAttributerListener接口,因此它既可以监听用户请求的初始化和销毁,也可监听request范围内属性的变化。

由于实现了ServletRequestListener接口的监听器可以非常方便地监听到每次请求的创建、销毁,因此Web应用可通过实现该接口的监听器来监听访问该应用的每个请求,从而实现系统日志。