JavaWeb開發中的Session管理
Session管理是Web應用程式開發中一個非常重要的主題,這是因為Web語言HTTP是無狀態的。在預設情況下,Web伺服器不知道一個HTTP請求時來自初次使用者,還是來自之前訪問過的使用者。例如,webmail應用程式要求使用者在檢視郵件之前要先登入。但是,一旦使用者輸入正確的使用者名稱和密碼,使用者在訪問應用程式的其他部分時,就不應該提示他們再次登入。應用程式需要記住哪些使用者已經登入成功。換句話說,它必須弄個管理使用者Session。
保持狀態的四種方法:
1.URL重寫
2.表單隱藏域
3.cookie機制
4.HttpSession物件
1.URL重寫
URL重寫是一種Session追蹤技術,需要將一個或多個token作為一個查詢字串新增到一個URL中。token的格式一般是鍵=值:
url?key1=value1&key2=value2&key3=value3&key4=value4...
注意,URL和token之間要用一個?隔開,兩個token之間則用一個&符號隔開。
如果token不必在過多的URL中四處攜帶,那麼URL重寫就比較合適。但其也有缺點:
1.在有些文字瀏覽器中,URL限制為兩千個字元;
2.僅當有連結要插入值時,值才能轉換為後面的資源。此外,要把值新增到靜態頁面的連結中,可不是一件容易的事。
3.URL重寫必須在伺服器端有效。所有的連結都必須帶有值,這樣可能出現一個問題,即一個頁面可能有多個連結。
4.某些字元,例如空格、&和問號都必須進行編碼。
5.新增到URL中的資訊是明顯可見的,這種情況有時可能不是我們想要的。
由於上述侷限性,URL重寫只適用於那些既需要保持,卻又不跨越太多頁面,並且又不太重要的資訊。
2.表單隱藏域
利用隱藏域來保持狀態,與URL重寫技術類似。但它不是將值添到URL後面,而是將它們放在HTML表單的隱藏域當中。當用戶提交表單時,隱藏域中的值也傳送到伺服器。只有當頁面包含表單時,或者可以在頁面新增表單時,才適合使用表單域。這種技術勝過URL重寫的地方在於,可以將更多的字元傳到伺服器,並且不需要進行字元編碼。但跟URL重寫一樣,只有當傳遞的資訊不需要跨越多個頁面時,才適合使用這種技術。
3.cookie機制
URL重寫和表單隱藏域只適用於那些不需要跨越太多頁面的資訊。如果這些資訊需要
cookie是自動地在瀏覽器和伺服器來回傳遞的一小塊資訊。cookie適用於那些需要跨越很多頁面的資訊。由於cookie是作為HTTP標頭嵌入的,因此傳輸它的過程由HTTP協議處理。除此之外,還可以根據自己的需要設定cookie的有效期限。對於web瀏覽器而言每臺web伺服器最多可以支援20個cookie。
cookie的不足之處在於,使用者可以通過修改他的瀏覽器設定來禁止cookie。
要使用cookie,必須熟悉javax.servlet.http.Cookie類,以及HttpServletRequest和HttpServletResponse中的幾個方法。
要建立cookie,只需傳遞一個名稱和值給Cookie的構造器:
Cookie cookie=new Cookie(name,value);
建立cookie之後,可以設定它的domain、path、maxAge屬性。尤其值得關注的是maxAge屬性,因為它決定了cookie的有效期限。為了將一個cookie傳送到瀏覽器,需在HttpServletResponse上呼叫add方法:
httpServletResponse.add(cookie);
當瀏覽器再次發出對同一資源或者同一臺伺服器中的不同資源的請求時,它會同時把從web瀏覽器收到的cookie傳回去。要訪問瀏覽器發出的cookie,可以在HttpServletRequest中使用getCookies方法。該方法返回一個Cookie陣列,如果請求中沒有cookie,將返回null。為了找到某個名稱的cookie,需要迭代陣列,下面舉例說明如何讀取一個名為maxRecords的cookie:
Cookie[] cookies=request.getCookies();
Cookie maxRecordsCookie=null;
if(cookies!=null){
for(Cookie cookie:cookies){
if(cookie.getName().equals("maxRecords")){
maxRecordsCookie=cookie;
break;
}
}
}
令人遺憾的是,沒有getCookieByName方法可以使獲取cookie變得更簡單一些。更令人難過的是,也沒有方法直接刪除cookie。為了刪除cookie,需要建立一個同名coolie,將它的maxAge屬性設為0,並在HttpServletResponse中新增一個新的cookie。舉例刪除一個名為userName的cookie:
Cookie cookie=new Cookie("userName","");
cookie.setMaxAge(0);
response.addCookie(cookie);
4.HttpSession物件
在所有Session追蹤技術中,HttpSession物件是最強大的,也是功能最多的。使用者可以沒有或有一個HttpSession,並且只能訪問他自己的HttpSession。
HttpSession是當一個使用者第一次訪問某個網站時自動建立的。通過在HttpServletRequeat中呼叫getSession方法,可以獲取HttpSession。getSession有兩個過載方法:
HttpSession getSession()
HttpSession getSession(boolean create)
無參的getSession方法返回當前HttpSession,如果當前沒有,則建立一個並返回。getSession(false)方法返回當前的HttpSession(若有),如果沒有,則返回null。getSession(true)和getSession()一樣。
HttpSession的setAttribute方法簽名如下:
void setAttribute(String name,Object obj)
注意,與前三種技術不同,放在HttpSession中的值是儲存在記憶體中的。因此,你只能將盡可能小的物件放裡面,並且數量不能太多。即使現代的Servlet容器可以在記憶體將滿時將HttpSession中的物件移到輔助儲存裝置中,但是這樣會影響效能。所以,對於保存在HttpSession中的內容一定要慎重。新增到HttpSession中的值可以使任意java物件,只要它的類實現了java.io.Serializable介面即可,以便當servlet容器認為有必要時,將其序列化成一個檔案或儲存到資料庫中,例如,當容器的記憶體快要用完時。但仍可以將非序列化的物件儲存在HttpSession中,但如果容器試圖將它們序列化,將以失敗告終,並丟擲異常。setAttribute方法要求不同的物件有不同的名稱。如果傳遞一個以前用過的的屬性名稱,那麼該名稱將與舊值無關聯,而與新值相關聯了。通過在HttpSession中呼叫getAttribute方法,同時傳遞一個屬性名稱,可以獲取HttpSession中儲存的物件。方法簽名如下:
java.lang.Object getAttribute(java.lang.String name)
HttpSession中另一個有用的方法是getAttributeNames,它返回一個Enumeration,迭代一個HttpSession中的所有屬性:
java.util.Enumeration<java.lang.String> getAttributeNames()
注意,HttpSession中儲存的值不傳送到瀏覽器,這與其他Session管理方法不同。而是Servlet容器為它所建立的HttpSession生成一個唯一的識別符號,並將這個識別符號作為一個token傳送給瀏覽器,一般是作為一個名為JSESSIONID的cookie,或者作為一個jsessionid引數新增到URL後面。在後續的請求中,瀏覽器會將這個token發給伺服器,使伺服器能夠知道是哪個使用者在發出請求。無論servlet容器選擇用哪一種方式傳輸session識別符號,都是後臺自動完成的,不需要你去做額外的處理工作。
通過在HttpSession中呼叫getId方法,可以獲取HttpSession的識別符號。
HttpSession中還定義了一個invalidate方法,這個方法強制session過期,並將綁定到它的所有物件解除繫結。在預設情況下,HttpSession是在使用者靜默一定時間之後過期。很多時候,還需要銷燬未過期卻又沒用的HttpSession例項,以便釋放一些記憶體空間。可以呼叫getMaxInactiveInterval方法,以瞭解一個HttpSession在使用者最後一次訪問之後還能維持多久。這個方法返回使用者離開的秒數。setMaxInactiveInterval方法可以幫助你為個別HttpSession設定一個過期期限。
void setMaxInactiveInterval(int seconds)
如果將這個值設為0,則這個HttpSession將永不過期。一般來說,這不是一種好辦法,因為HttpSession佔用的堆空間將永不釋放,直到應用程式解除安裝或servlet容器關閉為止。