一.Session简介

  • Session的使用场景
  • 当我们登陆电商网站时,无论浏览哪个页面都会显示登陆人的名字,还可以随时查看购物车里面的商品
  • 也就是说当一个用户浏览一个网站的不同页面时,服务器怎么知道此时是张三在访问还是李四在访问

这也就引出我们的另一个会话技术Session 与cookie不同session是保存在服务器端上,在每一次与浏览器的会话中,服务器都会创建该会话独享的session空间用于存储数据,用户浏览多个页面时可以从session对象中读取数据进行相关操作

  • 会话

在解释session前,我们要先了解什么是会话。会话就是用户通过浏览器访问多个网站页面,并关闭浏览器这一过程,严谨的讲一次会话和浏览器保存的JSessionID和服务器端保存的Session对象有关

总之,用户通过浏览器访问服务器,并操作Session时,服务器会在内存中为这次会话分配一个Session对象,被该浏览器所独占。

这个session可以看作一个容器/集合,默认存在时间为30分钟(可以在web.xml文件中修改)

二.Session的简单理解

1. Session的存储结构
session的存储结构类似于HashMap,相当于一张表

session里的值 session内容_session里的值

2. Session简单的执行流程

session里的值 session内容_java_02


总结session的实现基于cookie,服务器端通过得到cookie来判断是一个新的会话,还是以前的会话

三.Session的使用

  • 创建session

getSession方法的调用在某些情况下就相当于创建了一个Session对象

HttpSession session = request.getSession();

什么时候创建session

  • 浏览器的HTTP请求cookie中没有携带JSESSIONID
  • 浏览器的HTTP请求cookie中携带了JSESSIONID,但在服务器内存中没有与其匹配的JESSIONID
    抓包分析
    如果浏览器没有携带JESSIONID,操作session时服务器会为该浏览器分配一个ID以cookie的形式返回给浏览器进行保存

再此访问该服务器资源时浏览器会携带上次分配的JSESSIONID,到服务器端找到对应的session对象进行数据的操作

session里的值 session内容_html_03

  • 向session添加/读取属性
session.setAttribute("user", "jbc");
session.getAttribute("user");
  • 移除session中的属性
session.removeAttribute("user");
  • 获取JESSIONID

每一个session对象都有与之唯一对应的JSESSIONID

session.getID();
  • 判断是否是新创建的session
session.isNew();

四.Session的生命周期

  • setMaxInterval方法设置session的生命周期(以秒为单位)
    正数是session的超时时间
    负数为永不超时
  • getMaxInterval()得到该session的生命周期
  • invalidate()销毁该session
  • 在没有设置session的超时时长时默认为30分钟失效
  • Tomcat会在底层轮询存储JSESSIONID-session的容器,如果最近访问时间
    lastAccessDate与现在的时间超过session的MaxInterval,就会销毁该session

要说明的是session的生命周期是:浏览器能够访问到该session间隔的最大时长,而不是累计时长,在每次访问session时都会重置session的MaxInterval

代码举例

创建与访问该资源的浏览器关联的session对象,设置超时时长60秒

HttpSession session = request.getSession();
        System.out.println("JSessionID= " + session.getId());
        session.setMaxInactiveInterval(60);
        session.setAttribute("user", "jbc");

读取当前会话的session中的数据

HttpSession session = request.getSession();
        System.out.println("JSessionID= " + session.getId());
        System.out.println(session.getAttribute("user"));

抓包分析

由于我们没有携带JSESSIONID,服务器分配了这次会话的ID

session里的值 session内容_session里的值_04


分析可知,在超过60秒后,服务器会将这次会话的session销毁,

这时我们再想要读取该session中的数据时,我们发现服务器端又返回了一个新的JSESSIONID,说明原来的会话已经被销毁,再对session进行操作时,服务器认为当前是新的会话,会创建session对象并返回给浏览器SID

session里的值 session内容_java_05

需要再次说明的是session的生命周期是指,间隔的最大时长,如果在间隔时间内再次访问就会重置他的生命周期

五.应用实例

1.只要密码为 666666, 我们认为就是登录成功 ,用户名不限制
2. 如果验证成功,则进入管理页面 ManageServelt.java ,否则进入 error.html
3. 如果用户直接访问 ManageServet.java , 重定向到到 login.html

此案例只是为了理解session做的简单案例

package homework;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet(name = "LoginCheck", value = "/LoginCheck")
public class LoginCheck extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String pwd = request.getParameter("pwd");
        //如果密码正确就创建一个会话
        if ("666666".equals(pwd)) {
            HttpSession session = request.getSession();
            session.setAttribute("username", request.getParameter("username"));
            request.getRequestDispatcher("/Manger").forward(request, response);
        } else {
        //否则请求转发到error.html         
        request.getRequestDispatcher("/error.html").forward(request, response);
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}
package homework;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(name = "Manger", value = "/Manger")
public class Manager extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        String username = (String) session.getAttribute("username");
        //获得一个session对象如果该session对象是刚刚创建的
        //该对象就不会存储username这一属性,就可以判断用户是非法访问的该资源
        if (username == null) {
        //重定向到login.html
            response.sendRedirect("/session/login.html");
        } else {
        //如果是通过CheckLogin通过的就显示成功登陆
            response.setContentType("text/html;charset=utf-8");
            PrintWriter writer = response.getWriter();
            writer.print("<h1>欢迎" + username + "登陆</h1>");
        }
    }

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