JAVA Web Session介绍

97 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情

基本介绍

Session:服务器端会话管理技术,本质也是采用客户端会话管理技术,不过在客户端保存的是一个特殊标识,共享的数据保存到了服务器的内存对象中。每次请求时,会将特殊标识带到服务器端,根据标识来找到对应的内存空间,从而实现数据共享。简单说它就是一个服务端会话对象,用于存储用户的会话数据

Session 域(会话域)对象是 Servlet 规范中四大域对象之一,并且它也是用于实现数据共享的

域对象功能创建销毁使用场景
ServletContext应用域服务器启动服务器关闭在整个应用之间实现数据共享 (记录网站访问次数,聊天室)
ServletRequest请求域请求到来响应了这个请求在当前请求或者请求转发之间实现数据共享
HttpSession会话域getSession()session过期,调用invalidate(),服务器关闭在当前会话范围中实现数据共享,可以在多次请求中实现数据共享。 (验证码校验, 保存用户登录状态等)

基本使用

获取会话

HttpServletRequest类获取Session:

方法说明
HttpSession getSession()获取HttpSession对象
HttpSession getSession(boolean creat)获取HttpSession对象,未获取到是否自动创建


常用API

方法说明
void setAttribute(String name, Object value)设置会话域中的数据
Object getAttribute(String name)获取指定名称的会话域数据
Enumeration getAttributeNames()获取所有会话域所有属性的名称
void removeAttribute(String name)移除会话域中指定名称的数据
String getId()获取唯一标识名称,Jsessionid的值
void invalidate()立即失效session

实现会话

通过第一个Servlet设置共享的数据用户名,并在第二个Servlet获取到

项目执行完以后,去浏览器抓包,Request Headers 中的 Cookie JSESSIONID的值是一样的

@WebServlet("/servletDemo01")
public class ServletDemo01 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.获取请求的用户名
        String username = req.getParameter("username");
        //2.获取HttpSession的对象
        HttpSession session = req.getSession();
        System.out.println(session);
        System.out.println(session.getId());
        //3.将用户名信息添加到共享数据中
        session.setAttribute("username",username);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
@WebServlet("/servletDemo02")
public class ServletDemo02 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.获取HttpSession对象
        HttpSession session = req.getSession();
        //2.获取共享数据
        Object username = session.getAttribute("username");
        //3.将数据响应给浏览器
        resp.getWriter().write(username+"");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

生命周期

Session 的创建:一个常见的错误是以为 Session 在有客户端访问时就被创建,事实是直到某 server 端程序(如 Servlet)调用 HttpServletRequest.getSession(true) 这样的语句时才会被创建

Session 在以下情况会被删除:

  • 程序调用 HttpSession.invalidate()
  • 距离上一次收到客户端发送的 session id 时间间隔超过了 session 的最大有效时间
  • 服务器进程被停止

注意事项:

  • 客户端只保存 sessionID 到 cookie 中,而不会保存 session
  • 关闭浏览器只会使存储在客户端浏览器内存中的 cookie 失效,不会使服务器端的 session 对象失效,同样也不会使已经保存到硬盘上的持久化cookie消失

打开两个浏览器窗口访问应用程序会使用的是不同的session,通常 session cookie 是不能跨窗口使用,当新开了一个浏览器窗口进入相同页面时,系统会赋予一个新的 session id,实现跨窗口信息共享:

  • 先把 session id 保存在 persistent cookie 中(通过设置session的最大有效时间)
  • 在新窗口中读出来,就可以得到上一个窗口的 session id,这样通过 session cookie 和 persistent cookie 的结合就可以实现跨窗口的会话跟踪

会话问题

禁用Cookie

浏览器禁用Cookie解决办法:

  • 方式一:通过提示信息告知用户

    @WebServlet("/servletDemo03")
    public class ServletDemo03 extends HttpServlet{
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //1.获取HttpSession对象
            HttpSession session = req.getSession(false);
            System.out.println(session);
            if(session == null) {
                resp.setContentType("text/html;charset=UTF-8");
                resp.getWriter().write("为了不影响正常的使用,请不要禁用浏览器的Cookie~");
            }
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  • 方式二:访问时拼接 jsessionid 标识,通过 encodeURL() 方法重写地址

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        //实现url重写  相当于在地址栏后面拼接了一个jsessionid
        resp.getWriter().write("<a href='"+ resp.encodeURL
                               ("http://localhost:8080/session/servletDemo03") +
                               "'>go servletDemo03</a>");
    
    }
    

钝化活化

Session 存放在服务器端的内存中,可以做持久化管理。

钝化:序列化,持久态。把长时间不用,但还不到过期时间的 HttpSession 进行序列化写到磁盘上。

活化:相反的状态

何时钝化:

  • 当访问量很大时,服务器会根据getLastAccessTime来进行排序,对长时间不用,但是还没到过期时间的HttpSession进行序列化(持久化)
  • 当服务器进行重启的时候,为了保持客户HttpSession中的数据,也要对HttpSession进行序列化(持久化)

注意:

  • HttpSession的持久化由服务器来负责管理,我们不用关心
  • 只有实现了序列化接口的类才能被序列化