之前也有介绍Cookie和Session,这里接着回顾+介绍
HTTP 协议自身是属于 "无状态" 协议.------->"无状态" 的含义指的是:默认情况下 HTTP 协议的客户端和服务器之间的这次通信, 和下次通信之间没有直接的联系.
但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的.
例如登陆网站成功后, 第二次访问的时候服务器就能知道该请求是否是已经登陆过了.
图中的 "令牌" 通常就存储在 Cookie 字段中
像上面例子中此时在服务器这边就需要记录令牌信息, 以及令牌对应的用户信息, 这个就是 Session 机制(session叫理解会话机制)所做的工作.
服务器同一时刻受到的请求很多,服务器需要清楚的区分每个请求属于哪个用户,因此就需要在服务器这边记录每个用户令牌以及用户的信息的对应关系(就像上面的例子中,就诊卡就是一张令牌,要想让这个令牌能够生效,就需要医院通过系统记录每个就诊卡和患者信息之间的关联关系)
会话的本质是一个哈希表,存储了一些键值对结构,key就是令牌的ID(token/sessionId),value就是用户信息
sessionId是由服务器生成的一个"唯一性字符串",从session机制的角度来看,这个唯一性字符串成为"sessionId";但是站在整个登录流程中看待,也可以把这个唯一性字符串称为"token".token和sessionId可以理解为同一个东西,只不过是不同视角的不同叫法
注意:Servlet 的 Session 默认是保存在内存中的. 如果重启服务器则 Session 数据就会丢失.
Cookie和Session的区别:
下面我们来看看和Cookie和Session有关的核心方法
先说第一个方法吧
getSession()方法既能用于获取到服务器上的会话,也能用于创建会话.具体行为取决于参数:
如果参数为true,会话不存在,则创建;会话存在,则获取
如果参数为false,会话不存在,则返回null;会话存在,则获取
在调用getSession()方法的时候具体要做的事:
1.创建会话
首先先获取到请求中cookie里面的sessionId字段,判断这个sessionId是否在当前服务器上存在,如果不存在,则进入创建会话逻辑.
创建会话会创建一个HttpSession对象,并且生成一个sessionId.接下来就会把这个sessionId作为key,把这个HttpSession对象作为value,把这个键值对保存到服务器内存的一个哈希表这样的结构中(实际的是先不一定真的是哈希表,但一定是类似的能够存储键值对的结构,并且这个数据是在内存中的)
HttpSession对象和sessionId的关系如下图:
之后,服务器会返回一个HTTP响应,把sessionId通过Set-Cookie字段返回给浏览器.浏览器可以保存这个sessionId到Cookie中了
2.获取会话
先获取到请求中的cookie里面的sessionId字段(也就是会话的身份标识),判断这个sessionId是否在当前服务器上存在(也就是这个哈希表是否存在),如果存在就直接查询出这个HttpSession对象,并且通过返回值返回回去
我们上面提到了HttpSession对象,我们再来具体介绍下:
HttpSession对象本质上也是一个"键值对"的结构,允许程序员往HttpSession对象中存储任意的键值对数据(key必须是String,value是Object).HttpSession对象中的每个键值对,我们称其为属性(Attribute)
既然讲到这里了,那我们就把HttpSession类中的方法也说了吧先
好,我们继续说HttpServletRequest 类中的另一个方法
getCookies()方法
getCookies()方法是用来获取请求中的Cookie数据.
返回值是Cookie[],每个元素是一个Cookie对象,每个Cookie对象又包含了两个属性name和value(键值对),(HTTP请求中的Cookie字段就是按照简直短的方式来组织的)这些键值对会在请求中通过Cookie字段传给服务器,服务器收到请求后,就会进行解析,解析成Cookie[]这样的形式
注意:Cookie中可以保存任意自定制的键值对,如果是一般的键值对,直接通过getCookie来获取;如果是特殊的键值对(表示sessionId的键值对),就直接使用getSession就可以了,它就自动帮我们从Cookie中取sessionId了
响应中可以根据addCookie方法来添加一个Cookie信息到响应报文中,这个添加进来的键值对就会作为HTTP响应中的Set-Cookie字段来表示
下面我们来实操一下看看
写一个案例---->网页登录(如下图这样的)
首先第一步我们需要约定前后端交互接口
两组交互:
1.登录的交互
2.获取主页的交互
约定好前后端接口之后
下面我们来编写代码了
1.首先我们先编写了一个登录页面 (前端)
使用form表单来构造post请求
2. 编写一个Servlet来处理这个登录请求
对于这个代码我们需要解释一下:
这里面尤为注意的一点是,你看这个代码中,如果登录成功,那么当下就创建好一个Session,并且在Session中填写上一些必要的身份信息供后面的逻辑来使用(就是下图这段代码)
为什么呢?------->因为后续跳转到index的时候,服务器要能够获取到当前用户的身份信息
然后还需要注意,我们在登录逻辑中还加了一个简单的功能------->那就是记录一下当前用户访问主页的次数,当登陆之后,首次访问主页,主页就显示当前访问1次,后续再刷新页面,次数就会累加
3.编写服务器端返回主页的逻辑
你看吼,由于我们在前面的登录逻辑中已经创建好一个Session,并且在Session中填写上一些必要的身份信息,因此这里的主页逻辑就可以获取到当前用户的身份信息了~~
上面说的在登录逻辑中加入的累计次数功能,在主页逻辑中我们也要添加相应的代码(如下)
注意,这里为什么是Integer而不是int呢?原因如下
好,现在让我们打开前端登录页面 ,同时进行抓包看看交互情况
经过三次交互,最终呈现出这样的页面
下面说一下上传文件案例
上传文件的时候在前端需要用到form表单,form表单中需要使用特殊的类型----->form-data
此时提交文件的时候,浏览器就会把文件内容以form-data的格式构造到HTTP请求中,服务器就可以通过getPart来获取了
一个HTTP请求可以一次性提交多个文件,每个文件都称为一个Part,每个Part都有一个name(身份标识),服务器代码中就可以根据name找到对应的Part,基于这个Part就可以进一步的获取到文件信息,并进行下一阶段操作
知道了上述知识,我们就可以接着编写后端代码:
可以看一下下图的标注
同时需要特别指出的是编写后端代码的时候一定别忘了写给这个类加上注释@MultipartConfig
下面我们来试验一下: