java 頁面線上訪問人數統計和線上登入人數統計
OnlineSessionListener監聽器(實現HttpSessionListener)介面來實現頁面線上訪問人數統計,當有使用者訪問到頁面就會建立一個session,此時會觸發public void sessionCreated(HttpSessionEvent se)方法,如果session失效,此時會觸發public void sessionDestroyed(HttpSessionEvent se)方法。在此方法裡我們用OnlineList進行線上訪問人數的統計
public class OnlineList { private static final OnlineList onlineList = new OnlineList(); private int maxSession; private int activeSession; private OnlineList() { //v = new Vector(); } public static OnlineList getInstance() { return onlineList; } public void addSession(){ activeSession++; if(activeSession>=maxSession){ maxSession=activeSession; } } public void delSession(){ if(activeSession > 0) activeSession--; } public int getActiveSession(){ return activeSession; } public int getmaxSession(){ return maxSession; } } public class OnlineSessionListener implements HttpSessionListener { private OnlineList ol = OnlineList.getInstance(); public void sessionCreated(HttpSessionEvent arg0) { ol.addSession(); } public void sessionDestroyed(HttpSessionEvent arg0) { ol.delSession(); } }
用UserListener監聽器(實現HttpSessionAttributeListener介面)來實現線上登入人數統計,當有使用者新增到session中,監聽器就呼叫public void valueBound(HttpSessionBindingEvent event)方法。如果有使用者退出系統,監聽器就呼叫public void valueUnbound(HttpSessionBindingEvent event)方法。我們用UserList來統計使用者資訊
在UserList這個類的設計上,我們應用了單例(Singleton)設計模式,關於設計模式的知識,讀者可以參看相關的書籍。UserList是一個單例類,所謂單例類,是指一個類只有一個例項,而且自行例項化並向整個系統提供這個例項。單例類的一個最重要的特點是類的構造方法是私有的,從而避免了外部利用該類的構造方法直接建立多個例項。在程式碼的第8行,定義一個靜態的常量userList,它表示了UserList類的一個物件。在UserList類載入的時候,這個物件就產生了。第11~14行,宣告UserList類的構造方法為private,這是為了避免在外部使用UserList類的構造方法建立其物件。要注意的是,如果在類中不寫構造方法,那麼Java編譯器就會為這個類提供一個預設的不帶引數的公開的構造方法,這樣,在外部就可以通過類的構造方法建立物件了,那麼UserList也就不再是一個單例類了。既然UserList類的構造方法是私有的,那麼在外部就不能用new去構造物件,於是在程式碼的第16~19行,定義了一個靜態的方法getInstance(),在這個方法中,返回在類載入時建立的UserList類的物件。因為getInstance()方法本身是靜態的,所以可以直接通過類名來呼叫。
那麼為什麼要將UserList設計成單例類呢?這是因為UserList類的物件是用於儲存和獲取線上使用者的列表,而這個使用者列表對於所有的頁面來說都應該是同一個,所以將UserList類設計成單例類,這樣,所有的類訪問的就是同一個UserList物件了。
程式碼的第9行,定義了一個私有的Vector型別的變數,在UserList類的構造方法中,對Vector型別的變數v進行了初始化,用於存放String型別的物件。注意,在這個地方沒有使用ArrayList,是考慮到UserList物件可能會被多個執行緒同時訪問,因為ArrayList不是同步的,而Vector是同步的,所以採用Vector來儲存使用者列表。
import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; public class UserListener implements HttpSessionAttributeListener { //使用者登入身份證 private String USERNAME; private UserList u1 = UserList.getInstance(); //判斷使用者是否存在 public boolean IsExist(String sfz)throws Exception { try { return u1.IsExist(sfz); } catch(Exception ex) { ex.printStackTrace(); return false; } } public String getUSERNAME() { return USERNAME; } public void setUSERNAME(String username) { USERNAME = username; } public void attributeAdded(HttpSessionBindingEvent event) { try{ if("USERNAME".equals(event.getName())){ u1.addUser((String)event.getValue()); } }catch(Exception e){ e.printStackTrace(); } } public void attributeRemoved(HttpSessionBindingEvent event) { try{ if("USERNAME".equals(event.getName())){ u1.RemoveUser((String)event.getValue()); } }catch(Exception e){ e.printStackTrace(); } } public void attributeReplaced(HttpSessionBindingEvent arg0) { // TODO Auto-generated method stub } } import java.util.Enumeration; import java.util.Iterator; import java.util.Vector; public class UserList { private static final UserList userList = new UserList(); private Vector v = new Vector(); private int maxUser; private UserList() { //v = new Vector(); } public static UserList getInstance() { return userList; } //將使用者登陸身份證儲存到Vector中 public void addUser(String sfz) throws Exception { try{ if ( sfz != null&&!"".equals(sfz)) { if ( v.indexOf(sfz) >= 0)//判斷是否已經存在 return ; //可能的操作 //新增登入ID v.addElement(sfz); if(getUserCount()>maxUser){ maxUser=getUserCount(); } } } catch(Exception ex) { ex.printStackTrace(); } finally{ } } public boolean IsExist(String sfz)throws Exception { try{ if ( v.indexOf(sfz) >= 0) return true; return false; } catch(Exception ex) { ex.printStackTrace(); return false; } } //刪除使用者登入ID public void RemoveUser(String sfz)throws Exception { try{ if ( sfz != null&&!"".equals(sfz) ) { //修改資料庫 //移除使用者登入ID v.removeElement(sfz); } } catch(Exception ex) { ex.printStackTrace(); //寫日誌 } finally{ } } //返回Vector列舉 public Enumeration getUserList() { return v.elements(); } //返回迭代器 public Iterator getUserListItera(){ return v.iterator(); } //返回線上人數 public int getUserCount() { return v.size(); } //返回線上人數峰值 public int getMaxUser(){ return maxUser; } } 最後在web-xml裡 加入如下資訊 <listener> <listener-class> com.myxmu.listener.UserListener </listener-class> </listener>
線上人數統計程式存在一些問題,如果使用者沒有退出登入而直接關閉了瀏覽器,那麼在伺服器端的Session中,這個使用者仍然是存在的,直到Session的超時值發生。所以線上人數統計只能做到在一個時間段內統計出大致的線上人數,而不能統計出精確的人數。為了提高統計的精確性,可以在客戶端設定指令碼,當瀏覽器關閉時,自動向伺服器傳送一個請求,伺服器收到這個請求後,使Session失效。不過,這也不能做到100%的精確,因為還存在著客戶端的瀏覽器異常終止,或者客戶機器崩潰的可能。