2016-1-30 Servlet中Session管理(Sesssion追踪)
Session管理(Sesssion追踪)是Web应用程序开发中非常重要的一个主题。这是因为HTTP是无状态的,在默认情况下,Web服务器不知道一个HTTP请求是来自初次用户,还是来自之前已经访问过的用户。
应用程序应该记住哪些程序成功登陆。换句话说,它必须能够管理用户Session
保持状态的4中方法:网址重写(URL rewriting)、隐藏域、cookie、及HTTPSession对象。
2.1 网址重写
是一种Session追踪技术,需要将一个或多个token作为一个查询字符串添加到一个URL中。token的格式一般是 键=值:
url?key-1=value-1&key-2=value-2...&key-n=value-n
注意,URL和token之间要用一个问号(?)隔开,两个token之间则是用一个&符号隔开
如果token不必再过多的URL中四处携带,那么网址重写就比较合适。
但网址重写有如下缺点:
在有些Web浏览器中,URL限制为2000个字符。
仅当有链接要插入值时,值才能转换成后面的资源。此为,要把值添加到静态页面的链接中一般不容易。
网址重写必须在服务器端有效。所有的链接必须带有值。这样可能出现一个问题,即一个页面可能偶许多个链接。
某些字符,例如空格、&、及问号都必须进行编码。
添加到URL中的信息时明显可见的,这是情况有时候可不是我们所期待的。
由于以上限制,网址重写适用于那些即需要保持,有不跨太多页面,并且有不太重要的信息。
2.2 隐藏域
利用隐藏域来保持状态,与网址重写类似。但是它不将值添加到URL后面,而是将他们发到HTML表单的隐藏域中。
当用户提交表单时,隐藏域中的值也传送到服务器。只有当页面包含表单,或者可以在页面中添加表单时,才适合使用隐藏域。
这种技术胜过网址重写的地方在于,可以将更多的字符串传到服务器,而不需要进行字符编码。
但是也像网址重写一样,也只有当要传递的信息不需要跨越多个页面时,才适合这种技术。
2.3 Cookie
cookie是自动地在Web服务器和浏览器之间来回传递的一小块消息。cookie适用于那些需要跨越多个页面的信息。
由于cookie是作为HTTP标头切入的。因此传输它的过程有HTTP协议处理。除此之外,可以根据自己的需要设置Cookie的有效期。
每台Web服务器最多可以支持20个Cookie。
cookie的不足之处在于,用户可以通过修改浏览器设置来拒绝接受Cookie。
要使用Cookie,必须熟悉javax.servlet.http.Cookie类,以及HttpServletRequest和HttpServletResponse接口中的几个方法。
要创建cookie,传递一个名称和一个值给Cookie类的构造器。
Cookie cookie = new Cookie(name, value);
例如要创建一个选择语言的Cookie,可以这么写:
Cookie languageSelectCookie = new Cookie("language", "Italian");
创建了Cookie之后,可以设置它的domain、path、及maxAge属性。
为了将一个cookie发送到浏览器,需要在HttpServletResponse上调用add方法。
HttpServletResponse.add(cookie);
当浏览器再一次发出对同一个资源或者同一台服务器中不同资源的请求时,它会同时把从Web浏览器处收到的Cookie再传回去。
cookie也可以利用JavaScript在客户端进行创建和删除。(!!)
要访问浏览器发出的Cookie,可以在HttpServletRequest中使用getCookies方法。
该方法将返回一个Cookie数组,如果请求中没有Cookie,将返回null。为了找到某个名称的cookie,需要迭代数组。
没有getCookieByName方法可以是获取Cookie更简单一些。
也没有方法可以直接删除Cookie。为了删除Cookie,需要创建一个同名的Cookie,将他的maxAge属性设为0,并在HttpServletResponse中添加一个新的cookie。
2.4 HttpSession对象
所有的Session追踪中,HttpSession对象是最强大的,也是功能最多的。用户可以没有或者有一个HttpSession,并且只能访问自己的HttpSession对象。
HttpSession对象当一个用户在第一次访问某个网站时自动创建的。通过HttpServletRequest中调用的getSession方法,可以获取用户的HttpSession。getSession有两个重载方法:
HttpSession getSession()
HttpSession getSession(boolean create)
无参数的getSession方法返回当前的HttpSession,如果没有将创建一个并返回。
getSession(false)方法返回当前的HttpSession,如果没有HttpSession,将返回null
getSession(true)方法返回当前的HttpSession,如果没有HttpSession,将新建一个并返回。
getSession() 和 getSession(true)是一样的。
HttpSession的setAttribute方法将放一个值在HttpSession中,其方法签名如下:
void setAttribute(java.lang.String.name, java.lang.Object value)
注意与网址重写、隐藏域、cookie不同的是,放在HttpSession中的值是放在内存中的。因此你要确保将尽可能小的对象放在里面,并且数量不能太多。
总而言之,放在HttpSession中的内容要慎重。
添加到HttpSession中不一定是String,可以是任意java对象,只要它的类实现了java.io.Serializable接口就好,以便当Servlet容器认为有必要的时候,保存的对象可以序列化成一个文件或者保存到数据库中,
--例如容器的内存将要用完时,任然可以将非序列化的对象保存在HttpSession中,但是如果Servlet容器试图将其序列化时,将会抛出异常。
setAttribute方法要求不同的对象要有不同的名称。如果传递一个之前用过的属性名称,那么该名称将于旧值无关,而与新值有关。
通过在HttpSession中调用getAttribute方法,同时传递一个属性名称,可以获取HttpSession中保存的对象。
java.lang.Object getAttribute(java.lang.String name)
HttpSession中的另一个有用的方法是getAttributNames,它返回一个Enumeration,迭代一个HttpSession中的所有属性。
java.util.Enumeration<java.lang.String> getAttributeNames()
注意,HttpSession中保存的值不发送到客户端,这这与其他Session管理方法不同。而是Servlet容器为它所创建的每一个HttpSession生成一个唯一标识符,
并将这个标识符作为一个token发送给浏览器,一般是作为一个名为JSESSIONID的cookie,或者作为一个jsessionid参数添加到URL后面。在后续的请求中,浏览器会将这个token发送回服务器,使服务器能够知道是哪个用户在发送请求。无论Servlet容器选择用哪一种方法传输session标识符,那都是在后台自动完成的,不需要你做额外的处理工作。
通过在HttpSession中调用getId方法,可以获取HttpSession的标识符。
java.lang.String getId()
HttpSession中还定义了一个invalidate方法。这个方法强制Session过期,并将绑定到它的所有对象都解除绑定。在默认情况下,HttpSession是在用户静默一段时间后过期。可以在部署描述符的session-timeout中将session的期限设置为整个应用程序。
很多时候,还需要销毁未过期却没有用的HttpSession实例,以便释放一些内存空间。
可以调用getMaxInactiveInterval方法,以了解一个HttpSession在用户最后一次访问之后还可以维持多久。这个方法返回用户离开的秒数。
void setMaxIncativeInterval(int seconds)
如果向这个方法传递0,那么HttpSession将永远不会过期。