【JavaWeb】Cookie

Cookie 有什么用

思考问题 1-抛砖引玉

大家在访问某个网站的时候,是否能看到提示你上次登录网站的时间,而且要注意的是不同
用户上次登录的时间肯定是不一样的,这是怎么实现的?

image-20221218200759797

思考问题2-抛砖引玉

大家在访问某个购物网站的时候,是否能看到提示你曾经浏览过的商品,不同用户浏览过 的商品肯定不一样,这是怎么实现的?

解决之道—cookie 技术

Cookie(小甜饼)是客户端技术,服务器把每个用户的数据以 cookie 的形式写给用户各自的浏 览器。当用户使用浏览器再去访问服务器中的 web 资源时,就会带着各自的数据去。这样, web 资源处理的就是用户各自的数据了。【简单示意图】

image-20221218201836766

image-20221218201900683

image-20221218202141883

cookie 介绍

二说 cookie

  1. Cookie 是服务器在客户端保存用户的信息,比如登录名,浏览历史等, 就可以以 cookie 方式保存。
  2. Cookie 信息就像是小甜饼(cookie)一样,数据量并不大,服务器端在需要的时候可以从客户端浏览器读取,可以通过图来理解。

image-20221218202705919

image-20221218202754090

cookie可以用来做啥

  1. 保存上次登录时间等信息
  2. 保存用户名,密码, 在一定时间不用重新登录
  3. 网站的个性化,比如定制网站的服务,内容。

Cookie是保存在本地浏览器的!!!

cookie 基本使用

使用文档

https://docs.oracle.com/javaee/7/api/

image-20221218204243983

cookie常用方法

  1. Cookie 有点象一张表(K-V),分两列,一个是名字,一个是值,数据类型都是 String , 如图
    image-20221218204501185

  2. 如何创建一个 Cookie(在服务端创建的)

Cookie c = new Cookie(String name,String val); 
c.setMaxAge();//保存时间
  1. 如何将一个 Cookie 添加到客户端
response.addCookie(c);
  1. 如何读取 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);
    }
}

image-20221218224843369

image-20221218224847269

服务器端读取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);
    }
}

image-20221219112132718

image-20221219112242221

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生命周期

介绍

  1. Cookie 的生命周期指的是如何管理 Cookie 什么时候被销毁(删除)
  2. setMaxAge()
    1. 正数,表示在指定的秒数后过期
    2. 负数,表示浏览器关闭,Cookie就会被删除(默认值是-1)
    3. 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);

image-20221219125200350

访问CookieLive,返回Set-Cookie: job=java; Max-Age=20; Expires=Mon, 19-Dec-2022 04:51:49 GMT。告诉浏览器在60秒后这个cookie无效(不携带)。

image-20221219124749931

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

image-20221219130136261

然后就能看到浏览器里的这个cookie已经被删除了。

image-20221219130336578

如果不设置生命周期会如何

不过不设置生命周期,默认是setMaxAge(-1),是一个会话级别的生命周期,表示浏览器关闭,Cookie就会被删除。

image-20221219131005538

cookie有效路径

  1. Cookie 有效路径 Path 的设置
  2. Cookie 的 path 属性可以有效的过滤哪些 Cookie 可以发送给服务器。哪些不发。 path属性是通过请求的地址来进行有效的过滤

image-20221219131349399

image-20221219131409832

  1. 规则如下

image-20221219131709379

应用实例

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>");

image-20221219132859263

image-20221219133055612

image-20221219133249790

作业:自动填写登录账号

  1. 如果用户名是 hspedu, 密码是 123456, 则认为该用户合法, 登录成功,否则登录失效
  2. 要求实现如果登录成功,则该用户,在 3 天内登录,可以自动填写其登录名
  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注意事项和细节

  1. 一个 Cookie 只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值
    (VALUE)。
  2. 一个 WEB 站点可以给一个浏览器发送多个 Cookie,一个浏览器也可以存储多个 WEB 站点提供的 Cookie。
  3. cookie 的总数量没有限制,但是每个域名的 COOKIE 数量和每个 COOKIE 的大小是有限制的 (不同的浏览器限制不同, 知道即可) , Cookie 不适合存放数据量大的信息。
  4. 注意,删除 cookie 时,path 必须一致,否则不会删除
  5. Java servlet 中 cookie 中文乱码解决 [代码演示 EncoderCookie.java ReadCookie2.java]

不建议存放中文的cookie信息,可能会乱码,可以通过url编码和解码来解决。

解决中文cookie乱码问题

如果直接保存中文Cookie,会报错

image-20221219163432769

image-20221219163508477

  • 通过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();

image-20221219163842135

  • 通过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();

image-20221219164433308

猜你喜欢

转载自blog.csdn.net/weixin_46421722/article/details/129463900