因为HTTP协议是无状态的,所以无法记录客户端的当前状态,但许多情况下又必须要web服务器能够跟踪客户端状态。比如许多客户在同一个购物网站上购物,web服务器为每个客户配置了一个虚拟的购物车,当某个客户请求将一个商品放入购物车时,服务器就必须根据发出请求客户的身份,找到该客户的购物车,然后把商品放入其中。
至今为止,我们已经学到了二种方法使web服务器能够跟踪客户的状态:
方法一:利用request对象的getParameter或getParameterValues方法一页一页传递过去(即建立含有跟踪数据的隐藏表格字段或重写包含额外参数的URL)。
方法二:利用持续的Cookies。
session对象用来记载特定客户的信息,即使该客户从一个页面跳转到另一个页面,该session信息仍然存在,客户在该网站的任何一个页面都可以存取session信息。同时session信息是对一个客户的,不同的客户信息用不同的session对象记载。打个比方每个人去超市购物时会得到一个购物车,用于存放自己选购的商品,当离开超市时就会回收购物车,重新分配给其他人。session就好比超市的购物车,每个客户端访问服务器时就会在服务器端分配一块空间用于存放客户端的信息,当客户端离开后或长时间不用它的session时服务器就会回收session空间在分配给其他客户端。
DQM容器session的工作原理我们简单的介绍一下:当启用session时客户端访问服务器时,容器会自动生成一个不重复的sessionID,并把这个ID送给客户端浏览器,浏览器会把这个ID存放在cookie内,当客户端再次向服务器端请求时会读取这个cookie中的ID,并返回该ID对应的session对象。
注意:因为session会占用资源,所以在不需要的情况下可以关闭session,如果关闭了则session内置对象就无法使用了。打开或关闭session指令请参见3.2节。 |
session对象主要用于存取信息,本节介绍一下存取信息的方法。
1. public void setAttribute(String name, Object value)
将特定的值以特定的关键字存入当前客户端所对应的session对象中。关键字是唯一的,如果关键字已存在则此方法会覆盖先前所对应的值。如果value值为null,则此方法就等价于removeAttribute(name)方法。
参数:name用户指定的关键字。
value指定关键字所对应的值。
异常:如果关键字为null则此方法会抛出IllegalArgumentException异常。
2. public Object getAttribute(String name)
读取特定的关键字所对应的值。
参数:name用户指定的关键字。
返回:指定关键字所对应的值,如果关键字不存在则返回null。
3. public void removeAttribute(String name)
删除特定关键字所对应的值。如果指定的关键字不存在则本方法什么都不做。
参数:name用户指定的关键字。
我们来举一个例子,sessionName.dqm源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
14 15 16 17 18 19 20 21 22 23 24 25 |
<html>
<head> <meta http-equiv="Content-Language" content="zh-cn"> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <title>访问者名字</title> </head>
<body>
<form method="POST" action="addSessionName.dqm"> <p>访问者名字:<input type="text" name="sessionName" size="20"></p> <p><input type="submit" value="Submit" name="B1"><input type="reset" value="Reset" name="B2"> <a href="delSessionName.dqm">删除名字</a></p> </form> <%String name = (String)session.getAttribute("name"); if (name == null) { name = "访客"; } %> <p>欢迎您:<%=name%></p>
</body>
</html> |
上面源程序16行用于读取当前session中记录的访问者名字,17到19行用于判断session中是否找到访问者记录,如果找到则在21行显示访问者姓名,否则显示“访客”。
addSessionName.dqm用于在当前session中记录访问者的姓名,源程序如下:
1 2 3 4 5 6 7 8 9 10 |
<% String name = request.getParameter("sessionName"); if (name != null) { session.setAttribute("name", name); out.print("访问者的名字记录成功!"); } else { out.print("请输入访问者的名字!"); } %> |
delSessionName.dqm用于从当前session中删除访问者的姓名(如果有的话),源程序如下:
1 2 3 4 5 |
<% session.removeAttribute("name"); %>
已删除访客名字! |
执行时首先打开sessionName.dqm,会看到“欢迎您:访客”(见图8-2-1),因为这时还没有在session记录名字。
图8-2-1
我们在本页面“访问者名字”一栏中写入“dunne”,提交成功后再次访问sessionName.dqm,此时就会看到“欢迎您:dunne”了(如果没有看到请刷新浏览器)。如果此时用另一台机器访问sessionName.dqm则还是会看到“欢迎您:访客”的提示,这就验证了前面所说的session信息是对一个客户的,不同的客户信息用不同的session对象记载。在sessionName.dqm页面点击删除名字后再访问sessionName.dqm就会看到先前保存在session中的名字已经被删除了,因此会象第一次打开时那样显示“欢迎您:访客”。
session对象本身也有很多信息,这些信息在很多情况下是很有用的,比如session存活期、sessionID等,本节介绍一下获取这些信息的方法。
1. public long getCreationTime()
读取对应当前客户端的session对象创建时间的毫秒格式。
请参阅java.util.Date类的描述,了解可能发生在“计算机时间”和协调世界时(UTC)之间的细微差异的讨论。
返回:session对象创建时间与协调世界时1970年1月1日午夜之间的时间差(以毫秒为单位测量)。
2. public long getLastAccessedTime()
读取对应当前客户端的session对象最后一次访问时间的毫秒格式。新生成的session对象最后一次访问时间就等于创建时间。
请参阅java.util.Date类的描述,了解可能发生在“计算机时间”和协调世界时(UTC)之间的细微差异的讨论。
返回:session对象最后一次访问时间与协调世界时1970年1月1日午夜之间的时间差(以毫秒为单位测量)。
3. public void setMaxInactiveInterval(int interval)
设定当前客户端对应的session对象可以处于不活动状态的最大时间间隔,以秒为单位,如果在此时间内当前的session对象没有被使用(访问)过则此session自动失效,即判断getLastAccessedTime方法返回值减去getCreationTime方法返回值转换成秒后是否大于本次设定的值。如果没有使用本方法设定此值,则默认的值为webconfig.xml中主机和虚拟主机中sessionTimeOut设定的值(参见2.4和2.5节)。
参数:interval设置当前session对象处于不活动状态的最大存活时间,如果本值为负数则表示当前的session对象立即过期。
4. public int getMaxInactiveInterval()
读取当前客户端对应的session对象可以处于不活动状态的最大时间间隔,以秒为单位,此方法返回的就是setMaxInactiveInterval方法所设定的值,如果没有设定过则返回默认值(webconfig.xml中主机和虚拟主机中sessionTimeOut设定的值,参见2.4和2.5节)。
返回:客户端对应的session对象可以处于不活动状态的最大时间间隔。
5. public boolean isNew()
判断当前客户端对应的session是否是新创建的。
返回:如果是新创建的session返回true,否则返回false。
6. public String getId()
在前面8.1节介绍过session工作原理,其中提到了不重复的sessionID,而本方法就是用于获取当前客户端对应session的ID。
返回:当前客户端对应session的ID。
为了更好的理解上面这些方法,我们举些例子,sessionInfo.dqm使用了上面介绍过的方法,其源程序如下:
1 2 3
4 5 6 7 8 |
<pre> 当前session对象创建时间:<%=new java.util.Date(session.getCreationTime())%> 当前session对象最后一次访问(使用)时间:<%=new java.util.Date(session.getLastAccessedTime())%> 当前session对象过期时间:<%=session.getMaxInactiveInterval()%>秒 将当前session过期时间设置为5分钟<%session.setMaxInactiveInterval(60 * 5);%> 当前session对象是否是新创建的:<%=session.isNew()%> 当前session对象的ID:<%=session.getId()%> </pre> |
当第一次访问此动态文件时结果大致如下:
1 2 3 4 5 6 |
当前session对象创建时间:Thu Jan 12 15:28:29 GMT+08:00 2006 当前session对象最后一次访问(使用)时间:Thu Jan 12 15:28:29 GMT+08:00 2006 当前session对象过期时间:1200秒 将当前session过期时间设置为5分钟 当前session对象是否是新创建的:true 当前session对象的ID:037149dd-ebd2-4017-b935-e90f8be457fa |
从上面结果可以看出第一次访问时此session是新创建的(执行结果第5行),过期时间为1200秒(此值为默认的过期事件, 执行结果第3行),同时session的创建时间和最后一次访问时间也是相同的(执行结果第1和2行)。
当再次访问时结果就变成了:
1 2 3 4 5 6 |
当前session对象创建时间:Thu Jan 12 15:28:29 GMT+08:00 2006 当前session对象最后一次访问(使用)时间:Thu Jan 12 15:30:27 GMT+08:00 2006 当前session对象过期时间:300秒 将当前session过期时间设置为5分钟 当前session对象是否是新创建的:false 当前session对象的ID:037149dd-ebd2-4017-b935-e90f8be457fa |
可以看到此时session已经不是新创建的了(执行结果第5行),过期时间也变成了300秒(第一次访问时执行设置为5分钟,执行结果第3行),同时最后一次访问时间与创建时间也不同了(执行结果第1和2行)。
前面提到过session 会过期,但是过期的session并不会立即释放内存,而是每隔一段时间才会释放过期的session(此时间由webconfig.xml中的clearTimeoutSession指定,参见2.1节)。所以即使将过期时间设置为负数(参见8.3节setMaxInactiveInterval方法)也只是将当前的session对象立即过期,但并不表示立即回收此过期session的内存,而本节介绍的方法将会把当前session立即回收。
1. public void invalidate()
立即回收当前客户端对应的session对象,不管其是否过期,都从内存中清除此对象。
我们来举个例子,removeSession1.dqm用于向当前对应的session中写入姓名,源程序如下:
<%session.setAttribute("name", "Shemin Dunne");%> 增加session成功。 |
removeSession2.dqm用于显示当前对应的session中的姓名,源程序如下:
姓名:<%=session.getAttribute("name")%> |
removeSession3.dqm使用invalidate方法清除session,源程序如下:
<%session.invalidate();%> 采用invalidate方法删除session。 |
removeSession4.dqm使用setMaxInactiveInterval方法清除session,源程序如下:
<%session.setMaxInactiveInterval(-1);%> 采用setMaxInactiveInterval方法删除session。 |
首先我们执行removeSession1.dqm,增加了姓名后再执行removeSession2.dqm就可以看见刚才增加的姓名了,这时执行removeSession3.dqm清除session后再次访问removeSession2.dqm就会看到先前增加的姓名没有了即session被删除了。在这里使用removeSession4.dqm删除session也可以起到同样的效果,不过区别在于采用invalidate方法必定立即从内存中删除session对象,而采用setMaxInactiveInterval方法不一定立即从内存中删除session对象,有可能只是将session标记为过期不再使用。