1. 程式人生 > >[Servlet&JSP] HttpSession會話管理

[Servlet&JSP] HttpSession會話管理

我們可以將會話期間必須共享的資料儲存在HttpSession中,使之成為屬性。如果使用者關掉瀏覽器接受Cookie的功能,HttpSession也可以改用URL重寫的方式繼續其會話管理功能。

HttpSession的使用

在Servlet/JSP中,如果要進行會話管理,可以使用HttpServletRequest的getSession()方法取得HttpSession物件。語句如下:

HttpSession session = request.getSession();

getSession()方法有兩個版本,另一個版本可以傳入布林值,預設為true,表示若尚未存在HttpSession例項,則直接建立一個新的物件;若傳入為false,表示若尚未存在HttpSession例項,則直接返回null。

HttpSession上最常用的方法時setAttribute()與getAttribute(),可以在物件中設定和取得屬性。預設在關閉瀏覽器前,所取得的HttpSession都是形同的例項。如果想要在此次會話期間直接讓目前的HttpSession失效,則可以執行HttpSession的invalidate()方法。一個使用的時機就是實現登出機制。一個示例如下:

Login.java:

@WebServlet("/login.do")
public class Login extends HttpServlet{
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
        throws
ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); if ("abc".equals(username) && "123".equals(password)) { request.getSession().setAttribute("login", username); request.getRequestDispatcher("user.jsp"
) .forward(request, response); } else { response.sendRedirect("login.html"); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } }

在登入時,如果使用者名稱與密碼正確,就會取得HttpSession並設定一個login屬性,用以代表使用者完成登入的動作。對於其他的Servlet/JSP,如果可以從HttpSession取得login屬性,基本就可以確定是個已登入的使用者,這類用來識別使用者是否登入的屬性,通常稱為登入字元(Login Token)。在上例中,登入成功後會轉發到使用者介面。

User.jsp:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
    <c:choose>
        <c:when test="${sessionScope.login == null}">
            <jsp:include page="login.html" />
        </c:when>
        <c:otherwise>
            <h1>Welcome! ${sessionScope.login}!</h1>
            <a href="logout.do">Sign out</a>
        </c:otherwise>
    </c:choose>
</body>
</html>

Login.html

<body>
    <form action="login.do" method="post">
        username:<input type="text" name="username" /><br />
        password:<input type="password" name="password" /><br />
        <input type="submit" value="Sign in" />
    </form>
</body>

Logout.java:

@WebServlet("/logout.do")
public class Logout extends HttpServlet{
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        request.getSession().invalidate();
        response.sendRedirect("login.html");
    }
}

指定HttpSession的invalidate()之後,容器就會銷燬並回收HttpSession物件。如果再次執行HttpServletRequest的getSession(),則說的取得的HttpSession就是另外一個新的物件了。

HttpSession會話管理原理

當執行HttpServletRequest的getSession()時,web容器會建立HttpSession物件,每個HttpSession都會有一個特殊的ID,稱之為Session ID。可以執行HttpSession的getID()可以取得Session ID。這個Session ID預設會使用Cookie將其存放至瀏覽器。在Tomcat中,Cookie的名稱是JSESSIONID,數字則是getID()所取得的Session ID。

每個HttpSession都有個特殊的Session ID,當瀏覽器請求應用程式時,會將Cookie中存放的Session ID一併傳送給應用程式,web容器根據Session ID來取出對應的HttpSession物件,如此就可以取得各個瀏覽器的會話資料。

所以使用HttpSession來進行會話管理時,設定為屬性的資料是儲存在伺服器端的,而Session ID預設使用Cookie存放於瀏覽器中。web容器儲存Session ID的Cookie被設定為關閉則瀏覽器就會失效,重新開啟瀏覽器請求應用程式時,通過getSession()所取得的是新的HttpSession物件。

由於HttpSession會佔用記憶體空間,所以HttpSession得屬性中儘量不要儲存耗資源的大型物件,必要時可將屬性移除,或者不需使用HttpSession時,執行invalidate()讓HttpSession失效。

關閉瀏覽器時會馬上失效的是瀏覽器上的Cookie,而不是HttpSession。

可以執行HttpSession的setMaxInactiveInterval()方法,設定瀏覽器在多久沒有請求應用程式的情況下,HttpSession就會自動失效,設定的單位是”秒”。也可以在web.xml中設定HttpSession預設的失效時間,但要注意的時,這裡設定的時間單位是”分鐘”。例如:

<web-app ...>
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
</web-app>

儲存Session ID的Cookie被設定為關閉瀏覽器就失效。關閉瀏覽器後若希望儲存資訊,必須通過自行操作Cookie來達成,例如完成自動登入機制。

HttpSession與URL重寫

如果在使用者禁用Cookie的情況下,仍打算運用HttpSession來進行會話管理,那麼可以搭配URL重寫的方式,向瀏覽器響應一段超連結,超連結URL後附加Session ID,當用戶點選超連結時,則將Session ID以GET請求方式傳送給web應用程式。

如果要使用URL重寫的方式來發送Session ID,則可以使用HttpServletRequest的encodeURL()協助產生所需的URL重寫。當容器嘗試取得HttpSession例項時,若可以從HTTP請求中取得帶有Session ID的Cookie,encodeURL()會將設定給它的URL原封不動的輸出;若無法從HTTP請求中取得帶有Session ID的Cookie(通常是瀏覽器禁用Cookie的情況),encodeURL()會自動產生帶有Session ID的URL重寫。

如果有執行encdeURL(),在瀏覽器第一次請求網站時,容器並不知道瀏覽器是否禁用Cookie,所以容器的做法是Cookie(傳送set-cookie標頭)與URL重寫都做,因此若Servlet有以下語句,無論瀏覽器是否禁用Cookie,第一次請求時,都會顯示編上Session ID的URL。

request.getSession();
out.println(response.encodeURL("index.jsp"));

當再次請求時,如果瀏覽器沒有禁用Cookie,則容器可以從Cookie(從cookie標頭)中取得Session ID,此時encodeURL()就只會輸出index.jsp。如果瀏覽器禁用Cookie,則encodeURL()就會繼續在URL上編上Session ID

HttpServletResponse的另一個方法encodeRedirectURL()方法,可以在要去瀏覽器重定向時,在URL上編上Session ID。