2004 Marty Hall 会话跟踪 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 议程 从零开始实现会话跟踪 使用基本的会话跟踪 了解会话跟踪 API 区分服务器会话和浏览器会话 URL 编码 不可变对象和可变对象的存储 跟踪用户的访问计数 累计用户的购物 购物车的实现 构建在线商店 3 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
会话跟踪和电子商务 Why session tracking? 当客户在在线商店中向他们的购物车中添加商品时, 服务器如何才能知道购物车中已经有什么商品了呢? 当客户决定结账时, 服务器如何能够确定客户对应之前创建的哪个购物车呢? Dilbert used with permission of United Syndicates Inc. 4 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 进行会话跟踪 :cookie 思想 : 把 cookie 与服务器上的数据关联起来 String sessionid = makeuniquestring(); HashMap sessioninfo = new HashMap(); HashMap globaltable = findtablestoringsessions(); globaltable.put(sessionid, sessioninfo); Cookie sessioncookie = new Cookie("JSESSIONID", sessionid); sessioncookie.setpath("/"); response.addcookie(sessioncookie); 接下来要做的是 : 提取出存储会话标识符的 cookie 为 cookie 设置合适的过期时间 将散列表与每个请求关联起来 生成唯一的会话标识符 5 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
进行会话跟踪 :URL 重写 思想 客户程序在每个 URL 的尾部添加一些额外的数据来标识会话 服务器将这个标识符与它所存储的有关会话的数据关联起来 例如,http://host/path/file.html;jsessionid=1234 优点 cookie 被禁用或者根本不支持的情况下依旧能够工作 缺点 必须对所有指向您的网站的 URL 进行编码 所有页面必须动态生成 不能使用预先记录下来的 URL 进行访问, 或者从其他 网站链接进行访问 6 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 进行会话跟踪 : 隐藏的表单域 思想 : <INPUT TYPE="HIDDEN" NAME="session" VALUE="..."> 优点 cookie 被禁用或者根本不支持的情况下依旧能够工作 缺点 涉及许多冗长的处理工作 所有的页面必须是表单提交之后的结果 7 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
Java 的会话跟踪 会话对象生存于服务器上 会话自动通过 cookie 或 URL 重写与客户关联起来 使用 request.getsession 来得到会话 后台 : 系统检查 cookie 或附加在 URL 上的额外信息, 看看是否与之前存储的会话对象的键相匹配 如果匹配, 它返回该对象, 如果不匹配, 则创建新的对象, 指定一个 cookie 或 URL 信息作为它的键, 并返回新创建的会话对象 类散列表机制允许我们将任何对象存储到会话中 setattribute 存储值 getattribute 读取值 8 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 会话跟踪基础 访问会话对象 调用 request.getsession 获取 HttpSession 对象 这是一个与用户相关联的散列表 查找与会话相关联的信息 调用 HttpSession 对象的 getattribute, 将返回的值转换成合适的类型, 要注意检查结果是否为 null 将信息存入会话 使用 setattribute 给出相应的键和值 废弃会话数据 调用 removeattribute 废弃指定的值 调用 invalidate 废弃整个会话 调用 logout 将客户从 Web/ 应用服务器注销 9 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
会话跟踪基础 : 示例代码 HttpSession session = request.getsession(); SomeClass value = (SomeClass)session.getAttribute("someID"); if (value == null) { value = new SomeClass(...); session.setattribute("someid", value); dosomethingwith(value); 如果被修改的值为同一对象,( 在对值做出修改后 ) 不需要再次调用 setattribute 但是, 如果值是不可变的, 那么修改后的值将会是新对象的引用, 我们必须再次调用 setattribute 10 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 如果服务器使用 URL 重写有哪些变化? 会话跟踪代码 : 没有变动 生成链接到同一网站的超链接的代码 : 将 URL 传给 response.encodeurl 处理 如果服务器使用 cookie, 它原封不动地返回 URL 如果服务器使用 URL 重写, 它将会话信息附加到 URL 上 例如 : String url = "order-page.html"; url = response.encodeurl(url); sendredirect 到自己网站的代码 : 将 URL 传递给 response.encoderedirecturl 11 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
HttpSession 的方法 getattribute 从会话对象中提取出一个之前存储的值 如果没有找到与给定名称相关联的值, 则返回 null setattribute 把值与名称关联起来 更改的监控 : 让值实现 HttpSessionBindingListener removeattribute 移除与名称关联的值 getattributenames 返回会话中所有属性的名称 getid 返回惟一的标识符 12 JSP/servlet/Struts/JSF training: http://www.coreservlets.com HttpSession 的方法 ( 续 ) isnew 确定会话对于客户 ( 不是针对页面 ) 来说是否为新创建的 getcreationtime 返回会话初次创建的时间 getlastaccessedtime 返回客户端最近一次发送会话的时间 getmaxinactiveinterval, setmaxinactiveinterval 取得或设置在未被访问的情况下多长时间应该将会话置为无效 invalidate 废弃当前的会话 logout 废弃与用户相关联的所有会话 13 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
显示客户访问计数的 servlet public class ShowSession extends HttpServlet { public void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { response.setcontenttype("text/html"); HttpSession session = request.getsession(); String heading; Integer accesscount = (Integer)session.getAttribute("accessCount"); if (accesscount == null) { accesscount = new Integer(0); heading = "Welcome, Newcomer"; else { heading = "Welcome Back"; accesscount = new Integer(accessCount.intValue() + 1); session.setattribute("accesscount", accesscount); 14 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 显示客户访问计数的 servlet ( 续 ) PrintWriter out = response.getwriter(); out.println (doctype + "<HTML>\n" + "<HEAD><TITLE>" + title + "</TITLE></HEAD>\n" + "<BODY BGCOLOR=\"#FDF5E6\">\n" + "<CENTER>\n" + "<H1>" + heading + "</H1>\n" + "<H2>Information on Your Session:</H2>\n" + "<TABLE BORDER=1>\n" + "<TR BGCOLOR=\"#FFAD00\">\n" + " <TH>Info Type<TH>Value\n" + " <TD>Number of Previous Accesses\n" + " <TD>" + accesscount + "\n" + "</TABLE>\n" + "</CENTER></BODY></HTML>"); 15 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
显示客户访问计数的 servlet ( 结果 1) 16 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 显示客户访问计数的 servlet ( 结果 2) 17 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
累积用户数据的列表 public class ShowItems extends HttpServlet { public void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getsession(); ArrayList previousitems = (ArrayList)session.getAttribute("previousItems"); if (previousitems == null) { previousitems = new ArrayList(); session.setattribute("previousitems", previousitems); 18 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 累积用户数据的列表 ( 续 ) String newitem = request.getparameter("newitem"); PrintWriter out = response.getwriter(); synchronized(previousitems) { if (newitem!= null) { previousitems.add(newitem); if (previousitems.size() == 0) { out.println("<i>no items</i>"); else { out.println("<ul>"); for(int i=0; i<previousitems.size(); i++) { out.println("<li>" + (String)previousItems.get(i)); out.println("</ul>"); out.println("</body></html>"); 19 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
累积用户数据的列表 ( 前端 ) 20 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 累积用户数据的列表 ( 结果 ) 21 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
在线书店 会话跟踪代码和简单示例中所使用的代码相同 购物车类相对复杂 用唯一的分类 ID 来标识每个商品 在购物车中并不重复出现同一商品 相反, 每个条目拥有一个关联的计数 如果计数到达 0, 则从购物车中删除该商品 页面根据含有书籍描述的对象自动构建 22 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 在线书店 23 JSP/servlet/Struts/JSF training: http://www.coreservlets.com
在线书店 24 JSP/servlet/Struts/JSF training: http://www.coreservlets.com 小结 会话并不跨网络传递 传递的只是唯一标识符 获取会话 request.getsession 从会话中提取数据 session.getattribute 进行类型转换, 并注意检查结果是否为 null 将数据存入会话 session.setattribute 25 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 26 JSP and Servlet Books from Sun Press: http://www.coreservlets.com Available in English, Chinese (simplified and traditional script), and 12 other languages