cookie和session
学习目标
- cookie技术
- session技术
- 用户管理应用场景案例
会话及其会话技术:
1、会话
什么是会话?
用户打开浏览器,访问一个网站进行一系列操作,关闭浏览器离开,完整过程 就是会话;
什么是会话技术?
在Web开发中,服务器要跟踪用户信息的技术成为会话技术;
会话过程中要解决的一些问题:
- 每个用户与服务器进行交互的过程中,各自会有一些数据,程序要想办法保存每个用户的数据;
- 例如:用户点击超链接通过一个servlet购买了一个商品,程序应该保存用户购买的商品,以便用户点击结账servlet时,结账servlet可以得到用户商品为用户结账;
- 思考:用户购买的商品保存在request或servletContext中行不行?
不可以,原理分析:- reuqest只能保存本次请求所传递的参数;
- servletContext,同一个Web应用共享的是同一个ServletContext对象;
- 因此,为了保存会话过程中产生的数据,在servlet技术中,提供了两个用于保存会话数据的对象,分别是Cookie和Session!
2、cookie技术
一种将用户信息保存在客户端(用户的浏览器中)技术 ,客户端后续访问服务器会将cookie信息自动发送给服务器。
什么是Cookie?
- 服务器向客户端发送cookie时,会在HTTP响应头字段中增加Set-Cookie响应头字段。Set-Cookie头字段中设置Cookie遵循一定的语法格式,如:
Set-Cookie:user=ittest; Path=/;
如上:user表示cookie的名称,ittest表示cookie的值,Path表示cookie的属性。需要注意的是Cookie必须以键值对的形式存在,其属性可以有多个,但必须以分号(;)和空格分隔。
2.1、cookieAPI介绍
注意:Cookie一旦创建,Cookie的名称是不能更改的,值可以更改!
- 代码示例:
1 import java.io.IOException; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.http.Cookie; 5 import javax.servlet.http.HttpServlet; 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 9 public class CookieDemo1 extends HttpServlet { 10 11 public void doGet(HttpServletRequest request, HttpServletResponse response) 12 throws ServletException, IOException { 13 doPost(request, response); 14 15 } 16 17 public void doPost(HttpServletRequest request, HttpServletResponse response) 18 throws ServletException, IOException { 19 // 开始coding................ 20 /** 21 * 向浏览器发送cookie 信息 api 演示 22 */ 23 // 1: 创建一个cookie 对象 24 // 第一个参数 cookie 名称 第二个参数 保存该cookie 的值 cookie是不能存储中文信息 25 Cookie cookie = new Cookie("cc", "hellocookieCC"); 26 // 默认cookie 会话结束 cookie 失效 会话机制的cookie 27 cookie.setMaxAge(3600 * 24 * 7);// 设置浏览器保存cookie 信息的有效时间 持久化cookie 28 // 2: 发送给浏览器 response 对象发送cookie 29 // 3: 设置cookie 访问的有效路径 30 cookie.setPath("/");// cookie 的有效路径 表示 /day11/aa 31 // 下面的所有目录都可以访问该cookie 32 33 // 结论 cookie path 设置 / 34 // 发送cookie 到 浏览器 35 response.addCookie(cookie); 36 37 } 38 39 }
2.2、cookieAPI详解
- 读取cookie
request.getCookies() 返回Cookie[]
首先判断cookies数组是否存在 cookies == null,如果cookies存在,根据cookie的name去查找指定cookie
代码示例:
1 import java.io.IOException; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.http.Cookie; 5 import javax.servlet.http.HttpServlet; 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 9 public class GetCookie extends HttpServlet { 10 11 public void doGet(HttpServletRequest request, HttpServletResponse response) 12 throws ServletException, IOException { 13 doPost(request, response); 14 15 } 16 17 public void doPost(HttpServletRequest request, HttpServletResponse response) 18 throws ServletException, IOException { 19 // 开始coding................ 20 /** 21 * 获取浏览器保存的cookie 信息 浏览器发送 .... 浏览器每次发送请求,都携带cookie信息,这是浏览器本身的机制 22 */ 23 // 1: 获取cookie信息 ... 对象 request 24 Cookie[] cookies = request.getCookies();// 获取cookie 数组 空? 25 26 for (Cookie cookie : cookies) { 27 System.out.println(cookie.getName() + "----" + cookie.getValue() 28 + "-----" + cookie.getPath()); 29 } 30 31 } 32 33 }
1 import javax.servlet.http.Cookie; 2 3 public class CookieUtils { 4 5 public static Cookie getCookie(String name, Cookie[] cookies) { 6 // 通过cookie name 在所有cookie 返回指定 的cookie 7 if (cookies == null) { 8 return null; 9 } else { 10 for (Cookie cookie : cookies) { 11 if (cookie.getName().equals(name)) { 12 return cookie; 13 } 14 } 15 } 16 return null; 17 } 18 19 }
- 服务器向客户端发送cookie
cookie对象创建 new Cookie(name,value)
response.addCookie(cookie) 将cookie发送客户端 保存到浏览器中
* cookie有name和value
提供三个方法:getName 获取cookie的名称
getValue 获取cookie 的值
setValue 设置cookie 的值
- cookie从持久性上分为两类:会话cookie和持久cookie
会话cookie:保存在浏览器内存中,当会话结束浏览器关闭,会话cookie信息就是丢失;
持久cookie:保存在浏览器临时文件缓存区中cookie(硬盘上) ,当关闭浏览器结束会话,持久cookie不会被删除
* 持久cookie存在过期时间,过期后会自动删除
- Max-Age>0,表示cookie信息保存在本地硬盘中;
- Max-Age<0,表示cookie信息保存在缓存中[默认值:-1];
- Max-Age=0,表示通知浏览器立刻删除这个cookie信息。
- cookie访问有效路径
携带cookie 必须path一致
默认 http://localhost/day11/visit 生成cookie ----
默认path 就是/day11/ (visit资源所在目录就是默认path)
* 只有在访问 http://localhost/day11/ 目录和子目录情况下 才会携带cookie 信息,即:该Cookie只对当前访问路径所属的目录及其子目录有效。
cookie 路径: 设置Cookie 路径 /day11/aa
表示在此路径下的所有子目录下的 都可以获取该cookie信息
所以cc目录下的cc.jsp可以获取cookie信息 而 bb目录下的获取不到cookie 信息
- 删除持久cookie
删除持久cookie,可以将cookie最大时效设为0,注意,删除cookie时,path必须一致,否则不会删除 - Cookie访问的域setDomain(String pattern)和getDomain()方法
Domain属性用来指定浏览器访问的域。默认情况,Domain属性的值为当前主机名,浏览器在访问当前主机下的资源时,都会将Cookie信息会送给服务器。例如,当前主机名为“ittest.com”,那么当设置Domain属性时,其值必须以“.”开头,如Domain=.itttest.com。需要注意的是,Domain属性的值是不区分大小写的。
2.3、cookie案例之——记录上次访问时间案例
CookieUtils.java——class【参考上面工具类:CookieUtils】
VisitServlet.java——servlet
1 import java.io.IOException; 2 import java.util.Date; 3 4 import javax.servlet.ServletException; 5 import javax.servlet.http.Cookie; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 import cn.itcast.day11.utils.CookieUtils; 11 12 public class VisitServlet extends HttpServlet { 13 14 public void doGet(HttpServletRequest request, HttpServletResponse response) 15 throws ServletException, IOException { 16 doPost(request, response); 17 18 } 19 20 public void doPost(HttpServletRequest request, HttpServletResponse response) 21 throws ServletException, IOException { 22 // 开始coding................ 23 response.setContentType("text/html;charset=utf-8"); 24 // 1: 先获取 cookie 25 Cookie cookie = CookieUtils 26 .getCookie("lastvisit", request.getCookies()); 27 if (cookie == null) { 28 // 第一次访问 29 response.getWriter().print("你是第一次访问!"); 30 } else { 31 // cookie 不为空 已经访问过... 32 String visitTime = cookie.getValue(); 33 34 response.getWriter().print( 35 "您上次访问的时间:" 36 + 37 new Date(Long.parseLong(visitTime)).toLocaleString()); 38 39 } 40 long time = System.currentTimeMillis();//获取当前访问时间 41 cookie = new Cookie("lastvisit", time + "");//设置cookie的值 42 cookie.setMaxAge(3600 * 24 * 3);//设置cookie的有效时间 43 cookie.setPath("/");//设置cookie的有效路径 44 response.addCookie(cookie);//将cookie发送给客户端,保存在浏览器中 45 46 } 47 48 }
*服务端向客户端写出一个新的cookie
默认cookie都是浏览器内存(缓存区)中进行缓存的 ,当浏览器关闭,会话结束,内存释放
2.4、cookie应用——显示商品浏览记录
- 代码实现:Product.jsp
1 <%@page import="cn.itcast.day11.utils.CookieUtils"%> 2 <%@ page language="java" contentType="text/html; charset=UTF-8" 3 pageEncoding="UTF-8"%> 4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 5 <html> 6 <head> 7 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 8 <title>Insert title here</title> 9 </head> 10 <body> 11 12 <h2>商品列表</h2> 13 <a href="/day11/look?id=1">mac 电脑</a> 14 <a href="/day11/look?id=2">小米手机3</a> 15 <a href="/day11/look?id=3">雕牌洗衣液2瓶装</a> 16 <a href="/day11/look?id=4">百事可乐一听</a> 17 <hr> 18 <h3>商品浏览记录</h3> 19 <% 20 // java code ..... 21 Cookie cookie = CookieUtils.getCookie("ids", request.getCookies()); 22 if(cookie==null){ 23 out.print("你尚未浏览商品"); 24 return; 25 } 26 String[] pros = {"mac 电脑","小米手机3","雕牌洗衣液2瓶装","百事可乐一听"}; 27 String[] ids = cookie.getValue().split(",");// 1 3 4 28 for(int i=0;i<ids.length;i++){ 29 out.print(pros[Integer.parseInt(ids[i])-1]+"<br>"); 30 } 31 %> 32 </body> 33 </html>
- LookProductServlet.java
1 import java.io.IOException; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.http.Cookie; 5 import javax.servlet.http.HttpServlet; 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 9 import cn.itcast.day11.utils.CookieUtils; 10 11 public class LookProductServlet extends HttpServlet { 12 13 public void doGet(HttpServletRequest request, HttpServletResponse response) 14 throws ServletException, IOException { 15 doPost(request, response); 16 17 } 18 19 public void doPost(HttpServletRequest request, HttpServletResponse response) 20 throws ServletException, IOException { 21 // 开始coding................ 22 response.setContentType("text/html;charset=utf-8"); 23 /** 24 * servlet 存放用户浏览商品的id 到cookie 1,2 ,3 25 */ 26 String id = request.getParameter("id");// 1 27 // 先判断 id 28 Cookie cookie = CookieUtils.getCookie("ids", request.getCookies()); 29 if (cookie == null) { 30 // 第一查看 31 cookie = new Cookie("ids", id); 32 cookie.setMaxAge(3600 * 24 * 7); 33 cookie.setPath("/"); 34 } else { 35 // 商品浏览 过 判断 id 在不在已知的ids 里面 36 String ids[] = cookie.getValue().split(",");// 1,2,3,4,5 37 if (!check(id, ids)) { 38 // 不 存在 ... 39 cookie.setValue(cookie.getValue() + "," + id); 40 cookie.setMaxAge(3600 * 24 * 7); 41 cookie.setPath("/"); 42 } 43 44 } 45 response.addCookie(cookie); 46 response.getWriter().print("查看成功<a href='/day11/product.jsp'>返回</a>"); 47 48 } 49 50 private boolean check(String id, String[] ids) { 51 for (String eachId : ids) { 52 if (eachId.equals(id)) { 53 return true; 54 } 55 } 56 return false; 57 } 58 59 }
3、session技术
Session :一种将用户信息保存在服务器端技术 ,客户端会持有Session信息对应key,通过key找到session信息
* Session 占用服务器空间,安全性更高 ,Cookie节省服务器资源,安全性差一些
Session 将用户相关信息保存服务器端,服务器会为每个浏览器创建单独Session对象,每个用户各自数据保存各自浏览器对应Session对象中。不同用户获取到各自浏览器对应Session 保存数据。
session依赖cookie机制来实现用户信息的保存.
通过JSESSIONID 将sessionId() 发送给浏览器,使得浏览器可以保存session id信息
获取用户的session 绑定数据.
*注意: 默认级别,发送的cookie 机制是会话级别的,浏览器关闭session对象存在,但是cookie保存的sessionId会消失.
3.1、Session对象创建
HttpSession 何时创建? session对象可以在servlet和jsp中创建
- 如果是在jsp session对象会由容器自动创建
- servlet 容器不会自动创建,需要自己手动创建
HttpSession session = request.getSession();
创建好session 容器会自动将seesionId通过cookie 机制 发送给浏览器保存
* Session 通过cookie 传输 jsessionid 用来在服务器端查找对应Session对象
3.2、问题:如何实现关掉浏览器后,再开浏览器,上次购买的商品还在?
如何实现关闭浏览器保留sessionid 信息 ?
解决方案:修改服务器默认的cookie机制 变成持久化cookie
1 Cookie cookie = new Cookie("JSESSIONID", session.getId());// session对应的cookie信息 2 cookie.setPath("/"); 3 cookie.setMaxAge(3600 * 24);//设置sessionId 的有效时间 4 response.addCookie(cookie);//发送给浏览器保存sessionid 信息 5 //浏览器获取的cookie持久化的cookie,下次打开浏览器就可以在服务器端找到sessio对象 (前提是session对象没有被销毁!)
3.3、Session的生命周期及对象销毁
- session对象创建
*servlet 代码request.getSession() 执行时创建(当前会话第一次执行)
*jsp 容器自动创建session对象
- session对象销毁
1: 自然销毁,默认30分钟过期(连续不使用Session对象时间。即:session 如果一直处于休息状态,容器主动销毁session)
默认过期时间在tomcat/conf/web.xml 配置:
1 <session-config> 2 <session-timeout>30</session-timeout> 3 </session-config>
如果将session-timeout设置为0或负数,则表示会话永不超时!
也可手动设置:
1 setMaxInactiveInterval(int interval)
2: 程序员主动销毁session 对象
1 session.invalidate();//session 对象存放的数据就没有了
3: 非正常关闭服务器(正常关闭服务器Session信息会被序列化到硬盘中 保存tomcat/work目录)
- 浏览器关闭,session对象是否就销毁了?
答案:不是,Session保存在服务器端,和浏览器是否关闭没有关系,关闭浏览器时删除会话cookie,丢失jsessionid,没有jsession无法找到服务器端对应Session
3.4、问题:session.removeAttribute 和 session.invalidate区别 ?
-
1 session.removeAttribute();// 删除当前Session对象中一个属性值 2 session.invalidate();// 销毁当前Session对象,删除所有属性
4、session 案例——采用一次性验证码(用户登录)
- 验证码分析图:
- 代码示例:Register.jsp
1 <%@ page language="java" contentType="text/html; charset=utf-8" 2 pageEncoding="utf-8"%> 3 <html> 4 <head> 5 <meta charset="UTF-8"> 6 <title>Insert title here</title> 7 <script type="text/javascript"> 8 function change() { 9 document.getElementById('img').src = '/day11/check?' 10 + new Date().getTime(); 11 } 12 </script> 13 </head> 14 <body> 15 <h3>注册页面</h3> 16 <h3 style="color:red">${error }</h3> 17 <form action="/day11/register" method="post"> 18 用户名<input type="text" name="name"><br> 19 密码<input type="password" name="password"><br> 20 验证码<input type="text" name="checkCode"><img src="/day11/check" 21 style="cursor: pointer;" onclick="change();" id="img"><br> 22 <input type="submit" value="注册"> 23 </form> 24 </body> 25 </html>
- RegisterServlet.java
1 import java.io.IOException; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.http.HttpServlet; 5 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletResponse; 7 8 public class RegisterServlet extends HttpServlet { 9 10 public void doGet(HttpServletRequest request, HttpServletResponse response) 11 throws ServletException, IOException { 12 doPost(request, response); 13 14 } 15 16 public void doPost(HttpServletRequest request, HttpServletResponse response) 17 throws ServletException, IOException { 18 // 开始coding................ 19 // 获取表单提交的信息 20 request.setCharacterEncoding("utf-8"); 21 String name = request.getParameter("name"); 22 String password = request.getParameter("password"); 23 String inputCode = request.getParameter("checkCode"); 24 25 // 第一步 验证验证码信息是否正确 26 // 获取之前session 绑定验证码信息 比对 27 String codeSession = (String) request.getSession() 28 .getAttribute("check"); 29 // 一次验证码 用完就销毁... 30 request.getSession().removeAttribute("check"); 31 // 比对 用户输入的code 和 session code 如果一致... 32 if (codeSession.equals(inputCode)) { 33 // 注册事情..... 34 response.sendRedirect("/day11/login.jsp"); 35 36 } else { 37 // 验证码错误 跳回来 38 request.setAttribute("error", "验证码错误"); 39 request.getRequestDispatcher("/register.jsp").forward(request, 40 response); 41 } 42 43 } 44 45 }
* 一次性验证码,当验证码生成后,只使用一次,不管成功或者失败,验证码都将失效
注意:一次验证码,用完就销毁!
5、session 案例——购物车
- 购物车逻辑图
- 代码示例:Product_cart.jsp
1 <%@page import="cn.itcast.day11.utils.CookieUtils"%> 2 <%@ page language="java" contentType="text/html; charset=UTF-8" 3 pageEncoding="UTF-8"%> 4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 5 <html> 6 <head> 7 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 8 <title>Insert title here</title> 9 </head> 10 <body> 11 <h2>商品列表</h2> 12 mac电脑<a href="/day11/cart?id=1"> 购买</a><br> 13 小米手机3 <a href="/day11/cart?id=2">购买</a><br> 14 雕牌洗衣液2瓶装<a href="/day11/cart?id=3">购买</a><br> 15 百事可乐一听 <a href="/day11/cart?id=4">购买</a><br> 16 17 <hr> 18 <a href="/day11/cart.jsp">查看购物车</a> 19 </body> 20 </html>
- CartServlet.java
1 import java.io.IOException; 2 import java.util.HashMap; 3 import java.util.Map; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 public class CartServlet extends HttpServlet { 11 12 public void doGet(HttpServletRequest request, HttpServletResponse response) 13 throws ServletException, IOException { 14 doPost(request, response); 15 16 } 17 18 public void doPost(HttpServletRequest request, HttpServletResponse response) 19 throws ServletException, IOException { 20 // 开始coding................ 21 response.setContentType("text/html;charset=utf-8"); 22 String id = request.getParameter("id");// 3 2 3 23 // 通过id --->product 24 String pros[] = { "mac电脑", "小米手机3", "雕牌洗衣液2瓶装", "百事可乐一听" }; 25 String pro = pros[Integer.parseInt(id) - 1]; 26 27 // 做一个 购物车 28 Map<String, Integer> cart = (Map<String, Integer>) request.getSession() 29 .getAttribute("cart"); 30 // 2: 判断购物车存在与否? 31 if (cart == null) { 32 // 购物车空 33 cart = new HashMap<String, Integer>(); 34 cart.put(pro, 1); 35 } else { 36 // 已经存在购物车 37 if (cart.containsKey(pro)) { 38 // 表示该购物车已经含有此商品 39 int count = cart.get(pro);// 得到该购物车商品的数量 40 // 数量+1 41 cart.put(pro, count += 1); 42 // 将已有的商品数量+1 43 } else { 44 cart.put(pro, 1); 45 } 46 47 } 48 request.getSession().setAttribute("cart", cart); 49 response.getWriter().print( 50 "购买成功!<a href='/day11/product_cart.jsp'>返回主页</a>"); 51 } 52 53 }
- cart.jsp
1 <%@page import="java.util.*"%> 2 <%@ page language="java" contentType="text/html; charset=UTF-8" 3 pageEncoding="UTF-8"%> 4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 5 <html> 6 <head> 7 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 8 <title>Insert title here</title> 9 </head> 10 <body> 11 <h3>购物车列表</h3> 12 <!-- 如何从session 获取购物车信息 --> 13 <% 14 // 1session 获取数据 15 Map<String,Integer> cart = (Map<String,Integer>)session.getAttribute("cart"); 16 if(cart!=null){ 17 // 2: 如何迭代数据? 18 Set<String> set = cart.keySet(); 19 Iterator<String> it = set.iterator(); 20 while(it.hasNext()){ 21 String proName = it.next(); 22 int count = cart.get(proName); 23 out.print("商品名称:"+proName+"---数量"+count+"<br>"); 24 } 25 }else{ 26 out.print("购物车无商品"); 27 } 28 %> 29 </body> 30 </html>
6、session、request、ServletContext对象的比较
- ServletContext 每个web工程对应唯一对象,全局的Servlet上下文对象,允许将数据保存
ServletContext --- 所有Servlet共享 - HttpServletRequest 每次请求产生一个HttpServletRequest对象,允许将数据保存request对象中,结合请求转发一起使用
* 当请求结束后,数据就会删除 - HttpSession 服务器会为每个客户端创建单独Session对象,允许将数据保存session中 ,session保存的是每个用户各自的数据
* 用户之间没有影响 (用户购物车、用户登录信息 ) - 小结
Servlet三种数据访问范围:ServletContext 、HttpSession、HttpServletRequest 1、保存ServletContext数据 ,在服务器关闭时才会删除,生命周期最长,全局都可以访问 (最少使用) * 应用场景:网站访问次数、全局数据库连接池 需要保存ServletContext 2、保存HttpSession数据 ,三种情况下丢失 ,主要保存用户相关数据 (不建议存放大规模数据) * 应用场景: 用户登录信息、购物信息 保存HttpSession 3、保存HttpServletRequest,当前请求发生时产生,响应结束数据立刻释放 (生命周期最短,最建议使用) *应用场景: Servlet获得数据处理结果,通过请求转发 传递信息给JSP显示 三种数据范围提供相同几个方法 setAttribute getAttribute removeAttribute
本章小结
1、Cookie和Session区别 ?
Cookie保存会话信息在客户端,Session保存会话信息在服务器端,Session基于Cookie实现的
2、浏览器关闭后,是不是Session对象就销毁了 ?
不是,Session保存在服务器端,关闭浏览器丢失jsessionid,
无法找到服务器对应Session对象了,需要等到Session过期后才会销毁
3、会话cookie和持久cookie区别 ?
会话cookie 保存浏览器内存缓存区中,关闭浏览器后,会话cookie就会删除
持久cookie 保存浏览器临时文件区 硬盘上,存在过期时间,当过期后会自动删除,通过设置maxage为0删除持久cookie
4、session的三种销毁原因?
服务器非正常关闭、session过期、invalidate
5、如何实现关闭浏览器再次打开,Session仍然可以访问?
将jsessionid 对应cookie 持久化
多学一招:利用URL重写实现Session跟踪
考虑浏览器不支持Cookie的情况(如,浏览器cookie禁用),Servlet规范中还引入了URL重写机制来保存用户的会话信息。所谓URL重写,指的就是将Session的会话标识号以参数的形式附加在超链接的URL地址后面。