write:2022-4-16
上文学习了java web的一个核心组件JSP:Java Web之JSP技术详解,这篇文章学习java web开发中一个非常重要的概念:Session(会话)

1. 理解Session的概念

1.1 Session的概念

Session用于跟踪客户的状态。
Session指的是在一段时间内,单个客户与Web服务器的一个Web应用一连串相关的交互过程。
在一个Session中,客户可能会多次请求访问同一个网页,也有可能请求访问各种不同的服务器资源。
Session的例子:
例1:在电子邮件应用中,从一个客户登录到电子邮件系统开始,经过收信、写信和发信等一系列操作,直至最后退出邮件系统,整个过程为一个Session。
例2:在购物网站应用中,从一个客户开始购物,到最后结账,整个过程为一个Session。

1.2 Session的运行机制

当一个Session开始时,Servlet容器将创建一个HttpSession对象(HttpSession对象与会话具有同样的生命周期),在HttpSession对象中可以存放客户状态的信息(例如购物车)。
Servlet容器为HttpSession分配一个惟一标志符,称为Session ID。Servlet容器把Session ID作为Cookie保存在客户的浏览器中。
每次客户发出HTTP请求时,Servlet容器可以从HttpRequest对象中读取Session ID,然后根据Session ID找到相应的HttpSession对象,从而获取客户的状态信息。

1.3 HttpSession接口

HttpSession对象的生命周期是会话开始即开始,会话结束即结束;
Servlet和JSP组件可以访问当前的HttpSession对象,调用它的各种方法;
HttpSession接口中的方法:
getId():返回Session的ID
invalidate():使当前的Session失效,Servlet容器会释放HttpSession对象占用的资源
setAttribuate(String name, Object value) :将一对name/value属性保存在HttpSession对象中
getAttribute(String name):根据name参数返回保存在HttpSession对象中的属性值
isNew() :判断是否是新创建的Session。如果是新创建的Session,返回true,否则返回false
setMaxInactiveInterval():设定一个Session可以处于不活动状态(当Session开始后,在一段时间内客户没有和Web服务器交互)的最大时间间隔,以秒为单位。如果超过这个时间,Session自动失效。如果设置为负数,表示不限制Session处于不活动状态的时间

2. 理解Session的生命周期

2.1 Session的生命周期

当客户第一次访问Web应用中支持Session的某个网页时,就会开始一个新的Session。此时Servlet容器会创建一个表示这个会话的HttpSession对象。
接下来当客户浏览这个Web应用的不同网页时,始终处于同一个Session中。
服务器调用支持Session的JSP网页时,会操纵SessionID和Session对象。
默认情况下,JSP网页都是支持Session的,也可以通过以下语句显式声明支持Session:<%@ page session= “true”>

在以下情况中,Session将结束生命周期,(与Session对应的HttpSession对象也结束生命周期,HttpSession对象里面存放的数据也结束生命周期)Servlet容器会将Session所占用的资源释放掉:
1)客户端关闭浏览器,终止会话
2)Session过期
3)服务器端调用了HttpSession的invalidate()方法

2.2 Session过期

Session过期是指当Session开始后,在一段时间内客户没有和Web服务器交互,这个Session会失效。
HttpSession类的setMaxInactiveInterval()方法可以设置允许Session保持不活动状态的时间(以秒为单位),如果超过这一时间,Session就会失效。客户端关闭浏览器,终止会话的操作并不会再向服务器端发送消息通知它已关闭会话,那么服务器端只有等时间超过setMaxInactiveInterval()方法设置的时间才明白已结束会话,释放资源。

2.3 Session范例程序

创建一个简单的邮件系统,由3个JSP文件组成:
maillogin.jsp
mailcheck.jsp(用户收信)
maillogout.jsp

2.3.1 maillogin.jsp

在maillogin.jsp提供了一个登录界面,要求用户输入用户名和口令,并且显示当前的Session ID

<%@ page contentType="text/html; charset=GB2312" %>
<%@ page session="true" %>
<html>
<head>
  <title>helloapp</title>
</head>

<body bgcolor="#FFFFFF" onLoad="document.loginForm.username.focus()">

<%
  String name="";
if(!session.isNew()){
    name=(String)session.getAttribute("username");
    if(name==null)name="";
}
%>
<p>欢迎光临邮件系统</p>
<p>Session ID:<%=session.getId()%></p>
  <table width="500" border="0" cellspacing="0" cellpadding="0">
    <tr>
      <td>
        <table width="500" border="0" cellspacing="0" cellpadding="0">
          <form name="loginForm" method="post" action="mailcheck.jsp">
          <tr>
            <td width="401"><div align="right">User Name:&nbsp;</div></td>
            <td width="399"><input type="text" name="username" value=<%=name%>></td>
          </tr>
          <tr>
            <td width="401"><div align="right">Password:&nbsp;</div></td>
            <td width="399"><input type="password" name="password"></td>
          </tr>
          <tr>
            <td width="401">&nbsp;</td>
            <td width="399"><br><input type="Submit" name="Submit"  value="提交"></td>
          </tr>
          </form>
        </table>
      </td>
    </tr>
  </table>


</body>
</html>

运行http://localhost:8080/helloapp/maillogin.jsp,无论刷新多少次,SessionID都不会变,因为多次请求都是在这个会话中。
在这里插入图片描述

2.3.2 mailcheck.jsp

mailcheck.jsp从HttpRequest中读取用户名,将用户名作为属性保存在HttpSession中,然后返回新邮件数目,在这里只是简单地返回一个固定的邮件数目。在mailcheck.jsp中还提供了到maillogin.jsp和maillogout.jsp的链接。

<%@ page contentType="text/html; charset=GB2312" %>
<%@ page session="true" %>
<html>
<head>
<title>
checkmail
</title>
</head>
<body>

<%
String name=null;
name=request.getParameter("username");
if(name!=null)session.setAttribute("username",name);
%>

<a href="maillogin.jsp">登录</a>&nbsp;&nbsp;&nbsp;
<a href="maillogout.jsp">注销</a>&nbsp;&nbsp;&nbsp;
<p>当前用户为:<%=name%> </P>
<P>你的信箱中有100封邮件</P>

</body>
</html>

访问mailcheck.jsp:http://localhost:8080/helloapp/mailcheck.jsp
在这里插入图片描述
再点击登录,又回到maillogin.jsp,并且Session ID不变,username也有在这里插入图片描述

2.3.3 maillogout.jsp

maillogout.jsp调用HttpSession的invalidate()方法结束当前的Session,并且提供了到maillogin.jsp的链接:

<%@ page contentType="text/html; charset=GB2312" %>
<%@ page session="true" %>
<html>
<head>
<title>
maillogout
</title>
</head>
<body>

<%
String name=(String)session.getAttribute("username");
session.invalidate();

 %>

<%=name%>,再见!
<p>
<p>
<a href="maillogin.jsp">重新登录邮件系统</a>&nbsp;&nbsp;&nbsp;
</body>
</html>

访问maillogout.jsp:http://localhost:8080/helloapp/maillogout.jsp
点击下方的“重新登录邮件系统”链接:
在这里插入图片描述
原会话结束原HttpSession对象生命周期也结束,Session ID发生改变,新的会话开始新的HttpSession对象。

3. 禁用Cookie

3.1 禁用Cookie

在实际情况中,某些客户端出于安全需要,可以禁止服务器端把Cookie 存放在客户端。
如果客户浏览器禁止Cookie,Servlet容器无法从客户端浏览器中取得作为Cookie的Session ID,也就无法跟踪客户状态,因此每次客户请求支持Session的JSP页面,Servlet容器都会创建一个新的Session,这样就失去了跟踪客户状态的功能。

以下操作时让自己的本地浏览器禁用Cookie:
在这里插入图片描述

3.2 跟踪Session的另一种机制

在客户端浏览器禁用Cookie的情况下,照样跟踪会话。
1)在Java Servlet API中提出了跟踪Session的另一种机制,如果客户浏览器不支持Cookie,Servlet容器可以重写客户请求的URL,把Session ID添加到URL信息中。HtttServletResponse接口提供了重写URL的方法:
String encodeURL(java.lang.String url)
2)HttpServletResponse接口的encodeURL()方法的处理流程:
(1)先判断当前的Web组件是否启用Session,如果没有启用Session,例如在JSP中声明
<%@ page session=“false” %>,或者已经执行了session.invalidate()方法,那么直接返回参数url;
(2)再判断客户浏览器是否支持Cookie,如果支持Cookie,就直接返回参数url;如果不支持Cookie,就在参数url中加入Session ID信息,然后返回修改后的url。

<a href="<%=response.encodeURL("maillogin.jsp")%>">登入< /a>

3)把mailcheck.jsp中对maillogin.jsp的链接作如下修改(修改后的文件位于/nocookie目录下):
修改前:

<a href= "maillogin.jsp" >登入< /a>

修改后:

<a href="<%=response.encodeURL("maillogin.jsp")%>">登入< /a>

以上代码生成的网页内容为:

<a href="maillogin.jsp;jsessionid=95493599415695F01771DB6F270F68EF">登入< /a>

4. Session的持久化

当一个Session开始时,Servlet容器会为Session创建一个HttpSession对象。Servlet容器在某些情况下把这些HttpSession对象从内存中转移到文件系统或数据库中, 在需要访问HttpSession信息时再把它们加载到内存中。
在这里插入图片描述

4.1 Session持久化的作用

  1. 假定有一万个人同时在访问某个Web应用,Servlet容器中会生成一万个HttpSession对象。如果把这些对象都一直存放在内存中,将消耗大量的内存资源,显然是不可取的。因此可以把处于不活动状态的HttpSession对象转移到文件系统或数据库中,这样可以提高对内存资源的利用率。
  2. 假定某个客户正在一个购物网站上购物,他将购买的物品先放在虚拟的购物车(ShoppingCart)中,Servlet容器将这个包含购物信息的购物车对象保存在HttpSession对象中。如果此时Web服务器忽然出现故障而终止,那么内存中的HttpSession对象连同客户的购物信息都会丢失。如果把HttpSession对象事先保存在文件系统或数据库中,当Web服务器重启后,还可以从文件系统或数据库中恢复Session数据。

4.2 Session的持久化

Session的持久化是由Session Manager来管理的。Tomcat提供了两个实现类:
org.apache.catalina.session.StandardManager
org.apache.catalina.session.PersistentManager

  1. StandardManager
    StandardManager是默认的Session Manager。它的实现机制为:当Web应用被终止时,会对在内存中的HttpSession对象进行持久化,把它们保存到文件系统中,默认的文件为:
    <CATALINA_HOME>/work/Catalina/hostname/applicationname/SESSIONS.ser
  2. PersistentManager
    PersistentManager能够把Session对象保存到Session Store中,它提供了比StandardManager更为灵活的Session管理功能,它具有以下功能:
    当Web应用被终止时,会对在内存中的HttpSession对象进行持久化,把它们保存到Session Store中。
    具有容错功能,及时把Session备份到Session Store中,当Tomcat服务器意外的关闭后再重启,可以从Session Store中恢复Session对象。
    可以灵活控制在内存中的Session数目,将部分Session转移到Session Store中。
    在这里插入图片描述
  3. Session Store
    org.apache.Catalina.FileStore:将HttpSession对象保存在一个文件中,这个文件的默认目录为<CATALINA_HOME>/work/Catalina/hostname/applicationname。每个HttpSession对象都会对应一个文件,它以Session的ID作为文件名,扩展名为.session。
    org.apache.Catalina.JDBCStore:将HttpSession对象保存在数据库的一张表中。

5. 练习题

  1. 问题:下面哪些说法是正确的?
    选项:
    (A) 对于每个要求访问maillogin.jsp的HTTP请求,Servlet容器都会创建一个HttpSession对象
    (B)每个HttpSession对象都有惟一的ID。
    ©JavaWeb应用程序必须负责为HttpSession分配惟一的ID
    答案:B
  2. 问题:如果不希望JSP网页支持Session,应该如何办?
    选项:
    (A) 调用HttpSession的invalidate()方法
    (B) <%@ page session= “false">

答案:B

  1. 问题:以下这段代码是否有问题?
    <%
    session.invalidate();
    String name=(String)session.getAttribute(“username”);
    %>

答案: 抛出以下异常:
java.lang.IllegalStateException: getAttribute:
Session already invalidated
org.apache.catalina.session.StandardSession.getAttribute(StandardSession.java:972)

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐