J2EE使用session监听实现在线用户明细及数量统计

/*************************************************************/ 
/*
wallimn原创文章,欢迎转载,转载请保留本文信息。
博客:http://blog.csdn.net/wallimn    邮件:wallimn@sohu.com
*/
/*************************************************************/ 

思路很简单,但与网上多数文章有所不同。我使用两个监听器,通过HttpSessionListener监听用户退出事件,通过HttpSessionAttributeListener监听用户登录事件。一般来讲,用户登录,都是向session中写入一个登录用户名。因此,可以通过监听session属性的变化,得到用户登录的情况。监听器配制方法,就是在web.xml加入如下代码:
 <listener>
  <listener-class>com.wallimn.onlinestat.SessionListener</listener-class>
 </listener>

使用工厂模式来设计,定义一个保存用户登录信息的接口(IStatStore),以便可以通过多种机制保存用户登录信息,如内存(MemStat)或数据库(JdbcStat)。定义一个类厂(StoreFactory),来实现保存机制的切换。

注:我在代码中,没有完成JdbcStat这个类,若哪位用我的方法,写了这个类,最好能通过邮件发给我。谢谢。

以上是一些设计思想的简单介绍,下面把几个程序贴一下。

SessionListener.java

/**
 * 文件:SessionListener.java<br/>
 * 功能:<br/>
 * 编码:wallimn(Email: wallimn@sohu.com  QQ: 54871876)<br/>
 * 版本:V1.0<br/>
 * 时间:2008-3-25<br/>
 * 备注:此代码欢迎讨论,转载请保留以上信息。
 
*/

package  com.wallimn.onlinestat;

import  javax.servlet.http.HttpSessionAttributeListener;
import  javax.servlet.http.HttpSessionBindingEvent;
import  javax.servlet.http.HttpSessionEvent;
import  javax.servlet.http.HttpSessionListener;

/**
 * session监听器,通过监听器来实现在线用户统计功能的类<br/>
 * 
 * 
@version : V1.0<br/>
 * 
@author : wallimn(Email: wallimn@sohu.com QQ: 54871876)<br/>
 * @date : 2008-3-25 上午09:41:11<br/>
 
*/

public   class  SessionListener  implements  HttpSessionListener,
        HttpSessionAttributeListener 
{
    
/**
     * 这个值应该根据不同的应用,改成不同的值
     
*/

    
private static final String LOGIN = "loginusername";

    
/**
     * 功能描述: 编码时间:2008-3-25 上午09:41:11 参数及返回值:
     * 
     * 
@param arg0
     * 
@see javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent)
     
*/

    
public void sessionCreated(HttpSessionEvent se) {
        
// 时间: 2008-3-25 上午09:41:11
        System.out.println("Session创建:"+se.getSession().getId());
    }


    
/**
     * 功能描述:session销毁监控,销毁时注销用户 编码时间:2008-3-25 上午09:41:11 参数及返回值:
     * 
     * 
@param arg0
     * 
@see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent)
     
*/

    
public void sessionDestroyed(HttpSessionEvent se) {
        
// 时间: 2008-3-25 上午09:41:11
        String name = (String) se.getSession().getAttribute(LOGIN);
        System.out.println(
"有人登出:"+name);
        
if (name != null{
            StoreFactory.getStore().logoff(name);
        }

    }


    
/**
     * 
     * 功能描述:监控用户登录。有登录的,记录其状态。
     * 编码时间:2008-4-3  上午10:58:36
     * 参数及返回值:
     *  
@param event
     *  
@see javax.servlet.http.HttpSessionAttributeListener#attributeAdded(javax.servlet.http.HttpSessionBindingEvent)
     
*/

    
public void attributeAdded(HttpSessionBindingEvent event) {
        
// 时间: 2008-3-25 上午09:55:42
        String name = event.getName();
        
if (LOGIN.equals(name)) {
            StoreFactory.getStore().login((String) event.getValue());
            System.out.println(
"有人登录:"+event.getValue());
        }

    }


    
public void attributeRemoved(HttpSessionBindingEvent event) {
        
// 时间: 2008-3-25 上午09:55:42
    }


    
public void attributeReplaced(HttpSessionBindingEvent event) {
        
// 时间: 2008-3-25 上午09:55:42
    }


}

 接口:IStatStore.java 

package  com.wallimn.onlinestat;
import  java.util.List;
/**
 * 在线人数统计的接口,可以使用多种方式实现,如:内存、数据库等,只要实现这个接口就可以了。
 *<br/>
 * 
@version      :  V1.0<br/>
 * 
@author       : wallimn(Email: wallimn@sohu.com  QQ: 54871876)<br/>
 * @date           : 2008-4-4 下午02:01:07<br/>
 
*/

public   interface  IStatStore  {
    
/**
     * 记录登录状态
     *<br/>
     *编码:wallimn     时间:2008-4-3  上午10:08:05<br/>
     *参数及返回值:<br/>
     *  
@param username
     
*/

    
public void login(String username);
    
/**
     * 取消登录状态
     *<br/>
     *编码:wallimn     时间:2008-4-3  上午10:08:17<br/>
     *参数及返回值:<br/>
     *  
@param username
     
*/

    
public void logoff(String username);
    
    
/**
     * 返回登录用户及信息。
     *<br/>
     *编码:wallimn     时间:2008-4-3  上午10:20:08<br/>
     *参数及返回值:<br/>
     *  
@return链表里的对象是个数组,数组包含两个元素,0:用户名,1:登录时间。这样是为了便于为jstl标签处理
     
*/

    
public List getUsers();
    
    
/**
     * 在线用户数量
     *<br/>
     *编码:wallimn     时间:2008-4-4  下午01:52:55<br/>
     *参数及返回值:<br/>
     *  
@return
     
*/

    
public int getCount();
}

 

MemStat.java

package  com.wallimn.onlinestat;

import  java.util.Date;
import  java.util.HashMap;
import  java.util.Iterator;
import  java.util.LinkedList;
import  java.util.List;
import  java.util.Map;
/**
 * 依托内存实现在线用户统计功能。适合于在线用户数量较少的情况。
 *<br/>
 * 
@version      :  V1.0<br/>
 * 
@author       : wallimn(Email: wallimn@sohu.com  QQ: 54871876)<br/>
 * @date           : 2008-4-4 下午01:53:36<br/>
 
*/

public   class  MemStat  implements  IStatStore  {

    
private static Map userMap=null;
    
static {
        userMap 
= new HashMap();
    }


    
public void login(String username) {
        
//时间: 2008-4-3 上午10:09:13
        userMap.put(username, new Date());//如果存在,会覆盖已有的值
    }


    
public void logoff(String username) {
        
//时间: 2008-4-3 上午10:09:13
        userMap.remove(username);
    }


    
public List getUsers() {
        
//时间: 2008-4-3 上午10:23:34
        List list = new LinkedList();
        String user 
= null;
        
for(Iterator it = userMap.keySet().iterator();it.hasNext();){
            user 
= (String) it.next();
            list.add(
new Object[]{user,userMap.get(user)});
        }

        
return list;
    }


    
public int getCount() {
        
//时间: 2008-4-4 下午01:53:25
        return userMap.size();
    }


}

类厂:StoreFactory.java

 

package  com.wallimn.onlinestat;

public   class  StoreFactory  {
    
/**
     * 返回实现IStatStore接口的某种对象。
     *<br/>
     *编码:wallimn     时间:2008-4-3  上午10:54:05<br/>
     *参数及返回值:<br/>
     *  
@return 实现IStatStore接口的某种对象
     
*/

    
public static IStatStore getStore(){
        
//这里应该设计成从配制文件中读取,暂时先这样写。
        
//如果想在系统中使用jdbc的方式来实现统计功能,则返回JdbcStat对象即可。
        return new MemStat();
    }

}

 

页面上使用方法示例:

 

<% @ page language="java" pageEncoding="GB18030"  %>
<% @ page import="com.wallimn.onlinestat.*"  %>
<% @ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"  %>
<%
    
String path = request.getContextPath();
    
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    request.setAttribute(
"stat",StoreFactory.getStore().getUsers());
%>
<% --2007-9-20-- %>
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html  xmlns ="http://www.w3.org/1999/xhtml" >
  
< head >
    
< base  href ="<%=basePath%>" />     
    
< title > 在线用户统计 </ title >     
    
< meta  http-equiv ="pragma"  content ="no-cache" />
    
< meta  http-equiv ="cache-control"  content ="no-cache" />
    
< meta  http-equiv ="expires"  content ="0" />     
    
< meta  http-equiv ="keywords"  content ="wallimn" />
    
< meta  http-equiv ="description"  content ="在线用户显示,wallimn,2008年4月" />
    
< style  >
        h1
{
            text-align
:center;
            font-size
:18px;
            margin-top
:10px;
            margin-bottom
:10px;
        
}

        table
{
            border-collapse
:collapse;
            font-size
:12px;
        
}

        table,td,th
{
            border
:1px solid #EAEAEA;
        
}

        th
{
            height
:28px;
        
}

        td
{
            height
:24px;
            padding-left
:1em;
        
}

    
</ style >
    
< script  type ="text/javascript" >
    
</ script >
  
</ head >   
  
< body >
      
< h1 > 登录用户列表 </ h1 >
      
< table  width ="80%"  align ="center" >
               
< tr >
                  
< th > 用户 </ th >< th > 登录时间 </ th >
              
</ tr >
          
< c:forEach  items ="${stat}"  var ="item" >
              
< tr >
                  
< td > ${item[0]} </ td >< td > ${item[1]} </ td >
              
</ tr >
          
</ c:forEach >
      
</ table >
 
</ body >
 
</ html >

/*************************************************************/ 
/*
wallimn原创文章,欢迎转载,转载请保留本文信息。
博客:http://blog.csdn.net/wallimn    邮件:wallimn@sohu.com
*/
/*************************************************************/ 


版权声明:本文为wallimn原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。