再论Session事件的捕获
来源:百度文库 编辑:神马文学网 时间:2024/04/28 17:19:04
最近又有网友问到,如何用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文件里了。
下面是具体的代码:
/** * OnlineUserListener.java * Created on 2004-11-19 */ package com.ccctc.view.web; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * @author litf * */ public class OnlineUserListener implements HttpSessionListener { /** * 浏览器第一次访问的时候,调用本方法 * @see javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent) */ public void sessionCreated(HttpSessionEvent event) { User u = new User(); u.setName("guest"); u.setId(event.getSession().getId()); event.getSession().setAttribute("currentUser",u); OnlineUsers.getInstance().addUser(u); } /** * Session超时的时候,调用本方法 * @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent) */ public void sessionDestroyed(HttpSessionEvent event) { OnlineUsers.getInstance().removeUser(event.getSession().getId()); } }
/** * OnlineUsers.java * Created on 2004-11-19 */ package com.ccctc.view.web; import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; /** * @author litf * 在线用户统计 */ public class OnlineUsers implements HttpSessionBindingListener{ private Map users = new HashMap(); private static OnlineUsers onlineUsers = new OnlineUsers(); public static OnlineUsers getInstance(){ return onlineUsers; } /** * @return */ public Collection getUsers() { return users.values(); } public void addUser(User user) { users.put(user.getId(),user); } public void removeUser(String userId){ users.remove(userId); } /** * 对象实例(即OnlineUserListener的实例)作为一个属性被设置到session的 * 时候,会调用本方法,这种情况一般发生在点击登录按钮以后的处理过程中 * 设置 * @see javax.servlet.http.HttpSessionBindingListener#valueBound(javax.servlet.http.HttpSessionBindingEvent) */ public void valueBound(HttpSessionBindingEvent event) { //现在暂时不需要额外处理,你可以在这里记录日志等 } /** * 当Session超时,或本实例被从session中移除的时候被调用,这种情况一般 * 发生在注销方法的处理过程中 * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(javax.servlet.http.HttpSessionBindingEvent) */ public void valueUnbound(HttpSessionBindingEvent event) { try { HttpSession session = event.getSession(); User u = (User)session.getAttribute("currentUser"); u.setName("guest"); } catch (RuntimeException e) { //e.printStackTrace(); } } }
/** * User.java * Created on 2004-11-19 */ package com.ccctc.view.web; /** * @author litf * */ public class User{ private String address; private String id; private String name; /** * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { if (obj == null || !(obj instanceof User)) { return false; } if(this.id !=null && this.id.equals(((User)obj).getId())){ return true; } return false; } /** * @return */ public String getAddress() { return address; } /** * @return */ public String getId() { return id; } /** * @return */ public String getName() { return name; } /** * @param string */ public void setAddress(String string) { address = string; } /** * @param string */ public void setId(String string) { id = string; } /** * @param string */ public void setName(String string) { name = string; } /** * @see java.lang.Object#toString() */ public String toString() { return "name:"+name + ",id:" + id + ",address:"+address; } }
test.jsp
<%@ page import="com.ccctc.view.web.*" %> <% User u = (User)session.getAttribute("currentUser");String name = request.getParameter("user"); if(u != null){ String remote = request.getRemoteAddr(); u.setAddress(remote); } //User Login if(name != null){ if(u != null){ session.setAttribute("_listener",OnlineUsers.getInstance()); u.setName(name); } } //User LogoutString logout = request.getParameter("logout"); if(logout != null){ session.removeAttribute("_listener"); } %> current users:
第一篇文章是基于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文件里了。
下面是具体的代码:
/** * OnlineUserListener.java * Created on 2004-11-19 */ package com.ccctc.view.web; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * @author litf * */ public class OnlineUserListener implements HttpSessionListener { /** * 浏览器第一次访问的时候,调用本方法 * @see javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent) */ public void sessionCreated(HttpSessionEvent event) { User u = new User(); u.setName("guest"); u.setId(event.getSession().getId()); event.getSession().setAttribute("currentUser",u); OnlineUsers.getInstance().addUser(u); } /** * Session超时的时候,调用本方法 * @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent) */ public void sessionDestroyed(HttpSessionEvent event) { OnlineUsers.getInstance().removeUser(event.getSession().getId()); } }
/** * OnlineUsers.java * Created on 2004-11-19 */ package com.ccctc.view.web; import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; /** * @author litf * 在线用户统计 */ public class OnlineUsers implements HttpSessionBindingListener{ private Map users = new HashMap(); private static OnlineUsers onlineUsers = new OnlineUsers(); public static OnlineUsers getInstance(){ return onlineUsers; } /** * @return */ public Collection getUsers() { return users.values(); } public void addUser(User user) { users.put(user.getId(),user); } public void removeUser(String userId){ users.remove(userId); } /** * 对象实例(即OnlineUserListener的实例)作为一个属性被设置到session的 * 时候,会调用本方法,这种情况一般发生在点击登录按钮以后的处理过程中 * 设置 * @see javax.servlet.http.HttpSessionBindingListener#valueBound(javax.servlet.http.HttpSessionBindingEvent) */ public void valueBound(HttpSessionBindingEvent event) { //现在暂时不需要额外处理,你可以在这里记录日志等 } /** * 当Session超时,或本实例被从session中移除的时候被调用,这种情况一般 * 发生在注销方法的处理过程中 * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(javax.servlet.http.HttpSessionBindingEvent) */ public void valueUnbound(HttpSessionBindingEvent event) { try { HttpSession session = event.getSession(); User u = (User)session.getAttribute("currentUser"); u.setName("guest"); } catch (RuntimeException e) { //e.printStackTrace(); } } }
/** * User.java * Created on 2004-11-19 */ package com.ccctc.view.web; /** * @author litf * */ public class User{ private String address; private String id; private String name; /** * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { if (obj == null || !(obj instanceof User)) { return false; } if(this.id !=null && this.id.equals(((User)obj).getId())){ return true; } return false; } /** * @return */ public String getAddress() { return address; } /** * @return */ public String getId() { return id; } /** * @return */ public String getName() { return name; } /** * @param string */ public void setAddress(String string) { address = string; } /** * @param string */ public void setId(String string) { id = string; } /** * @param string */ public void setName(String string) { name = string; } /** * @see java.lang.Object#toString() */ public String toString() { return "name:"+name + ",id:" + id + ",address:"+address; } }
test.jsp
<%@ page import="com.ccctc.view.web.*" %> <% User u = (User)session.getAttribute("currentUser");String name = request.getParameter("user"); if(u != null){ String remote = request.getRemoteAddr(); u.setAddress(remote); } //User Login if(name != null){ if(u != null){ session.setAttribute("_listener",OnlineUsers.getInstance()); u.setName(name); } } //User LogoutString logout = request.getParameter("logout"); if(logout != null){ session.removeAttribute("_listener"); } %> current users:
<% java.util.Collection l = OnlineUsers.getInstance().getUsers(); for(java.util.Iterator it = l.iterator(); it.hasNext();) { User tu = (User)it.next(); if(u.equals(tu)) { %> <%=tu.getName()%>:<%=tu.getAddress()%> <% }else{ %> <%=tu.getName()%>:<%=tu.getAddress()%> <% } } %>
refresh
web.xml文件中增加:
附件:SessionTest.rar(95K)
再论Session事件的捕获
Servlet中如何捕获Session事件
jsp的session详解
session的工作原理
主力的捕获
主力的捕获
Ruby on Rails的session和session存储方案
关于session的详细解释
关于session的详细解释
jsp的session详解 (下
jsp的session详解 (上)
jsp的session详解 (下)
Session失效的处理办法
cookie与session的关系
改变SecureCrt的Session标题
翻译的Hibernate的Session的javadoc
介绍一篇关于session的好文章
在Flex中内嵌Session的存取操作
弹出窗口Session丢失的解决办法?
弹出窗口Session丢失的解决办法?
在Flex中内嵌Session的存取操作
设置Session过期时间的问题
捕获控制台的所有输出信息
基金经理:长线大牛股是这样捕获的