Cookie 和 Session

1. 回顾

Cookie是浏览器在本地持久化存储结构的一种机制.

1.1 Cookie的数据从哪里来?

服务器返回给浏览器的.

1.2 Cookie的数据是什么样的?

Cookie的数据是键值对结构.

并且这里的键值对都是程序员自定义的.

1.3 Cookie的作用是什么?

Cookie可以在浏览器这边存储一些"临时性的数据".

其实最典型的一种使用方式,就是用来存储"身份标识".(sessionId)

这里涉及到 Cookie和Session之间的联动.

后续在访问该网站的其它页面的时候,请求中就会自动带上刚才的sessionId,进一步服务器就可以知道当前是哪个用户在操作了.

1.4 Cookie到哪里去?

Cookie的内容会在下次访问该网站的时候,自动的被带到HTTP请求中.

1.5 Cookie怎么存的?

浏览器按照不同的"域名",分别存储Cookie.

域名和域名之间的Cookie是不能干扰的.

Cookie存储在硬盘上,往往会有一个超时时间. 

2. Cookie操作

2.1 方法 

①HttpServletRequest 类中的相关方法:

方法描述
Cookie[] getCookies()返回一个数组, 包含客户端发送该请求的所有的 Cookie 对象. 会自动把 Cookie 中的格式解析成键值对.

②HttpServletResponse 类中的相关方法:

方法描述
void addCookie(Cookie cookie)把指定的 cookie 添加到响应中.

把Cookie添加到响应中,在HTTP响应报文里,加了一个Set-Cookie header.


③Cookie 类中的相关方法:

每个 Cookie 对象就是一个键值对.

方法描述
String getName()该方法返回 cookie 的名称。名称在创建后不能改变。(这个值是 Set Cooke 字段设置给浏览器的)
String getValue()该方法获取与 cookie 关联的值
void setValue(String newValue)该方法设置与 cookie 关联的值。

 

2.2 方法实现

@WebServlet("/setcookie")
public class SetCookieServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//期望通过这个doGet方法,把一个自定义的Cookie数据返回到浏览器这边Cookie cookie = new Cookie("date","2023-04-02");resp.addCookie(cookie);Cookie cookie2 = new Cookie("time","15:18");resp.addCookie(cookie2);resp.getWriter().write("setCookie ok");}
}
@WebServlet("/getcookie")
public class GetCookieServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取到这次请求的cookieCookie[] cookies = req.getCookies();if (cookies != null){for (Cookie cookie : cookies) {System.out.println(cookie.getName() + ": " + cookie.getValue());}}else {System.out.println("请求中没有cookie");}resp.getWriter().write("ok");}}

①首先,发送getcookie请求:

 

此时并没有Cookie,自然getcookie请求里面也没有.

②下面发起setcookie请求:

请求这里并没有cookie内容:

响应这边:

 

访问setcookie请求的时候,代码中就会构造Cookie放在响应中.

进一步会写入浏览器,浏览器就会持久化保存.

 

③后续再次发送请求的时候,cookie内容就会出现在请求中:

再次发送,服务器就能拿到cookie内容了.(浏览器已经有了)

这个过程中,可以看到实际上真正发挥作用,还得是在服务器这边的逻辑中生效的. 

 

3. 理解会话机制

3.1 Session相关方法 

Servlet也提供了Session相关的支持.

实现登录功能,不需要直接使用Cookie AIP,直接使用Session的API就可以了.


①HttpServletRequest 类中的相关方法:

方法描述
HttpSession getSession()在服务器中获取会话. 参数如果为 true, 则当不存在会话时新建会话; 参数如果 为 false, 则当不存在会话时返回 null

getSession方法中,最核心的API.

效果有两方面:

1.如果当前用户没有session(会话),就会创建出session.

2.如果已经有了session,就能查询到这个session.

getSession背后具体做的事情:

①先读取请求中的Cookie,看Cookie里是否有JSESSIONID属性,以及值是什么.

(平时说的SessionId是一个广义的概念,不同的库中具体实现过程中会有一些细节的差异,在Servlet中,把这个属性具体叫做JSESSIONID)

如果没有,就认为需要创建新对话,

如果有,就拿着这个Id去查询看看当前的Session是否存在.

  如果存在,就直接返回该Session

  如果不存在,就准备创建新对话.

②当前确实需要创建对话,就会创建出一个Session对象,同时生成唯一的一个JSESSIONID,以该JSESSIONID为key,Session对象为value,把这个键值对给插入到服务器上述的哈希表中.

③刚才生成的JSESSION又会通过addCookie方法,加入到响应中.

此时响应里就会带有Set-Cookie字段,这里的值就是JSESSION=xxxx.

通过响应,就把JSESSION返回到浏览器这边了.

问:

什么情况下会有SessionId但没有Session?

服务器这边存储上述这些Session对象也是在内存中进行的.

比如把SessionId返回给服务器了,SessionId和Session对象是保存在服务器内存的,此时如果服务器重启,内存中的这些会话数据就没了.

但是浏览器中的SessionId这个Cookie还是存在的.

Session保存在内存中,这样的设定其实也不是很合理.

因此实践中往往会把会话保存在其它的介质上,来达到"持久化存储"目的.


②HttpSession 类中的相关方法:

一个 HttpSession 对象里面包含多个键值对.

方法描述
Object getAttribute(String name)该方法返回在该 session 会话中具有指定名称的对象,如果没有 指定名称的对象,则返回 null.
void setAttribute(String name, Object value)该方法使用指定的名称绑定一个对象到该 session 会话
boolean isNew()判定当前是否是新创建出的会话

Session存在的意义,也是为了让用户能够保存一些自定义的数据.

此处Session更像是一个Map<String.Object>.

此时,程序员想保持什么样的键值对,就可以直接进行设置了.


3.2 Session整体的存储的数据结构

Session在一个服务器上,存在很多份,每个用户都应该有一个自己的Session.

服务器同时会有多个用户,服务器就会使用Map的方式来组织多个Session.

 

多个客户端对应多个键值对,key是sessionId,value是Session对象.

这些会话里面,每个会话又可以存一些用户的键值对(自定义的).

4. 实现用户登陆

4.1 前端

当前,页面是一个form表单.

当用户点击登陆按钮,就会发起一个HTTP请求. 

形如:

服务器这边就可以根据这个请求做出处理.

 

4.2 后端

4.2.1 登陆页面 

@WebServlet("/login")
public class LoginServlet extends HelloServlet{@Overrideprotected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//1.获取到用户的用户名和密码String username = req.getParameter("username");String password = req.getParameter("password");if (username == null || password == null || username.equals("") || password.equals("")) {//确定引用本身非空,内容非空resp.setContentType("text/html;charset=utf8");resp.getWriter().write("请求的参数不完整!");return;}//2.验证用户名密码是否正确.//正确的验证,是从数据库读取数据.//注册账号,就会给数据库插入用户名和密码.//登陆的时候,就是验证当前用户名是否存在,密码是否匹配.//当前为了简单,先不引入数据库,直接通过硬编码的方式来判定用户密码//此处约定,合法的用户名是zhangshan,密码123if (!username.equals("zhangshan")){resp.setContentType("text/html;charset=utf8");resp.getWriter().write("用户名错误!");return;}if (!password.equals("123")){resp.setContentType("text/html;charset=utf8");resp.getWriter().write("密码错误!");return;}//3.登陆成功!!//此时就可以给用户创建会话HttpSession session = req.getSession(true);//在会话中,可以顺便保存点自定义的数据,比如保存一个登陆的时间戳.//setAttribute后面的value是个Object,想存什么都可以.session.setAttribute("username",username);session.setAttribute("time",System.currentTimeMillis());//4.让页面自动跳转到网站主页.//此处约定主页的路径是index(也使用Servlet生成一个动态页面)resp.sendRedirect("index");}
}

 4.2.2 跳转页面

//通过这个Servlet生成一个主页
@WebServlet("/index")
public class IndexServlet extends HelloServlet{@Override//重定向的请求是Get请求protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//先验证一下用户的登陆状态//如果未登陆,就要求用户先登陆HttpSession session = req.getSession(false);if (session == null){//用户未登陆resp.setContentType("text/html;charset=utf8");resp.getWriter().write("请先登陆!!!");return;}//已经登陆成功.//取出之前的attributeString username = (String) session.getAttribute("username");Long time = (Long) session.getAttribute("time");System.out.println("username="+username + ", time= "+time);//根据这样的内容去构造页面.resp.setContentType("text/html;charset=utf8");resp.getWriter().write("欢迎您, "+ username + "! 上次登陆时间: "+time);}
}

 

4.2.3 总结 

此时先访问index页面,是未登陆的状态:

此时故意输出用户名:

输入对的:

这个登陆时间,取决于我们的登陆时间,而不是访问时间.


总结:

这个程序就涉及到三个部分进行联动.

1.登陆页面(静态的html,使用form表单构造HTTP请求).

2.LoginServlet(doPost处理登陆的逻辑流程).

3.IndexServlet(doGet处理主页的生成).

在会话中存储的这些attribute,就相当于"埋下伏笔",后续其它页面中就可以使用到这里的东西.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/788216.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql 数据库基本操作

mysql 数据库基本操作 1、创建五张表 – user 表&#xff1a;后台用户表 – product 表&#xff1a;产品表 – account 表&#xff1a;客户账户表 – product_account 表 : 客户购买表 – customer 表 &#xff1a; 客户表 2、创建表 SQL 语句&#xff1a; 注意&#xff1a…

Figma使用问题(更新自己遇到的问题)

文章目录 前言一、如何安装插件&#xff1f;方法1&#xff1a;Figma Community / Figma中文社区方法2&#xff1a;菜单栏 二、图片倾斜插件使用1.Angle Mockups前提&#xff1a;执行过程&#xff1a; 三.中文字体插件&#xff08;宋体等&#xff09;Chinese Font Picker前提&am…

续-开发组件更新-提效工具分享

前言 小一个月没更新了&#xff0c;有各种各样的事啦&#xff0c;这一篇有点水吧。围绕两方面&#xff0c;开发组件更新以及IDEA插件的分享&#xff0c;题目和我一样水&#xff0c;有点像是日本轻小说取名了&#xff0c;整这么长。本篇的触动来源于&#xff0c;我今天偶然发现…

【保姆级讲解下Docker容器】

&#x1f308;个人主页:程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

openldap(一):简介和安装

目录 1 OpenLDAP简介1.1 LDAP介绍1、什么LDAP2、为什么要使用LDAP3、LDAP 的特点4、LDAP常用关键字5、LDAP的objectClass6、LADP使用场景 1.2 OpenLDAP介绍1、什么OpenLDAP2、OpenLDAP特点3、OpenLDAP的组件 2 OpenLDAP安装3 简单使用3.1 创建用户1、创建ou2、创建Group 3、创建…

NoSQL(非关系型数据库)之Redis的简介与安装

一、简介 1.1 关系型数据库与非关系型数据库 1.1.1 概念 1.1.2 区别 1.2 非关系型数据库产生背景 1.3 redis 简介 1.4 redis 优点 1.5 redis 快的原因 二、安装 2.1 关闭核心防护 2.2 安装相关依赖 2.3 解压软件包并进行编译安装 2.4 设置 Redis 服务所需相关配置文…

网络编程详解(select poll epoll reactor)

1. 客户端服务器建立连接过程 1.1 编写一个server的步骤是怎么样的&#xff1f; int main(){int listenfd, connfd;pid_t childpid;socklen_t clilen;struct sockaddr_in cliaddr, servaddr;listenfd socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr…

Java基础核心Map

在Java中&#xff0c;Map是一种用于存储键值对&#xff08;key-value pairs&#xff09;的集合类型。它提供了一种将键映射到值的方式&#xff0c;其中每个键在Map中都是唯一的。Map接口是java.util包中的一部分。 常用实现类&#xff1a; HashMap: 基于哈希表实现的Map&#…

JavaScript发票查验接口如何集成?返回错误的信息原因是什么呢?

发票查验的过程中&#xff0c;很可能出现各种各样的问题&#xff0c;那么返回错误信息的原因一般可能是因为以下几种原因&#xff1a;第一种是接口没有调通&#xff0c;第二种是本身发票就是一张错票、假票&#xff0c;第三种可能是税局系统或网络问题等等&#xff0c;如果在使…

6、Cocos Creator 2D 渲染组件:​Sprite 组件​

Sprite 组件 Sprite&#xff08;精灵&#xff09;是 2D/3D 游戏最常见的显示图像的方式&#xff0c;在节点上添加 Sprite 组件&#xff0c;就可以在场景中显示项目资源中的图片。 属性功能说明Type渲染模式&#xff0c;包括普通&#xff08;Simple&#xff09;、九宫格&#x…

网易云首页单页面html+css

网页设计与网站建设作业htmlcss 预览 源码查看https://hpc.baicaitang.cn/2083.html

Java | Leetcode Java题解之第4题寻找两个正序数组的中位数

题目&#xff1a; 题解&#xff1a; class Solution {public double findMedianSortedArrays(int[] A, int[] B) {int m A.length;int n B.length;if (m > n) { return findMedianSortedArrays(B,A); // 保证 m < n}int iMin 0, iMax m;while (iMin < iMax) {int…

linux shell命令(进程管理、用户管理)

一、进程的概念 主要有两点&#xff1a; 1.进程是一个实体。每一个进程都有它自己的地址空间&#xff0c;一般情况下&#xff0c;包括文本区域&#xff08;text region&#xff09;、数据区域&#xff08;data region&#xff09;和堆栈&#xff08;stack region&#xff09;…

Visual Studio 2022报错c1083,win11解决办法

如果头文件报错&#xff0c;并且编译器报错是c1083&#xff0c;无法处理的时候&#xff0c;包括卸载重装也是无济于事的时候 此时可以采取一下办法进行修改 出现这个的主要原因是安装 Windows SDK 时版本出错&#xff0c;需要根据自己的 windows 版本选择安装对应版本的 Wind…

SpringBoot+ECharts+Html 地图案例详解

1. 技术点 SpringBoot、MyBatis、thymeleaf、MySQL、ECharts 等 此案例使用的地图是在ECharts社区中查找的&#xff1a;makeapie echarts社区图表可视化案例 2. 准备条件 在mysql中创建数据库echartsdb&#xff0c;数据库中创建表t_location_count表&#xff0c;表中设置两个…

Redis底层数据库之SDS

高速的存储介质&#xff1a;内存优秀的底层数据结构高效的IO模型高效的线程模型 1. 动态字符串SDS Redis中保存的Key是字符串&#xff0c;value往往是字符串或者字符串的集合。可见字符串是redis中最常用的一种数据结构。 C语言种字符串存在的一些问题&#xff1a; 获取字符…

【嵌入式智能产品开发实战】(十四)—— 政安晨:通过ARM-Linux掌握基本技能【链接静态库与动态库】

目录 链接静态库 动态链接 与地址无关的代码 全局偏移表 延迟绑定 共享库 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 嵌入式智能产品开发实战 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论…

初阶数据结构—算法的时间复杂度和空间复杂度

第一章&#xff1a;数据结构前言&#xff08;Lesson 1&#xff09; 1. 什么是数据结构&#xff1f; 数据结构 (Data Structure) 是计算机存储、组织数据的方式&#xff0c;指相互之间存在一种或多种特定关系的 数据元素的集合。 2. 什么是算法&#xff1f; 算法(Algorithm)…

【数据处理包Pandas】多级索引的创建及使用

目录 一、元组作为一级索引&#xff08;一&#xff09;示例1&#xff08;二&#xff09;示例2 二、引入多级索引&#xff08;一&#xff09;多级索引的创建&#xff08;二&#xff09;多级索引中的数学选取 首先&#xff0c;导入 NumPy 库和 Pandas 库。 import numpy as np i…

monitor link 联合smart link配合应对复杂的网络

monitor link关键词&#xff1a;上行和下行端口&#xff0c;当上行端口异常&#xff0c;下行端口立即down掉&#xff0c;也就是一种联动机制 如果上行端口里面是smart link方式&#xff0c;则当主从端口都出问题时候&#xff0c;下行端口才会down掉 monitor link 配置步骤 1创…