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对象移除后显示的页面信息