再论Session事件的捕获

(转)最近又有网友问到,如何用Session实现在线统计的功能,其实只要对Servlet规范详细了解一下,明白其基本原理,编写一个类似的功能并不是一件很复杂的事情。我以前的一篇文章,最初也是发表在JavaResearch上的(http://www.javaresearch.org/article/showarticle.jsp?column=106&thread=2164),不过可能源码没有全部给出,只给出了最重点的源码,所以还是有很多网友给我发信索取全部源码。因为那个项目是以前做的,所以我手头上也没有原来的代码了,所以可能有的网友的要求就满足不了了,在这里一并致歉。

     第一篇文章是基于Servlet2.2规范编写的,那时候没有HttpSessionListener,鉴于目前绝大多数的应用服务器都支持2.3的规范,所以为了回应网友的提问,特地又基于2.3以上的规范编写了一个简单的测试例子。
这个例子的最主要功能就是提供在线用户列表显示(既然用户列表都可以显示了,那人数统计自然也不在话下了)。

     在给出代码之前,先简单说一下监听器的常识。

     HttpSessionListener:网友rdfei 在他的文章(http://www.javaresearch.org/article/showarticle.jsp?column=106&thread=18541)中也已经进行了比较详细的描述,这是2.3以上规范所提供的一个新功能,也就是可以定义监听器监听HttpSession对象的创建和销毁。每当有新的用户访问网站,应用服务器会创建一个HttpSession对象,每当Session超时,应用服务器则会销毁这个对象。
HttpSessionBindingListener:每当往Session中存入一个对象(setAttribute)或从Session中删除一个对象的时候,如果这个对象实现了此监听器接口,应用服务器将会自动调用接口相应的方法。

     需要注意的一点就是,在sessionDestroyed方法和valueUnbound方法中,你可以得到HttpSession对象的实例,但是其getAttribute方法不再可用,也就是在这两个方法中,你不能再次得到存入session中的对象。

基于以上这些粗浅的认识,再简单介绍一下我提供的测试例子的情况:

测试例子总共包含如下文件:
OnlineUserListener.java:它实现了HttpSessionListener接口
OnlineUsers.java:它包含了所有正在访问网站的用户信息,为了方便起见,它也实现了HttpSessionBindingListener接口(实际中你最好把他们分开吧)
User.java:这是用户的信息
test.jsp:为了方便,我把登录,退出,显示在线用户列表等功能都做在同一个jsp文件里了。
下面是具体的代码:


  1. /**
  2. * OnlineUserListener.java
  3. * Created on 2004-11-19
  4. */
  5. package com.ccctc.view.web;

  6. import javax.servlet.http.HttpSessionEvent;
  7. import javax.servlet.http.HttpSessionListener;

  8. /**
  9. * @author litf
  10. *
  11. */
  12. public class OnlineUserListener
  13.     implements HttpSessionListener {

  14.     /**
  15.       * 浏览器第一次访问的时候,调用本方法
  16.       * @see javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent)
  17.       */
  18.     public void sessionCreated(HttpSessionEvent event) {
  19.          User u = new User();
  20.          u.setName("guest");
  21.          u.setId(event.getSession().getId());
  22.          event.getSession().setAttribute("currentUser",u);
  23.          OnlineUsers.getInstance().addUser(u);
  24.      }

  25.     /**
  26.       * Session超时的时候,调用本方法
  27.       * @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent)
  28.       */
  29.     public void sessionDestroyed(HttpSessionEvent event) {
  30.          OnlineUsers.getInstance().removeUser(event.getSession().getId());
  31.      }

  32. }




  1. /**
  2. * OnlineUsers.java
  3. * Created on 2004-11-19
  4. */
  5. package com.ccctc.view.web;

  6. import java.util.Collection;
  7. import java.util.HashMap;
  8. import java.util.Map;

  9. import javax.servlet.http.HttpSession;
  10. import javax.servlet.http.HttpSessionBindingEvent;
  11. import javax.servlet.http.HttpSessionBindingListener;

  12. /**
  13. * @author litf
  14. * 在线用户统计
  15. */
  16. public class OnlineUsers implements HttpSessionBindingListener{

  17.     private Map users = new HashMap();
  18.     
  19.     private static OnlineUsers onlineUsers = new OnlineUsers();
  20.     
  21.     public static OnlineUsers getInstance(){
  22.         return onlineUsers;
  23.      }
  24.     
  25.     /**
  26.       * @return
  27.       */
  28.     public Collection getUsers() {
  29.         return users.values();
  30.      }
  31.     
  32.     public void addUser(User user) {
  33.          users.put(user.getId(),user);
  34.      }
  35.     
  36.     public void removeUser(String userId){
  37.          users.remove(userId);
  38.      }
  39.     
  40.     /**
  41.       * 对象实例(即OnlineUserListener的实例)作为一个属性被设置到session的
  42.       * 时候,会调用本方法,这种情况一般发生在点击登录按钮以后的处理过程中
  43.       * 设置
  44.       * @see javax.servlet.http.HttpSessionBindingListener#valueBound(javax.servlet.http.HttpSessionBindingEvent)
  45.       */
  46.     public void valueBound(HttpSessionBindingEvent event) {
  47.         //现在暂时不需要额外处理,你可以在这里记录日志等
  48.      }

  49.     /**
  50.       * 当Session超时,或本实例被从session中移除的时候被调用,这种情况一般
  51.       * 发生在注销方法的处理过程中
  52.       * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(javax.servlet.http.HttpSessionBindingEvent)
  53.       */
  54.     public void valueUnbound(HttpSessionBindingEvent event) {
  55.         try {
  56.             HttpSession session = event.getSession();
  57.              User u = (User)session.getAttribute("currentUser");
  58.              u.setName("guest");
  59.          } catch (RuntimeException e) {
  60.             //e.printStackTrace();
  61.          }
  62.      }

  63.     
  64. }




  1. /**
  2. * User.java
  3. * Created on 2004-11-19
  4. */
  5. package com.ccctc.view.web;

  6. /**
  7. * @author litf
  8. *
  9. */
  10. public class User{
  11.     private String address;
  12.     private String id;
  13.     private String name;

  14.     /**
  15.       * @see java.lang.Object#equals(java.lang.Object)
  16.       */
  17.     public boolean equals(Object obj) {
  18.         if (obj == null || !(obj instanceof User)) {
  19.             return false;
  20.          }
  21.         if(this.id !=null && this.id.equals(((User)obj).getId())){
  22.             return true;
  23.          }
  24.         return false;
  25.      }

  26.     /**
  27.       * @return
  28.       */
  29.     public String getAddress() {
  30.         return address;
  31.      }

  32.     /**
  33.       * @return
  34.       */
  35.     public String getId() {
  36.         return id;
  37.      }

  38.     /**
  39.       * @return
  40.       */
  41.     public String getName() {
  42.         return name;
  43.      }

  44.     /**
  45.       * @param string
  46.       */
  47.     public void setAddress(String string) {
  48.          address = string;
  49.      }

  50.     /**
  51.       * @param string
  52.       */
  53.     public void setId(String string) {
  54.          id = string;
  55.      }

  56.     /**
  57.       * @param string
  58.       */
  59.     public void setName(String string) {
  60.          name = string;
  61.      }
  62.     
  63.     /**
  64.       * @see java.lang.Object#toString()
  65.       */
  66.     public String toString() {
  67.         return "name:"+name + ",id:" + id + ",address:"+address;
  68.      }

  69. }



test.jsp


  1. <%@ page import="com.ccctc.view.web.*" %>

  2. <%
  3. User u = (User)session.getAttribute("currentUser");
  4. String name = request.getParameter("user");

  5. if(u != null){
  6.     String remote = request.getRemoteAddr();
  7.      u.setAddress(remote);
  8.     
  9. }

  10. //User Login
  11. if(name != null){
  12.     if(u != null){
  13.          session.setAttribute("_listener",OnlineUsers.getInstance());
  14.          u.setName(name);
  15.         
  16.      }
  17. }

  18. //User Logout
  19. String logout = request.getParameter("logout");
  20. if(logout != null){
  21.      session.removeAttribute("_listener");
  22. }
  23. %>

  24. current users:<p>

  25. <%
  26. java.util.Collection l = OnlineUsers.getInstance().getUsers();
  27. for(java.util.Iterator it = l.iterator(); it.hasNext();)
  28. {
  29.      User tu = (User)it.next();
  30.     if(u.equals(tu))
  31.      {
  32. %>

  33. <font color=red><%=tu.getName()%>:<%=tu.getAddress()%> </font>  

  34. <%
  35.      }else{
  36. %>

  37. <%=tu.getName()%>:<%=tu.getAddress()%>  

  38. <%
  39.      }
  40. }
  41. %>
  42. <form action="/cctc/login.jsp">
  43. User : <input name="user" type="text"> <br>
  44. <input type="submit" name="Submit">
  45. </form>
  46. <p>
  47. <a href="/cctc/login.jsp?logout=true">Logout</a> <p>
  48. <a href="/cctc/login.jsp">refresh</a>



web.xml文件中增加:


  1.      <listener>
  2.          <listener-class>com.ccctc.view.web.OnlineUserListener</listener-class>
  3.      </listener>
posted @ 2009-01-05 20:42  瞭望者  阅读(476)  评论(0)    收藏  举报