2004 Marty Hall cookie 管理 JSP, Servlet, & Struts Training Courses: http://courses.coreservlets.com Available in US, China, Taiwan, HK, and Worldwide 2 JSP and Servlet Books from Sun Press: http://www.coreservlets.com Available in English, Chinese (simplified and traditional script), and 12 other languages 议程 cookie 的优点和缺点 输出 cookie 的发送 输入 cookie 的接收 跟踪重复用户 cookie 属性的指定 会话 cookie 和持续性 cookie 之间的差异 用实用工具类简化 cookie 的使用 cookie 值的修改 用户偏好的记录 3 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
cookie 的潜能 思想 servlet 发送简单的名称和值到客户程序 客户程序在访问同一站点 ( 或同一域, 依 cookie 设置的不同而定 ) 时将名称和值原样返回 cookie 的典型应用 在电子商务会话中标识用户 针对这项任务 servlet 拥有专门的高层 API 避免存储用户名和密码 对站点进行定制 定向广告 4 JSP/servlet/Struts/JSF training: http://www.coreservlets.com cookie 和定向广告 5 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
cookie 和隐私 FoxTrot 1998 Bill Amend. Reprinted with permission of Universal Press Syndicate. All rights reserved. 6 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 与 cookie 相关的一些问题 问题在于隐私, 不是安全 服务器能够记住您之前的动作 如果您给出自己的个人信息, 服务器能够将这些信息与您之前的动作关联起来 多个服务器能够通过提供协作服务的第三方, 如 doubleclick.net, 共享 cookie 信息 设计欠考虑的网站直接将敏感的信息, 如信用卡号码, 存储在 cookie 中 JavaScript 的 bug 能够使敌对网站窃取 cookie ( 老浏览器 ) servlet 作者应该遵守下面这些法则 如果 cookie 对于您的任务并非至关重要, 则要避免在 cookie 被禁用时 servlet 完全不能工作 不要将敏感的信息存储在 cookie 中 7 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
手动删除 cookie ( 为使测试工作简化 ) 8 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 向客户程序发送 cookie 创建 Cookie 对象 调用 Cookie 的构造函数, 给出 cookie 的名称和 cookie 的值, 二者都是字符串 Cookie c = new Cookie("userID", "a1234"); 设置最大时效 如果要告诉浏览器将 cookie 存储到磁盘上, 而非仅仅保存在内存中, 使用 setmaxage ( 参数为秒数 ) c.setmaxage(60*60*24*7); // One week 将 Cookie 放入到 HTTP 响应中 使用 response.addcookie 如果忘记这一步, 那么不会有任何 cookie 被发送到浏览器! response.addcookie(c); 9 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
从客户端读取 cookie 调用 request.getcookies 这会得到 Cookie 对象组成的数组 在这个数组中循环, 调用每个对象的 getname, 直到找到想要的 cookie 为止 根据应用程序的具体情况使用这个值 (getvalue) String cookiename = "userid"; Cookie[] cookies = request.getcookies(); if (cookies!= null) { for(int i=0; i<cookies.length; i++) { Cookie cookie = cookies[i]; if (cookiename.equals(cookie.getname())) { dosomethingwith(cookie.getvalue()); 10 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 使用 cookie 检测初访者 public class RepeatVisitor extends HttpServlet { public void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { boolean newbie = true; Cookie[] cookies = request.getcookies(); if (cookies!= null) { for(int i=0; i<cookies.length; i++) { Cookie c = cookies[i]; if ((c.getname().equals("repeatvisitor"))&& (c.getvalue().equals("yes"))) { newbie = false; break; 11 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
使用 cookie 检测初访者 ( 续 ) String title; if (newbie) { Cookie returnvisitorcookie = new Cookie("repeatVisitor", "yes"); returnvisitorcookie.setmaxage(60*60*24*365); response.addcookie(returnvisitorcookie); title = "Welcome Aboard"; else { title = "Welcome Back"; response.setcontenttype("text/html"); PrintWriter out = response.getwriter(); // (Output page with above title) 12 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 使用 cookie 检测初访者 ( 结果 ) 13 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
使用 cookie 的属性 getdomain/setdomain 允许我们指定 cookie 适用的域 当前的主机必须是所指定的域的一部分 getmaxage/setmaxage 读取 / 设置 cookie 的到期时间 ( 秒 ) 如果没有设置, 则 cookie 只适用于当前的浏览会话 参见前面给出的 LongLivedCookie 辅助类 getname 读取 cookie 的名称 不存在 setname 方法 ; 因为我们在构造函数中提供了名称 对于输入 cookie 构成的数组来说, 我们使用 getname 来找到感兴趣的 cookie 14 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 使用 cookie 的属性 getpath/setpath 读取 / 设置 cookie 适用的路径 如果未指定, 则 cookie 适用于含有当前页面的目录中的 URL, 以及该目录之下的 URL getsecure/setsecure 读取 / 设置标志, 标示 cookie 是否只应适用于 SSL 连接, 或者适用于所有连接 getvalue/setvalue 读取 / 设置与 cookie 关联的值 对于新的 cookie, 我们将值提供给构造函数, 而非 setvalue 对于输入 cookie 组成的数组, 我们使用 getname 找到感兴趣的 cookie, 然后调用所获得对象的 getvalue 方法 如果设置了某个输入 cookie 的值, 我们依旧需要用 response.addcookie 将它发送回去 15 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
区分会话 cookie 和持续性 cookie public class CookieTest extends HttpServlet { public void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { for(int i=0; i<3; i++) { Cookie cookie = new Cookie("Session-Cookie-" + i, "Cookie-Value-S" + i); // No maxage (ie maxage = -1) response.addcookie(cookie); cookie = new Cookie("Persistent-Cookie-" + i, "Cookie-Value-P" + i); cookie.setmaxage(3600); response.addcookie(cookie); 16 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 区分会话 cookie 和持续性 cookie(cont) // Start an HTML table Cookie[] cookies = request.getcookies(); if (cookies == null) { out.println("<tr><th COLSPAN=2>No cookies"); else { Cookie cookie; for(int i=0; i<cookies.length; i++) { cookie = cookies[i]; out.println ("<TR>\n" + " <TD>" + cookie.getname() + "\n" + " <TD>" + cookie.getvalue()); 17 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
区分会话 cookie 和持续性 cookie 首次访问 CookieTest servlet 的结果 访问该 servlet, 退出浏览器, 等待一小时, 然后再次访问这个 servlet 得到相同的结果 18 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 区分会话 cookie 和持续性 cookie 首次访问后一小时之内再次访问 CookieTest 的结果 ( 使用同一浏览器会话 ) 也就是说, 初次访问和此处访问之间浏览器保持打开 19 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
区分会话 cookie 和持续性 cookie 首次访问后一小时之内再次访问 CookieTest 的结果 ( 使用不同的浏览器会话 ) 也就是说, 浏览器在初次访问和此次访问之间重新启动过 20 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 实用程序 : 查找指定名称的 cookie public class CookieUtilities { public static String getcookievalue (HttpServletRequest request, String cookiename, String defaultvalue) { Cookie[] cookies = request.getcookies(); if (cookies!= null) { for(int i=0; i<cookies.length; i++) { Cookie cookie = cookies[i]; if (cookiename.equals(cookie.getname())) { return(cookie.getvalue()); return(defaultvalue); 21 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
实用程序 : 创建长生存期的 cookie public class LongLivedCookie extends Cookie { public static final int SECONDS_PER_YEAR = 60*60*24*365; public LongLivedCookie(String name, String value) { super(name, value); setmaxage(seconds_per_year); 22 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 实用程序的使用 : RepeatVisitor2 public class RepeatVisitor2 extends HttpServlet { public void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { boolean newbie = true; String value = CookieUtilities.getCookieValue(request, "repeatvisitor2", "no"); if (value.equals("yes")) { newbie = false; String title; if (newbie) { LongLivedCookie returnvisitorcookie = new LongLivedCookie("repeatVisitor2", "yes"); response.addcookie(returnvisitorcookie); title = "Welcome Aboard"; else { title = "Welcome Back"; 23 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
修改 cookie 的值 替换 cookie 的值 使用不同的值发送相同的 cookie 名称 重用输入的 cookie 对象 需要调用 response.addcookie; 只是调用 setvalue 是没用的 不需要通过调用 setmaxage,setpath 等重新设置所有相关的 cookie 属性 输入的 cookie 中并不含有 cookier 的属性 一般不值得这样做, 因而常使用新的 Cookie 对象 指示浏览器删除某个 cookie 使用 setmaxage 将最大时效指定为 0 24 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 记录用户的访问计数 public class ClientAccessCounts extends HttpServlet { public void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { String countstring = CookieUtilities.getCookieValue(request, "accesscount", "1"); int count = 1; try { count = Integer.parseInt(countString); catch(numberformatexception nfe) { LongLivedCookie c = new LongLivedCookie("accessCount", String.valueOf(count+1)); response.addcookie(c); 25 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
记录用户的访问计数 ( 续 ) out.println(doctype + "<HTML>\n" + "<HEAD><TITLE>" + title + "</TITLE></HEAD>\n" + "<BODY BGCOLOR=\"#FDF5E6\">\n" + "<CENTER>\n" + "<H1>" + title + "</H1>\n" + "<H2>This is visit number " + count + " by this browser.</h2>\n"+ "</CENTER></BODY></HTML>"); 26 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 记录用户的访问计数 ( 结果 ) 27 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
使用 cookie 记录用户的偏好 RegistrationForm servlet 使用 cookie 的值预先填写表单的字段 如果未找到相应的 cookie 则使用默认值 课程的后面将会在 JSP 中重做这项工作 Registration servlet 基于接收到的请求参数创建 cookie 如果得到所有的参数则显示这些值 如果任何参数缺失, 则重定向到表单 28 JSP/servlet/Struts/JSF training: http://www.coreservlets.com RegistrationForm Servlet public class RegistrationForm extends HttpServlet { public void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { response.setcontenttype("text/html"); PrintWriter out = response.getwriter(); String actionurl = "/servlet/coreservlets.registrationservlet"; String firstname = CookieUtilities.getCookieValue(request, "firstname", ""); String lastname = CookieUtilities.getCookieValue(request, "lastname", ""); String emailaddress = CookieUtilities.getCookieValue(request, "emailaddress", ""); 29 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
RegistrationForm Servlet ( 续 ) out.println (doctype + "<HTML>\n" + "<HEAD><TITLE>" + title + "</TITLE></HEAD>\n" + "<BODY BGCOLOR=\"#FDF5E6\">\n" + "<CENTER>\n" + "<H1>" + title + "</H1>\n" + "<FORM ACTION=\"" + actionurl + "\">\n" + "First Name:\n" + " <INPUT TYPE=\"TEXT\" NAME=\"firstName\" " + "VALUE=\"" + firstname + "\"><BR>\n" + "Last Name:\n" + " <INPUT TYPE=\"TEXT\" NAME=\"lastName\" " + "VALUE=\"" + lastname + "\"><BR>\n"+ "Email Address: \n" + " <INPUT TYPE=\"TEXT\" NAME=\"emailAddress\" " + "VALUE=\"" + emailaddress + "\"><P>\n" + "<INPUT TYPE=\"SUBMIT\" VALUE=\"Register\">\n" + "</FORM></CENTER></BODY></HTML>"); 30 JSP/servlet/Struts/JSF training: http://www.coreservlets.com Registration Servlet public class RegistrationServlet extends HttpServlet { public void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { response.setcontenttype("text/html"); boolean ismissingvalue = false; String firstname = request.getparameter("firstname"); if (ismissing(firstname)) { firstname = "Missing first name"; ismissingvalue = true; String lastname = request.getparameter("lastname"); if (ismissing(lastname)) { lastname = "Missing last name"; ismissingvalue = true; 31 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
Registration Servlet( 续 ) Cookie c1 = new LongLivedCookie("firstName", firstname); response.addcookie(c1); Cookie c2 = new LongLivedCookie("lastName", lastname); response.addcookie(c2); Cookie c3 = new LongLivedCookie("emailAddress", emailaddress); response.addcookie(c3); String formaddress = "/servlet/coreservlets.registrationform"; if (ismissingvalue) { response.sendredirect(formaddress); else { 32 JSP/servlet/Struts/JSF training: http://www.coreservlets.com RegistrationForm( 最初结果 ) 33 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
RegistrationForm( 提交不完整的表单 ) 34 JSP/servlet/Struts/JSF training: http://www.coreservlets.com RegistrationForm( 提交完整的表单 ) 35 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
RegistrationForm( 稍后访问得到的初始结果 ) 36 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 小结 cookie 涉及将名称 / 值对从服务器发送到浏览器, 并在之后访问相同的页面 站点或域时返回 我们可以 跟踪会话 ( 使用高层 API) 对安全性要求较低的网站, 使用 cookie 可以避免用户每次都需要登录 根据用户的不同定制网站 有选择地投放内容或广告 设置 cookie 调用 Cookie 的构造函数, 设置时效, 调用 response.addcookie 读取 cookie 调用 request.getcookie, 检查得到的结果是否为 null, 在数组中查找匹配的名称, 使用相关的值 37 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
2004 Marty Hall 问题? JSP, Servlet, & Struts Training Courses: http://courses.coreservlets.com Available in US, China, Taiwan, HK, and Worldwide 38 JSP and Servlet Books from Sun Press: http://www.coreservlets.com Available in English, Chinese (simplified and traditional script), and 12 other languages