快精灵印艺坊 您身边的文印专家
广州名片 深圳名片 会员卡 贵宾卡 印刷 设计教程
产品展示 在线订购 会员中心 产品模板 设计指南 在线编辑
 首页 名片设计   CorelDRAW   Illustrator   AuotoCAD   Painter   其他软件   Photoshop   Fireworks   Flash  

 » 彩色名片
 » PVC卡
 » 彩色磁性卡
 » 彩页/画册
 » 个性印务
 » 彩色不干胶
 » 明信片
   » 明信片
   » 彩色书签
   » 门挂
 » 其他产品与服务
   » 创业锦囊
   » 办公用品
     » 信封、信纸
     » 便签纸、斜面纸砖
     » 无碳复印纸
   » 海报
   » 大篇幅印刷
     » KT板
     » 海报
     » 横幅

会话状态

  10.1 会话状态概述

   HTTP协议的“无状态”(Stateless)特点带来了一系列的问题。特殊是通过在线商店购物时,服务器不能顺利地记住以前的事务就成了严峻的问题。它使得“购物篮”之类的应用很难实现:当我们把商品加入购物篮时,服务器如何才能知道篮子里原先有些什么?即使服务器保存了上下文信息,我们仍然会在电子商务应用中碰到问题。例如,当用户从选择商品的页面(由普通的服务器提供)转到输入信用卡号和送达地址的页面(由支持SSL的安全服务器提供),服务器如何才能记住用户买了些什么?

   这个问题一般有三种解决方式:

Cookie。利用HTTP Cookie来存储有关购物会话的信息,后继的各个连接可以查看当前会话,然后从服务器的某些地方提取有关该会话的完整信息。这是一种优秀的,也是应用最广泛的方式。然而,即使Servlet提供了一个高级的、使用方便的Cookie接口,仍然有一些繁琐的细节问题需要处理:
从其他Cookie中分别出保存会话标识的Cookie。
为Cookie设置合适的作废时间(例如,中断时间超过24小时的会话一般应重置)。
把会话标识和服务器端相应的信息关联起来。(实际保存的信息可能要远远超过保存到Cookie的信息,而且象信用卡号等敏感信息永远不应该用Cookie来保存。)
改写URL。你可以把一些标识会话的数据附加到每个URL的后面,服务器能够把该会话标识和它所保存的会话数据关联起来。这也是一个很好的方式,而且还有当浏览器不支持Cookie或用户已经禁用Cookie的情况下也有效这一长处。然而,大部分使用Cookie时所面临的问题同样存在,即服务器端的程序要进行许多简朴但单调冗长的处理。另外,还必须十分小心地保证每个URL后面都附加了必要的信息(包括非直接的,如通过Location给出的重定向URL)。假如用户结束会话之后又通过书签返回,则会话信息会丢失。
隐藏表单域。HTML表单中可以包含下面这样的输入域:<INPUT TYPE="HIDDEN" NAME="session" VALUE="...">。这意味着,当表单被提交时,隐藏域的名字和数据也被包含到GET或POST数据里,我们可以利用这一机制来维持会话信息。然而,这种方式有一个很大的缺点,它要求所有页面都是动态生成的,因为整个问题的核心就是每个会话都要有一个唯一标识符。
   Servlet为我们提供了一种与众不同的方案:HttpSession API。HttpSession API是一个基于Cookie或者URL改写机制的高级会话状态跟踪接口:假如浏览器支持Cookie,则使用Cookie;假如浏览器不支持 Cookie或者Cookie功能被关闭,则自动使用URL改写方式。Servlet开发者无需关心细节问题,也无需直接处理Cookie或附加到URL 后面的信息,API自动为Servlet开发者提供一个可以方便地存储会话信息的地方。

   10.2 会话状态跟踪API

   在Servlet中使用会话信息是相称简朴的,主要的操作包括:查看和当前哀求关联的会话对象,必要的时候创建新的会话对象,查看与某个会话相关的信息,在会话对象中保存信息,以及会话完成或中止时释放会话对象。

   10.2.1 查看当前哀求的会话对象

  查看当前哀求的会话对象通过调用HttpServletRequest的getSession方式实现。假如getSession方式返回null,你可以创建一个新的会话对象。但更常常地,我们通过指定参数使得不存在现成的会话时自动创建一个会话对象,即指定getSession的参数为true。因此,访问当前哀求会话对象的第一个步骤通常如下所示:
HttpSession session = request.getSession(true);



   10.2.2 查看和会话有关的信息

   HttpSession对象生存在服务器上,通过Cookie或者URL这类后台机制自动关联到哀求的发送者。会话对象提供一个内建的数据结构,在这个结构中可以保存任意数量的键-值对。在2.1或者更早版本的Servlet API中,查看以前保存的数据使用的是getValue("key")方式。getValue返回Object,因此你必须把它转变成更加详细的数据类型。假如参数中指定的键不存在,getValue返回null。

   API 2.2版推荐用getAttribute来代替getValue,这不仅是因为getAttribute和setAttribute的名字更加匹配(和 getValue匹配的是putValue,而不是setValue),同时也因为setAttribute答应使用一个附属的 HttpSessionBindingListener 来监视数值,而putValue则不能。

   但是,由于目前还只有很少的商业Servlet引擎支持2.2,下面的例子中我们仍然使用getValue。这是一个很典型的例子,假定ShoppingCart是一个保存已购买商品信息的类:
HttpSession session = request.getSession(true);
ShoppingCart previousItems =
(ShoppingCart)session.getValue("previousItems");
if (previousItems != null) {
doSomethingWith(previousItems);
} else {
previousItems = new ShoppingCart(...);
doSomethingElseWith(previousItems);
}



  大多数时候我们都是根据特定的名字寻找与它关联的值,但也可以调用getValueNames得到所有属性的名字。getValuesNames返回的是一个String数组。API 2.2版推荐使用getAttributeNames,这不仅是因为其名字更好,而且因为它返回的是一个Enumeration,和其他方式(比如 HttpServletRequest的getHeaders和getParameterNames)更加一致。

   虽然开发者最为关心的往往是保存到会话对象的数据,但还有其他一些信息有时也很有用。

getID:该方式返回会话的唯一标识。有时该标识被作为键-值对中的键使用,比如会话中只保存一个值时,或保存上一次会话信息时。
isNew:假如客户(浏览器)还没有绑定到会话则返回true,通常意味着该会话刚刚创建,而不是引用自客户端的哀求。对于早就存在的会话,返回值为false。
getCreationTime:该方式返回建立会话的以毫秒计的时间,从1970.01.01(GMT)算起。要得到用于打印输出的时间值,可以把该值传递给Date构造函数,或者GregorianCalendar的setTimeInMillis方式。
getLastAccessedTime:该方式返回客户最后一次发送哀求的以毫秒计的时间,从1970.01.01(GMT)算起。
getMaxInactiveInterval:返回以秒计的最大时间间隔,假如客户哀求之间的间隔不超过该值,Servlet引擎将保持会话有效。负数表示会话永远不会超时。
   10.2.3 在会话对象中保存数据

  如上节所述,读取保存在会话中的信息使用的是getValue方式(或,对于2.2版的Servlet规范,使用getAttribute)。保存数据使用putValue(或setAttribute)方式,并指定键和相应的值。注重putValue将替换任何已有的值。有时候这正是我们所需要的(如下例中的referringPage),但有时我们却需要提取原来的值并扩充它(如下例previousItems)。示例代码如下:
HttpSession session = request.getSession(true);
session.putValue("referringPage", request.getHeader("Referer"));
ShoppingCart previousItems =
(ShoppingCart)session.getValue("previousItems");
if (previousItems == null) {
previousItems = new ShoppingCart(...);
}
String itemID = request.getParameter("itemID");
previousItems.addEntry(Catalog.getEntry(itemID));

session.putValue("previousItems", previousItems);



   10.3 实例:显示会话信息

   下面这个例子生成一个Web页面,并在该页面中显示有关当前会话的信息。
package hall;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.net.*;
import java.util.*;

public class ShowSession extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession(true);
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Searching the Web";
String heading;
Integer accessCount = new Integer(0);;
if (session.isNew()) {
heading = "Welcome, Newcomer";
} else {
heading = "Welcome Back";
Integer oldAccessCount =
// 在Servlet API 2.2中使用getAttribute而不是getValue
(Integer)session.getValue("accessCount");
if (oldAccessCount != null) {
accessCount =
new Integer(oldAccessCount.intValue() + 1);
}
}
// 在Servlet API 2.2中使用putAttribute
session.putValue("accessCount", accessCount);

out.println(ServletUtilities.headWithTitle(title) +
"<BODY BGCOLOR="#FDF5E6">n" +
"<H1 ALIGN="CENTER">" + heading + "</H1>n" +
"<H2>Information on Your Session:</H2>n" +
"<TABLE BORDER=1 ALIGN=CENTER>n" +
"<TR BGCOLOR="#FFAD00">n" +
" <TH>Info Type<TH>Valuen" +
"<TR>n" +
" <TD>IDn" +
" <TD>" + session.getId() + "n" +
"<TR>n" +
" <TD>Creation Timen" +
" <TD>" + new Date(session.getCreationTime()) + "n" +
"<TR>n" +
" <TD>Time of Last Accessn" +
" <TD>" + new Date(session.getLastAccessedTime()) + "n" +
"<TR>n" +
" <TD>Number of Previous Accessesn" +
" <TD>" + accessCount + "n" +
"</TABLE>n" +
"</BODY></HTML>");
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
返回类别: 教程
上一教程: JSP教程(一)
下一教程: JSP+XML构架网站的实例

您可以阅读与"会话状态"相关的教程:
· 十、会话状态
· EJB之无状态会话Bean简朴应用-学习与实践
· 七、HTTP应答状态
· HTTP应答状态
· Java 理论与实践: Web 层的状态复制
    微笑服务 优质保证 索取样品