新聞中心
一、 Servlet的會(huì)話管理機(jī)制

創(chuàng)新互聯(lián)是工信部頒發(fā)資質(zhì)IDC服務(wù)器商,為用戶提供優(yōu)質(zhì)的四川電信機(jī)房托管服務(wù)
HttpSession接口提供了存儲(chǔ)和返回標(biāo)準(zhǔn)會(huì)話屬性的方法。標(biāo)準(zhǔn)會(huì)話屬性如會(huì)話標(biāo)識(shí)符、應(yīng)用數(shù)據(jù)等,都以“名字-值”對(duì)的形式保存。簡(jiǎn)而言之,HttpSession接口提供了一種把對(duì)象保存到內(nèi)存、在同一用戶的后繼請(qǐng)求中提取這些對(duì)象的標(biāo)準(zhǔn)辦法。在會(huì)話中保存數(shù)據(jù)的方法是setAttribute(String s, Object o),從會(huì)話提取原來(lái)所保存對(duì)象的方法是getAttribute(String s)。
每當(dāng)新用戶請(qǐng)求一個(gè)使用了HttpSession對(duì)象的JSP頁(yè)面,JSP容器除了發(fā)回應(yīng)答頁(yè)面之外,它還要向?yàn)g覽器發(fā)送一個(gè)特殊的數(shù)字。這個(gè)特殊的數(shù)字稱(chēng)為“會(huì)話標(biāo)識(shí)符”,它是一個(gè)***的用戶標(biāo)識(shí)符。此后,HttpSession對(duì)象就駐留在內(nèi)存之中,等待同一用戶返回時(shí)再次調(diào)用它的方法。
在客戶端,瀏覽器保存會(huì)話標(biāo)識(shí)符,并在每一個(gè)后繼請(qǐng)求中把這個(gè)會(huì)話標(biāo)識(shí)符發(fā)送給服務(wù)器。會(huì)話標(biāo)識(shí)符告訴JSP容器當(dāng)前請(qǐng)求不是用戶發(fā)出的***個(gè)請(qǐng)求,服務(wù)器以前已經(jīng)為該用戶創(chuàng)建了HttpSession對(duì)象。此時(shí),JSP容器不再為用戶創(chuàng)建新的HttpSession對(duì)象,而是尋找具有相同會(huì)話標(biāo)識(shí)符的HttpSession對(duì)象,然后建立該HttpSession對(duì)象和當(dāng)前請(qǐng)求的關(guān)聯(lián)。
會(huì)話標(biāo)識(shí)符以Cookie的形式在服務(wù)器和瀏覽器之間傳送。如果客戶端不支持cookie,運(yùn)用url改寫(xiě)機(jī)制來(lái)保證會(huì)話標(biāo)識(shí)符傳回服務(wù)器。
二、 Servlet Session事件偵聽(tīng)
HttpSessionBindingEvent類(lèi)\
定義\
public class HttpSessionBindingEvent extends EventObject
這個(gè)事件是在監(jiān)聽(tīng)到HttpSession發(fā)生綁定和取消綁定的情況時(shí)連通HttpSessionBindingListener的。這可能是一個(gè)session被終止或被認(rèn)定無(wú)效的結(jié)果。
事件源是HttpSession.putValue或HttpSession.removeValue。
構(gòu)造函數(shù)
public HttpSessionBindingEvent(HttpSession session, String name);
通過(guò)引起這個(gè)事件的Session和發(fā)生綁定或取消綁定的對(duì)象名構(gòu)造一個(gè)新的HttpSessionBindingEvent。
方法
1、getName
public String getName();
返回發(fā)生綁定和取消綁定的對(duì)象的名字。
2、getSession
public HttpSession getSession();
返回發(fā)生綁定和取消綁定的session的名字。
HttpSessionBindingListener接口
定義\
public interface HttpSessionBindingListener
這個(gè)對(duì)象被加入到HTTP的session中,執(zhí)行這個(gè)接口會(huì)通告有沒(méi)有什么對(duì)象被綁定到這個(gè)HTTP session中或被從這個(gè)HTTP session中取消綁定。
方法
1、valueBound
public void valueBound(HttpSessionBindingEvent event);
當(dāng)一個(gè)對(duì)象被綁定到session中,調(diào)用此方法。HttpSession.putValue方法被調(diào)用時(shí),Servlet引擎應(yīng)該調(diào)用此方法。
2、valueUnbound
public void valueUnbound(HttpSessionBindingEvent event);
當(dāng)一個(gè)對(duì)象被從session中取消綁定,調(diào)用此方法。HttpSession.removeValue方法被調(diào)用時(shí),Servlet引擎應(yīng)該調(diào)用此方法。
Session的事件處理機(jī)制與swing事件處理機(jī)制不同。Swing采用注冊(cè)機(jī)制,而session沒(méi)有;當(dāng)任一session發(fā)生綁定或其他事件時(shí),都會(huì)觸發(fā)HttpSessionBindingEvent ,如果servlet容器中存在HttpSessionBindingListener的實(shí)現(xiàn)類(lèi),則會(huì)將事件作為參數(shù)傳送給session偵聽(tīng)器的實(shí)現(xiàn)類(lèi)。在HttpSessionBindingEvent 中可以通過(guò)getsession得到發(fā)生綁定和取消綁定的session的名字,而偵聽(tīng)器可以據(jù)此做更多處理。
因此,對(duì)session的事件偵聽(tīng),只需實(shí)現(xiàn)HttpSessionBindingListener即可。
從servlet2.3增加了
HttpSessionEvent(This is the class representing event notifications for changes to sessions within a web application)
HttpSessionActivationListener(Objects that are bound to a session may listen to container events notifying them that sessions will be passivated and that session will be activated.)
HttpSessionAttributeListener(This listener interface can be implemented in order to get notifications of changes to the attribute lists of sessions within this web application.)
分別執(zhí)行不同的任務(wù),處理基本相同。
三、 例子(zz)
捕獲Servlet Session事件的意義:
1、 記錄網(wǎng)站的客戶登錄日志(登錄,退出信息等)
2、 統(tǒng)計(jì)在線人數(shù)
3、 等等還有很多,呵呵,自己想吧……總之挺重要的。
Session代表客戶的會(huì)話過(guò)程,客戶登錄時(shí),往Session中傳入一個(gè)對(duì)象,即可跟蹤客戶的會(huì)話。在Servlet中,傳入Session的對(duì)象如果是一個(gè)實(shí)現(xiàn)HttpSessionBindingListener接口的對(duì)象(方便起見(jiàn),此對(duì)象稱(chēng)為監(jiān)聽(tīng)器),則在傳入的時(shí)候(即調(diào)用HttpSession對(duì)象的setAttribute方法的時(shí)候)和移去的時(shí)候(即調(diào)用HttpSession對(duì)象的removeAttribute方法的時(shí)候或Session Time out的時(shí)候)Session對(duì)象會(huì)自動(dòng)調(diào)用監(jiān)聽(tīng)器的valueBound和valueUnbound方法(這是HttpSessionBindingListener接口中的方法)。由此可知,登錄日志也就不難實(shí)現(xiàn)了。
另外一個(gè)問(wèn)題是,如何統(tǒng)計(jì)在線人數(shù),這個(gè)問(wèn)題跟實(shí)現(xiàn)登錄日志稍微有點(diǎn)不同,統(tǒng)計(jì)在線人數(shù)(及其信息),就是統(tǒng)計(jì)現(xiàn)在有多少個(gè)Session實(shí)例存在,我們可以增加一個(gè)計(jì)數(shù)器(如果想存儲(chǔ)更多的信息,可以用一個(gè)對(duì)象來(lái)做計(jì)數(shù)器,隨后給出的實(shí)例中,簡(jiǎn)單起見(jiàn),用一個(gè)整數(shù)變量作為計(jì)數(shù)器),通過(guò)在valueBound方法中給計(jì)數(shù)器加1,valueUnbound方法中計(jì)數(shù)器減1,即可實(shí)現(xiàn)在線人數(shù)的統(tǒng)計(jì)。當(dāng)然,這里面要利用到ServletContext的全局特性。(有關(guān)ServletContext的敘述請(qǐng)參考Servlet規(guī)范),新建一個(gè)監(jiān)聽(tīng)器,并將其實(shí)例存入ServletContext的屬性中,以保證此監(jiān)聽(tīng)器實(shí)例的***性,當(dāng)客戶登錄時(shí),先判斷ServletContext的這個(gè)屬性是否為空,如果不為空,證明已經(jīng)創(chuàng)建,直接將此屬性取出放入Session中,計(jì)數(shù)器加1;如果為空則創(chuàng)建一個(gè)新的監(jiān)聽(tīng)器,并存入ServletContext的屬性中。
舉例說(shuō)明:
實(shí)現(xiàn)一個(gè)監(jiān)聽(tīng)器:
// SessionListener.java
import java.io.*; import java.util.*; import javax.servlet.http.*;
//監(jiān)聽(tīng)登錄的整個(gè)過(guò)程 public class SessionListener implements HttpSessionBindingListener {
public String privateInfo=""; //生成監(jiān)聽(tīng)器的初始化參數(shù)字符串 private String logString=""; //日志記錄字符串 private int count=0; //登錄人數(shù)計(jì)數(shù)器
public SessionListener(String info){ this.privateInfo=info; }
public int getCount(){ return count; }
public void valueBound(HttpSessionBindingEvent event) { count++; if (privateInfo.equals("count")) { return; } try{ Calendar calendar=new GregorianCalendar(); System.out.println("LOGIN:"+privateInfo+" TIME:"+calendar.getTime()); logString="\nLOGIN:"+privateInfo+" TIME:"+calendar.getTime()+"\n"; for(int i=1;i<1000;i++){ File file=new File("yeeyoo.log"+i); if(!(file.exists())) file.createNewFile(); //如果文件不存在,創(chuàng)建此文件 if(file.length()>1048576) //如果文件大于1M,重新創(chuàng)建一個(gè)文件 continue; FileOutputStream foo=new FileOutputStream("yeeyoo.log"+i,true); //以append方式打開(kāi)創(chuàng)建文件 foo.write(logString.getBytes(),0,logString.length()); //寫(xiě)入日志字符串 foo.close(); break;//退出 } }catch(FileNotFoundException e){} catch(IOException e){} }
public void valueUnbound(HttpSessionBindingEvent event) { count--; if (privateInfo.equals("count")) { return; } try{ Calendar calendar=new GregorianCalendar(); System.out.println("LOGOUT:"+privateInfo+" TIME:"+calendar.getTime()); logString="\nLOGOUT:"+privateInfo+" TIME:"+calendar.getTime()+"\n"; for(int i=1;i<1000;i++){ File file=new File("yeeyoo.log"+i); if(!(file.exists())) file.createNewFile(); //如果文件不存在,創(chuàng)建此文件 if(file.length()>1048576) //如果文件大于1M,重新創(chuàng)建一個(gè)文件 continue; FileOutputStream foo=new FileOutputStream("yeeyoo.log"+i,true); //以append方式打開(kāi)創(chuàng)建文件 foo.write(logString.getBytes(),0,logString.length()); //寫(xiě)入日志字符串 foo.close(); break;//退出 } }catch(FileNotFoundException e){} catch(IOException e){} }
} |
登錄日志的實(shí)現(xiàn):
下面再來(lái)看看我們的登錄Servlet中使用這個(gè)監(jiān)聽(tīng)器的部分源代碼:
…… HttpSession session = req.getSession (true); …… ////////////////////////////////////////////////////////////////// SessionListener sessionListener= new SessionListener("IP:"+req.getRemoteAddr()); //對(duì)于每一個(gè)會(huì)話過(guò)程均啟動(dòng)一個(gè)監(jiān)聽(tīng)器 session.setAttribute("listener",sessionListener); //將監(jiān)聽(tīng)器植入HttpSession,這將激發(fā)監(jiān)聽(tīng)器調(diào)用valueBound方法, //從而記錄日志文件。 ////////////////////////////////////////////////////////////////// |
當(dāng)系統(tǒng)退出登錄時(shí),只需簡(jiǎn)單地調(diào)用session.removeAttribute(“l(fā)istener”);
即可自動(dòng)調(diào)用監(jiān)聽(tīng)器的valueUnbound方法。或者,當(dāng)Session Time Out的時(shí)候也會(huì)調(diào)用此方法。
登錄人數(shù)的統(tǒng)計(jì):
ServletContext session1=getServletConfig().getServletContext(); //取得ServletContext對(duì)象實(shí)例 if((SessionListener)session1.getAttribute("listener1")==null) { SessionListener sessionListener1=new SessionListener("count"); //只設(shè)置一次,不同于上面日志文件的記錄每次會(huì)話均設(shè)置。 //即當(dāng)***個(gè)客戶連接到服務(wù)器時(shí)啟動(dòng)一個(gè)全局變量, //此后所有的客戶將使用相同的上下文。 session1.setAttribute("listener1",sessionListener1); //將監(jiān)聽(tīng)器對(duì)象設(shè)置成ServletContext的屬性,具有全局范圍有效性, //即所有的客戶均可以取得它的實(shí)例。 } session.setAttribute("listener1",(SessionListener)session1. getAttribute("listener1")); //取出此全局對(duì)象,并且將此對(duì)象綁定到某個(gè)會(huì)話中, //此舉將促使監(jiān)聽(tīng)器調(diào)用valueBound,計(jì)數(shù)器加一。 |
在此后的程序中隨時(shí)可以用以下代碼取得當(dāng)前的登錄人數(shù):
((SessionListener)session.getAttribute("listener1")).getCount() |
Servlet Session中的getCount()是監(jiān)聽(tīng)器的一個(gè)方法,即取得當(dāng)前計(jì)數(shù)器的值也就是登錄人數(shù)了。
【編輯推薦】
- 淺析Java Servlet構(gòu)建系統(tǒng)
- HTTP Servlet應(yīng)用編程接口介紹
- 再談如何理解JSP和Servlet的概念
- Servlet和JavaServer Page使用介紹
- ServletResponse是什么
新聞名稱(chēng):ServletSession機(jī)制詳解
網(wǎng)頁(yè)鏈接:http://www.5511xx.com/article/dpcoohh.html


咨詢(xún)
建站咨詢(xún)
