Session基础篇

本篇供个人学习使用,有问题欢迎讨论
其中有部分Cookie内容,不清楚的可以参考我的另一篇博文Cookie的使用

HttpSession

​ Session,即会话,是 Web 开发中的一种会话状态跟踪技术。当然,Cookie也是一种会话跟踪技术。不同的是 Cookie是将会话状态保存在了客户端,而Session则是将会话状态保存在了服务器端

​ 那么,到底什么是 “ 会话 ” ? 当用户打开浏览器,从发出第一次请求开始, 一直到最后关闭浏览器,就表示一次会话的完成。

Session并不是 JavaWeb 开发所特有的,而是整个Web开发中所使用的技术。在 JavaWeb开发中,Session是以 javax.servlet.http.HttpSession的接口对象的形式出现的。

一、Session的访问

1、Session 对象的创建

​ 若要对Session进行操作,则可以通过HttpServletRequest的getSession()方法获取。该方法具有两个重载的方法。

(1)public HttpSession getSession(boolean create)

该方法用于创建 Session。

  • 若参数 create 为 true,则表示若当前没有 Session,则新建一个Session
  • 若当前存在 Session,则使用当前的 Session
  • 若参数 create 为 false 表示若当前没有Session,则直接返回 null
(2)public HttpSession getSession()

该方法用于创建 Session。

  • 相当于 getBession(true),即没有 Session 则创建新的 Session。
2、何时使用getSession(true),即 getSession)。何时使用 getSesson(false)呢?

一般情况下, 若要向 Session 中存放数据,则使用 getSession(true),即getSession()。意义为:若当前存在 Session,则使用当前的 Session;若当前不存在 Session,则创建一个新的Session。因为存放数据是必须要有 Session的。

若要从 Session 中获取数据,则一般使用 getSession(false)。意义为:若当前存在 Session,则从中获取数据;若当前根本就没有 Session,那就更不可能存在 Session中的数据了。无需创建一个新的 Session。再从新的 Session 中获取数据,因为新创建的 Session 中是不可能有数据的。

3、对 Session 域属性空间的操作

​ Session是一个专门用于存放数据的集合,我们一般称这个用于存放数据的内存空间为域属性空间,简称域。HttpSession 中具有三个方法,是专用于对该域属性空间中数据进行写、读操作的。

(1)该方法用于向 Session 的域属性空间中放入指定名称、指定值的域属性

public void setAttribute(String name, Object value)

(2)该方法用于从 Session 的域属性空间中读取指定名称的域属性值

public Object getAttribute(String name)

(3)该方法用于从 Session 的域属性空间中删除指定名称的域属性

public void removeAttribute(String name)
4、Session 对象的使用
(1)hhh.html
<form action="/myWeb/one.do">    
    客户:<input type="text" name="username" /><br>    
    <input type="submit" value="点餐" /> 
</form>

在这里插入图片描述

(2)OneServlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    
    //获取用户提交的参数    
    String name = request.getParameter("username");    
    //将参数放入request域中    
    request.setAttribute("user",name);    
    //获取Session对象    
    HttpSession session = request.getSession();    
    //向Session域中写入属性    
    session.setAttribute("username",name);    
    //在OneServlet页面上进行显示    
    PrintWriter out = response.getWriter();    
    out.println("OneServlet user :" + name);    
    out.println("OneServlet Session :" + session); 
}

在这里插入图片描述

(3)TwoServlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    
    //从request域中读取user属性    
    String user = request.getParameter("user");    
    //获取Session    
    HttpSession session = request.getSession(false);    
    //从Session中读取指定属性    
    String username = null;    
    if (session != null){        
        username = (String) session.getAttribute("username");    
    }    
    //在TwoServlet页面上进行显示    
    PrintWriter out = response.getWriter();    
    out.println("TwoServlet user :" + user);    
    out.println("TwoServlet username :" + username);    
    out.println("TwoServlet session :" + session); 
}

在这里插入图片描述

二、Session的工作原理(重点)

​ 在服务器中系统会为每个会话维护一个Session。不同的会话,对应不同的Session。那么,系统是如何识别各个Session对象的?即是如何做到在同一会话过程中,一直使用的是同一个 Session对象呢?

1、写入 Session 列表

​ 其实当前应用中的 Session 是以 Map 的形式进行管理的,这个Map称为Session 列表。该 Map的 key 为一个32位长度的随机串,这个随机串称为 JSessionID,value 则为 Session对象的引用

​ 当用户第一次提交请求时, 服务端 Servlet 中执行到 request.getSession() 方法后,会自动生成一个 Map.Entry 对象,key 为一个根据某种算法新生成的 JSessionID,value则为新创建的 HttpSession对象。
在这里插入图片描述

2、服务器生成并发送Cookie

​ 在将 Session 信息写入 Session 列表后,系统还会自动将 “JSESSIONID” 作为 name,这个32位长度的随机串作为 value,以 Cookie 的形式存放到【响应头】中,并随着响应,将该 Cookie发送到客户端。
在这里插入图片描述

3、客户端接收并发送Cookie

客户端接收到这个Cookie后会将其存放到浏览器的缓存中。即只要客户端浏览器不关闭,浏览器缓存中的 Cookie就不会消失

​ 当用户提交第二次请求时,会将缓存中的这个Cookie,伴随着请求的头部信息,一块发送到服务端。
在这里插入图片描述

4、从Session列表中查找

​ 服务端从请求中读取到客户端发送来的Cookie,并根据Cookie的 JSSESSIONID 的值,从Map中查找相应key 所对应的value,即Session对象。然后,对该Session对象的域属性进行读、写操作。

三、Session的失效

​ Web 开发中引入的Session超时的概念,Session的失效就是指Session的超时。若某个Session在指定的时间范围内一直未被访问,那么Session将超时,即将失效。在 web.xml 中可以通过 <session-config> 标签设置 Session的超时时间,单位为分钟。默认Session的超时时间为 30分钟。需要再次强调的是,这个时间并不是从 Session被创建开始计时的生命周期时长,而是从最后一次被访问开始计时,在指定的时长内一直未被访问的时长

<!--设置Session的失效时间--> 
<session-config>    
    <session-timeout>120</session-timeout>  //失效时长为120分钟 
</session-config>

若未到超时时限,也可通过代码提前使Session失效。HttpSession中的方法 invalide(),使得Session失效。

session.invalidate(); 
System.out.println("session: " + session);

以上代码表示使 Session失效,但失效的Session值并不为 null。如图所示:
在这里插入图片描述
在这里插入图片描述

四、Cookie禁用后使用Session进行会话跟踪

​ 从前面 Session 的工作原理可知,服务器之所以可以针对不同的会话找到不同的 Session,是因为 Cookie 完成了会话的跟踪。但是,若客户端浏览器将 Cookie 禁用,那么服务器还怎样保证同一会话使用的是同一个Session呢?

​ 若客户端浏览器禁用了。Cookie 会发现向服务器所提交的每一次请求,服务器在给出的响应中都会包含名称为 JESSIONID 的 Cookie,只不过这个 Cookie 的值每一次都不同。 也就是说,只要客户端浏览器所提交的请求中没有包含 JESSIONID,服务器就会认为这是一次新的会话的开始,就会为其生成一个 Map.Entry 对象,key 为新的32位长度的随机串,value 为新创建的 Session 会话用。这样的话,也就无法实现会话跟踪了。

1、禁用Cookie(谷歌浏览器)

(1)【设置】-------> 【高级设置】
在这里插入图片描述
(2)【网站设置】-------> 【权限】
在这里插入图片描述
(3)即可在Cookie中设置了
在这里插入图片描述

2、重定向的URL重写(解决Cookie禁用后,Session跟踪问题)

(1)当仅使用普通重定向时,跳转到 TwoServlet 时,没有相应的 JESSIONID 的值

response.sendRedirect(request.getContextPath() + "/two.do");

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(2)对重定向使用 encodeRedirectURL 后,即可在 Cookie 禁用的状态下依然跟踪 Session

String uri = request.getContextPath() + "/two.do"; 
uri = response.encodeRedirectURL(uri); 
response.sendRedirect(uri);

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(3)即使打开Cookie后,依然能使用重定向的跳转。

3、超链接的URL重写(**解决Cookie禁用后,非重定向时的Session跟踪问题)

​ HttpServletResponse具有一个方法 encodeURL,可以完成类似对超链接这样的非重定向页面跳转的 URL 的重写,即在其路径后会自动添加 jsessionid。

(1)当只使用超链接跳转时,跳转到 TwoServlet 时,没有相应的 JESSIONID 的值

response.setContentType("text/html;charset=UTF-8"); 
PrintWriter out = response.getWriter(); 
out.println("<a href='two.do'>跳转<a>到TwoServlet");

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(2)对超链接使用 encodeURL 后,即可在 Cookie 禁用的状态下依然跟踪 Session

response.setContentType("text/html;charset=UTF-8"); 
PrintWriter out = response.getWriter(); 
String uri = "two.do"; 
uri = response.encodeURL(uri); 
out.println("<a href='"+ uri +"'>跳转<a>到TwoServlet");

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意:当每次禁用Cookie后跟踪Session时,jsessionid都会暴露在地址栏中,存在危险。因此,能不禁用Cookie时尽量别禁用!!!

地址栏中的 jsessionid 前使用的是“ ;(分号)”,不是冒号 。
在这里插入图片描述

五、域属性空间范围对比

​ 在 JavaWeb 编程的 API 中,存在三个可以存放域属性的空间范围对象,这三个对象中所存储的域属性作用范围,由大到小分别为:
在这里插入图片描述
ServletContext:即 application,置入其中的域属性是整个应用范围的,可以完成跨会话共享数据

HttpSession:置入其中的域属性是会话范围的,可以完成跨请求共享数据

HttpServletRequest:置入其中的域属性是请求范围的,可以完成跨 Servlet 共享数据。但这些 Servlet 必须在同一请求中。

​ 对于这三个域属性空间对象的使用原则是,在可以保证功能需求的前提下,优先使用小范围的。这样不仅可以节省服务器内存,还可以保证数据的安全性。

六、购物车的简单实现

1、hhh.html(商品展示页面)
<center>     
    <h1>商品展示页面</h1>     
    <table border="2">         
        <tr>             
            <td>面包</td>             
            <td>15.00</td>             
            <td><a href="/myWeb/one.do?name=面包">放入购物车</a></td>         
        </tr>         
        <tr>             
            <td>啤酒</td>             
            <td>10.00</td>             
            <td><a href="/myWeb/one.do?name=啤酒">放入购物车</a></td>         
        </tr>         
        <tr>             
            <td>烤肠</td>             
            <td>5.00</td>             
            <td><a href="/myWeb/one.do?name=烤肠">放入购物车</a></td>         
        </tr>     
    </table> 
</center>

在这里插入图片描述

2、根据商品名称加入购物车
//获取浏览器推送过来的名称 
String name = request.getParameter("name"); 
//向Tomcat索要当前浏览器在服务端的Session对象 
HttpSession session = request.getSession(); 
//将用户选择商品保存到当前用户Session 
Integer nums = (Integer) session.getAttribute(name); 
if (nums == null){    
    session.setAttribute(name,1); 
} else {    
    session.setAttribute(name,nums+1); 
}

当商品数量为空时,如把烤肠加入到购物车:
在这里插入图片描述
此时已加入到购物车中,商品数量为1,返回商品展示页面,再次对烤肠进行操作,加入到购物车:
在这里插入图片描述
如何调出以上界面?

先对程序加入断点,运行到最后一行,如下图所示:
在这里插入图片描述
之后把鼠标放到任意 session 上,点击 session,过一会出现如下图所示:
在这里插入图片描述
此时点击+号即可出现对 session 的详细页面:
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值