Session对象的原理在于,服务器可以为客户端创建并维护一个所谓的Session对象,用于存放数据。在创建Session对象的同时,服务器将会为该Session对象产生一个唯一编号,这个编号称之为SessionID,服务器以Cookie的方式将SessionID存放在客户端。当浏览器再次访问该服务器时,会将SessionID作为Cookie信息带到服务器,服务器可以通过该SessionID检索到以前的Session对象,并对其进行访问。需要注意的是,此时的Cookie中仅仅保存了一个SessionID,而相对较多的会话数据保存在服务器端对应的Session对象中,由服务器来统一维护,这样一定程度保证了会话数据安全性,但增加了服务器端的内存开销。
存放在客户端的用于保存SessionID的Cookie会在浏览器关闭时清除。我们把用户打开一个浏览器访问某个应用开始,到关闭浏览器为止交互过程称为一个“会话”。在一个“会话”过程中,可能会向同一个应用发出了多次请求,这些请求将共享一个Session对象,因为这些请求携带了相同的SessionID信息。
1. java Servlet实现Session
java Servlet用来演示Session的工作原理代码1:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String option = request.getParameter("option");
if ("create".equals(option)) {
//获得HttpSession对象
HttpSession session = request.getSession();
//设置Session对象的最长不活动间隔
session.setMaxInactiveInterval(30);
//获取Session中的数据
List list = (List) session.getAttribute("list");
if (list == null) {
list = new ArrayList();
list.add("hey");
//向Session中添加数据
session.setAttribute("list", list);
} else {
list.add("hey");
}
out.println(list);
}elseif ("invalidate".equals(option)) {
HttpSession session = request.getSession(false);
if (session != null) {
//使Session对象失效
session.invalidate();
}
}
该servlet的url-pattern为/testsession。
当浏览器请求地址“.../tst/testSession?option=create”时,Servlet调用request的getSession方法获得Session对象,如果此时服务器端存在与请求信息中SessionID(作为Cookie信息携带)对应的Session对象,则返回这个Session对象,否则将会创建一个新的Session对象并将其产生的SessionID以Cookie的形式通过响应信息送回。注意,Session对象的setMaxInactiveInterval方法用于设置最长不活动间隔,单位是秒,如果出现在这个的时间段内Session对象没有被存取,则该Session对象将会失效。通常为了保证服务器的性能和出于安全性考虑,这个值要妥善的设置(Tomcat针对Session的MaxInactiveInterval会有默认的设置)。若setMaxInactiveInterval设置为负值,则表示该Session永不过期。另外,Session对象分别通过setAttribute和getAttribute方法存取数据,数据以“名称-对象”对的形式存放。该请求对应的请求和响应的HTTP信息为:
请求:
GET /tst/testSession?option=create HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/x-silverlight, **
Accept-Language: zh-cn
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
Host: 192.168.5.100:8080
Connection: Keep-Alive
Cookie: JSESSIONID=C69B3053C575ECC8C7FCAF7D189A4FD1
响应
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 12
Date: Sun, 29 Jun 2008 07:20:41 GMT
[hey, hey]
注意:请求信息中携带的SessionID值与上一次相应的SessionID之一致。另外响应输出的HTML文本中有两个“hey”,这是因为这次请求Servlet往存放在Session中的list对象中又放置了一个String对象。
当浏览器请求“.../tst/testSession?option=invalidate”时,Servlet会调用Session对象的invalidate方法用于使该Session对象失效。需要注意的是,此时获取Session对象的方法为重载的getSession(boolean b)其中boolean类型的参数表示当前请求没有和服务器端的某个Session对象关联时是创建新的Session(参数为true时)还是返回null(参数为false时)。
java Servlet用来演示Session的工作原理代码2:
下面例子演示如何在HttpServlet中存取Session。 Session实例可以通过HttpServletRequest的getSession()方法获得,此方法会返回一个布尔值来表示是否成功得到了Session。然后我们尝试获得键名为“VisitCounter”的session值,然后将获得的值转换为Integer对象。 如果是空则说明session还没有设置,就往session中添加VisitCounter。 否认则对VisitCounter+1并保存到session中。
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class ExampleServlet extends HttpServlet {
/** Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
* @param request servlet request
* @param response servlet response
*/
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
printPageStart(out);
//Obtain the session object, create a new session if doesn't exist
HttpSession session = request.getSession(true);
//Check if our session variable is set, if so, get the session variable value
//which is an Integer object, and add one to the value.
//If the value is not set, create an Integer object with the default value 1.
//Add the variable to the session overwriting any possible present values.
Integer param = (Integer) session.getAttribute("MySessionVariable");
if (param != null) {
session.setAttribute("MySessionVariable", new Integer(param.intValue() + 1));
param = (Integer) session.getAttribute("MySessionVariable");
} else {
param = new Integer(1);
session.setAttribute("MySessionVariable", param);
}
out.println("You have displayed this page <b>" + param.intValue() + "</b> times this session.<br/><br/>");
out.println("Hit the browsers refresh button.");
printPageEnd(out);
}
/** Prints out the start of the html page
* @param out the PrintWriter object
*/
private void printPageStart(PrintWriter out) {
out.println("<html>");
out.println("<head>");
out.println("<title>Example Servlet of how to store and retrieve session variables</title>");
out.println("</head>");
out.println("<body>");
}
/** Prints out the end of the html page
* @param out the PrintWriter object
*/
private void printPageEnd(PrintWriter out) {
out.println("</body>");
out.println("</html>");
out.close();
}
}
2、java servlet URL重写
从上面的介绍可以看出,Session对象的正常使用要依赖于Cookie。如果考虑到客户端浏览器可能出于安全的考虑禁用了Cookie,应该使用URL重写的方式使Session在客户端禁用Cookie的情况下继续生效。
下面有两个jsp页面:1.jsp中向session对象中存入了名为“hi”的一个string类型对象。通过超级链接可以链接到2.jsp,在2.jsp中将获取session中名为“hi”的对象,并显示在页面上。需要注意的是:在1.jsp中超级链接的地址并不是直接写了“2.jsp”而是通过resopnse的encodeURL方法对这个地址进行了处理。
1.jsp
<%
session.setAttribute("hi","Do you work or are you a student?");
%>
<a href="/article/<%=response.encodeURL("/article/2.html")%>">2.jsp</a>
2.jsp
<%=session.getAttribute("hi")%>
首先将浏览器的Cookie禁用(注意要重启IE),然后请求1.jsp,响应后点击链接到2.jsp,这个交互过程涉及到两次请求和相应,HTTP信息如下:
请求1.jsp
GET /tst/session/1.jsp HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/x-silverlight, **
Referer: http://192.168.5.100:8080/tst/session/1.jsp
Accept-Language: zh-cn
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
Host: 192.168.5.100:8080
Connection: Keep-Alive
响应:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 33
Date: Sun, 29 Jun 2008 07:31:36 GMT
Do you work or are you a student?
注意:由于Cookie的禁用,这次请求协议头中虽然没有携带SessionID的信息,但SessionID的信息作为请求地址的一部分传到了服务器端,这就是URL重写的意义所在。
response的encodeURL方法将根据浏览器是否不支持Cookie决定是否将SessionID信息写入链接地址。