在所有的Session追踪技术中,HttpSession对象是最强大的,也是功能最多的。用户可以没有或者有一个HttpSession,并且只能访问他/她自己的HttpSession。HttpSession是当一个用户第一次访问某个网站时自动创建的。通过在HttpServlet-Request中调用getSession方法,可以获取用户的HttpSession。getSession有两个重载方法:
无参的getSession方法返回当前的HttpSession,如果当前没有,则创建一个并返回。getSession(false)方法返回当前的HttpSession(若有),如果没有,则返回null。getSession(true)方法返回当前的HttpSession(若有),如果没有,则新建一个并返回。getSession(true)和getSession()是一样的。HttpSession的setAttribute方法将一个值放在HttpSession中,其方法签名如下:
注意,与网址重写、隐藏域和cookie不同的地方在于,放在HttpSession中的值是保存在内存中的。因此,你只能将尽可能小的对象放在里面,并且数量不能太多。即使现代的Servlet容器可以在内存将满时将HttpSession中的对象移到辅助存储设备中,但是这样会影响性能。因此,对于保存在HttpSession里面的内容一定要慎重。添加到HttpSession中的值不一定是String,可以为任意Java对象,只要它的类实现了java.io.Serializable接口即可,以便当Servlet容器认为有必要的时候,保存的对象可以序列化成一个文件或者保存到数据库中,例如,当容器的内存快要用完的时候。仍然可以将非序列化的对象保存在HttpSession中,但是如果Servlet容器试图将它们序列化,将会以失败告终,并抛出异常。setAttribute方法要求不同的对象要有不同的名称。如果传递一个之前用过的属性名称,那么该名称将与旧值无关联,而与新值相关联了。通过在HttpSession中调用getAttribute方法,同时传递一个属性名称,可以获取HttpSession中保存的对象。这个方法的签名如下:
HttpSession中另一个有用的方法是getAttributeNames,它返回一个Enumeration,迭代一个HttpSession中的所有属性:
注意,HttpSession中保存的值不发送到客户端,这与其他的Session管理方法不同。而是Servlet容器为它所创建的每一个HttpSession生成一个唯一标识符,并将这个标识符作为一个token发送给浏览器,一般是作为一个名为JSESSIONID的cookie,或者作为一个jsessionid参数添加到URL后面。在后续的请求中,浏览器会将这个token发送回服务器,使服务器能够知道是哪个用户在发出请求。无论Servlet容器选择用哪一种方式传输session标识符,那都是在后台自动完成的,不需要你去做额外的处理工作。通过在HttpSession中调用getId方法,可以获取HttpSession的标识符。
HttpSession中还定义了一个invalidate方法。这个方法强制Session过期,并将绑定到它的所有对象都解除绑定。在默认情况下,HttpSession是在用户静默一定时间之后过期。可以在部署描述符的session-timeout元素中将session的期限设置为整个应用程序(详情查看第16章的内容)。例如,将这个值设为30,使所有session对象在用户最后一次访问之后30分钟过期。如果没有配置这个元素,这个期限将由Servlet容器决定。很多时候,还需要销毁未过期却又没用的HttpSession实例,以便释放一些内存空间。可以调用getMaxInactiveInterval方法,以了解一个HttpSession在用户最后一次访问之后还可以维持多久。这个方法返回用户离开的秒数。setMaxInactiveInterval方法可以帮助你为个别HttpSession的Session期限设置一个不同的值。
如果向这个方法传递0,那么HttpSession将永远不会过期。一般来说,这不是一种好办法,因为HttpSession占用的堆(heap)空间将永远不会释放,直到应用程序卸载或Servlet容器关闭为止。举个例子,请看代码清单2-9中的ShoppingCartServlet类。这个Servlet实现了一个小型的在线商店,里面有4种商品。它允许用户将商品添加到购物车中,并浏览它的内容。Servlet利用代码清单2-7中的Product类和代码清单2-8中的ShoppingItem类。Product定义了4个属性(id、name、description及price),ShoppingItem则包含一个quantity和一个Product。
ShoppingCartServlet Servlet映射为以下这些URL模式:/products。展示所有商品。/viewProductDetails。展示某件商品的详细描述。/addToCart。将一件商品添加到购物车中。/viewCart。展示购物车的内容。除/addToCart之外的所有URL都要调用ShoppingCartServlet的doGet方法。doGet首先查看请求的URI,并生成相应的内容:
下列URL是调用应用程序的主页面:
访问这个URL将会执行doGet方法,然后将一个商品清单发送到浏览器(如图2-9所示)。如果单击Details链接,doGet就会显示出被选商品的详细说明,如图2-10所示。注意输入域和Buy按钮了吗?要添加商品时,可以在输入域中输入一个数字,并单击Buy(立即购买)按钮。
在Product Details页面中提交Buy表单,将会调用ShoppingCartServlet的doPost方法。正是这个时候往用户的HttpSession中添加了一件商品。doPost方法首先根据用户输入的数量和被选商品的标识符构造一个ShoppingItem:
之后,它获取当前用户的HttpSession,查看其中是否已经包含一个与属性名称“cart”相关的List:
如果找到List,将会用它添加ShoppingItem。如果没有找到List,则会创建一个,再添加到HttpSession中。
最终,把ShoppingItem添加到了列表中。
当用户单击View Cart链接查看购物车的内容时,会再次调用doGet方法,并调用showCart方法。后者获取当前用户的HttpSession,并调用它的getAttribute方法,获得购物清单:
之后,它迭代List,并将每件商品的内容发送给浏览器:
相关资源:七夕情人节表白HTML源码(两款)