JSP作為後起之秀能夠在服務器編程環境中占據一定地位是和它良好支持一系列業界標准密切相關的Session就是它提供的基礎設施之一作為一個程序員你可以不介意具體在客戶端是如何實現就方便的實現簡單的基於session的用戶管理現在對於處理在線用戶有幾種不同的處理方法
一種是頁面刷新由用戶控制服務器端控制一個超時時間比如分鐘到了時間之後用戶沒有動作就被踢出這種方法的優點是如果用戶忘了退出可以防止別人惡意操作缺點是如果你在做一件很耗時間的事情超過了這個時間限制submit的時候可能要再次面臨登陸如果原來的葉面又是強制失效的話就有可能丟失你做的工作在實現的角度來看這是最簡單的Server端默認實現的就是這樣的模式
另一種方式是站點采用框架結構有一個Frame或者隱藏的iframe在不斷刷新這樣你永遠不會被踢出但是服務器端為了判斷你是否在線需要定一個發呆時間如果超過這個發呆時間你除了這個自動刷新的頁面外沒有刷新其他頁面的話就認為你已經不在線了采取這種方式的典型是xicinet 他的優點是可以可以利用不斷的刷新實現一些類似serverpush的功能比如網友之間發送消息
不管哪一種模式為了實現浏覽當前所有的在線用戶還需要做一些額外的工作Servlet API中沒有得到Session列表的API
可以利用的是Listener Servlet 和規范在這裡略微有一些不一樣中HttpSessionBindingListener可以實現當一個HTTPSession中的Attribute變化的時候通知你的類而中還引入了HttpSessionAttributeListener鑒於我使用的環境是Visual age for Java 和JRun server 他們還不直接支持Servlet 的編程這裡我用的是HttpSessionBindingListener
需要做的事情包括做一個新的類來實現HttpSessionBindingListener接口這個接口有兩個方法
public void valueBound(HttpSessionBindingEvent event)
public void valueUnbound(HttpSessionBindingEvent event)
當你執行SessionaddAttribute(StringObject)的時候如果你已經把一個實現了HttpSessionBindingListener接口的類加入為AttributeSession會通知你的類調用你的valueBound方法相反SessionremoveAttribute方法對應的是valueUndound方法
public class HttpSessionBinding implements javaxservlet
{
ServletContext application = null;
public HttpSessionBinding(ServletContext application)
{
super();
if (application ==null)
throw new IllegalArgumentException("Null application is not accept");
thisapplication = application;
public void valueBound(javaxservlet
{
Vector activeSessions = (Vector) applicationgetAttribute("activeSessions");
if (activeSessions == null)
{
activeSessions = new Vector();
JDBCUser sessionUser = (JDBCUser)egetSession()getAttribute("user");
if (sessionUser != null)
{
activeSessionsadd(egetSession());
}
applicationsetAttribute("activeSessions"activeSessions);
public void valueUnbound(javaxservlet
{
JDBCUser sessionUser = (JDBCUser)egetSession()getAttribute("user");
if (sessionUser == null)
{
Vector activeSessions = (Vector) applicationgetAttribute("activeSessions");
if (activeSessions != null)
{
activeSessionsremove(egetSession()getId());
applicationsetAttribute("activeSessions"activeSessions);
}
}
}
假設其中的JDBCUser類是一個任意User類在執行用戶登錄時把User類和HttpSessionBinding類都加入到Session中去
這樣每次用戶登錄後在application中的attribute "activeSessions"這個vector中都會增加一條記錄每當session超時valueUnbound被觸發在這個vector中刪去將要被超時的session
public void login()
throws ACLExceptionSQLExceptionIOException
{
/* get JDBC User Class */
if (user != null)
{
logout();
}
{
// if session time out or user didnt login save the target url temporary
JDBCUserFactory uf = new JDBCUserFactory();
if ( (thisrequestgetParameter("userID")==null) || (thisrequestgetParameter("password")==null) )
{
throw new ACLException("Please input a valid userName and password");
JDBCUser user = (JDBCUser) ufUserLogin(
thisrequestgetParameter("userID")
thisrequestgetParameter("password") );
usertouchLoginTime();
thissessionsetAttribute("user"user);
thissessionsetAttribute("BindingNotify"new HttpSessionBinding(application));
}
Login的時候把User和這個BindingNotofy目的的類都加入到session中去logout的時候就要主動在activeSessions這個vector中刪去這個session
public void logout()
throws SQLExceptionACLException
{
if (thisuser == null && thissessiongetAttribute("user")==null)
{
return;
Vector activeSessions = (Vector) thisapplicationgetAttribute("activeSessions");
if (activeSessions != null)
{
activeSessionsremove(thissession);
applicationsetAttribute("activeSessions"activeSessions);
javautilEnumeration e = thissessiongetAttributeNames();
while (ehasMoreElements())
{
String s = (String)enextElement();
thissessionremoveAttribute(s);
}
thisusertouchLogoutTime();
thisuser = null;
這兩個函數位於一個HttpSessionManager類中這個類引用了jsp裡面的application全局對象這個類的其他代碼和本文無關且相當長我就不貼出來了
下面來看看JSP裡面怎麼用
假設一個登錄用的表單被提交到doLoginjsp 表單中包含UserName和password域節選部分片段
<%
HttpSessionManager hsm = new HttpSessionManager(applicationrequestresponse);
try
{
hsmlogin();
}
catch ( UserNotFoundException e)
{
responsesendRedirect("InsufficientPrivilegejsp?detail=User%does%not%exist");
return;
}
catch ( InvalidPasswordException e)
{
responsesendRedirect("InsufficientPrivilegejsp?detail=Invalid%Password");
return;
}
catch ( Exception e)
{
%> Error:<%=etoString() %><br>
Press <a href="loginjsp">Here</a> to relogin
<% return;
}
responsesendRedirect("indexjsp");%>
再來看看現在我們怎麼得到一個當前在線的用戶列表
<body bgcolor="#FFFFFF">
<table cellspacing="" cellpadding="" width="%">
<tr >
<td style="width:px">SessionId
</td>
<td style="width:px" >User
</td>
<td style="width:px" >Login Time
</td>
<td style="width:px" >Last Access Time
</td>
</tr>
<%
Vector activeSessions = (Vector) applicationgetAttribute("activeSessions");
if (activeSessions == null)
{
activeSessions = new Vector();
applicationsetAttribute("activeSessions"activeSessions);
Iterator it = activeSessionsiterator();
while (ithasNext())
{
HttpSession sess = (HttpSession)itnext();
JDBCUser sessionUser = (JDBCUser)sessgetAttribute("user");
String userId = (sessionUser!=null)?sessionUsergetUserID():"None";
%>
<tr>
<td nowrap=><%= sessgetId() %></td>
<td nowrap=><%= userId %></td>
<td nowrap=>
<%= BeaconDategetInstance( new JavautilDate(sessgetCreationTime()))getDateTimeString()%></td>
<td class="<%= stl %>" nowrap=>
<%= BeaconDategetInstance( new javautilDate(sessgetLastAccessedTime()))getDateTimeString()%></td>
</tr>
<%
}
%>
</table>
</body>
以上的代碼從application中取出activeSessions並且顯示出具體的時間其中BeaconDate類假設為格式化時間的類
這樣我們得到了一個察看在線用戶的列表的框架至於在線用戶列表分頁等功能與本文無關不予討論
這是一個非刷新模型的例子依賴於session的超時機制我的同事sonymusic指出很多時候由於各個廠商思想的不同這有可能是不可信賴的考慮到這種需求需要在每個葉面刷新的時候都判斷當前用戶距離上次使用的時間是否超過某一個預定時間值這實質上就是自己實現session超時如果需要實現刷新模型就必須使用這種每個葉面進行刷新判斷的方法
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/20547.html