閱讀613 返回首頁    go 阿裏雲 go 技術社區[雲棲]


《Servlet、JSP和Spring MVC初學指南》——2.3 Cookies

本節書摘來自異步社區《Servlet、JSP和Spring MVC初學指南》一書中的第2章,第2.3節,作者:【加】Budi Kurniawan(克尼亞萬) , 【美】Paul Deck著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看

2.3 Cookies

URL重寫和隱藏域僅適合保存無須跨越太多頁麵的信息。如果需要在多個頁麵間傳遞信息,則以上兩種技術實現成本高昂,因為你不得不在每個頁麵都進行相應處理。幸運的是,Cookies技術可以幫助我們。

Cookies是一個很少的信息片段,可自動地在瀏覽器和Web服務器間交互,因此cookies可存儲在多個頁麵間傳遞的信息。Cookie作為HTTP header的一部分,其傳輸由HTTP協議控製。此外,你可以控製cookies的有效時間。瀏覽器通常支持每個網站高達20個cookies。

Cookies的問題在於用戶可以通過改變其瀏覽器設置來拒絕接受cookies。

要使用cookies,需要熟悉javax.servlet.http.Cookie類以及HttpServletRequest和HttpServlet Response兩個接口。

可以通過傳遞name和value兩個參數給Cookie 類的構造函數來創建一個cookies:

Cookie cookie = new Cookie(name, value);
如下是一個創建語言選擇的cookie示例:

Cookie languageSelectionCookie = new Cookie("language", "Italian");
創建完一個Cookie對象後,你可以設置domain、path和maxAge屬性。其中,maxAge 屬性決定cookie何時過期。

要將cookie發送到瀏覽器,需要調用HttpServletResponse的add方法:

httpServletResponse.addCookie(cookie);
瀏覽器在訪問同一Web服務器時,會將之前收到的cookie一並發送。

此外,Cookies也可以通過客戶端的javascript腳本創建和刪除,不過這些不在本書範圍內。

服務端若要讀取瀏覽器提交的cookie,可以通過HttpServletRequest接口的getCookies方法,該方法返回一個Cookie數組,若沒有cookies則返回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,並將maxAge屬性設置為0,並添加到HttpServletResponse接口中。如下為刪除一個名為userName的cookie代碼:

Cookie cookie = new Cookie("userName", "");
cookie.setMaxAge(0);
response.addCookie(cookie);

清單2.4的PreferenceServlet 類展示了如何通過cookies來進行會話管理,該Servlet允許用戶通過修改四個cookie值來設定顯示配置。

清單2.4 PreferenceServlet類

package app02a.cookie;
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;

@WebServlet(name = "PreferenceServlet",  urlPatterns = { "/preference" })
public class PreferenceServlet extends HttpServlet {
    private static final long serialVersionUID = 888L;
    public static final String MENU =
            "<div style='background:#e8e8e8;"
            + "padding:15px'>"
            + "<a href='cookieClass'>Cookie Class</a>&nbsp;&nbsp;"
            + "<a href='cookieInfo'>Cookie Info</a>&nbsp;&nbsp;"
            + "<a href='preference'>Preference</a>" + "</div>";

    @Override
    public void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException,
            IOException {
        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        writer.print("<html><head>" + "<title>Preference</title>"
                + "<style>table {" + "font-size:small;"
                + "background:NavajoWhite }</style>"
                + "</head><body>"
                + MENU
                + "Please select the values below:"
                + "<form method='post'>"
                + "<table>"
                + "<tr><td>Title Font Size: </td>"
                + "<td><select name='titleFontSize'>"
                + "<option>large</option>"
                + "<option>x-large</option>"
                + "<option>xx-large</option>"
                + "</select></td>"
                + "</tr>"
                + "<tr><td>Title Style & Weight: </td>"
                +"<td><select name='titleStyleAndWeight' multiple>"
                + "<option>italic</option>"
                + "<option>bold</option>"
                + "</select></td>"
                + "</tr>"
                + "<tr><td>Max. Records in Table: </td>"
                + "<td><select name='maxRecords'>"
                + "<option>5</option>"
                + "<option>10</option>"
                + "</select></td>"
                + "</tr>"
                + "<tr><td rowspan='2'>"
                + "<input type='submit' value='Set'/></td>"
                + "</tr>"
                + "</table>" + "</form>" + "</body></html>");
    }

    @Override
    public void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException,
            IOException {

        String maxRecords = request.getParameter("maxRecords");
        String[] titleStyleAndWeight = request
                .getParameterValues("titleStyleAndWeight");
        String titleFontSize =
                request.getParameter("titleFontSize");
        response.addCookie(new Cookie("maxRecords", maxRecords));
        response.addCookie(new Cookie("titleFontSize",
                titleFontSize));

        // delete titleFontWeight and titleFontStyle cookies first
        // Delete cookie by adding a cookie with the maxAge = 0;
        Cookie cookie = new Cookie("titleFontWeight", "");
        cookie.setMaxAge(0);
        response.addCookie(cookie);

        cookie = new Cookie("titleFontStyle", "");
        cookie.setMaxAge(0);
        response.addCookie(cookie);

        if (titleStyleAndWeight != null) {
            for (String style : titleStyleAndWeight) {
                if (style.equals("bold")) {
                    response.addCookie(new
                            Cookie("titleFontWeight", "bold"));
                } else if (style.equals("italic")) {
                    response.addCookie(new Cookie("titleFontStyle",
                            "italic"));
                }
            }
        }

        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        writer.println("<html><head>" + "<title>Preference</title>"
                + "</head><body>" + MENU
                + "Your preference has been set."
                + "<br/><br/>Max. Records in Table: " + maxRecords
                + "<br/>Title Font Size: " + titleFontSize
                + "<br/>Title Font Style & Weight: ");

        // titleStyleAndWeight will be null if none of the options
        // was selected
        if (titleStyleAndWeight != null) {
            writer.println("<ul>");
            for (String style : titleStyleAndWeight) {
                writer.print("<li>" + style + "</li>");
            }
            writer.println("</ul>");
        }
        writer.println("</body></html>");
    }
}

PreferenceServlet的doGet方法展示一個包含多個輸入項的表單,如圖2.6所示。

screenshot

圖2.6 通過cookies來管理用戶偏好

表單上部有3個鏈接:Cookie Class、Cookie Info和Preference。它們可以導航到本應用的其他Servlet上。關於Cookie Class和Cookie Info,我們稍後介紹。

當用戶提交表單時,Web服務器會調用PreferenceServlet的doPost方法,該方法創建4個cookies,即maxRecords、titleFontSize、titleFontStyle和titleFontWeight,並覆蓋該cookie之前的值,然後將用戶輸入的值返回給瀏覽器。

可以通過如下URL訪問PreferenceServlet:

https://localhost:8080/app02a/preference
CookieClassServlet(見清單2.5)和CookieInfoServlet(見清單2.6)各自應用這些cookie來格式化其內容。CookieClassServlet將Cookie的屬性展示為一個HTML列表。

Cookie中的max Records值決定顯示多少個列表項,可通過Preference Servlet調整該值。

清單2.5 CookieClassServlet類

package app02a.cookie;
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;

@WebServlet(name = "CookieClassServlet",
        urlPatterns = { "/cookieClass" })
public class CookieClassServlet extends HttpServlet {
    private static final long serialVersionUID = 837369L;

    private String[] methods = {
            "clone", "getComment", "getDomain",
            "getMaxAge", "getName", "getPath",
            "getSecure", "getValue", "getVersion",
            "isHttpOnly", "setComment", "setDomain",
            "setHttpOnly", "setMaxAge", "setPath",
            "setSecure", "setValue", "setVersion"
    };

    @Override
    public void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException,
            IOException {

        Cookie[] cookies = request.getCookies();
        Cookie maxRecordsCookie = null;
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals("maxRecords")) {
                    maxRecordsCookie = cookie;
                    break;
                }
            }
        }

        int maxRecords = 5; // default
        if (maxRecordsCookie != null) {
            try {
                maxRecords = Integer.parseInt(
                        maxRecordsCookie.getValue());
            } catch (NumberFormatException e) {
                // do nothing, use maxRecords default value
            }
        }

        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        writer.print("<html><head>" + "<title>Cookie Class</title>"
                + "</head><body>"
                + PreferenceServlet.MENU
                + "<div>Here are some of the methods in " +
                           "javax.servlet.http.Cookie");
        writer.print("<ul>");

        for (int i = 0; i < maxRecords; i++) {
            writer.print("<li>" + methods[i] + "</li>");
        }
        writer.print("</ul>");
        writer.print("</div></body></html>");
    }
}

CookieInfoServlet 類讀取titleFontSize、titleFontWeight和titleFontStyle 三個cookie值,並寫入到如下發給瀏覽器的CSS中,其中x、y和z分別為如上所提的cookie。

.title {
    font-size: x;
    font-weight: y;
    font-style: z;
}

該style應用在一個div元素中,並格式化文字“Session Management with Cookies:”。

清單2.6 CookieInfoServlet類

package app02a.cookie;
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;

@WebServlet(name = "CookieInfoServlet", urlPatterns = { "/cookieInfo" })
public class CookieInfoServlet extends HttpServlet {
    private static final long serialVersionUID = 3829L;

    @Override
    public void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException,
            IOException {

        Cookie[] cookies = request.getCookies();
        StringBuilder styles = new StringBuilder();
        styles.append(".title {");
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                String name = cookie.getName();
                String value = cookie.getValue();
                if (name.equals("titleFontSize")) {
                    styles.append("font-size:" + value + ";");
                } else if (name.equals("titleFontWeight")) {
                    styles.append("font-weight:" + value + ";");
                } else if (name.equals("titleFontStyle")) {
                    styles.append("font-style:" + value + ";");
                }
            }
        }
        styles.append("}");
        response.setContentType("text/html");
        PrintWriter writer = response.getWriter();
        writer.print("<html><head>" + "<title>Cookie Info</title>"
                + "<style>" + styles.toString() + "</style>"
                + "</head><body>" + PreferenceServlet.MENU
                + "<div class='title'>"
                + "Session Management with Cookies:</div>");
        writer.print("<div>");

        // cookies will be null if there's no cookie
        if (cookies == null) {
            writer.print("No cookie in this HTTP response.");
        } else {
            writer.println("<br/>Cookies in this HTTP response:");
            for (Cookie cookie : cookies) {
                writer.println("<br/>" + cookie.getName() + ":"
                        + cookie.getValue());
            }
        }
        writer.print("</div>");
        writer.print("</body></html>");
    }
}

可以通過如下URL來訪問CookieClassServlet:

https://localhost:8080/app02a/cookieClass
可以通過如下URL來訪問CookieInfoServlet:

https://localhost:8080/app02a/cookieInfo
圖2.7和圖2.8分別展示了CookieClassServlet和CookieInfoServlet的顯示界麵。

screenshot

圖2.7 CookieClassServlet輸出

screenshot

圖2.8 CookieInfoServlet輸出

最後更新:2017-05-27 18:01:30

  上一篇:go  《Servlet、JSP和Spring MVC初學指南》——2.4 HttpSession對象
  下一篇:go  《Servlet、JSP和Spring MVC初學指南》——2.2 隱藏域