如何用Session實現在線統計的功能,其實只要對Servlet規范詳細了解一下,明白其基本原理,編寫一個類似的功能并不是一件很復雜的事情。這個例子是基于2.3以上的規范編寫的,最主要功能就是提供在線用戶列表顯示(既然用戶列表都可以顯示了,那人數統計自然也不在話下了)。
在給出代碼之前,先簡單說一下監聽器的常識。
HttpSessionListener:這是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?Logout?
String?logout?=?request.getParameter("logout");?
if(logout?!=?null){?
?session.removeAttribute(
"_listener");?
}
?
%>?

current?users:
<p>?

<%?
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))?
?
{?
%>?

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

<%?
?}
else{?
%>?

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

<%?
?}
?
}
?
%>?
<form?action="/cctc/login.jsp">?
User?:?
<input?name="user"?type="text">?<br>?
<input?type="submit"?name="Submit">?
</form>?
<p>?
<a?href="/cctc/login.jsp?logout=true">Logout</a>?<p>?
<a?href="/cctc/login.jsp">refresh</a>?

web.xml文件中增加:

<listener>?
??
<listener-class>com.ccctc.view.web.OnlineUserListener</listener-class>?
?
</listener>