Cookie&Session
Cookie
一、概念
是一种客户端会话技术,其实就是保存在我们客户端上的一小份数据,以后执行请求就会自动带着这个cookie过去给服务器。 ,针对一次会话的多次请求有效。
Cookie和浏览器缓存有什么区别?
浏览器缓存可以缓存任意内容,上网浏览的任意内容。
Cookie只是缓存服务器需要浏览器缓存的数据。(是浏览器缓存中的一部分)
为什么要有Cookie?
原因是Http协议是无状态协议。
服务器有时候需要知道发起这次请求的客户端是否是以前的某一次来访的客户端,
以便做出更精确服务。 这时候就需要使用到cookie了。
二、使用
1.创建Cookie对象
第一次请求,客户端发送的请求没有cookie信息,创建Cookie对象:
Cookie cookie = new Cookie(String name,String value);
这里的参数用于存储数据,都必须是String类型。
2.将Cookie对象写回客户端
response.addCookie(cookie);
3.获取Cookie对象
后续的客户端请求,会携带cookie信息。通过request对象获取客户端请求发送过来的请求字段.
返回的是cookies的key的数组
String[] cookies = request.getCookies();
4.其他方法
cookie.setMaxAge(int) : 设置Cookie的最大缓存事件,以秒为单位,超过就销毁
cookie.setPath() : 设置Cookie的有效路径
cookie.getName() : 获取该cookie的名称
cookie.getValue() : 获取该cookie的值
三、Cookie的分类
-
cookie的类型
-
临时性cookie
默认的。没有针对cookie做任何设置,只要关闭了浏览器,Cookie就销毁了。
-
持久性cookie
设置有效时长,会保存到磁盘中,在一定的范围内都有效。 如果设置的是 0 表示要删除cookie, 立即删除 , 如果是 -1 ,那么是关闭浏览器后删除 cookie.setMaxAge(60*60*24 *7); 设置有效路径: cookie.setPath(url): 1. cookie.setPath("/day16/demo"); 表示day16项目下,【demo目录】下的所有servlet都可以访问当前cookie。但/day16或/day16/aa不能访问 2. cookie.setPath("/day16"); 表示【day16项目】下的所有servlet都可以访问当前cookie 3. cookie.setPath("/"); 表示【Tomcat下】的所有项目都可以访问当前cookie 例 Cookie cookie = new Cookie("password","admin123"); //设置有效期7天。 cookie.setMaxAge(60*60*24 *7); //设置cookie跨域名共享。 domain 域名. taobao tmall cookie.setDomain(".taobao.com"); //设置当前服务器里面的跨项目共享。 cookie.setPath("/"); response.addCookie(cookie);
-
Session
一、概念
是一种服务器端会话技术,基于|依赖Cookie存在
-
Cookie 和 Session的对比
cookie
数据存放在客户端 数据不安全 减轻服务器压力, 用户磁盘占用比较多。 存放的数据有限
session
数据存放在服务器端 数据相对比较安全。 服务器压力大一点。 存放的数据 依赖服务器的内存空间。
基于 | 依赖cookie的一种会话技术。
二、使用
因为Session是基于Cookie存在的,Cookie随着请求发送到服务器,因此Session也是使用request对象获取。
1.获取Session对象
HttpSession session = request.getSession();//获取到Session的时候会产生一个唯一的ID值
2.Session对象存|取值
session.setAttribute(String name,Object value) : 存值
session.getAttribute(String name) : 取值
session.removeAttribute() : 移除某个值
set和get的name值一致才能取出来。
3.其他方法
session.invalidate() : 销毁Session对象
session.getID() : 获取当前session的的ID值
-------------------------------------
三、Session的背后细节
//这里获取session的机制是这样的。
// 第一次来访问,
/*那么session都没有创建,并且咱们的请求对象里面也不带任何的cookie过来。
那么这个时候会在内存中给你创建一个新的session区域,并且把这个session的id值给我们的浏览器返回。
如果是第二次访问,那么浏览器会把之前的那个cookie给带过来, 服务器收到了cookie,里面有我们上一次给的
sessionid 值, 那么这个时候再调用request.getSesion() , 它先会拿我们待过来的id ,到内存里面去找有没有session的 id值
跟这个cookie带过来的一样 ,如果有,就直接返回这个内存空间, 否则就创建新的session空间
*/
public HttpSession getSession()
返回与此请求关联的当前会话,如果该请求没有会话,则创建一个会话。 如果有就返回这个会话Session对象
下图说明:
四、作用域&生命周期
-
作用域
在一次会话的多次请求中有效
-
生命周期
-
何时创建 :
在第一次调用request.getSession()时创建
-
何时销毁 :
1. 服务器非正常关闭时销毁。 服务器正常关闭时序列化(钝化) 2. Session对象超时。默认30分钟。(从最后一次请求开始算起) 3. 调用session.invalidate()方法手动销毁
-
有关Session的一个问题:
1. 浏览器关闭后,之前的Session对象会销毁吗?这个时候getSession()获得的Session对象还是之前的那个吗?
2. 如果不是的话,为什么?还能取到之前setAttribute()存进去的值吗?
3. 如果不能取到,但是我就是想要获取到之前的Session对象该怎么做?
解答:
1. 不会销毁。因为Session对象是服务器开辟的一个内存空间,与客户端浏览器的关闭与否没有关系。
在关闭浏览器后重新发起请求时获取的Session对象就不是之前的那个了,因为Session的定位是依靠
请求发送到服务器的Cookie:JESSIONID的,关闭后Cookie对象消失了,它的ID也就没了,因此就找不
之前的Session对象了。
2. 既然获取的Session对象与之前的Session对象不是同一个对象,那么自然就获取不到之前存入的值了。
3. 自己取那个sessionid ,然后自己存到cookie里面,并且给cookie设置有效期。
注意: cookie的那个name不能乱写。 JSESSIONID :
五、三个域的对比
1. ServletContex
-
作用域
当前ServletContex对象的整个项目
-
生命周期
何时创建: 服务器启动(这里是被托管的项目的ServletContext创建) | 项目部署 何时销毁: 服务器关闭 | 项目移除
-
作用
1. 存 | 取值 2. 获取全局参数 (web.xml的Context-Param中的全局参数) 3. 获取项目下的任意位置的资源
2. Session
-
作用域
一次会话的多次请求有效
-
生命周期
何时创建: 第一次调用request.getSession()时创建 何时销毁: 1. 服务器非正常关闭时销毁 服务器正常关闭时序列化(钝化) 2. Session对象等待超时 3. 手动调用session.invalidate()销毁
作用
3. Request
-
作用域
一次请求中有效
-
生命周期
何时创建: 每次请求都会创建一个Request和一个Response对象 何时销毁: 服务器对客户端做出了响应后
作用
六、案例
案例一:简易的访问时间的案例(Cookie)
需求:
A:写一个用户登录页面,用户填写账号密码后,校验是否成功登陆
校验失败:告知用户登录失败,2秒后回到登录页面重新登陆
校验成功,登陆成功。
B:获取用户客户端的Cookie。用于获取用户上一次登陆的时间
如果存在Cookie值,遍历获取到存储上次访问时间的Cokkie对象,输出到客户端,并存储当前访问时间到客户端
如果不存在Cookie对象,欢迎用户登录,存储访问时间写回到客户端
代码实现:
public class LastVisitedTimeDemo extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 利用Cookie存储访问时间,在访问时输出上次访问时间在控制台。
response.setContentType("text/html;charset=UTF-8");// 告诉服务器和客户端都以UTF-8编解码
// 获取用户的提交的表单参数,如果账号密码正确登陆成功
String username = request.getParameter("username");
String password = request.getParameter("password");
PrintWriter out = response.getWriter();//获取输出流
if (username.equals("admin") && password.equals("123")) {
// 获取Cookie对象,判断是否是新用户
Cookie[] cookies = request.getCookies();
if (cookies != null) { // 不是新用户
// 获取存储时间的cookie对象
for (int i = 0; i < cookies.length; i++) {
if (cookies[i].getName().equals("LastVisitedTime")) {
// 获取cookie的值
String value = cookies[i].getValue();
// 将毫秒值转换成有意义的日期
String localDate = new Date(Long.parseLong(value)).toLocaleString();
// 输出最后一次访问时间在浏览器
out.write("<h3>欢迎用户:"+username+"回来,您上次访问的时间是:" + localDate+"<h3>");
}
}
}else { //是新用户
out.println("<h3>欢迎用户:"+username+"</h3>");
}
//无论是否是有cookie缓存的用户,最后都要记录当前的毫秒值添加进cookie写回客户端保存
//创建Cookie对象
Cookie cookie = new Cookie("LastVisitedTime", ""+System.currentTimeMillis());
//将cookie对象写回客户端保存
response.addCookie(cookie);
}else {
out.println("<h3>登录失败,请重新登录</h3>");
response.setHeader("refresh", "2;"+getServletContext().getContextPath()+"/Login.html");
}
}
案例二:简易的购物车(Session)
需求:
在商品界面点击商品,将其添加至购物车。跳转页面:
继续购物:
返回到之前的商品选择页面。
购物结算:
获取到用户点击
思路:
代码实现
商品购物页面
<a href="cart?id=0">苹果8</a><br/>
<a href="cart?id=1">华为10</a><br/>
<a href="cart?id=2">vivo9</a><br/>
<a href="cart?id=3">魅族6</a><br/>
<a href="cart?id=4">小米7</a><br/>
<a href="cart?id=5">oppoR9s</a><br/>
通过携带参数id用于区分不同的商品
业务处理Servlet
//商品数组
private static String[] phones = {"苹果8","华为10","vivo9","魅族6","小米7","oppoR9s"};
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取Session对象
//寻找客户端是否有携带JSESSIONID的Cookie过来,如果有,通过这个ID找到ID对应Session对象并返回,如果没有就重新创建一个新的Session对象
HttpSession session = request.getSession();
//获取存储在session中的购物车cartMap
Map<String, Integer> cartMap = (Map<String, Integer>) session.getAttribute("cartMap");
//2.判断cartMap是否为空
if(cartMap == null) { //如果购物车为空,说明用户第一次访问,为其创建购物车Map对象
cartMap = new HashMap<>();
}
//3.获取到发送请求的商品的ID值,并将String类型转换为int类型
int id = Integer.parseInt(request.getParameter("id"));
//通过id值获取到对应的商品名称
String phone = phones[id];
//4.判断cartMap中是否包含该商品
if(cartMap.containsKey(phone)) { //如果包含当前商品,重新设置键值对
cartMap.put(phone, cartMap.get(phone)+1);
}else { //如果不包含当前商品,设置键值对:商品名:1
cartMap.put(phone, 1);
}
//5.将购物车添加至服务器Session对象存储
session.setAttribute("cartMap", cartMap);
//为了让关闭浏览器之后重新访问还能找到之前的Session对象,获取到该SessionID添加到Cookie里面返回给客户端
//Cookie的key一定要写成JSESSIONID才能找到
String sessionId = session.getId();
Cookie cookie = new Cookie("JSESSIONID", sessionId);
cookie.setMaxAge(60*24);//让该Cookie有效期为一天
response.addCookie(cookie);
//6.分发跳转,跳转到中转页面,用户选择继续购物或是结算商品
response.sendRedirect("select.html");//由于是用session存值,同一会话的多次请求有效,用请求转发和重定向都可以
}
中转选择页面
<p><a href="list.html"><h4>继续购物</h4></a></p>
<a href="result.jsp"><h4>购物结算</h4></a>
商品结算页面
<body>
<!-- 在这里取出购物车 -->
<%
//这里的session就是CartServlet的session,通过这个session取得购物车cartMap集合
Map<String, Integer> cartMap = (Map<String, Integer>) session.getAttribute("cartMap");
//keySet()获取到Map集合中所有key的集合
Set<String> names = cartMap.keySet();
//遍历集合取得所有的key和value写成页面
%>
<b>商品名称</b> <b>数量</b><br/>
<%
for (String name : names) {
int number = cartMap.get(name);
%>
<b><%=name+" : " %></b> <b><%=number%></b><br/>
<%
}
%>
</body>
结果显示:
~~~欢迎指正与交流。