Servlet Cookie 處理

Cookie 是存儲在客戶端電腦上的文本檔,並保留了各種跟蹤資訊。Java Servlet 顯然支持 HTTP Cookie。

識別返回用戶包括三個步驟:

  • 伺服器腳本向流覽器發送一組 Cookie。例如:姓名、年齡或識別號碼等。
  • 流覽器將這些資訊存儲在本地電腦上,以備將來使用。
  • 當下一次流覽器向 Web 伺服器發送任何請求時,流覽器會把這些 Cookie 資訊發送到伺服器,伺服器將使用這些資訊來識別用戶。

本章將向您講解如何設置或重置 Cookie,如何訪問它們,以及如何將它們刪除。

Servlet Cookie 處理需要對中文進行編碼與解碼,方法如下:

String   str   =   java.net.URLEncoder.encode("中文","UTF-8");            //編碼
String   str   =   java.net.URLDecoder.decode("編碼後的字串","UTF-8");   // 解碼

Cookie 剖析

Cookie 通常設置在 HTTP 頭資訊中(雖然 JavaScript 也可以直接在流覽器上設置一個 Cookie)。設置 Cookie 的 Servlet 會發送如下的頭資訊:

HTTP/1.1 200 OK
Date: Fri, 04 Feb 2000 21:03:38 GMT
Server: Apache/1.3.9 (UNIX) PHP/4.0b3
Set-Cookie: name=xyz; expires=Friday, 04-Feb-07 22:03:38 GMT;
                 path=/; domain=xuhuhu.com
Connection: close
Content-Type: text/html

正如您所看到的,Set-Cookie 頭包含了一個名稱值對、一個 GMT 日期、一個路徑和一個域。名稱和值會被 URL 編碼。expires 字段是一個指令,告訴流覽器在給定的時間和日期之後"忘記"該 Cookie。

如果流覽器被配置為存儲 Cookie,它將會保留此信息直到到期日期。如果用戶的流覽器指向任何匹配該 Cookie 的路徑和域的頁面,它會重新發送 Cookie 到伺服器。流覽器的頭資訊可能如下所示:

GET / HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.6 (X11; I; Linux 2.2.6-15apmac ppc)
Host: zink.demon.co.uk:1126
Accept: image/gif, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
Cookie: name=xyz

Servlet 就能夠通過請求方法 request.getCookies() 訪問 Cookie,該方法將返回一個 Cookie 對象的數組。

Servlet Cookie 方法

以下是在 Servlet 中操作 Cookie 時可使用的有用的方法列表。

序號方法 & 描述
1public void setDomain(String pattern)
該方法設置 cookie 適用的域,例如 xuhuhu.com。
2public String getDomain()
該方法獲取 cookie 適用的域,例如 xuhuhu.com。
3public void setMaxAge(int expiry)
該方法設置 cookie 過期的時間(以秒為單位)。如果不這樣設置,cookie 只會在當前 session 會話中持續有效。
4public int getMaxAge()
該方法返回 cookie 的最大生存週期(以秒為單位),默認情況下,-1 表示 cookie 將持續下去,直到流覽器關閉。
5public String getName()
該方法返回 cookie 的名稱。名稱在創建後不能改變。
6public void setValue(String newValue)
該方法設置與 cookie 關聯的值。
7public String getValue()
該方法獲取與 cookie 關聯的值。
8public void setPath(String uri)
該方法設置 cookie 適用的路徑。如果您不指定路徑,與當前頁面相同目錄下的(包括子目錄下的)所有 URL 都會返回 cookie。
9public String getPath()
該方法獲取 cookie 適用的路徑。
10public void setSecure(boolean flag)
該方法設置布爾值,表示 cookie 是否應該只在加密的(即 SSL)連接上發送。
11public void setComment(String purpose)
設置cookie的注釋。該注釋在流覽器向用戶呈現 cookie 時非常有用。
12public String getComment()
獲取 cookie 的注釋,如果 cookie 沒有注釋則返回 null。

通過 Servlet 設置 Cookie

通過 Servlet 設置 Cookie 包括三個步驟:

(1) 創建一個 Cookie 對象:您可以調用帶有 cookie 名稱和 cookie 值的 Cookie 構造函數,cookie 名稱和 cookie 值都是字串。

Cookie cookie = new Cookie("key","value");

請記住,無論是名字還是值,都不應該包含空格或以下任何字元:

[ ] ( ) = , " / ? @ : ;

(2) 設置最大生存週期:您可以使用 setMaxAge 方法來指定 cookie 能夠保持有效的時間(以秒為單位)。下麵將設置一個最長有效期為 24 小時的 cookie。

cookie.setMaxAge(60*60*24);

(3) 發送 Cookie 到 HTTP 回應頭:您可以使用 response.addCookie 來添加 HTTP 回應頭中的 Cookie,如下所示:

response.addCookie(cookie);

實例

讓我們修改我們的 表單數據實例,為名字和姓氏設置 Cookie。

package com.zaixian.test;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class HelloServlet
 */
@WebServlet("/HelloForm")
public class HelloForm extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public HelloForm() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        // 為名字和姓氏創建 Cookie
        Cookie name = new Cookie("name",
                URLEncoder.encode(request.getParameter("name"), "UTF-8")); // 中文轉碼
        Cookie url = new Cookie("url",
                      request.getParameter("url"));
        
        // 為兩個 Cookie 設置過期日期為 24 小時後

        name.setMaxAge(60*60*24);
        url.setMaxAge(60*60*24);
        
        // 在回應頭中添加兩個 Cookie
        response.addCookie( name );
        response.addCookie( url );
        
        // 設置回應內容類型
        response.setContentType("text/html;charset=UTF-8");
        
        PrintWriter out = response.getWriter();
        String title = "設置 Cookie 實例";
        String docType = "<!DOCTYPE html>\n";
        out.println(docType +
                "<html>\n" +
                "<head><title>" + title + "</title></head>\n" +
                "<body bgcolor=\"#f0f0f0\">\n" +
                "<h1 align=\"center\">" + title + "</h1>\n" +
                "<ul>\n" +
                "  <li><b>站點名:</b>:"
                + request.getParameter("name") + "\n</li>" +
                "  <li><b>站點 URL:</b>:"
                + request.getParameter("url") + "\n</li>" +
                "</ul>\n" +
                "</body></html>");
        }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

編譯上面的 Servlet HelloForm,並在 web.xml 檔中創建適當的條目:

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
  <servlet>
    <!-- 類名 -->
    <servlet-name>HelloForm</servlet-name>
    <!-- 所在的包 -->
    <servlet-class>com.zaixian.test.HelloForm</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloForm</servlet-name>
    <!-- 訪問的網址 -->
    <url-pattern>/TomcatTest/HelloForm</url-pattern>
  </servlet-mapping>
</web-app>
最後嘗試下麵的 HTML 頁面來調用 Servlet。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>IT研修(xuhuhu.com)</title>
</head>
<body>
<form action="/TomcatTest/HelloForm" method="GET">
站點名 :<input type="text" name="name">
<br />
站點 URL:<input type="text" name="url" /><br>
<input type="submit" value="提交" />
</form>
</body>
</html>

保存上面的 HTML 內容到檔 /TomcatTest/test.html 中。

接下來我們訪問http://localhost:8080/TomcatTest/test.html,Gif 演示如下:

注意:以上的一些路徑需要根據你專案實際路徑修改。

通過 Servlet 讀取 Cookie

要讀取 Cookie,您需要通過調用 HttpServletRequestgetCookies( ) 方法創建一個 javax.servlet.http.Cookie 對象的數組。然後迴圈遍歷數組,並使用 getName() 和 getValue() 方法來訪問每個 cookie 和關聯的值。

實例

讓我們讀取上面的實例中設置的 Cookie

package com.zaixian.test;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class ReadCookies
 */
@WebServlet("/ReadCookies")
public class ReadCookies extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public ReadCookies() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        Cookie cookie = null;
        Cookie[] cookies = null;
        // 獲取與該域相關的 Cookie 的數組

        cookies = request.getCookies();

         // 設置回應內容類型
         response.setContentType("text/html;charset=UTF-8");

         PrintWriter out = response.getWriter();
         String title = "Delete Cookie Example";
         String docType = "<!DOCTYPE html>\n";
         out.println(docType +
                   "<html>\n" +
                   "<head><title>" + title + "</title></head>\n" +
                   "<body bgcolor=\"#f0f0f0\">\n" );
          if( cookies != null ){
            out.println("<h2>Cookie 名稱和值</h2>");
            for (int i = 0; i < cookies.length; i++){
               cookie = cookies[i];
               if((cookie.getName( )).compareTo("name") == 0 ){
                    cookie.setMaxAge(0);
                    response.addCookie(cookie);
                    out.print("已刪除的 cookie:" +
                                 cookie.getName( ) + "<br/>");
               }
               out.print("名稱:" + cookie.getName( ) + ",");
               out.print("值:" +  URLDecoder.decode(cookie.getValue(), "utf-8") +" <br/>");
            }
         }else{
             out.println(
               "<h2 class=\"tutheader\">No Cookie founds</h2>");
         }
         out.println("</body>");
         out.println("</html>");
        }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

編譯上面的 Servlet ReadCookies,並在 web.xml 檔中創建適當的條目。嘗試運行 http://localhost:8080/TomcatTest/ReadCookies,將顯示如下結果:


通過 Servlet 刪除 Cookie

刪除 Cookie 是非常簡單的。如果您想刪除一個 cookie,那麼您只需要按照以下三個步驟進行:

  • 讀取一個現有的 cookie,並把它存儲在 Cookie 對象中。
  • 使用 setMaxAge() 方法設置 cookie 的年齡為零,來刪除現有的 cookie。
  • 把這個 cookie 添加到回應頭。

實例

下麵的例子將刪除現有的名為 "url" 的 cookie,當您下次運行 ReadCookies 的 Servlet 時,它會返回 url 為 null。

package com.zaixian.test;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class DeleteCookies
 */
@WebServlet("/DeleteCookies")
public class DeleteCookies extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public DeleteCookies() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        Cookie cookie = null;
        Cookie[] cookies = null;
        // 獲取與該域相關的 Cookie 的數組

        cookies = request.getCookies();

            // 設置回應內容類型
        response.setContentType("text/html;charset=UTF-8");

        PrintWriter out = response.getWriter();
        String title = "刪除 Cookie 實例";
        String docType = "<!DOCTYPE html>\n";
        out.println(docType +
                  "<html>\n" +
                  "<head><title>" + title + "</title></head>\n" +
                  "<body bgcolor=\"#f0f0f0\">\n" );
         if( cookies != null ){
           out.println("<h2>Cookie 名稱和值</h2>");
           for (int i = 0; i < cookies.length; i++){
              cookie = cookies[i];
              if((cookie.getName( )).compareTo("url") == 0 ){
                   cookie.setMaxAge(0);
                   response.addCookie(cookie);
                   out.print("已刪除的 cookie:" +
                                cookie.getName( ) + "<br/>");
              }
              out.print("名稱:" + cookie.getName( ) + ",");
              out.print("值:" + cookie.getValue( )+" <br/>");
           }
        }else{
            out.println(
              "<h2 class=\"tutheader\">No Cookie founds</h2>");
        }
        out.println("</body>");
        out.println("</html>");
        }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

編譯上面的 Servlet DeleteCookies,並在 web.xml 檔中創建適當的條目。現在運行 http://localhost:8080/TomcatTest/DeleteCookies,將顯示如下結果: