在Web服务器端编程中,会话状态管理是一个经常必须考虑的重要问题。本文分析JSP/Servlet的会话管理机制及其所面临的问题,然后提出了一种改进的会话管理方法。
一、Servlet的会话管理机制
根据设计,HTTP是一种无状态的协议。它意味着Web应用并不了解有关同一用户以前请求的信息。维持会话状态信息的方法之一是使用Servlet或者JSP容器提供的会话跟踪功能。Servlet API规范定义了一个简单的HttpSession接口,通过它我们可以方便地实现会话跟踪。
HttpSession接口提供了存储和返回标准会话属性的方法。标准会话属性如会话标识符、应用数据等,都以“名字-值”对的形式保存。简而言之,HttpSession接口提供了一种把对象保存到内存、在同一用户的后继请求中提取这些对象的标准办法。在会话中保存数据的方法是setAttribute(String s, Object o),从会话提取原来所保存对象的方法是getAttribute(String s)。
在HTTP协议中,当用户不再活动时不存在显式的终止信号。由于这个原因,我们不知道用户是否还要再次返回,如果不采取某种方法解决这个问题,内存中会积累起大量的HttpSession对象。
为此,Servlet采用“超时限制”的办法来判断用户是否还在访问:如果某个用户在一定的时间之内没有发出后继请求,则该用户的会话被作废,他的HttpSession对象被释放。会话的默认超时间隔由Servlet容器定义。这个值可以通过getMaxInactiveInterval方法获得,通过setMaxInactiveInterval方法修改,这些方法中的超时时间以秒计。如果会话的超时时间值设置成-1,则会话永不超时。Servlet可以通过getLastAccessedTime方法获得当前请求之前的最后一次访问时间。
要获得HttpSession对象,我们可以调用HttpServletRequest对象的getSession方法。为了正确地维持会话状态,我们必须在发送任何应答内容之前调用getSession方法。
用户会话既可以用手工方法作废,也可以自动作废。作废会话意味着从内存中删除HttpSession对象以及它的数据。例如,如果一定时间之内(默认30分钟)用户不再发送请求,Java Web Server自动地作废他的会话。
Servlet/JSP会话跟踪机制有着一定的局限,比如:
会话对象保存在内存之中,占用了可观的资源。
会话跟踪依赖于Cookie。由于各种原因,特别是安全上的原因,一些用户关闭了Cookie。
会话跟踪要用到服务器创建的会话标识符。在多个Web服务器以及多个JVM的环境中,Web服务器不能识别其他服务器创建的会话标识符,会话跟踪机制无法发挥作用。
要深入理解会话跟踪机制,首先我们必须理解在Servlet/JSP容器中会话如何运作。
二、会话标识符
每当新用户请求一个使用了HttpSession对象的JSP页面,JSP容器除了发回应答页面之外,它还要向浏览器发送一个特殊的数字。这个特殊的数字称为“会话标识符”,它是一个唯一的用户标识符。此后,HttpSession对象就驻留在内存之中,等待同一用户返回时再次调用它的方法。
在客户端,浏览器保存会话标识符,并在每一个后继请求中把这个会话标识符发送给服务器。会话标识符告诉JSP容器当前请求不是用户发出的第一个请求,服务器以前已经为该用户创建了HttpSession对象。此时,JSP容器不再为用户创建新的HttpSession对象,而是寻找具有相同会话标识符的HttpSession对象,然后建立该HttpSession对象和当前请求的关联。
会话标识符以Cookie的形式在服务器和浏览器之间传送。如果浏览器不支持Cookie又如何呢此时,对服务器的后继请求将不会带有会话标识符。结果,JSP容器认为该请求来自一个新用户,它会再创建一个HttpSession对象,而以前创建的HttpSession对象仍旧驻留在内存中,但该用户以前的会话信息却丢失了。
另外,Servlet/JSP容器只认可它自己创建的会话标识符。如果同一Web应用在“Web农场”(Web farm)的多台服务器上运行,则必须存在这样一种机制:保证来自同一用户的请求总是被定向到处理该用户第一次请求的服务器。
三、伪会话管理机制
如前所述,基于Cookie的会话管理技术面临着种种问题。下面我们要设计一种新的会话管理机制来解决这些问题。这种会话管理机制称为“伪会话”(Pseudo Session)机制,它具有如下特点:
对象和数据不是保存在内存中,而是以文本文件形式保存。每一个文本文件与一个特定的用户关联,文件的名字就是会话的标识符。因此,文件名字必须是唯一的。
文本文件保存在一个专用的目录中,所有Web服务器都可以访问这个目录。因此,伪会话可以用于Web农场。
会话标识符不作为Cookie发送,而是直接编码到URL里面。因此,采用伪会话技术要求修改所有的超级链接,包括HTML表单的ACTION属性。
此外,实现伪会话管理机制时我们还要考虑到以下几点:
它应该与应用无关,其他想要实现同样功能的开发者应该能够方便地重用它。
考虑到安全原因,应该有一种为会话标识符生成随机数字的办法。
为了作废过期的会话,应该设定一个超时值。同一个用户,如果他超过一定的时间之后再次返回,他将获得一个新的会话标识符。此举能够防止未经授权的用户冒用其他人的会话。
应该有一种收集过期会话并删除相应文本文件的机制。
如果用户使用已经过期的会话标识符再次访问服务器,即使这个会话标识符的文本文件还没有删除,系统也不应该允许用户使用原来的会话。
同时,应该存在一种更新会话文本文件最后改动时间的机制,使得用户在会话过期时限之前返回时会话总是保持最新且合法的状态数据
四、实现伪会话管理机制
下面所介绍的工程称为PseudoSession,它是伪会话机制一个很简单的实现。考虑到移植性,我们以JavaBean的形式实现它。PseudoSessionBean的完整代码可以从本文后面下载。
PseudoSessionBean拥有如下域(Field):
public String path;public long timeOut;
path是保存所有会话文本文件的目录。如果Web服务器的数量在一个以上,这个目录必须允许所有服务器访问。然而,为了防止用户直接访问这些文本文件,这个路径应该不允许用户直接访问。解决这个问题的一种方法是使用Web网站根之外的目录。
timeOut是用户的最后一个请求到会话过期作废之间的时间。在PseudoSessionBean的代码清单中,timeOut设置成了以毫秒表示的20分钟,这是一个比较合理的超时时间值。对于任何用户,如果他在这个超时时间之后才继续发出请求,他将得到一个新的会话标识符。
PseudoSessionBean有4个方法:getSessionID,setValue,getValue,deleteAllInvalidSessions。
4.1、getSessionID方法
getSessionID方法的声明如下:
public String getSessionID(HttpServletRequest request)
这个方法应该在每一个JSP页面的开头调用。它完成如下任务:
如果用户是第一次访问,则为该用户设定一个新的会话标识符。
检查URL所带会话标识符的合法性。如果会话标识符已经过期,则getSessionID方法返回一个新的会话标识符。
下面我们来看看getSessionID方法的工作过程。
String sessionId = request.getParameter("sessionId");
validSessionIdFound是一个标记,用于指示会话标识符是否合法。validSessionIdFound的初始值是false。
boolean validSessionIdFound = false;
long类型的now变量包含请求出现时的服务器时间。该变量用于确定用户会话的合法性。
long now = System.currentTimeMillis();
如果找到了会话标识符,则getSessionID方法检查它的合法性。检查过程如下:
一个合法的会话标识符必须有对应的同名文本文件。文件的最后修改时间加上timeOut应该大于当前时间。
如果存在与会话对应的文本文件,但文件已经过期,则原来的文件被删除。
把合法会话标识符所对应文本文件的最后修改日期改为now。
这些任务主要借助File对象完成,创建File对象的参数就是会话文本文件的路径:
if (sessionId!=null) {File f = new File(path + sessionId);if (f.exists()) {if (f.lastModified() + timeOut > now){// 会话合法// 使用setLastModified时,如果文件已经被其他程序锁定,// 程序不会产生任何异常,但文件数据不会改变f.setLastModified(now);validSessionIdFound = true;}else{// 会话已经过期// 删除文件f.delete(); }}//end if (f.exists) }//end if (sessionId!=null)
如果不存在合法的会话标识符,则getSessionID方法生成一个会话标识符以及相应的文本文件:
if (!validSessionIdFound) { sessionId = Long.toString(now); // 创建文件 File f = new File(path + sessionId); try {f.createNewFile(); }catch (IOException ioe) {}} // end of if !validSessionIdFound
程序保证文件名字随机性的方法非常简单:把当前的系统时间直接转换成会话标识符。对于那些涉及敏感数据的应用,我们应该考虑运用更安全的随机数生成器来生成会话标识符。
综上所述,getSessionID并不总是返回新的合法会话标识符:它返回的标识符可能与传递给它的标识符相同,也可能是新创建的会话标识符。
为了保证JSP页面拥有合法的会话标识符以便调用setValue、getValue方法,每个JSP页面都必须在开头位置调用getSesstionID方法
然后,我们用JSP的< jsp:useBean>标记告诉JSP容器程序要使用PseudoSessionBean:
< jsp:useBean id="PseudoSessionId" scope="application"class="pseudosession.PseudoSessionBean" />
在上面这个< jsp:useBean>标记中,class属性值是“包.类名字”形式。当然,对于不同的包名字,class属性的值应该作相应的修改。注意Bean的scope属性是“application”,这是因为我们要在应用的所有页面中使用这个Bean。在这个应用中,把Bean的scope属性设置为“application”具有最好的效率,因为我们只需创建Bean对象一次就可以了。另外,正如前面所提到的,getSessionID方法必须在所有其他代码之前调用。
< % String sessionId = PseudoSessionId.getSessionID(request);%>
为了说明PseudoSessionBean的应用,下面我们来看两个JSP页面,它们是index.jsp和secondPage.jsp。index.jsp页面在伪会话变量中保存用户的名字,而secondPage.jsp则提取这个用户名字。
index.jsp页面的代码如下:
< %@ page session="false" contentType="text/html;charset=gb2312" %>< jsp:useBean id="PseudoSessionId" scope="application"class="pseudosession.PseudoSessionBean" />< % String sessionId = PseudoSessionId.getSessionID(request);%>< html>< head>< title>伪会话< /title>< /head>< body>< h1>伪会话管理机制< /h1>< % String userName = "bulbul"; PseudoSessionId.setValue(sessionId, "userName", userName);%>< a href="/secondPage.jsp?sessionId=< ";%=sessionId%>>点击此处< /a>< form method="post" action=anotherPage.jsp?sessionId=< %=sessionId%>>输入数据:< input type="text" name="sample">< input type="submit" name="Submit" value="Submit">< /form>< /body>< /html>< % PseudoSessionId.deleteAllInvalidSessions();%>
注意,包括< form>标记的action属性在内,所有的超级链接都已经改写,现在都包含了会话标识符。另外也请注意页面的最后调用了deleteAllInvalidSessions方法。
secondPage.jsp页面只简单地返回以前保存的用户名字。
< %@ contentType="text/html;charset=gb2312" page session="false" %>< jsp:useBean id="PseudoSessionId" scope="application"class="pseudosession.PseudoSessionBean" />< % String sessionId = PseudoSessionId.getSessionID(request);%>< html>< head>< title>第2个页面< /title>< /head>< body>< % String userName = PseudoSessionId.getValue(sessionId,"userName");out.println("用户名字是 " + userName);%>< /body>< /html>
相关推荐
在IT行业中,Servlet和JSP(JavaServer Pages)是用于构建动态Web应用程序的关键技术,尤其在企业级应用开发中占据重要地位。孙鑫是一位知名的Java技术专家,他的作品常常深入浅出地解析复杂的编程概念。这个名为...
### Head First Servlet/JSP 2nd Edition:深入解析与学习指南 #### 一、书籍概述 《Head First Servlet/JSP 2nd Edition》是一本专为希望深入学习Servlet技术和Java Server Pages (JSP)的读者设计的专业教程。...
- **会话状态管理**: 理解如何在Servlet和JSP中管理用户的会话状态。 - **JSP语法概要**: 深入理解JSP指令、动作标签、表达式和脚本元素的使用。 - **官方参考**: 引导学习者查阅官方文档,获取最新和最权威的技术...
### JSP与Servlet技术解析 #### 一、概述 JSP (Java Server Pages) 是一种基于Java技术的服务器端脚本语言,它被用来创建动态网页。与传统的Servlet相比,JSP提供了更丰富的功能和更简便的方式来处理Web应用程序中...
这些项目不仅实现了Servlet和JSP的规范,还提供了丰富的功能,如会话管理、安全控制、URL重写等。通过查看和学习这些源码,开发者可以深入理解HTTP请求的处理流程、Servlet生命周期、JSP的编译过程等核心概念。 在...
Servlet会解析请求,执行必要的业务逻辑,然后将结果转发到相应的JSP页面或者直接生成响应返回给客户端。 网上书店系统的实现还涉及到数据库操作,通常使用JDBC(Java Database Connectivity)来连接和查询数据库。...
在开发基于JSP/Servlet/JavaBean的网上交易系统,如网上书店,这些技术的结合提供了构建高效、可扩展的Web应用程序的框架。这个系统的核心是实现购物车功能,这在电子商务网站中至关重要,因为它允许用户选择他们想...
【基于jsp/servlet/javabean网上订餐系统购物】是一个典型的Web应用开发案例,它采用MVC(Model-View-Controller)设计模式,这是一种广泛应用于Web应用程序架构的设计思想,旨在提高代码的可维护性和可扩展性。...
【标题】"考试系统--jsp/servlet/jdbc有数据库文件" 涉及到的核心技术是基于Java的Web开发,主要包括JSP(JavaServer Pages)、Servlet以及JDBC(Java Database Connectivity)。这个考试系统是一个用Java语言编写的...
### Servlet与JSP核心编程第二版5:关键技术与实践解析 #### 一、Servlet概述与核心技术 ##### 1.1 Servlet简介 Servlet 是 Java 平台的一种服务器端技术,用于扩展应用程序的功能。它是一个轻量级的应用程序组件...
5. **会话管理**:通过HttpSession对象实现用户会话跟踪,处理会话超时和会话失效问题。 6. **请求转发和重定向**:掌握这两种不同的请求处理方式,以及它们的区别。 7. **过滤器(Filter)**:利用Filter接口拦截...
- **便捷性**:Servlet 提供了一套丰富的 API 和工具方法,如自动解析 HTML 表单数据、读取和设置 HTTP 头、处理 Cookie、跟踪会话状态等,这些都极大地方便了开发者的工作。 - **强大的功能**:Servlet 能够与 Web...
Servlet和JSP(JavaServer Pages)是Java Web开发中的核心技术,用于构建动态Web应用程序。Servlet是一种Java编程接口,用于扩展服务器的功能,而JSP则是一种基于Java的动态网页技术,它将HTML、XML或其他标记语言与...
《Servlet和JSP学习指南》是由Budi Kurniawan编著的一本深入解析Servlet和JSP技术的专业书籍。这本书是IT从业者以及Web开发初学者理解这两种核心技术的重要资源。Servlet和JSP是Java Web开发中的核心组件,广泛用于...
【标题】"Servlet_Jsp_Login.rar" 是一个包含Java Servlet和JSP技术的登录系统实现。这个项目旨在演示如何将Servlet与JSP相结合,利用数据库处理用户登录验证,确保安全性并提供基本的用户身份验证功能。 【描述】...
在Java Web开发中,Servlet和JSP是两个关键的技术组件,它们被广泛用于构建动态、交互式的Web应用程序。本项目以"Servlet+jsp Java Web开发"为主题,采用经典的开发环境:MySQL数据库、Tomcat 6应用服务器、Eclipse...
Servlet+JSP与Spring+MVC是两种在Java Web开发中常见的技术栈,它们用于构建动态、交互式的Web应用程序。本指南将深入介绍这两种技术及其整合应用,通过配套的源码帮助初学者更好地理解概念和实践操作。 Servlet是...
9.2 java servlet api的会话跟踪 306 9.2.1 httpsession接口 306 9.2.2 session的生命周期 307 9.2.3 cookie的应用 319 9.2.4 httpsessionbindinglistener接口 328 9.2.5 在线人数统计程序 329 9.3 小结 335 ...
6. **Web容器**:为了运行JSP和Servlet,我们需要一个支持Java EE的Web容器,如Tomcat,它可以解析JSP页面并执行Servlet。 7. **项目结构**:ShopCart这个文件夹可能包含了JSP文件、Servlet类、配置文件(如web.xml...
Servlet和JSP是Java Web开发中的核心技术,它们在构建动态网站和Web应用程序中扮演着重要角色。本教程将深入解析这两个技术,帮助你理解和掌握它们的核心概念、工作原理以及实际应用。 Servlet是Java编程语言中用于...