Session


Cookie 已经能完成一次会话多次请求之间的数据共享,之前我们还提到过 Session 也可以实现,


那么:


什么是 Session?


Session 如何来使用 ?


Session 是如何实现的 ?


Session 的使用注意事项有哪些 ?



 Session 的基本使用



1. 概念


Session :服务端会话跟踪技术:将数据保存到服务端。


Session 是存储在服务端而 Cookie 是存储在客户端


存储在客户端的数据容易被窃取和截获,存在很多不安全的因素


存储在服务端的数据相比于客户端来说就更安全



2.Session 的工作流程




java存储每次请求的session java session存在哪里_前端


 


在服务端的 AServlet 获取一个 Session 对象,把数据存入其中


在服务端的 BServlet 获取到相同的 Session 对象,从中取出数据


就可以实现一次会话中多次请求之间的数据共享了


现在最大的问题是如何保证 AServlet 和 BServlet 使用的是同一个 Session 对象 ( 在原理分析会


讲解 )?



3.Session 的基本使用


在 JavaEE 中提供了 HttpSession 接口,来实现一次会话的多次请求之间数据共享功能。


具体的使用步骤为 :


获取 Session 对象 , 使用的是 request 对象


HttpSession session = request.getSession();


Session 对象提供的功能 :


存储数据到 session 域中


void setAttribute(String name, Object o)

根据 key,获取值


Object getAttribute(String name)


根据 key ,删除该键值对


void removeAttribute(String name)


介绍完 Session 相关的 API 后,接下来通过一个案例来完成对 Session 的使用,具体实现步骤为 :


需求 : 在一个 Servlet 中往 Session 中存入数据,在另一个 Servlet 中获取 Session 中存入的数据


1. 创建名为 SessionDemo1 的 Servlet 类


2. 创建名为 SessionDemo2 的 Servlet 类


3. 在 SessionDemo1 的方法中 : 获取 Session 对象、存储数据


4. 在 SessionDemo2 的方法中 : 获取 Session 对象、获取数据


5. 启动测试


(1) 创建名为 SessionDemo1 的 Servlet 类



@WebServlet("/demo1")
2 public class SessionDemo1 extends HttpServlet {
3 @Override
4 protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
5
6 }
7
8 @Override
9 protected void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
10 this.doGet(request, response);
11 }
12 }


(2) 创建名为 SessionDemo2 的 Servlet 类


@WebServlet("/demo2")
2 public class SessionDemo2 extends HttpServlet {
3 @Override
4 protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
5
6 }
7
8 @Override
9 protected void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
10 this.doGet(request, response);
11 }
12 }


(3)SessionDemo1: 获取 Session 对象、存储数据


@WebServlet("/demo1")
2 public class SessionDemo1 extends HttpServlet {
3 @Override
4 protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
5 //存储到Session中
6 //1. 获取Session对象
7 HttpSession session = request.getSession();
8 //2. 存储数据
9 session.setAttribute("username","zs");
10 }
11
12 @Override
protected void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
14 this.doGet(request, response);
15 }
16 }


(4)SessionDemo2: 获取 Session 对象、获取数据


1 @WebServlet("/demo2")
2 public class SessionDemo2 extends HttpServlet {
3 @Override
4 protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
5 //获取数据,从session中
6 //1. 获取Session对象
7 HttpSession session = request.getSession();
8 //2. 获取数据
9 Object username = session.getAttribute("username");
10 System.out.println(username);
11 }
12
13 @Override
14 protected void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
15 this.doGet(request, response);
16 }
17 }


(5) 启动测试,


先访问 http://localhost:8080/cookie - demo/demo1 , 将数据存入 Session


在访问 http://localhost:8080/cookie - demo/demo2 , 从 Session 中获取数据


查看控制台




java存储每次请求的session java session存在哪里_数据_02


 


通过案例的效果,能看到 Session 是能够在一次会话中两次请求之间共享数据。



小结


至此 Session 的基本使用就已经完成了,重点要掌握的是 :


Session 的获取


HttpSession session = request.getSession();


Session 常用方法的使用



void setAttribute(String name, Object o)
Object getAttribute(String name)


注意 : Session 中可以存储的是一个 Object 类型的数据,也就是说 Session 中可以存储任意数据


类型。


介绍完 Session 的基本使用之后,那么 Session 的底层到底是如何实现一次会话两次请求之间的数据


共享呢 ?



Session 的原理分析


Session 是基于 Cookie 实现的


这句话其实不太能详细的说明 Session 的底层实现,接下来,咱们一步步来分析下 Session 的具体实


现原理 :


(1) 前提条件



java存储每次请求的session java session存在哪里_前端_03


 


Session 要想实现一次会话多次请求之间的数据共享,就必须要保证多次请求获取 Session 的对象是


同一个。


那么它们是一个对象么?要验证这个结论也很简单,只需要在上面案例中的两个 Servlet 中分别打印


下 Session 对象


SessionDemo1



@WebServlet("/demo1")
public class SessionDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
5 //存储到Session中
6 //1. 获取Session对象
7 HttpSession session = request.getSession();
8 System.out.println(session);
9 //2. 存储数据
10 session.setAttribute("username","zs");
11 }
12
13 @Override
14 protected void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
15 this.doGet(request, response);
16 }
17 }


SessionDemo2

@WebServlet("/demo2")
2 public class SessionDemo2 extends HttpServlet {
3 @Override
4 protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
5 //获取数据,从session中
6 //1. 获取Session对象
7 HttpSession session = request.getSession();
8 System.out.println(session);
9 //2. 获取数据
10 Object username = session.getAttribute("username");
11 System.out.println(username);
12 }
13
14 @Override
15 protected void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
16 this.doGet(request, response);
17 }
18 }


启动测试,分别访问


http://localhost:8080/cookie - demo/demo1


http://localhost:8080/cookie - demo/demo2



java存储每次请求的session java session存在哪里_数据_04


 


通过打印可以得到如下结论 :


两个 Servlet 类中获取的 Session 对象是同一个


把 demo1 和 demo2 请求刷新多次,控制台最终打印的结果都是同一个


那么问题又来了,如果新开一个浏览器,访问 demo1 或者 demo2, 打印在控制台的 Session 还是同一个对象么?



java存储每次请求的session java session存在哪里_数据_05


 


注意 : 在一台电脑上演示的时候,如果是相同的浏览器必须要把浏览器全部关掉重新打开,才算新开的 一个浏览器。


当然也可以使用不同的浏览器进行测试,就不需要把之前的浏览器全部关闭。


测试的结果:如果是不同浏览器或者重新打开浏览器后,打印的 Session 就不一样了。


所以 Session 实现的也是一次会话中的多次请求之间的数据共享。


那么最主要的问题就来了, Session 是如何保证在一次会话中获取的 Session 对象是同一个呢 ?




java存储每次请求的session java session存在哪里_java存储每次请求的session_06


 


(1)demo1 在第一次获取 session 对象的时候, session 对象会有一个唯一的标识,假如是 id:10


(2)demo1 在 session 中存入其他数据并处理完成所有业务后,需要通过 Tomcat 服务器响应结果给浏


览器


(3)Tomcat 服务器发现业务处理中使用了 session 对象,就会把 session 的唯一标识 id:10 当做一个


cookie ,添加 Set - Cookie:JESSIONID=10 到响应头中,并响应给浏览器


(4) 浏览器接收到响应结果后,会把响应头中的 coookie 数据存储到浏览器的内存中


(5) 浏览器在同一会话中访问 demo2 的时候,会把 cookie 中的数据按照 cookie: JESSIONID=10 的格


式添加到请求头中并发送给服务器 Tomcat


(6)demo2 获取到请求后,从请求头中就读取 cookie 中的 JSESSIONID 值为 10 ,然后就会到服务器内存中寻找id:10 的 session 对象,如果找到了,就直接返回该对象,如果没有则新创建一个 session


对象


(7) 关闭打开浏览器后,因为浏览器的 cookie 已被销毁,所以就没有 JESSIONID 的数据,服务端获取 到的session 就是一个全新的 session 对象


至此, Session 是基于 Cookie 来实现的 这就话,我们就解释完了,接下来通过实例来演示下 :


(1) 使用 chrome 浏览器访问 http://localhost:8080/cookie - demo/demo1 , 打开开发者模式 (F12


或 Ctrl+Shift+I), 查看 响应头 (Response Headers) 数据 :




java存储每次请求的session java session存在哪里_前端_07


 


(2) 使用 chrome 浏览器再次访问 http://localhost:8080/cookie - demo/demo2 ,查看 请求头


(Request Headers) 数据 :




java存储每次请求的session java session存在哪里_数据_08


 


小结


介绍完 Session 的原理,我们只需要记住


Session 是基于 Cookie 来实现的




Session 的使用细节


我主要讲解两个知识,第一个是 Session 的钝化和活化,第二个是 Session 的销毁,首先来


学习什么是 Session 的钝化和活化?


1 Session 钝化与活化


首先需要大家思考的问题是 :


服务器重启后, Session 中的数据是否还在 ?


要想回答这个问题,我们可以先看下下面这幅图,





java存储每次请求的session java session存在哪里_服务器_09


 


1) 服务器端 AServlet 和 BServlet 共用的 session 对象应该是存储在服务器的内存中


(2) 服务器重新启动后,内存中的数据应该是已经被释放,对象也应该都销毁了


所以 session 数据应该也已经不存在了。但是如果 session 不存在会引发什么问题呢 ?


举个例子说明下,


(1) 用户把需要购买的商品添加到购物车,因为要实现同一个会话多次请求数据共享,所以假设把数据存入Session 对象中


(2) 用户正要付钱的时候接到一个电话,付钱的动作就搁浅了


(3) 正在用户打电话的时候,购物网站因为某些原因需要重启


(4) 重启后 session 数据被销毁,购物车中的商品信息也就会随之而消失


(5) 用户想再次发起支付,就会出为问题


所以说对于 session 的数据,我们应该做到就算服务器重启了,也应该能把数据保存下来才对。


分析了这么多,那么 Tomcat 服务器在重启的时候, session 数据到底会不会保存以及是如何保存的, 我们可以通过实际案例来演示下:


注意 : 这里所说的关闭和启动应该要确保是正常的关闭和启动。


那如何才是正常关闭 Tomcat 服务器呢 ?


需要使用命令行的方式来启动和停止 Tomcat 服务器 :


启动 : 进入到项目 pom.xml 所在目录,执行 tomcat7:run



java存储每次请求的session java session存在哪里_服务器_10


停止:在启动的命令行界面,输入ctrl+c



java存储每次请求的session java session存在哪里_数据_11


 


有了上述两个正常启动和关闭的方式后,接下来的测试流程是 :


(1) 先启动 Tomcat 服务器


(2) 访问 http://localhost:8080/cookie - demo/demo1 将数据存入 session 中


(3) 正确停止 Tomcat 服务器


(4) 再次重新启动 Tomcat 服务器


(5) 访问 http://localhost:8080/cookie - demo/demo2 查看是否能获取到 session 中的数据



java存储每次请求的session java session存在哪里_数据_12


 


经过测试,会发现只要服务器是正常关闭和启动, session 中的数据是可以被保存下来的。


那么 Tomcat 服务器到底是如何做到的呢 ?


具体的原因就是 :Session 的钝化和活化 :


钝化:在服务器正常关闭后, Tomcat 会自动将 Session 数据写入硬盘的文件中


钝化的数据路径为 : 项目目录 \target\tomcat\work\Tomcat\localhost\ 项目名称 \SESSIONS.ser




java存储每次请求的session java session存在哪里_前端_13


 


活化:再次启动服务器后,从文件中加载数据到 Session 中


数据加载到 Session 中后,路径中的 SESSIONS.ser 文件会被删除掉


对于上述的整个过程,大家只需要了解下即可。因为所有的过程都是 Tomcat 自己完成的,不需要我们参与。


小结


Session 的钝化和活化介绍完后,需要我们注意的是 :


session 数据存储在服务端,服务器重启后, session 数据会被保存


浏览器被关闭启动后,重新建立的连接就已经是一个全新的会话,获取的 session 数据也是一个新


的对象


session 的数据要想共享,浏览器不能关闭,所以 session 数据不能长期保存数据


cookie 是存储在客户端,是可以长期保存


 Session 销毁


session 的销毁会有两种方式 :


默认情况下,无操作, 30 分钟自动销毁


对于这个失效时间,是可以通过配置进行修改的


在项目的 web.xml 中配置


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<session-config>
<session-timeout>100</session-timeout>
</session-config>
</web-app>


如果没有配置,默认是 30 分钟,默认值是在 Tomcat 的 web.xml 配置文件中写死的




java存储每次请求的session java session存在哪里_数据_14


 


调用 Session 对象的 invalidate() 进行销毁


在 SessionDemo2 类中添加 session 销毁的方法

@WebServlet("/demo2")
2 public class SessionDemo2 extends HttpServlet {
3 @Override
4 protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
5 //获取数据,从session中
6
7 //1. 获取Session对象
8 HttpSession session = request.getSession();
9 System.out.println(session);
10
11 // 销毁
12 session.invalidate();
13 //2. 获取数据
14 Object username = session.getAttribute("username");
15 System.out.println(username);
16 }
17
18 @Override
19 protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
20 this.doGet(request, response);
21 }
22 }


启动访问测试,先访问 demo1 将数据存入到 session ,再次访问 demo2 从 session 中获取数据



java存储每次请求的session java session存在哪里_java_15


该销毁方法一般会在用户退出的时候,需要将session销毁掉。


Cookie Session 小结


Cookie 和 Session 都是来完成一次会话内多次请求间 数据共享 的。


所需两个对象放在一块,就需要思考 :


Cookie 和 Session 的区别是什么 ?


Cookie 和 Session 的应用场景分别是什么 ?


区别 :


存储位置: Cookie 是将数据存储在客户端, Session 将数据存储在服务端


安全性: Cookie 不安全, Session 安全


数据大小: Cookie 最大 3KB , Session 无大小限制


存储时间: Cookie 可以通过 setMaxAge() 长期存储, Session 默认 30 分钟


服务器性能: Cookie 不占服务器资源, Session 占用服务器资源


应用场景 :


购物车 : 使用 Cookie 来存储


以登录用户的名称展示 : 使用 Session 来存储


记住我功能 : 使用 Cookie 来存储


验证码 : 使用 session 来存储


结论


Cookie 是用来保证用户在未登录情况下的身份识别


Session 是用来保存用户登录后的数据


介绍完 Cookie 和 Session 以后,具体用哪个还是需要根据具体的业务进行具体分析。