《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> "
+ "<a href='cookieInfo'>Cookie Info</a> "
+ "<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所示。
圖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的顯示界麵。
圖2.7 CookieClassServlet輸出
圖2.8 CookieInfoServlet輸出
最後更新:2017-05-27 18:01:30