色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          EEPW首頁 > 手機與無線通信 > 設(shè)計應用 > JSP/Servlet:Servlet/JSP會話跟蹤機制 (1)

          JSP/Servlet:Servlet/JSP會話跟蹤機制 (1)

          ——
          作者: 時間:2006-07-25 來源:賽迪網(wǎng)論壇 收藏

          一、Servlet的會話管理機制 

          根據(jù)設(shè)計,HTTP是一種無狀態(tài)的協(xié)議。它意味著Web應用并不了解有關(guān)同一用戶以前請求的信息。維持會話狀態(tài)信息的方法之一是使用Servlet或者JSP容器提供的會話跟蹤功能。Servlet API規(guī)范定義了一個簡單的HttpSession接口,通過它我們可以方便地實現(xiàn)會話跟蹤。 

          HttpSession接口提供了存儲和返回標準會話屬性的方法。標準會話屬性如會話標識符、應用數(shù)據(jù)等,都以“名字-值”對的形式保存。簡而言之,HttpSession接口提供了一種把對象保存到內(nèi)存、在同一用戶的后繼請求中提取這些對象的標準辦法。在會話中保存數(shù)據(jù)的方法是setAttribute(String s, Object o),從會話提取原來所保存對象的方法是getAttribute(String s)。 

          在HTTP協(xié)議中,當用戶不再活動時不存在顯式的終止信號。由于這個原因,我們不知道用戶是否還要再次返回,如果不采取某種方法解決這個問題,內(nèi)存中會積累起大量的HttpSession對象。 

          為此,Servlet采用“超時限制”的辦法來判斷用戶是否還在訪問:如果某個用戶在一定的時間之內(nèi)沒有發(fā)出后繼請求,則該用戶的會話被作廢,他的HttpSession對象被釋放。會話的默認超時間隔由Servlet容器定義。這個值可以通過getMaxInactiveInterval方法獲得,通過setMaxInactiveInterval方法修改,這些方法中的超時時間以秒計。如果會話的超時時間值設(shè)置成-1,則會話永不超時。Servlet可以通過getLastAccessedTime方法獲得當前請求之前的最后一次訪問時間。 

          要獲得HttpSession對象,我們可以調(diào)用HttpServletRequest對象的getSession方法。為了正確地維持會話狀態(tài),我們必須在發(fā)送任何應答內(nèi)容之前調(diào)用getSession方法。 
          用戶會話既可以用手工方法作廢,也可以自動作廢。作廢會話意味著從內(nèi)存中刪除HttpSession對象以及它的數(shù)據(jù)。例如,如果一定時間之內(nèi)(默認30分鐘)用戶不再發(fā)送請求,Java Web Server自動地作廢他的會話。 

          Servlet/JSP會話跟蹤機制有著一定的局限,比如: 

          ? 會話對象保存在內(nèi)存之中,占用了可觀的資源。 

          ? 會話跟蹤依賴于Cookie。由于各種原因,特別是安全上的原因,一些用戶關(guān)閉了Cookie。 

          ? 會話跟蹤要用到服務(wù)器創(chuàng)建的會話標識符。在多個Web服務(wù)器以及多個JVM的環(huán)境中,Web服務(wù)器不能識別其他服務(wù)器創(chuàng)建的會話標識符,會話跟蹤機制無法發(fā)揮作用。 
          要深入理解會話跟蹤機制,首先我們必須理解在Servlet/JSP容器中會話如何運作。 


          二、會話標識符 

          每當新用戶請求一個使用了HttpSession對象的JSP頁面,JSP容器除了發(fā)回應答頁面之外,它還要向瀏覽器發(fā)送一個特殊的數(shù)字。這個特殊的數(shù)字稱為“會話標識符”,它是一個唯一的用戶標識符。此后,HttpSession對象就駐留在內(nèi)存之中,等待同一用戶返回時再次調(diào)用它的方法。 

          在客戶端,瀏覽器保存會話標識符,并在每一個后繼請求中把這個會話標識符發(fā)送給服務(wù)器。會話標識符告訴JSP容器當前請求不是用戶發(fā)出的第一個請求,服務(wù)器以前已經(jīng)為該用戶創(chuàng)建了HttpSession對象。此時,JSP容器不再為用戶創(chuàng)建新的HttpSession對象,而是尋找具有相同會話標識符的HttpSession對象,然后建立該HttpSession對象和當前請求的關(guān)聯(lián)。 

          會話標識符以Cookie的形式在服務(wù)器和瀏覽器之間傳送。如果瀏覽器不支持Cookie又如何呢?此時,對服務(wù)器的后繼請求將不會帶有會話標識符。結(jié)果,JSP容器認為該請求來自一個新用戶,它會再創(chuàng)建一個HttpSession對象,而以前創(chuàng)建的HttpSession對象仍舊駐留在內(nèi)存中,但該用戶以前的會話信息卻丟失了。 

          另外,Servlet/JSP容器只認可它自己創(chuàng)建的會話標識符。如果同一Web應用在“Web農(nóng)場”(Web farm)的多臺服務(wù)器上運行,則必須存在這樣一種機制:保證來自同一用戶的請求總是被定向到處理該用戶第一次請求的服務(wù)器。 

          三、偽會話管理機制 

          如前所述,基于Cookie的會話管理技術(shù)面臨著種種問題。下面我們要設(shè)計一種新的會話管理機制來解決這些問題。這種會話管理機制稱為“偽會話”(Pseudo Session)機制,它具有如下特點: 

          ? 對象和數(shù)據(jù)不是保存在內(nèi)存中,而是以文本文件形式保存。每一個文本文件與一個特定的用戶關(guān)聯(lián),文件的名字就是會話的標識符。因此,文件名字必須是唯一的。 
          ? 文本文件保存在一個專用的目錄中,所有Web服務(wù)器都可以訪問這個目錄。因此,偽會話可以用于Web農(nóng)場。 
          ? 會話標識符不作為Cookie發(fā)送,而是直接編碼到URL里面。因此,采用偽會話技術(shù)要求修改所有的超級鏈接,包括HTML表單的ACTION屬性。 
          此外,實現(xiàn)偽會話管理機制時我們還要考慮到以下幾點: 
          ? 它應該與應用無關(guān),其他想要實現(xiàn)同樣功能的開發(fā)者應該能夠方便地重用它。 
          ? 考慮到安全原因,應該有一種為會話標識符生成隨機數(shù)字的辦法。 
          ? 為了作廢過期的會話,應該設(shè)定一個超時值。同一個用戶,如果他超過一定的時間之后再次返回,他將獲得一個新的會話標識符。此舉能夠防止未經(jīng)授權(quán)的用戶冒用其他人的會話。 
          ? 應該有一種收集過期會話并刪除相應文本文件的機制。 
          ? 如果用戶使用已經(jīng)過期的會話標識符再次訪問服務(wù)器,即使這個會話標識符的文本文件還沒有刪除,系統(tǒng)也不應該允許用戶使用原來的會話。 
          ? 同時,應該存在一種更新會話文本文件最后改動時間的機制,使得用戶在會話過期時限之前返回時會話總是保持最新且合法的狀態(tài)數(shù)據(jù)。 
           

          四、實現(xiàn)偽會話管理機制 

          下面所介紹的工程稱為PseudoSession,它是偽會話機制一個很簡單的實現(xiàn)??紤]到移植性,我們以JavaBean的形式實現(xiàn)它。PseudoSessionBean的完整代碼可以從本文后面下載。 

          PseudoSessionBean擁有如下域(Field): 
          public String path;public long timeOut; 
          path是保存所有會話文本文件的目錄。如果Web服務(wù)器的數(shù)量在一個以上,這個目錄必須允許所有服務(wù)器訪問。然而,為了防止用戶直接訪問這些文本文件,這個路徑應該不允許用戶直接訪問。解決這個問題的一種方法是使用Web網(wǎng)站根之外的目錄。 

          timeOut是用戶的最后一個請求到會話過期作廢之間的時間。在PseudoSessionBean的代碼清單中,timeOut設(shè)置成了以毫秒表示的20分鐘,這是一個比較合理的超時時間值。對于任何用戶,如果他在這個超時時間之后才繼續(xù)發(fā)出請求,他將得到一個新的會話標識符。 
          PseudoSessionBean有4個方法:getSessionID,setValue,getValue,deleteAllInvalidSessions。 

          4.1 getSessionID方法 
          getSessionID方法的聲明如下: 
          public String getSessionID(HttpServletRequest request) 
          這個方法應該在每一個JSP頁面的開頭調(diào)用。它完成如下任務(wù): 
          ? 如果用戶是第一次訪問,則為該用戶設(shè)定一個新的會話標識符。 
          ? 檢查URL所帶會話標識符的合法性。如果會話標識符已經(jīng)過期,則getSessionID方法返回一個新的會話標識符。 
          下面我們來看看getSessionID方法的工作過程。 
          String sessionId = request.getParameter("sessionId"); 
          validSessionIdFound是一個標記,用于指示會話標識符是否合法。validSessionIdFound的初始值是false。 
          boolean validSessionIdFound = false; 
          long類型的now變量包含請求出現(xiàn)時的服務(wù)器時間。該變量用于確定用戶會話的合法性。 
          long now = System.currentTimeMillis(); 
          如果找到了會話標識符,則getSessionID方法檢查它的合法性。檢查過程如下: 
          ? 一個合法的會話標識符必須有對應的同名文本文件。 
          ? 文件的最后修改時間加上timeOut應該大于當前時間。 
          ? 如果存在與會話對應的文本文件,但文件已經(jīng)過期,則原來的文件被刪除。 
          ? 把合法會話標識符所對應文本文件的最后修改日期改為now。 
          這些任務(wù)主要借助File對象完成,創(chuàng)建File對象的參數(shù)就是會話文本文件的路徑: 
          if (sessionId!=null) {
          File f = new File(path + sessionId);
          if (f.exists()) {
           if (f.lastModified() + timeOut > now) { // 會話合法// 使用setLastModified時,如果文件已經(jīng)被其他程序鎖定,// 程序不會產(chǎn)生任何異常,但文件數(shù)據(jù)不會改變f.setLastModified(now);validSessionIdFound = true; } else { // 會話已經(jīng)過期 // 刪除文件f.delete(); }} // end if (f.exists) } // end if (sessionId!=null) 
          如果不存在合法的會話標識符,則getSessionID方法生成一個會話標識符以及相應的文本文件: 
          if (!validSessionIdFound) { sessionId = Long.toString(now); // 創(chuàng)建文件 File f = new File(path + sessionId); try {f.createNewFile(); } catch (IOException ioe) {}} // end of if !validSessionIdFound 
          程序保證文件名字隨機性的方法非常簡單:把當前的系統(tǒng)時間直接轉(zhuǎn)換成會話標識符。對于那些涉及敏感數(shù)據(jù)的應用,我們應該考慮運用更安全的隨機數(shù)生成器來生成會話標識符。 
          綜上所述,getSessionID并不總是返回新的合法會話標識符:它返回的標識符可能與傳遞給它的標識符相同,也可能是新創(chuàng)建的會話標識符。 
          為了保證JSP頁面擁有合法的會話標識符以便調(diào)用setValue、getValue方法,每個JSP頁面都必須在開頭位置調(diào)用getSesstionID方法。 


          4.2 setValue方法 
          setValue方法保存value字符串以及與它關(guān)聯(lián)的字符串名字。這種“名字-值”對很容易使人想起Dictionary對象。setValue方法要求在第一個參數(shù)中提供合法的會話標識符,它假定在自己被調(diào)用之前getSessionID方法已經(jīng)執(zhí)行,經(jīng)過檢驗的合法會話標識符必然存在,因此它不再對傳入的會話標識符進行合法性檢驗。 
          setValue方法按如下規(guī)則保存名字-值對: 
          ? 如果與value值關(guān)聯(lián)的name以前還沒有保存過,則新的名字-值對加入到文本文件的末尾。 
          ? 如果value字符串關(guān)聯(lián)的name值以前已經(jīng)保存過,則原來保存的值被新的value值替換。 
          setValue方法按照如下格式保存名字-值對,注意“名字”是大小寫敏感的: 
          name-1 value-1name-2 value-2name-3 value-3...name-n value-n 
          setValue方法的聲明如下: 
          public void setValue(String sessionId, String name, String value) 
          setValue方法首先尋找與當前會話對應的文本文件。如果不能找到文本文件,則setValue方法不做任何事情直接返回。如果找到了會話文本文件,setValue方法讀取文本文件的各個行,然后比較讀入的行與name:如果讀入的文本行開頭與name一樣,則說明該名字已經(jīng)保存,setValue方法將替換該行后面的值;如果name不能與讀入的文本行匹配,則這行文本被直接復制到一個臨時文件。 
          這部分功能的實現(xiàn)代碼如下: 
          try { FileReader fr = new FileReader(path + sessionId); BufferedReader br = new BufferedReader(fr); FileWriter fw = new FileWriter(path + sessionId + ".tmp"); BufferedWriter bw = new BufferedWriter(fw); String s; while ((s = br.readLine()) != null)if (!s.startsWith(name + " ")) { bw.write(s); bw.newLine();} bw.write(name + " " + value); bw.newLine(); bw.close(); br.close(); fw.close(); bw.close(); . . .}catch (FileNotFoundException e) {}catch (IOException e) { System.out.println(e.toString());} 
          原來文本文件中的所有行復制到臨時文件之后,setValue方法刪除原來的文本文件,然后把臨時文件改成會話文本文件的名字: 
          File f = new File(path + sessionId + ".tmp");File dest = new File(path + sessionId);dest.delete();f.renameTo(dest); 


          4.3 getValue方法 
          getValue方法用于提取原來保存在偽會話中的數(shù)據(jù)。正如setValue方法,getValue方法也要求傳入一個合法的會話標識符,而且getValue方法不再對傳入的會話標識符進行合法性檢查。getValue方法的第二個參數(shù)是待提取數(shù)據(jù)的name,返回值是與指定name關(guān)聯(lián)的value。 
          getValue方法的聲明如下: 
          public String getValue(String sessionId, String name) 
          getValue方法的基本執(zhí)行過程如下:首先找到會話文本文件,然后按行讀入直至找到與name匹配的文本行;找到匹配的文本行之后,getValue方法返回該行保存的value;如果不能找到,getValue方法返回null。 


          4.4 deleteAllInvalidSessions方法 
          deleteAllInvalidSessions方法刪除那些與已經(jīng)過期的會話關(guān)聯(lián)的文本文件。由于調(diào)用getSessionID方法時過期的會話文本文件會被刪除,deleteAllInvalidSessions方法并不是關(guān)鍵的方法。什么時候調(diào)用這個方法由應用自己決定。例如,我們可以編寫一個專用的后臺程序,由這個程序每天一次清除所有過期的文本文件。最簡單的辦法是在JSP文件末尾調(diào)用deleteAllInvalidSessions方法,但如果網(wǎng)站比較繁忙,重復地調(diào)用deleteAllInvalidSessions方法將降低整個網(wǎng)站的響應能力。一種明智的做法是:編寫一個在訪問量較少的時候自動進行清理的后臺程序。 
          deleteAllInvalidSessions方法的聲明如下: 
          public void deleteAllInvalidSessions() 
          它首先把所有會話文本文件的名字讀入files字符串數(shù)組: 
          File dir = new File(path); String[] files = dir.list(); 
          deleteAllInvalidSessions方法比較文本文件的最后修改時間(加上超時時間)和系統(tǒng)當前時間,確定會話是否過期。long類型的變量now用于保存系統(tǒng)的當前時間。 
          long now = System.currentTimeMillis(); 
          接下來,deleteAllInvalidSessions方法通過循環(huán)訪問files數(shù)組,依次檢查每個文件的lastModified屬性。所有與過期會話關(guān)聯(lián)的文件都將被刪除: 
          for (int i=0; i now) f.delete(); // 刪除過期的會話文本文件} 


          五、應用實例 


          編譯好PseudoSessionBean這個JavaBean之后,我們就可以利用偽會話管理機制來管理Web應用的會話狀態(tài)信息了。由于不必再使用服務(wù)器的會話管理機制,我們可以在page指令中把session屬性設(shè)置為false關(guān)閉默認的JSP/Servlet會話管理功能。 
          < %@ page session="false" %> 

          然后,我們用JSP的標記告訴JSP容器程序要使用PseudoSessionBean: 
          < jsp:useBean id="PseudoSessionId" scope="application" class="pseudosession.PseudoSessionBean" /> 

          在上面這個標記中,class屬性值是“包.類名字”形式。當然,對于不同的包名字,class屬性的值應該作相應的修改。注意Bean的scope屬性是“application”,這是因為我們要在應用的所有頁面中使用這個Bean。在這個應用中,把Bean的scope屬性設(shè)置為“application”具有最好的效率,因為我們只需創(chuàng)建Bean對象一次就可以了。另外,正如前面所提到的,getSessionID方法必須在所有其他代碼之前調(diào)用。 
          < % String sessionId = PseudoSessionId.getSessionID(request);%> 
          為了說明PseudoSessionBean的應用,下面我們來看兩個JSP頁面,它們是index.jsp和secondPage.jsp。index.jsp頁面在偽會話變量中保存用戶的名字,而secondPage.jsp則提取這個用戶名字。 

          index.jsp頁面的代碼如下: 
          < %@ page session="false" contentType="text/html;charset=gb2312" %>
          < jsp:useBean id="PseudoSessionId" scope="application" class="pseudosession.PseudoSessionBean" />
          < % String sessionId = PseudoSessionId.getSessionID(request);%>
          < html>
          < head>
          < title>偽會話< /title>
          < /head>
          < body>
          < h1>偽會話管理機制< /h1>
          < % String userName = "bulbul"; PseudoSessionId.setValue(sessionId, "userName", userName);%>
          < a href="/secondPage.jsp?sessionId=<";%=sessionId%>>點擊此處
          < form method="post" action=anotherPage.jsp?sessionId=< %=sessionId%>>
          輸入數(shù)據(jù):< input type="text" name="sample">
          < input type="submit" name="Submit" value="Submit">
          < /form>
          < /body>
          < /html>
          < % PseudoSessionId.deleteAllInvalidSessions();%> 

          注意,包括

          標記的action屬性在內(nèi),所有的超級鏈接都已經(jīng)改寫,現(xiàn)在都包含了會話標識符。另外也請注意頁面的最后調(diào)用了deleteAllInvalidSessions方法。 
          secondPage.jsp頁面只簡單地返回以前保存的用戶名字。 
          < %@ contentType="text/html;charset=gb2312" page session="false" %>
          < jsp:useBean id="PseudoSessionId" scope="application" class="pseudosession.PseudoSessionBean" />
          < % String sessionId = PseudoSessionId.getSessionID(request);%>
          < html>
          < head>
          < title>第2個頁面
          < /head>
          < body>
          < % String userName = PseudoSessionId.getValue(sessionId, "userName"); out.println("用戶名字是 " + userName);%>
          < /body>
          < /html>  




          關(guān)鍵詞: 通訊 網(wǎng)絡(luò) 無線

          評論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉