Java EE day14学习总结
今天主要学习Cookie和Session
思维导图:
一.会话管理
在日常的生活当中,从我们拨打电话,到结束电话,这个中间你问我答的这个过程其实就是一个会话的过程,又比如说我们打开微信,打开联系人进行聊天,这个过程其实也是一个会话的过程。
在web程序的开发当中,其实也存在了一个会话的过程,假设比喻成一个打电话的过程 那么在web程序当中,其实就是一个打开浏览器、访问网站、关闭浏览器。
打电话 web网站
拿起手机 打开浏览器
拨打电话 打开网站
进行沟通 浏览器网站
结束通话 离开访问
其实在日常的会话过程当中,我们的会话记录其实也会被经常的保存起来,比如运营商可以监听我们的通话记录,可以监听我们的短信记录。
比如微信当中的会话就可以被记录:打开一个微信,产生了聊天,关闭微信,打开微信 数据仍然存在(保存)
在web当中,作为开发者的我们,其实也经常需要保存一些数据
过程:
比如访问码云社->登录页面->输入账号密码(数据)->浏览一些技术文章(数据)->观看教学视频(数据)->离开
而这些会话数据,我们就完全可以利用起来。
比如账号数据保存起来:下次在访问码云社的时候,不需要你继续输入账号 把这个数据保存。
比如浏览文章的数据保存起来:可以告诉运营者用户文章浏览的喜好(大数据),用户产生了一个浏览记录,以便于用于下次继续浏览
比如视频播放的数据保存起来:运营者可以知道学员的播放记录,获取学员的学习状态,学员可以产生播放记录,下次访问从结束位置继续播放。
为了保存用户在整个浏览过程当中产生的会话数据,我们一共提供两种保存方式,分别是Cookie和Session。
1.Cookie:是可以将用户浏览数据保存到客户端(一般是交给浏览器负责,用过通过浏览器看到)可以将数据直接存放在浏览器(硬盘当中,可以永久保存),可以极大的减少服务器的负担,但是不安全 因为用户可以直接的通过浏览器来查看保存数据,甚至用户可删除他(一般不涉及到敏感的数据,用户删除不会产生程序问题的数据可以存放在浏览器)
2.Session:是可以将用户浏览数据保存到服务端(一般是交给服务端负责,一般用户看不到)
可以将数据存储在服务器当中(内存当中,有权限限制,默认30分钟),这些数据保存到服务器会极大的增加服务器的负担,但是安全因为用户没办法去访问服务器的资源(其实Session也是一个依赖于Cookie实现的技术)
二.Cookie
1.Cookie的概念:
Cookie是一个基于HTTP协议下的技术,也就是说整个Cookie的操作必须是通过HTTP的请求和响应进行传输操作。Cookie由web的服务器进行设置(tomcat),由web的客户端进保存的以文本文件(浏览器),他可以存储用户的信息和访问一些会话数据开发者可以选择性的将需要的数据保存在浏览器。
2.Cookie有哪一些应用场景:
(1)将Cookie保存在浏览器(假设保存的是账号数据),用户再次登录网站的时候不需要填写用户名(记住用户名)
(2)将Cookie保存在浏览器(假设保存的是账号密码数据),同时将账号和密码保存,用于下次就可以实现一个自动登录(自动登录)
3.Cookie大致操作流程:
(1)用户打开浏览器
(2)用户首次访问网址且输入账号和密码
(3)如果服务器有设置cookie的请求的话,用户在访问这个页面的过程当中会将服务端设置好的数据携带到服务端
(4)用户再次访问的时候,服务器端就将首次访问携带的Cookie数据,设置到浏览器当中(注意:用户首次访问的时候,并不会保存cookie吗,只有第二次访问的时候,cookie才会出来的)
4.cookie操作:
方式一:通过响应和请求头操作(不建议)
response.setHeader("set-Cookie","name=toobug");
String cookie = request.getHeader("Cookie");
System.out.println("从浏览器拿到的cookie:"+cookie);
方式二:通过Cookie对象操作(推荐)
Cookie cookie = new Cookie("age", "11");
response.addCookie(cookie);
注意:cookie是一个键值对的方式进行设置的,所以不能出现键重复,否则就被覆盖cookie可以设置多个,但是需要使用不同的对象进行发送,每一个Cookie都是一个对象,便于不同Cookie之间的管理,这个是非常合理的操作。
5.获取Cookie:
(1)获取本资源路径下的所有cookie
Cookie[] cookies = request.getCookies();
(2)获取Cookie的键值
获取键:
String name = c.getName();
获取值:
String value = c.getValue();
(3)循环遍历所有cookie
for (Cookie c : cookies) {
String name = c.getName();
String value = c.getValue();
System.out.println(name+"-----"+value);
}
6.修改Cookie的值:
在以后的开发当中,某一些cookie可能是不断发生变化的,如果需要替换cookie的值,就使用setValue
例:cookie.setValue("demo");
7.设置Cookie的有效路径:
在很多的时候,某一个Cookie的应用范围只限制在某一个路径,Tomcat默认的路径是整个项目,也就意味在不设置路径的情况下;一个Cookie生效的范围是整个项目,如果需要限制某一个Cookie的生效范围,就需要单独对整个Cookie进行路径的设置:
设置路径:
cookie.setPath("/cookie/cookie3");
/:整个Tomcat下面的所有项目全部有效
/cookie:Tomcat下面的cookie项目有效
/cookie/cookie3:仅在cookie项目下面的cookie3下面有效
8.设置Cookie的生命周期:
cookie.setMaxAge((int)Integer.MAX_VALUE);
参数小于0:可以是任意负数,你的浏览器关闭后,cookie消失(Mac的浏览器一旦确保进城完全杀死才算关闭)[默认]
参数等于0:cookie立即销毁(生效,只不过生效的时间很短,基本跟没设置一样)
参数大于0:单位是秒,这里周期是从生成Cookie开始计算秒数,秒数超过则Cookie消失,但是再次访问的时候又会重新创建一个新的Cookie,并且重新开始计算周期。
Cookie并没有永久时间的说法,只能尽量的将Cookie的周期设置到最长。
9.从浏览器删除Cookie:
在Cookie当中,并没有提供任何删除Cookie的方法,我们只能通过设置Cookie的生命周期的方式来解决这个问题。
//创建一个Cookie对象
Cookie cookie = new Cookie("sex","nas");
//设置一个资源路径(非必须)
cookie.setPath("/cookie/cookie3");
-- 删除操作
//根据Cookie对象,对这个对象设置一个参数为0的生命周期(删除浏览器指定名的Cookie)
cookie.setMaxAge(0);
10.设置Cookie的跨域:
以后在一个实际的项目当中,这个项目可能分为N个子项目。
那么n个子项目之间,如果需要去共享一个cookie,只需要将我们的setPath设置为根路径就可以了(setPath("/"))
http://localhost:8080/xxx1
http://localhost:8080/xxx2
http://localhost:8080/xxx3
这是理想的一种状态,确实可以实现一个cookie,多个webapps下面资源共用的一个问题。
但是,很多业务的场景,为了区分不同的业务,实际上是使用了一个二级域名进行区分
xxx1.demo.com
xxx2.demo.com
xxx3.demo.com
如果是这种情况,我们使用setPath是没办法解决的,因为setPath最顶层的结构就是"/"( demo.com/ -->)
情况一:
https://www.codeseeding.com/video = /video (setPath)
情况二:
https://www.edu.codeseeding.com/ = /video (setDomain)
如果Cookie之间是用资源路径进行映射共享的话,可以直接使用setPath解决(跨路径)
如果Cookie之间是用多级域名之间进行共享的话,可以使用setDomain解决(跨域名)
cookie.setDomain(".edu.codeseeding.com");
11.Cookie的总结:
(1)Cookie是一个通过HTTP协议方式,将一个键值对数据保存到浏览器的技术
(2)因为是保存到浏览器,所以具备不安全性,比如用户可以直接查看、用户可以删除、用户可以禁止、受浏览器限制(我们只管要求,浏览器怎么实现 我们没法控制),就建议,如果是敏感信息、涉及到代码稳定的信息就不要存储到Cookie.一般Cookie存储的都是可以随意让用户删除和修改的数据,大部分时候 设置Cookie都只是为了提供用户的体验度。
(3)我们是可以像浏览器存储多个cookie的,但是一般浏览器的标准是一个项目为20个cookie的数量,有些是超出不让存,有些是超出删除最早的一个。而且每一个Cookie大小限制为4kb。
(4)Cookie的存储类型必须是字符串类型,而且尽量不要包含特殊符号,特别是空格。
12.cookie的流程:
13.Cookie的执行路径:
二. Session:
我们之前就说过,会话分为两种,一个是cookie,另外一个是session,而cookie本身就存在了很多弊端[不安全/有数量限制 20个/有大小的限制 4kb/只能是字符串/不能支持中文(因为请求发送,如果只需要支持中文则需要进行URLEncode的编码处理)]正因为Cookie的这些弊端的特性,所有导致Cookie的使用场景是非常单一的,所以我们现在要来仔细了解另外一个会话Session
1.Session的引入:
假如我们生病了,要去医院就诊,一般的操作是病人先去医院办理一张就诊卡,病人的这张卡上面就只存在一个卡号,那以后再去医院就诊的时候,病人就只需要拿着这张卡或者卡号去医院就可以了,医院就根据这个卡号 可以获取病人的一些就诊信息、身份信息等等。
根据上面的案例,我们转换为WEB会话....
客户端第一次访问我们的服务,我们的后端就为这个客户端生成一个Session(存储会话数据),并且生成一个独立且唯一的JSESSIONID用于标识客户端信息,下一次客户端继续访问我们的服务,只需客户端通过Cookie携带一个JSESSIONID给我服务端,服务端就可以通过这个ID来找到这个客户端存储在服务端的信息。
注意:
需要注意的问题的是,由于客户端需要接收、记录和响应Seesion对象的ID,因此,通常情况下,Session本质上还是依赖于Cookie的技术进行的ID标识的传递的。
最本质的区别是,Cookie将ID存储在浏览器,这个ID对应的会话数据存储在服务器。
2.Session的概念:
是可以将用户浏览数据保存到服务端(一般是交给服务端负责,一般用户看不到)可以将数据存储在服务器当中(内存当中,有权限限制,默认30分钟),这些数据保存到服务器会极大的增加服务器的负担,但是安全因为用户没办法去访问服务器的资源(其实Session也是一个依赖于Cookie实现的技术)
3.Session的使用场景:
(1)保存购物车的数据
情况一:已经登录的情况(正常)
获取用户名 -> 挑选商品 -> 加入购物车 -> 获将购物车的数据存入到数据库 -> 用户离开 -> N次访问都可以拿到数据
情况二:用户没用登录
挑选商品 -> 加入购物车 -> 获取用户的JSESSIONID -> 数据到存储到Session -> 用户离开 ->下次根据JSESSIONID来获取唯一标识
(2)保存用户的浏览记录
(3)保存用户的登录状态数据
(4)处理验证码
我们之前也完成过利用验证码进行了登录,效果也还可以,但是实际是非常不合理的。
<1>保存到了ServletContext域(不能重复,重复就被替换) [不合理,验证码会被无限覆盖]
A用户访问了生产验证码的Servlet,同时显示出验证码图片
此时B用户也访问了生产验证码的Servlet,也就造成了A用户的验证码实际上已经被B用户替换掉了,现在只能B用户登录,A用户则验证码错误。
<2>保存到了reques t域(request域只在一次请求当中有效,除非使用转发)
在画图的案例当中,一共存在两个不同的Servlet,而request的作用域又只能在一个请求当中(一个Servlet)当中有效
那么也就意味着,两个Servlet之间不能共享数据,除非使用转发,即使使用了转发,也解决不了这个问题,因为转发后数据还是被共享,而且限制你的开发路径必须使用转发(不合理)
上面的两种存储方式,基本都不合理 不合理的原因是因为多个用户共享了一个作用域,所有导致了用户之间对数据造成了冲突,这种情况我们就应该使用一个独立且唯一的域 互不干扰的域(会话作用域 HttpSession)
4.文字描述下Session的执行流程:
(1)Tomcat服务器会在每一次获取请求时候都会为这个请求用户创建Session对象
(2)在创建这个Session对象的时候,会顺便为这个对象生成一个JSESSIONID的唯一标识
(3)在响应给浏览器的时候,会顺便将这个标识要求浏览器存储到Cookie(JSESSIONID=HJK2H3JH5HHJ12H4.....)
(4)当用户再一次访问的时候,就会将这个JSESSIONID通过请求一起携带到服务器
(5)服务器就可以根据携带JSESSIONID来找到这个ID所对应的Session
如果session找不到(比如说默认的30分钟时效过了,或者被手动清理),JSESSIONID则直接作废 浏览器删除。但是会再次创建一个新的session和JSESSIONID重新捆绑。如果seesion存在,但是没有JSESSIONID了,则seesion作废。
5.流程的实践:
(1)创建一个session对象
因为session是tomcat进行管理和创建,所以只能通过request进行获取
HttpSession session = req.getSession();
0HttpSession getSession(boolean var1);//true 则代表新创建Session,false则代表不创建
(2)获取JSESSIONID,来证实响应的JSESSIONID和请求的JSESSIONID是同一个
String id = session.getId();
注意:假设通过这个ID没有找到Session,Tomcat则会重新创建一个新的Session对象
如果找到就直接使用,不会创建新的。
(3)设置Seesion的值
我们,之前一直讲会话作用,现在学到的Seesion其实就是那个会话作用域
ServletContext > Session > Rquest > PageContext
Session作用域的的特点:
<1>仅在一次会话当中有效(一次网站的访问于离开)
<2>仅在一次会话有效期当中有效(Tomcat默认会话时长为30,超过30自动失效)
<3>仅在一个JSESSIONID匹配的Session有效(其他用户拿不到,每个客户都是独立的)
//给作用域设置值
session.setAttribute("username","admin");
(4)获取Seesion的值
session.getAttribute("username");
(5)删除Seesion的作用域
session.removeAttribute("username");
6.Session的持久化处理:
我们在使用一个Session的时候,其实是存在生命周期的问题,我需要知道哪几种情况 会造成Session的丢失
(1)Session默认时间为30000分钟,如果30分钟,客户端没有进行任何会话 则丢失。
配置路径在:
web.xml
<session-config>
<session-timeout>30</session-timeout>
</session-config>
(2)在服务端当中,Session 被手动清理或者某种原因无法存活,则丢失
手动销毁:
session.invalidate();
(3)当客户端的Cookie里面的JSESSIONID丢失,则Session也丢失
我们的JSESSIONID其实是存在Cookie里面,在没有对Cookie进行任何生命周期的设置的情况下;但我们浏览器关闭,也就意味着JSESSIONID也会被浏览器掉,于此同时因为Seesion已经和JSESSIONID失去了联系,所以我们Seesion也会被丢失掉。
(4)如何解决Cookie和Seesion同步周期的问题?
原因:因为浏览器关闭,JSESSIONID丢失
解决方案:
给Cookie设置一个稳定生命周期,并且将我们生成这个JSESSIONID保存到这个当中Cookie
HttpSession session = request.getSession();
Cookie cookie = new Cookie("JSESSIONID",session.getId());
cookie.setMaxAge(60*60*30);
response.addCookie(cookie);
7.需求:
访问index.jsp的页面
如果用户是未登录状态用户是登录状态,显示欢迎您xxx回来。
如果用户是未登录状态,您还未登录
(1)用户进行登录(成功)
给用户登录的浏览器设置一个cookie(loginStatus = yes)
(2)用户访问index.jsp
获取用户浏览的Cookie的loginStatus的值
yes:欢迎您TOOBUG回来
no:您还未登录
(3)用户退出账号
修改用户浏览器Cookie的loginStatus的值为no
8.Cookie和Session的区别:
(1)Cookie:
存储位置:存储在用户的浏览器,用于硬盘当中
安全性:不安全,可以被用户删除、查看、其他方式窃取
数据类型:只能是String类型
容量大小:单个4kb,不能超过20个
存在时长:可以灵活调整,因为是存在用户硬盘 所以不影响服务器性能 可以无限扩大
建议场景:不在乎安全,不涉及隐私,不影响代码,只能String 这种数据可以存在Cookie(但是要考虑个数和容量的问题)
(2)Session:
存储位置:存储在服务端的内存当中
安全性:安全,服务器管理(有可能被用户删除,不能被窃取和查看)
数据类型:可以是任意类型
容量大小:没有容量限制(请考虑JVM大小)
存在时长:可以灵活调整,因为是存在JVM内存 影响服务器性能 所以酌情考虑,同时要保持Session的持久化
建议场景:保证的安全的、涉及隐私的,可以是任意类型的
9.使用requset作用域存储验证码:
10.记录用于上一次访问时间:
11.使用ServletContext作用域,进行验证码校验不合理 :