会话概述
什么是会话:用户打开一个浏览器访问页面,访问网站的很多页面,访问完成后将浏览器关闭的过程称为是一次会话。
常见的会话技术:
* Cookie:将数据保存到客户端浏览器。
* Session:将数据保存到服务器端。
Cookie 技术的使用
向浏览器保存数据:
HttpServletResponse 的方法:
* void addCookie(Cookie cookie);
获得浏览器带过来的 Cookie:
HttpServletRequest 的方法:
* Cookie[] getCookies();
创建一个 Cookie 对象:
* Cookie(String name,String value);
Cookie 的常用 API
* getName();
* getValue();
* setDomain(String domain); -- 设置 Cookie 的有效域名. // www.baidu.com music.baidu.com
* setPath(String path); -- 设置 Cookie 的有效路径.
* setMaxAge(int maxAge); -- 设置 Cookie 的有效时间.(设置为0,即删除cookie)
Cookie 的分类有关:
* 会话级别的 Cookie:默认的 Cookie.关闭浏览器 Cookie 就会销毁.
* 持久级别的 Cookie:可以设置 Cookie 的有效时间.那么关闭浏览器 Cookie 还会存在. 手动销毁持久性 Cookie. setMaxAge(0)---前提是有效路径必须一致.

// 记录用户的上次登录访问时间 public class CountServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); Integer count = (Integer) this.getServletContext().getAttribute("count"); // response.getWriter().println("<h1>现在网站被访问的次数为:"+count+"</h1>"); /** * 获得浏览器中带过来的所有的Cookie信息,从数组中查找有没有指定名称的Cookie * 判断用户是否是第一次访问:(从数组中没有找到指定名称的Cookie) * * 如果是第一次:显示欢迎,记录当前访问的时间存入到Cookie中. * * 如果不是第一次:显示欢迎,上一次访问时间,同时记录当前访问的时间存入到Cookie中。 */ // 获得浏览器带过来的所有的Cookie: Cookie[] cookies = request.getCookies(); // 从数组中查找指定名称的Cookie: Cookie cookie = CookieUtils.findCookie(cookies, "lastVisit"); // 判断是否是第一次: if(cookie == null){ // 第一次访问 response.getWriter().println("您是第"+count+"位访客!"); }else{ // 不是第一次 Long l = Long.parseLong(cookie.getValue()); Date d = new Date(l); response.getWriter().println("您是第"+count+"位访客! 上次访问时间是:"+d.toLocaleString()); } // 创建一个Cookie对象: Cookie c = new Cookie("lastVisit",""+System.currentTimeMillis()); // 保存到浏览器端: response.addCookie(c); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }

// 记录用户的商品浏览记录 public class ProductServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /** * * 接收商品id. * * 接收从客户端带过来的所有Cookie. * * 从Cookie的数组中查找指定名称的Cookie. * * 判断是否是第一次浏览商品: * * 第一次浏览商品 * * 直接将商品的ID存入到Cookie. * * 将Cookie回写到浏览器. * * 不是第一次浏览商品 1-2 * * 判断当前的商品是否已经在浏览记录. * * 已经存在: 2-1 移除当前元素,将当前元素添加到最开始. * * 没在浏览记录中: * * 判断是否已经超过了最大长度:如果超过 2-1-3:删除最后一个 将当前元素添加到最前面. * * 没有超过:直接将该元素添加到最前位置. * * 将转换的id的值存入到Cookie,回写浏览器. */ // 接收id: String id = request.getParameter("id"); // 获得所有的Cookie的信息: Cookie[] cookies = request.getCookies(); // 判断是否是第一次: Cookie cookie = CookieUtils.findCookie(cookies, "history"); if(cookie == null){ // 第一次浏览商品 Cookie c = new Cookie("history",id); c.setPath("/day11"); c.setMaxAge(60*60*24*7); response.addCookie(c); }else{ // 不是第一次浏览 // 判断选择的商品是否已经在浏览记录中 2-1 String value = cookie.getValue(); String[] ids = value.split("-"); // 将数组变为集合: LinkedList<String> list = new LinkedList<String>(Arrays.asList(ids)); if(list.contains(id)){ // 之前浏览过该商品 list.remove(id); // 1-2-3 list.addFirst(id); }else{ // 没有浏览过该商品. if(list.size() >=3 ){ // 超过3个 list.removeLast(); list.addFirst(id); }else{ // 没到3个. list.addFirst(id); } } // 将list中的元素取出,使用-连接上保存到Cookie,写回浏览器. StringBuffer sb = new StringBuffer(); for(String s:list){ sb.append(s).append("-"); } String sValue = sb.toString().substring(0,sb.length()-1); System.out.println(sValue); // 存入到Cookie中 Cookie c = new Cookie("history",sValue); c.setPath("/day11"); c.setMaxAge(60*60*24*7); response.addCookie(c); } request.getRequestDispatcher("/demo2/product_info.htm").forward(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }

// 删除持久性的Cookie public class ClearServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Cookie cookie = new Cookie("history",null); cookie.setPath("/day11"); cookie.setMaxAge(0); response.addCookie(cookie); response.sendRedirect("/day11/demo2/product_list.jsp"); } /** * @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); } }
Session 概述
Cookie 本身是有大小和个数的限制.Session 没有限制.Cookie 的数据保存在客户端, Session 数据保存在服务器端.
Session 的执行原理:基于 Cookie 的.
使用 Session
* 获得 Session:request.getSession();
* 设置和获取 Session 参数:
request.getSession().getAttribute("cart");
request.getSession().setAttribute("cart", map);
重复提交的问题
添加完商品之后,转发到一个页面,刷新该页面.
网速很慢,点击提交的按钮,其实已经在提交了但是网速慢,不停的点击提交.
解决重复提交的根本解决办法:令牌机制(一次性).
生成随机的令牌保存在session中.
在表单的提交的时候,将随机的令牌放入到表单的隐藏字段中.
在Servlet中获得session中和表单中的令牌是否一致.
如果一致执行插入操作,不一致跳转到其他页面.将令牌销毁.

// 判断是否是重复提交: String token1 = (String)request.getSession().getAttribute("token"); String token2 = request.getParameter("token"); // 清空session中的令牌: request.getSession().removeAttribute("token"); if(!token2.equals(token1)){ request.setAttribute("msg", "亲!您已经提交过!请不要重复提交了!"); request.getRequestDispatcher("/jsp/msg.jsp").forward(request, response); return; }
session 的创建和销毁及作用范围
* 创建:服务器端第一次调用 getSession() 创建 session.
* 销毁:三种情况销毁 session:
* 1.session 过期. 默认过期时间为 30 分钟.
* 2.非正常关闭服务器.如果正常关闭 session 序列化到硬盘.
* 3.手动调用 session.invalidate();
* 作用范围:多次请求.(一次会话)
Session 失效时间设置
1. 在 web 容器中设置(此处以 tomcat 为例)
在 tomcat-5.0.28confweb.xml 中设置,以下是 tomcat 5.0 中的默认配置:
<session-config> <session-timeout>30</session-timeout> </session-config>
Tomcat 默认 session 超时时间为30分钟,可以根据需要修改,负数或0为不限制 session 失效时间。
2. 在工程的 web.xml 中设置
<!-- 时间单位为分钟 --> <session-config> <session-timeout>15</session-timeout> </session-config>
3. 通过 Java 代码设置
session.setMaxInactiveInterval(30*60);//以秒为单位
三种方式优先级:1 < 2 <3

// 商品添加到购物车 public class CartServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 接收商品名称: String name = new String(request.getParameter("name").getBytes("ISO-8859-1"),"UTF-8"); // 创建Map集合用于保存购物信息.Map<String,Integer> Map的key是商品的名称 value是购买的数量. Map<String,Integer> map = (Map<String, Integer>) request.getSession().getAttribute("cart"); if(map == null){ map = new LinkedHashMap<String,Integer>(); } // 判断购物车中是否已经买了该商品. if(map.containsKey(name)){ // map中已经有该商品:// * 如果购物车中已经有该商品: 获得到Map中该商品的数量+1。 存回到Map集合中. Integer count = map.get(name); count++; map.put(name, count); }else{ // map中没有该商品.// * 如果购物车中没有改商品: 将商品添加到Map集合中 数量1. map.put(name, 1); } // * 将Map集合保存到session中. //移除一个(一个键值对)session request.getSesion().removeAttribute (); request.getSession().setAttribute("cart", map); response.setContentType("text/html;charset=UTF-8"); response.getWriter().println("<h3><a href='/day11/demo2/product_list.jsp'>继续购物</a> | <a href='/day11/demo2/cart.jsp'>去结算</a></h3>"); } }

// 验证码校验 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 校验验证码程序: String code1 = request.getParameter("code"); String code2 = (String) request.getSession().getAttribute("code"); request.getSession().removeAttribute("code"); if(!code1.equalsIgnoreCase(code2)){ request.setAttribute("msg", "验证码输入错误!"); request.getRequestDispatcher("/demo2/login.jsp").forward(request, response); return ; } ... } // 使用JS控制图片切换: <script type="text/javascript"> function changeImg(){ document.getElementById("img1").src="/day11/CheckImgServlet?time="+new Date().getTime(); } </script>