Cookie 有什么用
思考问题 1-抛砖引玉
大家在访问某个网站的时候,是否能看到提示你上次登录网站的时间,而且要注意的是不同
用户上次登录的时间肯定是不一样的,这是怎么实现的?
思考问题2-抛砖引玉
大家在访问某个购物网站的时候,是否能看到提示你曾经浏览过的商品,不同用户浏览过 的商品肯定不一样,这是怎么实现的?
解决之道—cookie 技术
Cookie(小甜饼)是客户端技术,服务器把每个用户的数据以 cookie 的形式写给用户各自的浏 览器。当用户使用浏览器再去访问服务器中的 web 资源时,就会带着各自的数据去。这样, web 资源处理的就是用户各自的数据了。【简单示意图】
cookie 介绍
二说 cookie
- Cookie 是服务器在客户端保存用户的信息,比如登录名,浏览历史等, 就可以以 cookie 方式保存。
- Cookie 信息就像是小甜饼(cookie)一样,数据量并不大,服务器端在需要的时候可以从客户端浏览器读取,可以通过图来理解。
cookie可以用来做啥
- 保存上次登录时间等信息
- 保存用户名,密码, 在一定时间不用重新登录
- 网站的个性化,比如定制网站的服务,内容。
Cookie是保存在本地浏览器的!!!
cookie 基本使用
使用文档
https://docs.oracle.com/javaee/7/api/
cookie常用方法
-
Cookie 有点象一张表(K-V),分两列,一个是名字,一个是值,数据类型都是 String , 如图
-
如何创建一个 Cookie(在服务端创建的)
Cookie c = new Cookie(String name,String val);
c.setMaxAge();//保存时间
- 如何将一个 Cookie 添加到客户端
response.addCookie(c);
- 如何读取 cookie(在服务器端读取到 cookie 信息)
request.getCookies();
cookie 底层实现机制-创建和读取 Cookie
服务器端创建Cookie
package com.hspedu.cookie;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @ClassName CreateCookie
* @Description TODO
* @Author zephyr
* @Date 2022/12/18 22:37
* @Version 1.0
*/
@WebServlet(name = "CreateCookie", value = "/createCookie")
public class CreateCookie extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("==========CreateCookie被调用==========");
//1. 创建一个Cookie对象
/**
* 1) username 该cookie的名字,唯一的,可以理解成key
* 2) zephyr 该cookie的值
* 3) 可以创建多个cookie对象
* 4) 这是这个cookie在服务器端,还没有到浏览器
*/
Cookie cookie = new Cookie("username", "zephyr");
response.setContentType("text/html;charset=utf-8");
//2. 将cookie发送给浏览器,让浏览器将该cookie保存起来
response.addCookie(cookie);
PrintWriter writer = response.getWriter();
writer.println("<h1>创建cookie成功!<h1>");
writer.flush();
writer.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
服务器端读取Cookie
package com.hspedu.cookie;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
/**
* @ClassName ReadCookies
* @Description 演示:读取从客户端发送来的cookie信息
* @Author zephyr
* @Date 2022/12/19 10:47
* @Version 1.0
*/
@WebServlet(name = "ReadCookies", value = "/readCookies")
public class ReadCookies extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("==========CreateCookie被调用==========");
//1. 通过Request对象读取所有Cookie信息
Cookie[] cookies = request.getCookies();
//2. 遍历Cookie
if (cookies != null && cookies.length > 0){
for (Cookie cookie : cookies) {
System.out.println(cookie.getName() + " = " + cookie.getValue());
}
}
//Cookie: JSESSIONID=BA235330CCE65FE095ED5EFB37B3A113; username=zephyr
//3. 给浏览器返回信息
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("<h1>读取cookie信息成功<h1>");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
JSESSIONID有什么用?
session是会话的意思。
JSESSIONID是会话的唯一标识。
Cookie应用实例
读取指定的cookie
通过一个工具类遍历寻找指定cookie。
CookieUtils.java
package com.hspedu.cookie;
import javax.servlet.http.Cookie;
/**
* @ClassName CookieUtils
* @Description 对Cookie数组进行过滤
* @Author zephyr
* @Date 2022/12/19 11:40
* @Version 1.0
*/
public class CookieUtils {
public static Cookie readCookieByName(String cookieName, Cookie[] cookies) {
//如果传输参数不正确就返回null
if (cookieName == null || "".equals(cookieName) || cookies == null || cookies.length == 0) {
return null;
}
for (Cookie cookie : cookies
) {
if (cookieName.equals(cookie.getName())) {
return cookie;
}
}
//没找到就返回null
return null;
}
}
修改cookie
需求:给定一个指定的cookie,找到该cookie,如果找到,则修改值为jyl-hi;如果没找到,则提示找不到cookie。
UpdateCookie.java
package com.hspedu.cookie;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
/**
* @ClassName UpdateCookie
* @Description TODO
* @Author zephyr
* @Date 2022/12/19 11:59
* @Version 1.0
*/
@WebServlet(name = "UpdateCookie", value = "/updateCookie")
public class UpdateCookie extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("==========UpdateCookie被调用==========");
//1. 根据name,查找cookie
String cookieName = "email";
Cookie[] cookies = request.getCookies();
Cookie cookie = CookieUtils.readCookieByName(cookieName, cookies);
if (cookie == null){
System.out.println("当前访问服务器的客户端没有该cookie");
} else {
cookie.setValue("jyl-hi");
//2. 遍历cookie查看值
for (Cookie cookie_ : cookies) {
System.out.println(cookie_.getName() + " = " + cookie_.getValue());
}
//3. cookie返回给浏览器
response.addCookie(cookie);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
通过setValue重新设置cookie的值后,一定要通过
response.addCookie(cookie)
返回cookie!
如果新创建的cookie和浏览器已有的cookie重名,则会覆盖。
Cookie生命周期
介绍
- Cookie 的生命周期指的是如何管理 Cookie 什么时候被销毁(删除)
setMaxAge()
- 正数,表示在指定的秒数后过期
- 负数,表示浏览器关闭,Cookie就会被删除(默认值是-1)
- 0,表示马上删除Cookie
应用实例
演示Cookie的生命周期
System.out.println("==========CookieLive被调用==========");
//演示创建一个cookie,生命周期为60s
Cookie cookie = new Cookie("job", "java");
//1. 从创建该cookie开始计时,60s后就无效了
//2. 浏览器根据创建时间,计时到60s就认为该cookie无效
//3. 如果该cookie无效,那么浏览器在发出http请求时,就不在携带该cookie
cookie.setMaxAge(60);
response.addCookie(cookie);
访问CookieLive,返回Set-Cookie: job=java; Max-Age=20; Expires=Mon, 19-Dec-2022 04:51:49 GMT
。告诉浏览器在60秒后这个cookie无效(不携带)。
60秒后,浏览器向服务器发送http请求果然没有带上job这个cookie。
演示删除一个cookie
System.out.println("==========CookieLive被调用==========");
//演示删除一个cookie:username
//1. 先得到这个cookie
Cookie usernameCookie = CookieUtils.readCookieByName("username", request.getCookies());
//2. 将其的生命周期设置为0
usernameCookie.setMaxAge(0);
//3. 通知浏览器
response.addCookie(usernameCookie);
在浏览器端抓包可以看到响应头里:Set-Cookie: username=zephyr; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT
。
然后就能看到浏览器里的这个cookie已经被删除了。
如果不设置生命周期会如何
不过不设置生命周期,默认是setMaxAge(-1)
,是一个会话级别的生命周期,表示浏览器关闭,Cookie就会被删除。
cookie有效路径
- Cookie 有效路径 Path 的设置
- Cookie 的 path 属性可以有效的过滤哪些 Cookie 可以发送给服务器。哪些不发。 path属性是通过请求的地址来进行有效的过滤
- 规则如下
应用实例
System.out.println("==========CookiePath被调用==========");
//1. 创建2个cookie
Cookie bandCookie = new Cookie("band", "Gelneryus");
Cookie instrumentCookie = new Cookie("instrument", "Guitar");
//2. 设置不同的有效路径
bandCookie.setPath(request.getContextPath()); // ContextPath = /cs
// instrumentCookie的有效路径是 /cs/ins
instrumentCookie.setPath(request.getContextPath() + "/ins");
//3. 保存到浏览器
response.addCookie(bandCookie);
response.addCookie(instrumentCookie);
//4. 给浏览器返回信息
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("<h1>设置cookie路径成功<h1>");
作业:自动填写登录账号
- 如果用户名是 hspedu, 密码是 123456, 则认为该用户合法, 登录成功,否则登录失效
- 要求实现如果登录成功,则该用户,在 3 天内登录,可以自动填写其登录名
- 登录页面需要使用 servlet 返回,而不能使用 html
Login登录页面(写成了Servlet)
package com.hspedu.cookie;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @ClassName Login
* @Description TODO
* @Author zephyr
* @Date 2022/12/19 16:05
* @Version 1.0
*/
@WebServlet(name = "Login", value = "/login")
public class Login extends HttpServlet {
HttpServletRequest request = null;
HttpServletResponse response = null;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("==========Login被调用==========");
this.request = request;
this.response = response;
//先读取cookie,看看cookie里有没有username和pwd
Cookie[] cookies = request.getCookies();
Cookie usernameCookieRead = CookieUtils.readCookieByName("username", cookies);
Cookie pwdCookieRead = CookieUtils.readCookieByName("pwd", cookies);
if (usernameCookieRead != null && pwdCookieRead != null) {
//cookie存在
showLoginHtml(usernameCookieRead.getValue(), pwdCookieRead.getValue());
} else {
showLoginHtml("", "");
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
public void showLoginHtml(String username, String pwd) throws ServletException, IOException{
String content = "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <base href=\"/cs/\">\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>登录界面</title>\n" +
"</head>\n" +
"<body>\n" +
"<h1>用户登录界面</h1>\n" +
"<form action=\"loginServlet\" method=\"get\">\n" +
" 用户名:<input type=\"text\" name=\"username\" value=\""+username+"\"><br>\n" +
" 密码:<input type=\"text\" name=\"pwd\" value=\""+pwd+"\"><br>\n" +
" <input type=\"submit\" value=\"登录\">\n" +
"</form>\n" +
"\n" +
"</body>\n" +
"</html>";
if (request != null && response != null){
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println(content);
writer.flush();
writer.close();
}
}
}
LoginServlet
package com.hspedu.cookie;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @ClassName LoginServlet
* @Description TODO
* @Author zephyr
* @Date 2022/12/19 15:13
* @Version 1.0
*/
@WebServlet(name = "LoginServlet", value = "/loginServlet")
public class LoginServlet extends HttpServlet {
String correctUserName = "jingyl";
String correctPwd = "123456";
HttpServletRequest request = null;
HttpServletResponse response = null;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("==========LoginServlet被调用==========");
this.request = request;
this.response = response;
if (checkForm()){
showSuccess();
} else {
showFail();
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
/**
* 返回登陆成功的信息
*/
public void showSuccess() throws ServletException, IOException {
//通知浏览器已经写入cookie
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("<h1>登录成功!<h1>");
}
/**
* 返回登陆失败的信息
*/
public void showFail() throws ServletException, IOException {
//通知浏览器已经写入cookie
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("<h1>登录失败!<h1>");
}
public boolean checkForm() throws ServletException, IOException {
//读取表单里的username和pwd
String username = request.getParameter("username");
String pwd = request.getParameter("pwd");
if (username.equals(correctUserName) && pwd.equals(correctPwd)) {
//如果账号密码正确则保存在浏览器的cookie
//创建cookie保存用户名和密码
Cookie usernameCookie = new Cookie("username", username);
Cookie pwdCookie = new Cookie("pwd", pwd);
//生命周期为3天
usernameCookie.setMaxAge(60 * 60 * 24 * 3);
pwdCookie.setMaxAge(60 * 60 * 24 * 3);
response.addCookie(usernameCookie);
response.addCookie(pwdCookie);
return true;
} else {
return false;
}
}
}
Cookie注意事项和细节
- 一个 Cookie 只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值
(VALUE)。 - 一个 WEB 站点可以给一个浏览器发送多个 Cookie,一个浏览器也可以存储多个 WEB 站点提供的 Cookie。
- cookie 的总数量没有限制,但是每个域名的 COOKIE 数量和每个 COOKIE 的大小是有限制的 (不同的浏览器限制不同, 知道即可) , Cookie 不适合存放数据量大的信息。
- 注意,删除 cookie 时,path 必须一致,否则不会删除
- Java servlet 中 cookie 中文乱码解决 [代码演示 EncoderCookie.java ReadCookie2.java]
不建议存放中文的cookie信息,可能会乱码,可以通过url编码和解码来解决。
解决中文cookie乱码问题
如果直接保存中文Cookie,会报错
- 通过
URLEncoder.encode()
可以对中文进行编码
System.out.println("==========EncoderCookie被调用==========");
//1. 如果直接错放中文的cookie会报错
//2. 通过将中文编码成 URL 编码
String company = URLEncoder.encode("景风眠教育", "utf-8");
Cookie cookie = new Cookie("company", company);
response.addCookie(cookie);
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("<h1>EncoderCookie被成功调用[中文乱码测试]<h1>");
writer.flush();
writer.close();
- 通过
URLDecoder.decode()
进行解码
System.out.println("==========EncoderCookie被调用==========");
Cookie[] cookies = request.getCookies();
Cookie cookie = CookieUtils.readCookieByName("company", cookies);
System.out.println(cookie.getName() + " = " + cookie.getValue());
System.out.println("===========解码后===========");
String decode = URLDecoder.decode(cookie.getValue());
System.out.println(cookie.getName() + " = " + decode);
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("<h1>DecoderCookie被成功调用[中文解码测试]<h1>");
writer.flush();
writer.close();