一、相关概念
1、什么是会话?
HttpServletRequest对象和ServletContext对象都可以对数据进行保存,但是这两个对象都不可行,具体原因如下:
(1)客户端请求Web服务器时,针对每次HTTP请求,Web服务器都会创建一个HttpServletRequest对象,该对象只能保存本次请求所传递的数据。由于购买和结账是两个不同的请求,因此,在发送结账请求时,之前购买请求中的数据将会丢失。
(2)使用ServletContext对象保存数据时,由于同一个Web应用共享的是同一个ServletContext对象,因此,当用户在发送结账请求时,由于无法区分哪些商品是哪个用户所购买的,而会将该购物网站中所有用户购买的商品进行结算,这显然也是不可行的。
(3)为了保存会话过程中产生的数据,在Servlet技术中,提供了两个用于保存会话数据的对象,分别是Cookie和Session。关于Cookie和Session的相关知识,将在下面的小节进行详细讲解。
2、cookie和浏览器缓存的关系
浏览器缓存可以缓存任意内容(上网浏览的所有内容)
cookie只是服务器需要浏览器缓存数据(cookie只是浏览器缓存中一部分)
3、会话技术的分类
- 服务器端会话技术——session
-
客户端会话技术——cookie
二、cookie
1、什么是cookie?
cookie一种由服务器生成(响应头Set-Cookie),保存在客户端(请求头Cookie)的会话跟踪技术
cookie技术它是基于http协议的!
2、cookie的作用
Cookie将用户的信息保存到客户端浏览器的一个技术,当用户下次访问的时候,浏览器会自动携带Cookie的信息过来到服务器端
3、cookie的执行原理
4、cookie操作相关的方法
4.1 创建cookie
Cookie cookie = new Cookie(String name,String value);
4.2 响应
response.addCookie(Cookie cookie);//将cookie发送给浏览器
4.3 获取
Cookie[] cookies = request.getCookies(); //接收浏览器携带的所有cookie
5、cookie的生命
cookie的默认生命是一个会话级别的,关闭浏览器就没了
设置cookie的存活时间
setMaxAge(int s);//设置 cookie 的最大生存时间,以秒为单位
追杀cookie
setMaxAge(0);
6、cookie的规范
- cookie的规范是一个组织规定的
- 单个的cookie的大小不超过4KB
- 一个服务器最多可以向客户端浏览器保存20个cookie
- 一个客户端浏览器最多保存300个Cookie
- 在浏览器大战的今天,一些浏览器厂商为了抢夺客户,对cookie进行了扩容(也是有限度的),比如 8KB,100,500
7、cookie的路径
cookie的路径只与是否归还(归还的路径)有关,不能按照常规的路径去理解
cookie归还的路径:
- 目前指的就是创建这个cookie的路径
- cookie的默认路径就是当前创建这个cookie所在的Servlet的路径:端口之后servlet名称之前的这么一段
- 例如:设置cookie的路径是/web_day37/cookie,那么包含/web_day37/cookie路径,都可以访问到(http://localhost:8080/web_day37/cookie/abc/BServlet)
package com.itheima.web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 演示cookie路径问题
*
*/
public class AServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 处理post请求中文乱码问题
request.setCharacterEncoding("utf-8");
// 处理响应的中文乱码问题
response.setContentType("text/html;charset=utf-8");
// 1.创建cookie
Cookie cookie = new Cookie("msg", "hehe");
// 2.设置cookie的声明周期
cookie.setMaxAge(60 * 60 * 24 * 7);
// 3.设置cookie的访问路径
cookie.setPath("/web_day37/cookie");
// 4.写回cookie
response.addCookie(cookie);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
package com.itheima.web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.itheima.utils.CookieUtils;
/**
* 获取cookie的值
*
*/
public class BServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 处理post请求中文乱码问题
request.setCharacterEncoding("utf-8");
// 处理响应的中文乱码问题
response.setContentType("text/html;charset=utf-8");
// 1.获得所有的Cookie
Cookie[] cookies = request.getCookies();
// 2.获得指定cookie
Cookie cookie = CookieUtils.getCookieByName("msg", cookies);
// 3.非空判断
if (cookie != null) {
// 4.响应给浏览器
response.getWriter().write(cookie.getValue());
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
8、cookie的域(domain)
cookie的数据(用户名和密码)
www.baidu.com
tieba.baidu.com
news.baidu.com
cookie的域主要解决二级域名携带cookie数据的问题!
cookie.setDomain(.baidu.com);
cookie.setpath("/");
应用场景
在百度首页登录成功一次之后,下次再访问百度新闻,会把第一次访问百度首页保存在cookie里面的数据(用户名和密码)携带过来,完成自动登录功能
9、cookie的乱码问题
- cookie不能跨浏览器
- cookie的name和value都不能使用中文,不支持中文
- 解决:
- 把中文转换成URL编码后才能创建cookie,发送到浏览器
- 读取Cookie之后,还要使用URL解码
import java.io.IOException;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @ClassName: SetCookieServlet
* @Description:向cookie中保存中文数据
* @author jsz
* @date 2018年8月12日
*/
public class SetCookieServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
// 对请求的数据进行重新编码
String username = URLEncoder.encode("姓名", "utf-8");
String value = URLEncoder.encode("天明", "utf-8");
// 创建cookie
Cookie cookie = new Cookie(username, value);
// 设置cookie的生命
cookie.setMaxAge(60 * 60 * 24);
// 响应cookie
response.addCookie(cookie);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.itheima.utils.CookieUtils;
/**
* @ClassName: GetCookieServlet
* @Description:从Cookie中获得中文数据
* @author jsz
* @date 2018年8月12日
*/
public class GetCookieServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
// 1.获得所有Cookie
Cookie[] cookies = request.getCookies();
// 2.获得指定cookie
String username = URLEncoder.encode("姓名", "utf-8");
Cookie cookie = CookieUtils.getCookieByName(username, cookies);
// 3.非空判断
if (cookie != null) {
String value = cookie.getValue();
response.getWriter().write(URLDecoder.decode(value, "utf-8"));
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
案例
1、案例1:记录用户上次的访问时间
1.1 流程分析
1.2 实现
- web层代码
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.itheima.utils.CookieUtils;
public class LastVisitTimeServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
// 1.获取用户携带股票来的所有的cookie
Cookie[] cookies = request.getCookies();
// 2.获取最后一次访问时间的cookie
Cookie cookie = CookieUtils.getCookieByName("lastvisttime", cookies);
// 3.判断cookie
if (cookie == null) {
// 第一次访问,给一个提示信息
response.getWriter().write("欢迎光临");
} else {
// 4.获取cookie的值
String value = cookie.getValue();
// 5.格式化时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
String lastVistTime = sdf.format(new Date(Long.parseLong(value)));
// 6.将上次访问的时间返回给客户端浏览器
response.getWriter().write("<h3 style='color:blue'>客官,您上次访问的时间是:" + lastVistTime + "</h3>");
}
// 7.更新cookie的值
Cookie cookie1 = new Cookie("lastvisttime", System.currentTimeMillis() + "");
// 8.设置cookie的生命
cookie1.setMaxAge(60 * 60 * 24);
// 9.设置cookie的访问路径
cookie1.setPath(request.getContextPath() + "/");
// 10.将这个cookie响应给客户端浏览器
response.addCookie(cookie1);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
- 工具类
package com.itheima.utils;
import javax.servlet.http.Cookie;
public class CookieUtils {
public static Cookie getCookieByName(String cookieName, Cookie[] cookies) {
// 1.非空判断
if (cookies != null) {
// 2.遍历
for (Cookie cookie : cookies) {
// 3.判断(获得指定名称的)
if (cookieName.equals(cookie.getName())) {
// 4.返回
return cookie;
}
}
}
return null;
}
}
访问地址
http://localhost:8080/web_day37/LastVisitTimeServlet
案例2:展示用户的浏览历史
需求
当用户访问一个商品的时候,需要将该商品保留在浏览记录中
技术分析
cookie
步骤分析
- 先将product_list.htm转成jsp
- 点击一个商品,展示该商品的信息,将该商品id记录到cookie (GetProductById)
- 获取之前的浏览记录 例如名称:ids
- 判断cookie是否为空
- 若为空 将当前商品的id起个名称 ids 放入cookie中 ids=1
- 若不为空,获取值 例如:ids=2-1 当前访问的id=1 使用"-"分割商品id
- 判断之前记录中有无该商品
- 若有,将当前的id放入最前面 结果 ids=1-2
- 若没有,继续判断ids长度是否>=3
- 若>=3,移除最后一个,将当前的id放入最前面
- 若<3,直接将当前的id放入最前面
- 若 ids=3-2-1 现在访问1 结果 ids=1-3-2
- 若 ids=4-3-2 现在访问1 结果 ids=1-4-3
- 判断cookie是否为空
- 再次回到product_list.jsp页面,需要将之前访问商品展示在浏览记录中
- 获取ids 例如:ids=2-3-1
- 切割
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.itheima.utils.CookieUtils;
/**
* 记录商品浏览器历史
*/
public class GetProductByIdServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//0.设置编码
//0.1获取当前访问的商品id
String id=request.getParameter("id");
//1.获取指定的cookie ids
Cookie c = CookieUtils.getCookieByName("ids", request.getCookies());
String ids="";
//2.判断cookie是否为空
if(c==null){
//若cookie为空 需要将当前商品id放入ids中
ids=id;
}else{
//若cookie不为空 继续判断ids中是否已经该id // ids=2-11-
//获取值
ids=c.getValue();
String[] arr = ids.split("-");
//将数组转成集合 此list长度不可变
List<String> asList = Arrays.asList(arr);
//将aslist放入一个新list中
LinkedList<String> list = new LinkedList<>(asList);
if(list.contains(id)){
//若ids中包含id 将id移除 放到最前面
list.remove(id);
list.addFirst(id);
}else{
//若ids中不包含id 继续判断长度是否大于2
if(list.size()>2){
//长度>=3 移除最后一个 将当前的放入最前面
list.removeLast();
list.addFirst(id);
}else{
//长度<3 将当前放入最前面
list.addFirst(id);
}
}
ids="";
//将list转成字符串
for (String s : list) {
ids+=(s+"-");
}
//ids=ids.substring(0, ids.length()-1);
}
//将ids写回去
c=new Cookie("ids",ids);
//设置访问路径
c.setPath(request.getContextPath()+"/");
//设置存活时间
c.setMaxAge(3600);
//写回浏览器
response.addCookie(c);
//3.跳转到指定的商品页面上
response.sendRedirect(request.getContextPath()+"/product_info"+id+".htm");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
案例3:清空历史记录
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*清空浏览记录
*/
public class ClearHistroyServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//创建一个cookie
Cookie c=new Cookie("ids", "");
c.setPath(request.getContextPath()+"/");// /day1101/
//设置时间
c.setMaxAge(0);
//写回浏览器
response.addCookie(c);
//页面跳转
response.sendRedirect(request.getContextPath()+"/product_list.jsp");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}