介绍完了cookie,不得不介绍我们的HttpSession接口
一.介绍
1)HttpSession接口来自于Servlet规范下一个接口。存在于Tomcat中servlet-api.jar,其实现类由Http服务器提供。Tomcat提供实现类存在于servlet-api.jar
2)如果两个Servlet来自于同一个网站,并且为同一个浏览器/用户提供服务,此时便可以借助于HttpSession对象进行数据共享。
3)开发人员习惯于将HttpSession接口修饰对象称为【会话作用域对象】
二.HttpSession 与 Cookie 区别:【面试题】
(1)存储位置: 一个在天上,一个在地下
Cookie: 存放在客户端计算机(浏览器内存/硬盘)
HttpSession:存放在服务端计算机内存
(2)数据类型
Cookie对象存储共享数据类型只能是String
HttpSession对象可以存储任意类型的共享数据Object
(3) 数据数量
一个Cookie对象只能存储一个共享数据,所以这也是为什么当我们去创建Cookie类型的变量的时候,变量名必须不一样。
HttpSession是使用map集合存储共享数据,所以可以存储任意数量共享数据,所以只需要使用会话域对象调用setAttribute方法即可。
(4)参照物
Cookie相当于客户在服务端【会员卡】
HttpSession相当于客户在服务端【私人保险柜】,放的比cookie多
三.代码实现
此处我们还是拿OneServelet和TwoServlet来举例:
同一个网站(myWeb)下OneServlet将数据传递给TwoServlet
首先在OneServlet中将数据存入到我们的session中
public class OneServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) { //1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜 HttpSession session = request.getSession(); //2.将数据添加到用户私人储物柜 session.setAttribute("key1", 10); } }
浏览器访问/myWeb中T的woServlet,在TwoServlet中编写代码来获取我们的数据。
public class TwoServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) { //1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜 HttpSession session = request.getSession(); //2.从会话作用域对象得到OneServlet提供的共享数据 Integer num = session.getAttribute("key1"); System.out.println("获取到的共享数据值为="+num); } }
当然假如我们的用户在获取共享数据的时候不想去使用包装类强转,想使用我们的基本数据类型强转也可以,此时就需要用到一个方法叫做getAttributeNames方法,这个方法可以获取到我们session中使用map集合存储共享数据时的key值,下面来看具体的代码实现吧:此处只需要重写我们TwoServlet中的代码即可。
public class TwoServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.调用请求对象向Tomcat索要当前用户在服务端的私人储物柜 HttpSession session = req.getSession(); //2.从会话作用域对象得到OneServlet提供的共享数据 Enumeration keynames=session.getAttributeNames(); while(keynames.hasMoreElements()){ //获取到map集合中的每一个key值 String eachkeyname=(String)keynames.nextElement(); int eachvalue=(int)session.getAttribute("key1"); System.out.println("key值为"+eachkeyname+"value值为"+eachvalue); } } }
注意事项:
1:当我们使用getAttributeNames获取我们存入到map集合中的所有数据的时候,这个方法的返回值是一个枚举对象,所以需要将我们所获取的所有key值赋给我们的枚举对象。
2:当获取到所有的key值时,下一步需要使用while循环来遍历我们的枚举对象,方法为hasMoreElements()。
3:循环内部首先需要获取每一个具体的key值,那么就需要使用我们的nextElements()方法来获取,注意nextElements()方法的返回值为Object,所以此处涉及到我们的强转,假设之前我们的key值类型为String,那么此处的强转类型便为String.
4:当获取到我们的key值后,此时就需要获取我们的value值,获取方式还是使用我们的Httpsession对象的属性getAttribute方法,getAttribute方法的返回值仍为Object,所以此时获取我们的value值时仍然涉及到我们的强转,因为在OneServlet中我们存储的时候的value值为整形,所以此处的强转类型为int即可。
🆗,说到这里,一个问题戛然而生,之前我们在使用getAttribute方法获取整形类型的共享数据的时候,我们的强转类型为Integer,为什么当我们使用getAttributeNames方法后,此处当我们获取到我们的整型类型的共享数据的时候,我们的强转类型就变为了int呢?
首先先来看之前我们没有使用getAttributeNames的时候,此时假如用户给我们的key1赋了一个null值,然后在另一端接收的时候用户并不知道这个数据是否为null,假如此时不使用包装类进行强转,使用基本类型去进行强转,就会发生空指针异常,因为基本数据的默认值例如int为0,而其包装类Integer的话默认值为null,所以此时使用int进行强转的话,就相当于将null赋值给基本数据类型int,那么就会发生空指针异常,但是包装类就不会发生,因为其是可以存储null的。
一般在实际开发中我们都会拿包装类来进行传参,因为是可以进行
当我们使用getAttributeNames后,此时就相当于一个一个的从Map集合中将key值取出来,此时的key值都是有明确的value值与之对应的,所以不会发生空指针异常,那么即使在获取整形的value值时使用了基本数据类型进行强转也不会发生任何异常。
四.Http服务器如何将用户与HttpSession关联起来?
答案当然是使用cookie来进行连接,下面我们来看一张图来进行理解:
当用户第一次访问OneServlet的时候,会在OneServlet中使用请求对象代替Tomcat索要当前的HttpSession对象,在服务器端内部,我们的Tomcat会自动为每一个HttpSession对象设置一个编号(箱号),名为JSESSIONID,当我们在OneServlet中使用setAttribute方法存储数据到我们的HttpSession对象后,此时我们的HttpSession对象便会直接放在我们的Http服务器端,然后将我们的编号JSESSIONID放入到我们的cookie当中,再将我们的cookie放入到http响应协议包的响应头中返回给我们的浏览器,存在我们浏览器的缓存中,如上图所示。
当同一用户在同一网站下第二次访问TwoServlet时,此时发给TwoServlet的请求协议包中便会放入我们之前所收到的来自服务器端的cookie,这个cookie被放入了请求协议包中的请求头中,然后此时服务器端接收到我们的浏览器请求后,tomcat会根据cookie当中的JSESSIONID来判断当前用户是否之前索要到了HttpSession对象以及哪个HttpSession对象是当前这个用户的,从而就找到了之前这个用户第一次请求时在session中用于存储的数据HttpSession对象,然后就可以使用getAttribute方法来获取到数据了。
五.getSession() 与 getSession(false)的区别
1.getSession()
如果当前用户在服务端已经拥有了自己的私人储物柜.要求tomcat将这个私人储物柜进行返回.
如果当前用户在服务端尚未拥有自己的私人储物柜,要求tocmat为当前用户创建一个全新的私人储物柜.
2.getSession(false)
如果当前用户在服务端已经拥有了自己的私人储物柜.要求tomcat将这个私人储物柜进行返回
如果当前用户在服务端尚未拥有自己的私人储物柜,此时Tomcat将返回null
六.HttpSession销毁时机
1.用户与HttpSession关联时使用的Cookie只能存放在浏览器缓存中.
2.在浏览器关闭时,意味着用户与他的HttpSession关系被切断
3.由于Tomcat无法检测浏览器何时关闭,因此在浏览器关闭时并不会导致Tomcat将浏览器关联的HttpSession进行销毁
4.为了解决这个问题,Tomcat为每一个HttpSession对象设置【空闲时间】
这个空闲时间默认30分钟,如果当前HttpSession对象空闲时间达到30分钟
此时Tomcat认为用户已经放弃了自己的HttpSession,此时Tomcat就会销毁掉这个HttpSession
七.HttpSession对象空闲时间手动设置
在当前网站/web/WEB-INF/web.xml <session-config> <session-timeout>5</session-timeout> <!--当前网站中每一个session最大空闲时间5分钟--> </session-config>