Session,即会话,是web开发中的一种会话状态跟踪技术。前面所述的Cookie也是一种会话跟踪技术。Cookie是将会话状态保存在客户端,而Session则是将会话状态保存在了服务器端。 何为会话?用户打开浏览器,从发出第一次请求开始,一直到最终关闭浏览器,就表示一次会话的完成。
先看request的域属性: 在SessionDemo1中设置request域对象,然后再在OtherServlet类中取出域对象的值,看是否能取到。
import java.io.IOException; @javax.servlet.annotation.WebServlet("/SessionDemo1") public class SessionDemo1 extends javax.servlet.http.HttpServlet { protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { //获取用户提交参数 String username = request.getParameter("username"); //将参数放在request域 request.setAttribute("user",username); response.getWriter().print("SessionDemo1:"+username); } protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { this.doPost(request, response); } } import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/OtherServlet") public class OtherServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //从request域中读取user属性 Object user = request.getAttribute("user"); response.getWriter().print(user); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }可以看到,request对象代表一次请求,request域属性只能在同一次请求之间传递数据,所以两个不同的请求之间是无法传递数据。如果想要传递数据需要使用请求转发与重定向。
再来看Session域属性的设置:
先访问SessionDemo2可以看到Session=null 先访问SessionDemo1,再访问SessionDemo2,可以看到Session有值 并且在Request域中取不出request域中的值 Session域中恶意取出request域中的值 总结: 对于request对象作用于一次请求之间 对于session对象作用于一次会话之间 多次请求转发都共用一个Session对象。
对于request的getSession()的用法: 如果要向Session中写入数据,则需要使用getSession(true),即getSession()方法 存在Session对象就直接使用,没有Session对象就创建新的。 如果要向Session中读取数据,则需要使用getSession(false)方法 存在Session对象就直接使用,没有Session对象就返回null。因为只有已存在的session中国才有数据,新的session中没有数据。
在服务器中系统会为每个会话维护一个Session。不同的对话对应不同的session。那么系统时如何识别各个session对象的?即如何做到同一会话过程中,一直使用的是同一个Sesison对象呢?
SessionDemo1文件:
package Session域属性; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; import java.io.PrintWriter; @WebServlet("/SessionDemo1") public class SessionDemo1 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取用户提交参数 String username = request.getParameter("username"); //将参数放在request域 request.setAttribute("user",username); //获取Session对象 HttpSession session = request.getSession(); //向Session域中写入值 session.setAttribute("username",username); PrintWriter out = response.getWriter(); out.println("username="+username); out.println("session="+session); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }SessionDemo2文件:
package Session域属性; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; import java.io.PrintWriter; @WebServlet("/SessionDemo2") public class SessionDemo2 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //从request域中读取user属性 Object user = request.getAttribute("user"); //获取Session,必须写成false,因为一旦为true,就会重新创建session,此时session里面并没存值 HttpSession session = request.getSession(false); //从Session中读取指定属性 Object username=null; if(session!=null){ username = session.getAttribute("username"); } PrintWriter out = response.getWriter(); out.println("SessionDemo2:user="+user); out.println("SessionDemo2:username="+username); out.println("Session="+session); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }在火狐浏览器中: 可以看到两个Session对象相同 在SessionDemo2中可以获取SessionDemo1中设置的域属性的值 在谷歌浏览器中: 可以看到两个Session对象相同,但是火狐浏览器的session对象和谷歌浏览器的session对象不同。 在SessionDemo2中可以获取SessionDemo1中设置的域属性的值 既然谷歌浏览器和火狐浏览器的session对象不同,那么如何保证不错呢?
写入Session列表: 服务器对当前应用中的Session是以Map的形式进行管理的,这个Map称为Session列表 该Map的Key是一个32长度的随机串,这个随机串称为JSESSIONID,value为Session对象的引用。 当用户第一次提交请求时,服务端Servlet中执行到request.getSession()方法后,会自动生成一个Map.Entry对象,key为根据某种算法生成的JSESISONID,value为新创建的Httpsession对象。
服务器生成并发送Cookie 在将Session信息写入Session列表后,系统会自动将JSESSIONID作为name,32长度的随机字符串作为value,以Cookie的形式放在响应头中,并随着响应,将该cookie发送到 客户端。
客户端接收并发送Cookie 客户端收到Cookie后会将其存放到Cookie的缓存中。即,只要客户端浏览器不关闭,浏览器缓存中的Cookie就不会消失。 当用户提交第二次请求时,会将缓存中的这个Cookie伴随着请求的头信息,一块发给服务端。
从Session列表中查找 服务端从请求中读取到客户端发送过来的Cookie,并根据Cookie的JSESSIONID的值,从Map中查找响应Key对应的value,即Session对象。然后对该Session对象的域属性进行读写操作。