Web 开发会话技术 -Cookie&Session

  |   0 评论   |   0 浏览

Web 开发会话技术 -Cookie&Session

1.会话

1.1基本介绍

1.什么是会话?

会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个 web 资源,然后关闭浏览器,整个过程称之为一个会话。

image-20220313094650424

image-20220313095451970

2.会话过程中要解决的一些问题?
1)每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,服务器要想办法为每个用户保存这些数据
2)例如:多个用户点击超链接通过一个 servlet 各自购买了一个商品,服务器应该想办法把每一个用户购买的商品保存在各自的地方,以便于这些用户点结帐 servlet 时,结帐servlet 可以得到用户各自购买的商品为用户结帐。

1.2会话的两种技术

1.Cookie

2.Session

2.Cookie

1.Cookie的作用

1.思考问题 1
大家在访问某个网站的时候,是否能看到提示你上次登录网站的时间,而且要注意的是不同用户上次登录的时间肯定是不一样的,这是怎么实现的?

2.思考问题 2
☞大家在访问某个购物网站的时候,是否能看到提示你曾经浏览过的商品,不同用户浏览过 的商品肯定不一样,这是怎么实现的?

3.思考问题3

在我们登录网站时,往往都可以选择保存登录信息多久?不用重复输入登录信息,这个又是怎么实现呢?

2.解决之道—cookie 技术

Cookie(小甜饼)是客户端技术,服务器把每个用户的数据以 cookie 的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的 web 资源时,就会带着各自的数据去。这样, web 资源处理的就是用户各自的数据了。【简单示意图】

image-20220313100302836

3.Cookie介绍

1.Cookie 是服务器在客户端保存用户的信息,比如登录名,浏览历史等, 就可以以 cookie 方式保存.
2.Cookie 信息就像是小甜饼(cookie 中文)一样,数据量并不大,服务器端在需要的时候可以从客户端/浏览器读取(http 协议),可以通过图来理解

image-20220313103920131

image-20220313103932328

image-20220313104041481

3. cookie 数据是保存在浏览器的.

4.cookie 基本使用

1.cookie 常用方法

1.Cookie 有点象一张表(K-V),分两列,一个是名字,一个是值,数据类型都是 String , 如图

image-20220313110940249

2.如何创建一个 Cookie(在服务端创建的) Cookie c=new Cookie(String name,String val);
c.setMaxAge();//保存时间

3.如何将一个 Cookie 添加到客户端(浏览器)response.addCookie(c);

4.如何读取cookie(在服务器端读取到 cookie 信息) request.getCookies();

2.cookie 底层实现机制-创建和读取 Cookie

1.创建Cookie
@WebServlet(name = "CreateCookie",urlPatterns = {"/createCookie"})
public class CreateCookie extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie cookie = new Cookie("name","llp");
        response.addCookie(cookie);
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.write("<h1>创建cookie成功</h1>");
     	writer.flush();
        writer.close();
    }

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

image-20220313112126582

image-20220313112211843

2.读取Cookie
@WebServlet(name = "ReadCookie",urlPatterns = {"/readCookie"})
public class ReadCookie extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            System.out.println(cookie.getName()+"="+cookie.getValue());
        }
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>读取cookie成功</h1>");
        writer.flush();
        writer.close();
    }

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

保存在客户端(浏览器)的Cookie通过Http请求,发送给服务端

image-20220313113747256

不同会话,jsessionid 不同

第一次会话

image-20220313121429573

第二次会话:关闭浏览器再次访问

image-20220313121351253

3.cookie 应用实例
1.读取指定Cookie
@WebServlet(name = "ReadCookieByName",urlPatterns = {"/readCookieByName"})
public class ReadCookieByName extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        Cookie cookie = ReadCookieUtil.ReadCookieByName("name", cookies);
        if(cookie == null){
            System.out.println("该浏览器没有"+cookie.getName()+"的cookie");
        }
        System.out.println("name = "+cookie.getName()+", value = "+cookie.getValue());
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>读取Cookie任务完成...</h1>");
    }

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

根据Cookie名称获取值

public class ReadCookieUtil {

    public static Cookie ReadCookieByName(String name, Cookie[] cookies){
        if("".equals(name)||name == null || cookies == null || cookies.length ==0){
            return null;
        }
        for (Cookie cookie : cookies) {
            if(name.equals(cookie.getName())){
               return cookie;
            }
        }
        return null;
    }
}

image-20220313123918210

2.修改Cookie

如果我们创建了同名的Cookie并返回给了浏览器,等价于覆盖

//如果我们直接创建了一个同名的cookie
Cookie userNameCookie = new Cookie("username", "hahaha");

//把 新创建的userNameCookie 重新保存到浏览器
//如果 保存的userNameCookie 和已经有的cookie同名,就等价于替换.
if(userNameCookie != null) {
response.addCookie(userNameCookie);
}

@WebServlet(name = "UpdateCookie",urlPatterns = {"/updateCookie"})
public class UpdateCookie extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        Cookie cookie = ReadCookieUtil.ReadCookieByName("name", cookies);
        if(cookie == null){
            System.out.println("该浏览器没有"+cookie.getName()+"的cookie");
        }else{
            cookie.setValue("孙悟空~super");
        }
        System.out.println("修改后的cookie信息");
        for (Cookie cookie1 : cookies) {
            System.out.println("cookie name = "+cookie1.getName()+", value = "+cookie1.getValue());
        }
        if(cookie!=null){
            //将修改后的cookie返回给浏览器
            //response.addCookie(cookie);
        }
        //如果我们直接创建了一个同名的cookie
        Cookie userNameCookie = new Cookie("username", "hahaha");
        //把 新创建的userNameCookie 重新保存到浏览器
        //如果 保存的userNameCookie 和已经有的cookie同名,就等价于替换.
        if(userNameCookie != null) {
            response.addCookie(userNameCookie);
        }
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>更新Cookie任务完成...</h1>");
    }

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

**注意:**这里我们在服务端修改了Cookie但并没有返回给客户端response.addCookie(cookie);,所有客户端(浏览器)的Cookie是没有变化的

image-20220313124315074

3.cookie 生命周期

1.介绍

1.Cookie 的生命周期指的是如何管理 Cookie 什么时候被销毁(删除)
2.setMaxAge()
●正数,表示在指定的秒数后过期
●负数,表示浏览器关闭,Cookie 就会被删除(默认值是-1)
●0,表示马上删除 Cookie

2.应用实例
public class CookieLive extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("CookieLive 被调用...");

        //演示创建一个cookie , 生命周期为 60s
        Cookie cookie = new Cookie("job", "java");
        // 1. 从创建该cookie开始计时, 60秒后无效
        // 2. 浏览器来根据创建的时间,计时到60s秒,就认为该cookie无效
        // 3. 如果该cookie无效,那么浏览器在发出http请求时,就不在携带该cookie
        cookie.setMaxAge(60);
        //讲cookie保存到浏览器
        response.addCookie(cookie);


        //演示如何删除一个cookie, 比如删除username
        //1 先得到username cookie
        Cookie[] cookies = request.getCookies();
        Cookie usernameCookie =
                CookieUtils.readCookieByName("username", cookies);
        if(usernameCookie != null) {
            //2. 将其生命周期设置为0
            usernameCookie.setMaxAge(0);
            //3. 重新保存该cookie, 因为你将其生命周期设置0, 就等价于让浏览器删除该cookie
            //4. 说明:该cookie会被浏览器直接删除
            //   返回一个Set-Cookie: xxxxx => 一会抓包.
            //   Set-Cookie: username=tom; Expires=Thu, 01-Jan-1970 00:00:10 GMT
            response.addCookie(usernameCookie);//返回一个Set-Cookie: xxxxx => 一会抓包.
        }else{
            System.out.println("没有找到该cookie, 无法删除...");
        }

        /***********************
         * 默认的会话级别的 Cookie [即浏览器关闭就销毁了]
         * 前面我们讲课时,都是默认会话级别的生命周期
         ***********************/
        Cookie cookie3 = new Cookie("dkey", "dkey_value");
        /**
         * setMaxAge源码
         * public void setMaxAge(int expiry) {
         *         this.maxAge = expiry;
         * }
         * private int maxAge = -1; 默认就是-1
         */
        //cookie.setMaxAge(-1);//设置存活时间
        response.addCookie(cookie3);


        // 给浏览器返回信息
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println("<h1>设置cookie生命周期</h1>");
        writer.flush();
        writer.close();

    }

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

image-20220313140027849

image-20220313140334541

4.cookie 有效路径

1.cookie有效路径规则

1.Cookie 有效路径 Path 的设置
2.Cookie 的 path 属性可以有效的过滤哪些 Cookie 可以发送给服务器。哪些不发。 path属性是通过请求的地址来进行有效的过滤

3.规则如下:

cookie1.setPath = /工程路径cookie2.setPath = /工程路径/aaa

请求地址: http://ip:端口/工程路径/资源

cookie1 会发给服务器

cookie2 不会发给服务器

请求地址: http://ip:端口/工程路径/aaa/资源

cookie1 会发给服务器
cookie2 会发给服务器

2.应用实例
public class CookiePath extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("CookiePath 被调用...");
        //1. 创建两个cookie
        Cookie cookie = new Cookie("address", "bj");
        Cookie cookie2 = new Cookie("salary", "20000");
        //2. 设置不同有效路径
        //   request.getContextPath() => /cs
        cookie.setPath(request.getContextPath());
        //   cookie2有效路径 /cs/aaa
        cookie2.setPath(request.getContextPath() + "/aaa");

        //说明:如果我们没有设置cookie有效路径,默认就是 /工程路径

        //3. 保存到浏览器
        response.addCookie(cookie);
        response.addCookie(cookie2);

        //4. 给浏览器返回信息
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println("<h1>设置cookie有效路径成功</h1>");
        writer.flush();
        writer.close();

    }

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

如果没有设置cookiePath那默认就是 /工程路径,浏览器访问时会携带cookiePath为默认的工程路径下的cookie和指定路径的cookie

image-20220313140948984

image-20220313141010847

5.Cookie 经典案例-自动填写登录账号

●需求: 完成自动填写登录账户应用案例 , 如果用户登录成功,则下次登录自动填写登录账户(如图)

1)如果用户名是 wukong, 密码是 123456, 则认为该用户合法, 登录成功,否则登录失败
2)要求实现如果登录成功,则该用户,在 3 天内登录,可以自动填写其登录名

3)提示:登录页面需要使用 servlet 返回,而不能使用 html

先写一个login.html后面直接拷贝

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<h1>用户登录界面</h1>
<form action="/login" method="post">
    u:<input type="text" name="username"><br/>
    p:<input type="password" name="pwd"><br/>
    <input type="submit" value="登录">
</form>
</body>
</html>

UserUIServlet

@WebServlet(name = "UserUIServlet", urlPatterns = {"/user"})
public class UserUIServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        response.setContentType("text/html;charset=utf-8");
        Cookie userNameCookie = ReadCookieUtil.ReadCookieByName("username", cookies);
        Cookie pwdCookie = ReadCookieUtil.ReadCookieByName("pwd", cookies);
        String username = "", pwd = "";
        if (userNameCookie != null) {
            username = userNameCookie.getValue();
        }
        if (pwdCookie != null) {
            pwd = pwdCookie.getValue();
        }
        PrintWriter writer = response.getWriter();
        writer.print("<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <title>登录页面</title>\n" +
                "</head>\n" +
                "<body>\n" +
                "<h1>用户登录界面</h1>\n" +
                "<form action=\"/login\" method=\"post\">\n" +
                "    u:<input type=\"text\" value=\""+username+"\" name=\"username\"><br/>\n" +
                "    p:<input type=\"password\" value=\""+pwd+"\" name=\"pwd\"><br/>\n" +
                "    <input type=\"submit\" value=\"登录\">\n" +
                "</form>\n" +
                "\n" +
                "</body>\n" +
                "\n" +
                "</html>");
        writer.flush();
        writer.close();
    }

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

LoginServlet

/**
 * ●需求: 完成自动填写登录账户应用案例 , 如果用户登录成功,则下次登录自动填写登录账户(如图)
 *
 * 1)如果用户名是 wukong, 密码是 123456, 则认为该用户合法, 登录成功,否则登录失败
 * 2)要求实现如果登录成功,则该用户,在 3 天内登录,可以自动填写其登录名
 *
 * 3)提示:登录页面需要使用 servlet 返回,而不能使用 html
 */
@WebServlet(name = "LoginServlet",urlPatterns = {"/login"})
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //避免录入的参数含有中文,request在获取时乱码
        request.setCharacterEncoding("utf-8");
        String username = request.getParameter("username");
        String pwd = request.getParameter("pwd");
        //text/html text表示大的类型,html表示下面的小类型, charset表示字符集
        //简而言之就是响应支持文本类型(text)下的html格式且字符集为utf-8
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        if("wukong".equals(username) && "123456".equals(pwd)){
            Cookie userNameCookie = new Cookie("username",username);
            Cookie pwdCookie = new Cookie("pwd",pwd);
            userNameCookie.setMaxAge(3*60*60*24);
            pwdCookie.setMaxAge(3*60*60*24);
            response.addCookie(userNameCookie);
            response.addCookie(pwdCookie);
            writer.print("<h1>登录成功</h1>");
        }else{
            writer.print("<h1>登录失败</h1>");
        }
        writer.flush();
        writer.close();
    }

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

这里禁用了浏览器缓存,完全通过服务端获取cookie来自动填充用户名和密码

image-20220313150358266

6.Cookie 注意事项和细节

1.一个 Cookie 只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。

2.一个 WEB 站点可以给一个浏览器发送多个 Cookie,一个浏览器也可以存储多个 WEB 站点提供的 Cookie。
3.cookie 的总数量没有限制,但是每个域名的 COOKIE 数量和每个 COOKIE 的大小是有限制的 (不同的浏览器限制不同, 知道即可) , Cookie 不适合存放数据量大的信息。

4.获取cookie时,根据cookie有效路径进行区分;访问readCookie的路径是/readCookie而hobby的有效路径是/aaa,这里request获取不到hobby的cookie

image-20220313153840634

image-20220313153819130

5.注意,删除 cookie 时,path 必须一致,否则不会删除

image-20220313154456348

6.Java servlet 中cookie 中文乱码解决

如果存放中文的 cookie, 默认报错, 可以通过 URL 编码和解码来解决, 不建议存放中文的 cookie 信息

URL编码:String hobby = URLEncoder.encode("训练", "utf-8");
Cookie cookie = new Cookie("hobby",hobby);

URL解码:URLDecoder.decode(cookie.getValue(), "utf-8");

3.session

1.session 有什么用

1.不同的用户登录网站后,不管该用户浏览该网站的哪个页面,都可显示登录人的名字, 还可以随时去查看自己的购物车中的商品, 是如何实现的?
2.也就是说,一个用户在浏览网站不同页面时,服务器是如何知道是张三在浏览这个页面, 还是李四在浏览这个页面?

image-20220313160659752

image-20220313160727543

●解决之道—session 技术

1.Session 是服务器端技术,服务器在运行时为每一个用户的浏览器创建一个其独享的session 对象/集合
2.由于 session 为各个用户浏览器独享,所以用户在访问服务器的不同页面时,可以从各自的 session 中读取/添加数据, 从而完成相应任务

2.session 基本原理

1.Sesson 原理示意图

image-20220313161027029

image-20220313161100404

1.当用户打开浏览器,访问某个网站, 操作 session 时,服务器就会在内存(在服务端)为该浏览器分配一个 session 对象,该 session 对象被这个浏览器独占, 如图
2.这个 session 对象也可看做是一个容器/集合,session 对象默认存在时间为 30min(这是在tomcat/conf/web.xml),也可修改

image-20220313161129428

3.session可以做什么

1.网上商城中的购物车
2.保存登录用户的信息
3.将数据放入到 Session 中,供用户在访问不同页面时,实现跨页面访问数据
4.防止用户非法登录到某个页面

  1. .....

4.如何理解 Session

1.session 存储结构示意图

image-20220313161334885

2.你可以把 session 看作是一容器类似 HashMap,有两列(K-V),每一行就是 session 的一个属性。
3.每个属性包含有两个部分,一个是该属性的名字(String),另外一个是它的值(Object)

5.session 常用方法

1.Session 的基本使用

1.创建和获取 Session,API 一样 HttpSession hs=request.getSession();第 1 次调用是创建 Session 会话, 之后调用是获取创建好的 Session 对象
2.向 session 添加属性hs.setAttribute(String name,Object val);
3.从 session 得到某个属性Object obj=hs.getAttribute(String name);
4.从 session 删除调某个属性: hs.removeAttribute(String name);
5.isNew(); 判断是不是刚创建出来的 Session
6.每个 Session 都有 1 个唯一标识 Id 值。通过getId() 得到 Session 的会话 id 值

6.session 底层实现机制

●session 底层实现机制图解(重要)

image-20220313161658315

原理分析

不考虑访问首页创建JessionId的情况

1.浏览器第一次请求服务端时,服务器端会创建session对象分配sessionId并将JessionId的cookie放回给浏览器(这里SessionId=JessionId),看可以看到响应头含有set-cookie

———–简单理解为tomcat底层有一个Map<String,HttpSession> map这样的一个容器,key=sessionId,value=Session对象

2.浏览器再次请求服务端时,携带JessionId;tomcat从容器中查找sessionId对应的session对象,如果没有找到则创建并重新分配sessionId,浏览器端则会覆盖掉之前的JessionId对应的cookie信息

3.浏览器在请求服务端时,携带JessionId; tomcat从容器找到了sessionId对应的session对象则直接操作

image-20220313161709064

1. Session 底层实现机制-创建和读取 Session

创建Session

@WebServlet(name = "CreateSession",urlPatterns = {"/createSession"})
public class CreateSession extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //System.out.println("CreateSession 被调用...");

        //1. 获取session, 同时也可能创建session
        HttpSession session = request.getSession();

        //2. 给session获取id
        System.out.println("CreateSession 当前sessionid= " + session.getId());
        //3. 给session存放数据
        session.setAttribute("email", "zs@qq.com");

        //4. 给浏览器发送一个回复
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println("<h1>创建/操作session成功...</h1>");
        writer.flush();
        writer.close();
    }

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

获取Session

@WebServlet(name = "ReadSession",urlPatterns = {"/readSession"})
public class ReadSession extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //System.out.println("ReadSession 被调用...");
        // 演示读取session
        //1. 获取session, 如果没有sesion, 也会创建
        HttpSession session = request.getSession();
        //输出sessionId
        System.out.println("ReadSession sessionid= " + session.getId());
        //2. 读取属性
        Object email = session.getAttribute("email");
        if (email != null) {
            System.out.println("session属性 email= " + (String) email);
        } else {
            System.out.println("session中没有 email属性 ");
        }
        //给浏览器回复一下
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println("<h1>读取session成功...</h1>");
        writer.flush();
        writer.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}
1. 先访问主页在访问对应的servlet的情况

可以看到第一次上来就先访问主页index.jsp页面会创建创建session,浏览器会保存cookie=jessionidxxx

但是这里的sessionid和我们创建的sessionid是不一样的

image-20220313171654186

image-20220313171949468

2.服务启动直接访问Servlet

第一次访问时,服务器端创建session,分配sessionId并将 JSESSIONID=1B212982F1308B6912DBA29C3EBCF0F6的cookie返回给客户端(浏览器)

image-20220313172129904

再次访问

1.因为浏览器已经存在jessionid的cookie信息,会携带Jessionid去请求服务器

2.服务端端判断是否存在Jessionid的Session对象,如果存在则直接操作,如果不存或者session正好过期了,则创建session对象并重新分配

image-20220313172301251

可以看到通过浏览器的JSESSIONID=1B212982F1308B6912DBA29C3EBCF0F6找到的session对象的sessionId是一样的

可以简单理解为tomcat底层有一个Map<String,HttpSession> map这样的一个容器,key=sessionId,value=Session对象

image-20220313173056994

7.session 生命周期

Session 生命周期-说明

1.public void setMaxInactiveInterval(int interval) 设置 Session 的超时时间(以秒为单位),超过指定的时长,Session 就会被销毁。
2.值为正数的时候,设定 Session 的超时时长。
3.负数表示永不超时
4.public int getMaxInactiveInterval()获取 Session 的超时时间
5.public void invalidate() 让当前 Session 会话立即无效
6.如果没有调用 setMaxInactiveInterval() 来指定 Session 的生命时长,Tomcat 会以 Session
默认时长为准,Session 默认的超时为 30 分钟, 可以在tomcat 的web.xml 设置

image-20220313180248765

7.Session 的生命周期指的是 :客户端/浏览器两次请求最大间隔时长,而不是累积时长。即当客户端访问了自己的 session,session 的生命周期将从 0 开始重新计算。(老韩解读: 指的是同一个会话两次请求之间的间隔时间)
8.底层: Tomcat 用一个线程来轮询会话状态,如果某个会话的空闲时间超过设定的最大值, 则将该会话销毁

CreateSession

@WebServlet(name = "CreateSession2",urlPatterns = {"/createSession2"})
public class CreateSession2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("CreateSession2 被调用");
        //创建session
        HttpSession session = request.getSession();
        System.out.println("CreateSession2 sid= " + session.getId());
        //设置生命周期为 60s
        session.setMaxInactiveInterval(60);
        session.setAttribute("u", "jack");

        //回复一下浏览器
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println("<h1>创建session成功, 设置生命周期60s</h1>");
        writer.flush();
        writer.close();
    }

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

ReadSession

@WebServlet(name = "ReadSession2",urlPatterns = {"/readSession2"})
public class ReadSession2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //System.out.println("ReadSession2 被调用...");

        //1. 获取到session
        HttpSession session = request.getSession();
        System.out.println("ReadSession2 sid= " + session.getId());
        //2. 读取session的属性
        Object u = session.getAttribute("u");
        if (u != null) {
            System.out.println("读取到session属性 u= " + (String) u);
        } else {
            System.out.println("读取不到session属性 u 说明原来的session被销毁");
        }
    }

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

Session 的生命周期
1)指的是两次访问 session 的最大间隔时间
2)如果你在 session 没有过期的情况下,操作 session, 则会重新开始计算生命周期
3)session 是否过期,是由服务器来维护和管理
4)如我们调用了 invaliate() 会直接将该 session 删除/销毁
5)如果希望删除 session 对象的某个属性, 使用 removeAttribute("xx")

6)关闭浏览器会重新创建session,但并不影响之前的session的生命周期,session的生命周期由tomcat来管理

8.Session 经典案例-防止非法进入管理页面

1.需求说明: 完成防止用户登录管理页面应用案例

image-20220313192349109

image-20220313192404122

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

ManageServlet

@WebServlet(name = "ManageServlet", urlPatterns = {"/manageServlet"})
public class ManageServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        User user = (User)session.getAttribute("user");
        if (user==null) {
            response.sendRedirect("/login.html");
        }
        System.out.println("ManageServlet被调用...");
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("<h1>登录成功</h1>");
        writer.flush();
        writer.close();
    }

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

LoginCheckServlet

@WebServlet(name = "LoginCheckServlet", urlPatterns = {"/loginCheckServlet"})
public class LoginCheckServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("loginCheckServlet被调用。。。");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if (password != null && password.equals("666666")) {
            User user = new User(username, password);
            HttpSession session = request.getSession();
            session.setAttribute("user", user);
            RequestDispatcher requestDispatcher = request.getRequestDispatcher("/manageServlet");
            requestDispatcher.forward(request,response);
        }else {
//            response.sendRedirect(getServletContext().getContextPath()+"error.html");
            request.getRequestDispatcher("/error.html").forward(request,response);
        }
    }

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

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户登录</title>
</head>
<body>
<h1>用户登录</h1>
<form action="/loginCheckServlet" method="post">
    用户名:<input type="text" name="username"/><br/><br/>
    密	码:<input type="password" name="password"><br><br/>
    <input type="submit" value="登录"></form>
</body>
</html>

标题:Web 开发会话技术 -Cookie&Session
作者:llp
地址:https://llinp.cn/articles/2022/03/13/1647170859870.html