除了使用Cookie,Web应用程序中还经常使用Session来记录客户端状态。Session是服务器端使用的一种记录客户端状态的机制,相应地也增加了服务器的存储压力。
1. 什么是Session
Session是另外一种记录客户端状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。Session是一种连接状态变量,客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要客户档案表就可以了。
2. Session的使用
Session对应的类为javax.servlet.http.HttpSession类。每个来访者对应一个Session对象,所有该客户的状态信息都保存在这个Session对象里。Session是在客户端第一次请求服务器的时候创建的。Session也只有key-value的属性对,Session是一种集合型变量,可以存储多个key-value类型值对,key为字符串类型,value可以为任何对象类型。
通过getAttribute(String key)和setAttribute(String key,Object value)方法读写客户状态信息。Servlet通过request.getSession()方法获取该客户的Session。
当多个客户端执行程序时,服务器会保存多个客户端的Session。获取Session的时候也不需要声明获取谁的Session。Session机制决定了当前客户只会获取到自己的Session,而不会获取到别人的Session。各客户的Session也彼此独立,互不可见。
Session的使用比Cookie方便,但是过多的Session存储在服务器内存中,会对服务器造成压力。
3. Session的生命周期和有效期
Session保存在服务器端,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。如果Session内容过于复杂,当大量客户访问服务器时就可能会导致内存溢出,因此,Session里的信息应该尽量精简。
Session在用户第一次访问服务器时自动创建。需要注意的是,只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session。如果尚未生成Session,也可以使用request.getSession(true)强制生成Session。
Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户访问服务器一次,无论是否读写Session,服务器都认为该用户的Session活跃了一次。
由于有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把一段时间内没有活跃的Session从内存中删除。这段时间就是Session的超时时间。如果超过了超时时间没有访问过服务器,Session就自动失效了。
Session的超时时间为maxInactiveInterval属性,可以通过对应的getMaxInactiveInterval()获取,通过setMaxInactiveInterval(long interval)修改。
Session的超时时间也可以在web.xml中修改。另外,通过调用Session的invalidate()方法也可以使Session失效。
Tomcat中Session的默认超时时间为30分钟。通过setMaxInactiveInterval(int seconds)修改超时时间。
可以修改web.xml改变Session的默认超时时间。例如修改为60分钟。
web.xml文件存放路径在Tomcat目录的conf文件夹中。
<session-config>
<session-timeout>60</session-timeout>
</session-config>
web.xml中超时时间的单位为分钟,而setMaxInactiveInterval单位为秒。
下面通过例子来说明HttpSession的使用
首先创建一个Servlet,Session01继承自HttpServlet
//获取Session对象
HttpSession session=request.getSession();
//获取Session的会话标识符
String id=session.getId();
System.out.println(id);
//获取Session的创建时间
System.out.println(session.getCreationTime());
//获取最后一次访问时间
System.out.println(session.getLastAccessedTime());
//判断是否是新的session对象
System.out.println(session.isNew());
当获取Session对象时,会判断Session对象是否存在,存在就获取,没有就创建
IsNew()是true是新的对象,否则不是新的对象。
Session既然是为了标识一次会话,那么此次会话就应该有一个唯一的标志,这个标志就是SessionId。
每当一次请求到达服务器,如果开启了会话(访问了Session),服务器第一步会查看是否从客户端回传一个名为JSESSIONID的cookie,如果没有则认为这是一次新的会话,会创建一个新的session对象,并用唯一定的sessionId为此次会话做一个标志。如果有JSESSIONID这个cookie回传,服务器则会根据JSESSIONID这个值去查看是否含有id为JSESSIONID的session对象,如果没有则认为是一个新的会话,重新创建一个新的session对象,并标志此次会话;如果找到了相应的session对象,则认为是之前标志过的一次会话,返回该session对象,数据达到共享。
这里提到一个叫做JSESSIONID的cookie,这是一个比较特殊的cookie,当用户请求服务器时,如果访问了session,则服务器会创建一个名为JSESSIONID,值为获取到的session的sessionid的cookie对象,并添加到response对象中,响应给客户端,有效时间为关闭浏览器。
所以Session的底层依赖Cookie来实现。
Session域对象
Session用来标识一次会话,在一次会话中数据是可以共享的,这时Session作为域对象存在,可以通过setAttribute(name,value)方法向域对象中添加数据,通过getAttribute(name)从域对象中获取数据,通过removeAttribute(name)从域对象中移除数据。
下面重新创建一个Servlet来讲解Session的域对象。
创建一个Session02类,继承自HttpServlet。
setAttribute设置Session域对象
removeAttribute移除Session域对象
//获取Session对象
HttpSession session=request.getSession();
//设置Session域对象
session.setAttribute("uname","admin");
session.setAttribute("upwd","123456");
//移除Session对象
session.removeAttribute("upwd");
//设置request域对象
request.setAttribute("name","request_name");
//请求转发到JSP页面
request.getRequestDispatcher("index.jsp").forward(request,response);
然后创建一个Index.jsp页面来接收这些Session域对象和Request域对象
请求转发是一次请求,request作用域有效,session作用域有效
但是在该版本的Idea中out.print方法无法解析
点击Idea菜单中的文件→项目结构
点击项目结构后的界面展示如下图所示
选择选项卡中的“依赖”选项卡,然后点击项目结构中的“加号”
点击“加号”后的界面展示如下图所示,选择“库”
然后选中Tomcat 8.5.99,然后点击“添加所选项”按钮
然后红色的提示就会消失。
启动该web程序
然后使用URL地址 http://localhost:8080/s001/ser02
界面结果如下图所示
其中uname和upwd是Session域对象,但是upwd在设置后被移除了。name是Request域对象,请求转发到JSP后都可以获取到。
然后把请求转发的代码改为重定向的代码,代码示例如下图所示
重定向是两次请求,session还可以获取,request不能获取
再次重启该Web应用,再次访问ser02,结果如下图所