1.HttpSession接口简介
Session,即会话,是web开发中的一种会话状态跟踪技术。前面所述的Cookie也是一种会话跟踪技术。Cookie是将会话状态保存在客户端,而Session则是将会话状态保存在了服务器端。
何为会话?用户打开浏览器,从发出第一次请求开始,一直到最终关闭浏览器,就表示一次会话的完成。
2.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中没有数据。
3. 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对象的域属性进行读写操作。