javaweb之会话管理

Cookie:

1. Cookie 的定义

  • Cookie 是存储在用户浏览器中的小块数据,通常由服务器发送并存储,以便在用户浏览器和服务器之间保持会话状态。
  • 每次用户发送请求时,浏览器都会自动附带相应的 Cookie,允许服务器辨识用户。

2. Cookie 的用途

  • 保持会话状态:用于存储用户登录状态或购物车等会话信息。
  • 个性化设置:保存用户的偏好设置,比如语言选择、字体大小等。
  • 跟踪用户行为:例如分析用户访问网站的行为,以进行个性化推荐。

3. Cookie 的分类

  • 会话 Cookie(Session Cookie):在浏览器关闭后失效,通常用于临时数据存储。
  • 持久 Cookie(Persistent Cookie):设置了过期时间,在过期前即使关闭浏览器也不会被删除。
默认情况下 Cookie 的有效期是一次会话范围内,我们可以通过 Cookie setMaxAge() 方法让 Cookie 持久化保存到浏览器上。
cookie.setMaxAge(int expiry) 参数单位是秒,表示 cookie 的持久化时间,如果设置参数为 0 ,表示将 浏览器中保存的该cookie 删除。

 session:

HttpSession的概述:

HttpSession是一种保留更多信息在服务端的一种技术 服务器会为每一个客户端开辟一块内存空
间,即session对象.。客户端在发送请求时,都可以使用自己的session。这样服务端就可以通过
session来记录某个客户端的状态了。

  • 服务端在为客户端创建session时,会同时将session对象的id,即JSESSIONIDCookie的形式放入响 应对象;  
  • 后端创建完session后,客户端会收到一个特殊的Cookie,叫做JSESSIONID
  • 客户端下一次请求时携带JSESSIONID,后端收到后,根据JSESSIONID找到对应的session对象;
  • 通过该机制,服务端通过session就可以存储一些专门针对某个客户端的信息了;
  • session也是域对象(后续详细讲解)

应用场景:

  1.  记录用户的登录状态: 用户登录后,将用户的账号等敏感信息存入session
  2.  记录用户操作的历史: 如记录用户的访问痕迹,用户的购物车信息等临时性的信息;

测试:  

注意!!!

生成web项目后,一定要删去index.jsp;原因:里面有内置的session对象,会干扰

 servlet1:

package servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;
@WebServlet("/servlet1")
public class servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 接收请求中的username参数

        String username = req.getParameter("username");
        // 获得session对象
        HttpSession session = req.getSession();
        // 改变session的失效时间
        session.setMaxInactiveInterval(120);

        System.out.println(session.getId());
        System.out.println(session.isNew());
        //判断请求中有没有一个特殊的cookie JSESSIONID 值*****
        //1有
                //根据 JSESSIONID找对应的session对象
                // 找到了
                            // 返回之前的session
                // 没有找到
        // 创建一个新的session返回,并且向response对象中存放一个SESSIONID  的cookie
        // 2 没有
        // 创建一个新的session返回,并且向response对象中存放一个SESSIONID 的cookie


        // 将username存入session
        session.setAttribute("username",username);

        // 客户端响应信息
        resp.setContentType("text/html;charset = UTF-8");
        resp.getWriter().write("成功");
    }
}

servlet2:

package servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;
@WebServlet("/servlet1")
public class servlet1 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 接收请求中的username参数

        String username = req.getParameter("username");
        // 获得session对象
        HttpSession session = req.getSession();
        // 改变session的失效时间
        session.setMaxInactiveInterval(120);

        System.out.println(session.getId());
        System.out.println(session.isNew());
        //判断请求中有没有一个特殊的cookie JSESSIONID 值*****
        //1有
                //根据 JSESSIONID找对应的session对象
                // 找到了
                            // 返回之前的session
                // 没有找到
        // 创建一个新的session返回,并且向response对象中存放一个SESSIONID  的cookie
        // 2 没有
        // 创建一个新的session返回,并且向response对象中存放一个SESSIONID 的cookie


        // 将username存入session
        session.setAttribute("username",username);

        // 客户端响应信息
        resp.setContentType("text/html;charset = UTF-8");
        resp.getWriter().write("成功");
    }
}

getSession方法的处理逻辑:

  • 初次请求

    • 浏览器向服务器发起第一次请求(请求报文)。
    • 服务器端处理该请求,创建一个新的Session,并将Session的ID(如JSESSIONID)保存在Cookie中,作为响应的一部分(响应报文),发送给浏览器。
  • 浏览器存储Cookie

    • 浏览器接收到服务器的响应,将Cookie中的JSESSIONID存储下来。
  • 再次请求

    • 当浏览器再次发起请求时,会自动携带之前存储的Cookie(包含JSESSIONID)。
    • 服务器接收到请求后,读取该Cookie中的Session ID(如JSESSIONID),找到与之对应的Session,获取其中存储的键值对数据,处理请求。
  • 响应返回

    • 服务器处理完请求后,再次返回响应报文,浏览器接收并继续进行后续的操作。

总结

  • 每次请求时,浏览器都会携带上次存储的Cookie来标识当前用户的会话。
  • 服务器通过读取Cookie中的JSESSIONID,找到对应的Session,进而保持会话数据的连续性。

 HttpSession时效性:

为什么要设置session的时效?

  • 用户量很大之后,Session对象相应的也要创建很多。如果一味创建不释放,那么服务器端的内存 迟早要被耗尽;
  • 客户端关闭行为无法被服务端直接侦测,或者客户端较长时间不操作也经常出现,类似这些的情 况,就需要对session的时限进行设置了(例如很久没登录过的哔哩哔哩要重新登录)
默认的 session 最大闲置时间 ( 两次使用同一个 session 中的间隔时间 ) Tomcat/conf/web.xml 配置为 30分钟。

 如何看TomCat里面设置的session时效呢?

 注意!!!!

这里不再是30s了,在Tomcat的配置文件中,<session-timeout> 的单位是分钟。因此,在图中设置的<session-timeout>30</session-timeout>表示Session超时时间为30分钟,服务器将自动使该Session失效。

如何自己设置时间?

我们可以自己在当前项目的web.xml对最大闲置时间进行重新设定。

也可以通过HttpSessionAPI 对最大闲置时间进行设定。 

三大域对象: 

域对象:一些用于存储数据和传递数据的对象。传递数据不同的范围,我们称之为不同的域。不
同的域对象代表不同的域,共享数据的范围也不同
web 项目中,我们一定要熟练使用的域对象分别是 :请求域、会话域、应用域;
  • 请求域对象是HttpServletRequest ,传递数据的范围是一次请求之内及请求转发;
  • 会话域对象是HttpSession,传递数据的范围是一次会话之内,可以跨多个请求;
  • 应用域对象是ServletContext,传递数据的范围是本应用之内,可以跨多个会话;

1. 请求域(Request Scope)

  • 对象: HttpServletRequest
  • 作用范围: 仅限于一次HTTP请求。在同一个请求过程中,数据可以在Servlet、JSP或其他组件之间共享。
获取不到数据的情况:
  • 请求已经结束: 请求域中的数据只在当前请求有效。一旦请求结束(如重定向、返回响应给客户端后),请求对象会销毁,数据将不可访问。(当然可以进行请求转发,可以获取数据)
  • 跨请求: 如果想在一次请求中设置数据,然后在下一次请求中获取(如重定向或从不同的页面发起请求),由于请求已经变化,无法获取之前的请求域数据。

2. 会话域(Session Scope)

  • 对象: HttpSession
  • 作用范围: 作用于一个用户会话期间。只要用户会话没有过期或销毁,数据可以在多个请求之间共享。
获取不到数据的情况:
  • Session过期或销毁: 如果用户长时间没有操作(超过了Session的超时时间,默认30分钟),Session会被服务器销毁,之后再尝试访问会话域中的数据将获取不到。
  • Session手动销毁: 通过调用session.invalidate(),会立即销毁会话,所有的会话域数据将被清除。
  • 新建Session: 如果在一个新的请求中,用户没有携带之前的Session(如关闭浏览器后再访问),服务器会创建一个新的Session,之前的会话域数据将获取不到。又比如两个浏览器不能共享数据,清空浏览器的历史记录

3. 应用域(Application Scope)

  • 对象: ServletContext
  • 作用范围: 作用于整个Web应用程序的生命周期。数据可以在整个应用程序范围内(跨用户和跨请求)共享,直到服务器停止或Web应用重新部署。
获取不到数据的情况:
  • 应用程序重启或重新部署: 服务器重启或Web应用重新部署时,应用域中的数据将会被销毁,再次访问时获取不到原有的数据。
  • 数据未设置: 如果程序没有显式地通过ServletContext设置数据,访问时自然获取不到。
  • 应用域数据手动移除: 如果调用removeAttribute()方法手动移除了某个数据项,也会导致后续无法获取该数据。

 测试 API:

servletA:

package servlet;

import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;

@WebServlet("/servletA")
public class servletA extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 向请求域存放数据
        req.setAttribute("request","requestMessage");
        // 向会话域存放数据
        HttpSession session = req.getSession();
        session.setAttribute("session","sessionMessage");
        // 向应用域存放数据
        ServletContext servletContext = session.getServletContext();
        servletContext.setAttribute("application","applicationMessage");


        // 获取请求域
        String reqMse = (String) req.getAttribute("request");
        System.out.println("请求域" + reqMse);

//        // 请求转发
//        req.getRequestDispatcher("/servletB").forward(req,resp);
    }

}

servletB:

package servlet;

import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;
@WebServlet("/servletB")
public class servletB extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求域的数据
        String reqMse = (String) req.getAttribute("request");
        System.out.println("请求域" + reqMse);
        // 获取会话域的数据 换一个浏览器就获取不到数据了
        HttpSession session = req.getSession();
        String SessionMse = (String) session.getAttribute("session");
        System.out.println("会话域" + SessionMse);
        // 获取应用域的数据
        ServletContext servletContext =  session.getServletContext();
        String AppMse = (String) servletContext.getAttribute("application");
        System.out.println("应用域" + AppMse);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值