1. 程式人生 > >Servlet中Session實現原理

Servlet中Session實現原理

ession底層是依賴Cookie的!我們來理解一下session的原理吧!

當我首次去銀行時,因為還沒有賬號,所以需要開一個賬號,我獲得的是銀行卡,而銀行這邊的資料庫中留下了我的賬號,我的錢是儲存在銀行的賬號中,而我帶走的是我的卡號。

當我再次去銀行時,只需要帶上我的卡,而無需再次開一個賬號了。只要帶上我的卡,那麼我在銀行操作的一定是我的賬號!

 

當首次使用session時,伺服器端要建立session,session是儲存在伺服器端,而給客戶端的session的id(一個cookie中儲存了sessionId)。客戶端帶走的是sessionId,而資料是儲存在session中。

當客戶端再次訪問伺服器時,在請求中會帶上sessionId,而伺服器會通過sessionId找到對應的session,而無需再建立新的session。


session與瀏覽器

session儲存在伺服器,而sessionId通過Cookie傳送給客戶端,但這個Cookie的生命不-1,即只在瀏覽器記憶體中存在,也就是說如果使用者關閉了瀏覽器,那麼這個Cookie就丟失了。

當用戶再次開啟瀏覽器訪問伺服器時,就不會有sessionId傳送給伺服器,那麼伺服器會認為你沒有session,所以伺服器會建立一個session,並在響應中把sessionId中到Cookie中傳送給客戶端。     

你可能會說,那原來的session物件會怎樣?當一個session長時間沒人使用的話,伺服器會把session刪除了!這個時長在Tomcat中配置是30分鐘,可以在${CATALANA}/conf/web.xml找到這個配置,當然你也可以在自己的web.xml中覆蓋這個配置!

web.xml

    <session-config>

        <session-timeout>30</session-timeout>

    </session-config>

 

session失效時間也說明一個問題!如果你開啟網站的一個頁面開始長時間不動,超出了30分鐘後,再去點選連結或提交表單時你會發現,你的session已經丟失了


session其他常用API

l  String getId():獲取sessionId;

l  int getMaxInactiveInterval():獲取session可以的最大不活動時間(秒),預設為30分鐘。當session在30分鐘內沒有使用,那麼Tomcat會在session池中移除這個session;

l  void setMaxInactiveInterval(int interval):設定session允許的最大不活動時間(秒),如果設定為1秒,那麼只要session在1秒內不被使用,那麼session就會被移除;

l  long getCreationTime():返回session的建立時間,返回值為當前時間的毫秒值;

l  long getLastAccessedTime():返回session的最後活動時間,返回值為當前時間的毫秒值;

l  void invalidate():讓session失效!呼叫這個方法會被session失效,當session失效後,客戶端再次請求,伺服器會給客戶端建立一個新的session,並在響應中給客戶端新session的sessionId;

l  boolean isNew():檢視session是否為新。當客戶端第一次請求時,伺服器為客戶端建立session,但這時伺服器還沒有響應客戶端,也就是還沒有把sessionId響應給客戶端時,這時session的狀態為新。


URL重寫

我們知道session依賴Cookie,那麼session為什麼依賴Cookie呢?因為伺服器需要在每次請求中獲取sessionId,然後找到客戶端的session物件。那麼如果客戶端瀏覽器關閉了Cookie呢?那麼session是不是就會不存在了呢?

其實還有一種方法讓伺服器收到的每個請求中都帶有sessioinId,那就是URL重寫!在每個頁面中的每個連結和表單中都新增名為jSessionId的引數,值為當前sessionid。當用戶點選連結或提交表單時也伺服器可以通過獲取jSessionId這個引數來得到客戶端的sessionId,找到sessoin物件。

index.jsp

  <body>

<h1>URL重寫</h1>

<a href='/day06_5/index.jsp;jsessionid=<%=session.getId() %>' >主頁</a>

 

<form action='/day06_5/index.jsp;jsessionid=<%=session.getId() %>'method="post">

    <input type="submit" value="提交"/>

</form>

  </body>

 

也可以使用response.encodeURL()對每個請求的URL處理,這個方法會自動追加jsessionid引數,與上面我們手動新增是一樣的效果。

<a href='<%=response.encodeURL("/day06_5/index.jsp"%>' >主頁</a>

 

<form action='<%=response.encodeURL("/day06_5/index.jsp"%>'method="post">

    <input type="submit" value="提交"/>

</form>

 

  使用response.encodeURL()更加“智慧”,它會判斷客戶端瀏覽器是否禁用了Cookie,如果禁用了,那麼這個方法在URL後面追加jsessionid,否則不會追加。

什麼是HttpSesssion

javax.servlet.http.HttpSession介面表示一個會話,我們可以把一個會話內需要共享的資料儲存到HttSession物件


獲取HttpSession物件

l  HttpSession request.getSesssion():如果當前會話已經有了session物件那麼直接返回,如果當前會話還不存在會話,那麼建立session並返回;

l  HttpSession request.getSession(boolean):當引數為true時,與requeset.getSession()相同。如果引數為false,那麼如果當前會話中存在session則返回,不存在返回null


HttpSession是域物件

我們已經學習過HttpServletRequestServletContext,它們都是域物件,現在我們又學習了一個HttpSession,它也是域物件。它們三個是Servlet中可以使用的域物件,而JSP中可以多使用一個域物件,明天我們再講解JSP的第四個域物件。

l  HttpServletRequest:一個請求建立一個request物件,所以在同一個請求中可以共享request,例如一個請求從AServlet轉發到BServlet,那麼AServlet和BServlet可以共享request域中的資料;

l  ServletContext:一個應用只建立一個ServletContext物件,所以在ServletContext中的資料可以在整個應用中共享,只要不啟動伺服器,那麼ServletContext中的資料就可以共享;

l  HttpSession:一個會話建立一個HttpSession物件,同一會話中的多個請求中可以共享session中的資料;


下載是session的域方法:

l  void setAttribute(String name, Object value):用來儲存一個物件,也可以稱之為儲存一個域屬性,例如:session.setAttribute(“xxx”, “XXX”),在session中儲存了一個域屬性,域屬性名稱為xxx,域屬性的值為XXX。請注意,如果多次呼叫該方法,並且使用相同的name,那麼會覆蓋上一次的值,這一特性與Map相同;

l  Object getAttribute(String name):用來獲取session中的資料,當前在獲取之前需要先去儲存才行,例如:String value = (String) session.getAttribute(“xxx”);,獲取名為xxx的域屬性;

l  void removeAttribute(String name):用來移除HttpSession中的域屬性,如果引數name指定的域屬性不存在,那麼本方法什麼都不做;

l  Enumeration getAttributeNames():獲取所有域屬性的名稱;


登入案例

需要的頁面:

l  login.jsp:登入頁面,提供登入表單;

l  index1.jsp:主頁,顯示當前使用者名稱稱,如果沒有登入,顯示您還沒登入;

l  index2.jsp:主頁,顯示當前使用者名稱稱,如果沒有登入,顯示您還沒登入;

 

Servlet:

l  LoginServlet:在login.jsp頁面提交表單時,請求本Servlet。在本Servlet中獲取使用者名稱、密碼進行校驗,如果使用者名稱、密碼錯誤,顯示“使用者名稱或密碼錯誤”,如果正確儲存使用者名稱session中,然後重定向到index1.jsp;

 

  當用戶沒有登入時訪問index1.jsp或index2.jsp,顯示“您還沒有登入”。如果使用者在login.jsp登入成功後到達index1.jsp頁面會顯示當前使用者名稱,而且不用再次登入去訪問index2.jsp也會顯示使用者名稱。因為多次請求在一個會話範圍,index1.jsp和index2.jsp都會到session中獲取使用者名稱,session物件在一個會話中是相同的,所以都可以獲取到使用者名稱!