从零开始学Java Web开发
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

5.5 session内置对象

HTTP协议本身是无状态的,即信息无法通过HTTP协议本身进行传递。这与HTTP协议本来的目的是相符的,客户端只需要简单地向服务器发送请求,无论是客户端还是服务器都没有必要记录彼此过去的行为,每一次请求之间都是独立的。为了跟踪用户的操作状态,在多个页面之间保存共享信息,JSP中提供了session对象。该对象是产生于服务器端的,使用一种类似于散列表的结构来保存信息。

当需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了一个session id,它是session的标识。如果已包含一个session ID则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用,如果客户端请求不包含session ID,则为此客户端创建一个session并且生成一个与此session相关联的session ID,session ID的值应该是一个既不会重复又不容易被找到规律以仿造的字符串,这个session ID将在本次响应中返回给客户端保存。session ID将保存在客户机的cookie中。

session对象中主要方法如表5.5所示。

表5.5 session对象中常用方法

下面通过对几个session常用例程的介绍,来详细说明这些方法的具体用法。

5.5.1 获取session的ID

session对象的ID是用来唯一识别session的标识,该ID是由一个32位的十六进制字符串组成,可以保证服务器中所创建的所有session对象都不相同。

【实例5-8】获取session的ID。该实例通过一个获取session的ID来证明一个会话过程中的多个页面之间进行跳转时使用的是同一个session对象。

    01  <%@ page contentType="text/html;charset=GB2312" %>
    02  <HTML>
    03  <BODY>
    04  <P>
    05     <% String s=session.getId();        //获取当前页面的session对象的ID
    06     %>
    07  <P> 您的session对象的ID是:
    08     <BR>
    09     <%=s%>
    10  <P>输入用户姓名连接到session2.jsp
    11     <FORM action="session2.jsp" method=post name=form>
    12        <INPUT type="text" name="name">
    13        <INPUT TYPE="submit" value="提交" name=submit>
    14    </FORM>
    15  </BODY>
    16  </HTML>

【代码说明】在该页面的第5行中通过getId()方法获取当前页面的session ID并在第9行使用表达式显示在页面上。当单击页面中的“提交”按钮时,将通过<form>表单跳转到session2.jsp页面。

【运行结果】实例5-8 的JSP页面的执行结果如图5.14所示。

图5.14 显示session1.jsp页面的session的ID值

session2.jsp页面的具体代码如下:

    01  <%@ page contentType="text/html;charset=GB2312" %>
    02  <HTML>
    03  <BODY>
    04  <P>session2.jsp页面
    05     <% String s=session.getId();       //获取当前页面的session对象的ID
    06     %>
    07  <P> 在session2.jsp页面中的session对象的ID是:
    08     <%=s%>
    09  <P> 单击超链接,连接到session3.jsp页面。
    10  <A HREF="session3.jsp">
    11   <BR>  进入session3.jsp
    12  </A>
    13  </BODY>
    14  </HTML>

【代码说明】在该页面的第5行中通过getId()方法获取当前页面的session ID并在第8行使用表达式显示在页面上。在第10行通过<a>标签声明一个超链接,该链接的目标地址是session3.jsp页面。单击session2.jsp页面中的超链接,将转向session3.jsp页面。

【运行结果】session2.jsp页面的执行结果如图5.15所示。

session3.jsp页面的具体代码如下:

    01  <%@ page contentType="text/html;charset=GB2312" %>
    02  <HTML>
    03  <BODY>
    04  <P>session3.jsp页面
    05     <% String s=session.getId();       //获取当前页面的session对象的ID
    06     %>
    07  <P> 在session3.jsp页面中的session对象的ID是:
    08     <%=s%>
    09  <P> 单击超链接,连接到session1.jsp页面。
    10  <A HREF="session1.jsp">
    11   <BR>  进入session1.jsp
    12  </A>
    13  </BODY>
    14  </HTML>

【代码说明】在该页面的第5行中通过getId()方法获取当前页面的session ID并在第8行使用表达式显示在页面上。在第10行通过<a>标签声明一个超链接,该链接的目标地址是session1.jsp页面。单击session3.jsp页面中的超链接,将转回到session1.jsp页面。

【运行结果】session3.jsp页面的执行结果如图5.16所示。

图5.15 显示session2.jsp页面的session的ID值

图5.16 显示session3.jsp页面的session的ID值

通过比较图5.14和图5.15的运行结果可以看出,通过表单提交请求进行转向的两个页面共享同一个session对象。通过图5.16所示的运行结果可以看到,该页面中的session ID与之前的页面中的session ID也一样,所以通过超链接进行转向的两个页面也是共享同一个session对象的。

5.5.2 使用URL重写支持session

前面介绍过,session对象的ID将保存在客户机的cookie中,而cookie又被认为是一项不安全的技术。因此在浏览器中可以通过设置使cookie被禁用,这将直接导致session失效。

在浏览器中禁用cookie的操作步骤如下。

(1)选择浏览器菜单栏中的“工具”|“Internet选项”命令,在弹出的“Internet选项”对话框中选择“隐私”选项。

(2)在其中将隐私设置的滑块设置到最高,即阻止所有cookie,然后单击“确定”按钮,将使得浏览器不支持任何网站发来的cookie。

设置完成后,再次运行实例5-8将会发现每个页面中显示的session ID各不相同,而且即使是同一个页面,每次刷新之后显示的session ID也是不同的。这个结果说明当浏览器中设置禁用cookie后,session对象也随之失效了。那么对于应用程序来说,如果客户端设置为禁用cookie,那么依赖session对象所实现的功能是不是就无法完成了呢?表面上看是这样的,但是可以使用response对象的encodeURL()方法,通过URL重写机制来在cookie禁用的情况下支持session。

实质上,URL重写是通过向URL链接添加参数,并把session ID作为参数值包含在链接中。encodeURL()方法首先判断cookie是否被浏览器所支持,如果支持则参数URL被原样返回,否则session ID作为参数将添加到URL的后面。因此无论用户的浏览器是否禁用cookie使用URL重写机制都能正确支持session对象。

【实例5-9】使用URL重写机制支持session。使用URL重写机制改写实例5-8,使得该实例在禁用cookie的客户端浏览器中照样能够正常执行。修改后的实例5-8中的3个页面代码分别如下。

修改后的session1.jsp页面的具体代码如下:

    01  <%@ page contentType="text/html;charset=GB2312" %>
    02  <HTML>
    03  <BODY>
    04  <P>
    05     <%
    06       String url=response.encodeURL("session2.jsp");   //对URL地址进行重写
    07     %>
    08  <P> URL重写后的路径是:
    09     <BR>
    10     <%=url%>
    11  <P>输入用户姓名连接到session2.jsp
    12     <FORM action="<%=url%>" method=post name=form> <%--设置重写后的URL为提交路径--%>
    13        <INPUT type="text" name="name">
    14        <INPUT TYPE="submit" value="提交" name=submit>
    15    </FORM>
    16  </BODY>
    17  </HTML>

【代码说明】在该页面的第6 行中使用encodeURL()方法对要提交的页面路径进行URL重写,然后在第12行将重写后的路径作为新的提交路径赋值给<form>表单标签的action属性。

【运行结果】session1.jsp页面的执行结果如图5.17所示。

单击“提交”按钮后,将转向session2.jsp页面,修改后的session2.jsp页面的具体代码如下:

图5.17 session1.jsp页面显示URL重写后的路径

    01  <%@ page contentType="text/html;charset=GB2312" %>
    02  <HTML>
    03  <BODY>
    04  <P>session2.jsp页面
    05     <%
    06      String url=response.encodeURL("session3.jsp");   //对URL地址进行重写
    07     %>
    08  <P> URL重写后的路径是:
    09     <%=url%>
    10  <P> 单击超链接,连接到session3.jsp页面。
    11  <A HREF="<%=url%>"> <%--设置重写后的URL为超级链接的路径--%>
    12   <BR>  进入session3.jsp
    13  </A>
    14  </BODY>
    15  </HTML>

【代码说明】在该页面的第6 行中使用encodeURL()方法对要跳转到的链接页面的路径进行URL重写,然后在第11行将URL重写后的路径设置为超链接的路径。

【运行结果】session2.jsp页面的执行结果如图5.18所示。

单击超链接后,将转向session3.jsp页面,修改后的session3.jsp页面的具体代码如下:

图5.18 session2.jsp页面显示URL重写后的路径

    01  <%@ page contentType="text/html;charset=GB2312" %>
    02  <HTML>
    03  <BODY>
    04  <P>session3.jsp页面
    05     <%
    06      String url=response.encodeURL("session1.jsp");    //对URL地址进行重写
    07     %>
    08  <P> URL重写后的路径是:
    09     <%=url%>
    10  <P> 单击超链接,连接到session1.jsp页面。
    11  <A HREF="<%=url%>"> <%--设置重写后的URL为超级链接的路径--%>
    12   <BR>  进入session1.jsp
    13  </A>
    14  </BODY>
    15  </HTML>

【代码说明】在该页面的第6 行中使用encodeURL()方法对要跳转到的链接页面的路径进行URL重写,然后在第11行将URL重写后的路径设置为超链接的路径。

【运行结果】session3.jsp页面的执行结果如图5.19所示。

图5.19 session3.jsp页面显示URL重写后的路径

通过这三个页面的运行结果可以看出,即使客户端浏览器禁用了cookie,只要使用了URL重写机制一样可以支持session对象。

说明

建议读者在日后的实际开发中涉及到对session对象的使用时,最好使用URL重写机制,这样能够保证应用程序在任何的客户端浏览器上都能正常执行。

5.5.3 session中保存和读取共享数据

与request对象一样,session对象也有一对setAttribute()和getAttribute()方法,用来存储或者读取session中的共享信息。session对象与request对象的这两个方法的使用方式完全相同,区别在于共享信息的范围不同,session对象中保存的共享信息的范围是整个会话过程,而request对象中保存的共享信息的范围则是提交和被提交的页面。

【实例5-10】session和request对象共享信息的范围。

设置共享信息页面sessionSetAttribute.jsp的具体代码如下:

    01  <%@ page contentType="text/html;charset=GB2312" %>
    02  <HTML>
    03  <BODY >
    04     <%
    05       session.setAttribute("name","sun");      //将共享信息存储到session对象中
    06    %>
    07    <a href="sessionReadAttribute.jsp">读取共享信息</a>
    08  </BODY>
    09  </HTML>

【代码说明】在该页面的第5行中使用setAttribute(String name,Object object)方法将共享数据保存到session对象中,然后在第7行中使用超链接转向到读取共享信息的页面。

读取共享信息页面sessionReadAttribute.jsp的具体代码如下:

    01  <%@ page contentType="text/html;charset=GB2312" %>
    02  <HTML>
    03  <BODY >
    04     读取的共享信息是:
    05     <%
    06       out.println(session.getAttribute("name")); //从session对象中获取共享信息并显示
    07     %>
    08  </FONT>
    09  </BODY>
    10  </HTML>

【代码说明】在该页面的第6行中使用getAttribute(String name)方法来获取存储在session中的共享数据并使用out对象将其显示在页面上。

【运行结果】sessionReadAttribute.jsp页面的执行结果如图5.20所示。如果将代码中的session对象换成request对象,将显示如图5.21所示的运行结果。

图5.20 读取并显示session对象中的共享数据

图5.21 读取不到request对象中的共享信息

通过以上运行结果可以看出,request对象只能读取提交页面中保存的共享信息,而session对象则可以读取会话中存储的共享信息。

5.5.4 session的生命周期

session对象的创建是由服务器完成的,当客户端第一次请求服务器时由服务器创建。如果会话过程一直存在,则session对象也将一直存在下去。只有当session过期、客户端关闭浏览器或者服务器端调用了session的invalIDate()方法时session对象才被释放掉,结束其生命周期。

【实例5-11】session的生命周期。

    01  <%@ page contentType="text/html;charset=GB2312" %>
    02  <html>
    03  <head>
    04  <title>Session生命周期</title>
    05  </head>
    06  <body>
    07  <h2>Session生命周期</h2>
    08  <%
    09  if(session.isNew()) // 如果session是新的,设定session生命周期的初始值
    10      {
    11           session.setMaxInactiveInterval(10);  //设定session若10秒内没活动则使
                 Session过期
    12           session.setAttribute("expire","10"); //将此session的time out的秒数加入
                 过期时间中
    13           out.println("设定Session若十秒内没有活动则使Session过期");
    14           }
    15  else
    16      {
    17          String str_expire_time =(String)session.getAttribute("expire");
    18           long create_time=session.getCreationTime();  //取得session创建的时间
    19           long access_time=session.getLastAccessedTime();//获得session最后访问时间
    20           long current_time=System.currentTimeMillis();     //获取当前系统时间
    21           long exist_time=(current_time-create_time)/1000; //计算session存在时间
    22           out.println("session已存在"+exist_time+"秒");      //输出session存在时间
    23               if (exist_time>=30)  //如果session存在的时间超过30秒,则将session移除
    24               {
    25                   out.println("session时间已到...自动失效");
    26                   session.invalidate();                     //使session实效
    27               }
    28               }
    29  %>
    30  </body>
    31  </html>

【代码说明】在该页面的第9行中通过调用session对象的isNew()方法来判断session对象是否是第一次创建的。在第10~14行为新创建的session对象设置最大不活跃的时间,当超过这个时间时,session对象将被清除。在第16~28行表示如果不是新创建的session对象,则表示session对象已经存在,这样就显示出session对象已经存在的时间,并且当session对象存在超过30秒后,自动移除该session对象。

【运行结果】该页面在不同时间段内运行的结果如图5.22~图5.24所示。

图5.22 新建session对象时显示的页面信息

图5.23 在创建session对象30秒内显示的页面信息

图5.24 session对象移除后显示的页面信息