第一章:Cookie

1.1 Cookie简介

1.1.1 为什么需要Cookie?

  • HTTP是无状态的协议,服务器不能记录浏览器的访问记录,也就是说服务器不能区分两次请求是否由一个客户端发出。这样的设计严重阻碍了Web程序的发展,如:我们在进行网购的时候,买了一台电脑,又买了一部手机,由于HTTP协议是无状态的,如果不通过其他手段,服务器就不能知道用户到底买了什么,而Cookie就是解决方案之一。

1.1.2 Cookie是什么?

  • Cookie,翻译是小饼干的意思,实际上就是服务器保存在浏览器上的一段信息。浏览器有了Cookie之后,每次向服务器发送请求的时候都会同时携带该信息并发送给服务器,服务器接收到请求之后,就可以根据该信息处理请求。
  • 例如:我们上文说的网上商城,当用户向购物车中添加一个商品的时候,服务器会将这条信息封装成一个Cookie发送给浏览器,浏览器收到Cookie,会将其保存在内存中(注意:这里的内存是客户的浏览器的内存,而不是服务器的内存),之后每次向服务器发送请求,浏览器都会携带该Cookie来判断用户到底买了哪些商品,当用户进行结账操作的时候,服务器就可以根据Cookie的信息来做结算了。
  • Cookie的用途:
    • ① 网上商城的购物车。
    • ② 保持用户的登录状态。
  • 总而言之,Cookie是一种服务器告诉浏览器以键值对形式存储的少量信息的技术。

1.1.3 Cookie的工作原理

  • 总的来看,Cookie像是服务器发送给浏览器的一张“会员卡”,浏览器每次向服务器发送请求的时候,都会带着这张“会员卡”,当服务器看到这张“会员卡”就可以识别浏览器的身份,换言之,就是客户的身份。
  • 实际上,这个所谓的“会员卡”就是服务器发送的一个响应头:

Cookie工作原理1.png

  • 如上图所示,Set-Cookie这个响应头就是服务器向浏览器发送的“会员卡”,这个响应头的名字是Set-Cookie,后面的JSESSIONID=95A92EC1D7CCB4ADFC24584CB316382E和Path=/Test_cookie,是两组键值对的结构即服务器为这个“会员卡”设置的信息。浏览器收到该信息后会将其保存在内存或硬盘中。
  • 当浏览器再次向服务器发送请求的时候就会携带这个Cookie信息:

Cookie工作原理2.png

  • 这是浏览器发送的请求报文,中间画红框的就是Cookie的信息,这里可以理解为浏览器这次带有“会员卡”再次访问浏览器。
  • 于是,浏览器就可以根据Cookie的信息来判断浏览器的状态了。

1.2 Cookie的使用

1.2.1 Cookie的创建和设置

  • ① 在Servlet中创建Cookie对象,并添加到Response中。
  • ② 打开浏览器访问Servlet程序,服务器将Cookie信息发送给浏览器。
  • ③ 浏览器收到Cookie后会自动保存,那么我们可以在下次浏览器发送请求的时候读取Cookie信息。

  • 示例:

  • pom.xml
  1. <dependency>
  2. <groupId>javax.servlet</groupId>
  3. <artifactId>javax.servlet-api</artifactId>
  4. <version>4.0.1</version>
  5. <scope>provided</scope>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.thymeleaf</groupId>
  9. <artifactId>thymeleaf</artifactId>
  10. <version>3.0.12.RELEASE</version>
  11. </dependency>
  • index.html
  1. <!DOCTYPE html>
  2. <html lang="en" >
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <a href="/app/test1">test1</a>
  9. </body>
  10. </html>
  • ViewBaseServlet.java
  1. package com.example.javaweb2;
  2. import org.thymeleaf.TemplateEngine;
  3. import org.thymeleaf.context.WebContext;
  4. import org.thymeleaf.templatemode.TemplateMode;
  5. import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
  6. import javax.servlet.ServletContext;
  7. import javax.servlet.ServletException;
  8. import javax.servlet.http.HttpServlet;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import java.io.IOException;
  12. public class ViewBaseServlet extends HttpServlet {
  13. private TemplateEngine templateEngine;
  14. @Override
  15. public void init() throws ServletException {
  16. // 获取ServletContext对象
  17. ServletContext servletContext = this.getServletContext();
  18. // 创建Thymeleaf解析器对象
  19. ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
  20. // 给解析器设置参数
  21. // ①HTML是默认模式,明确设置是为了代码更容易理解
  22. templateResolver.setTemplateMode(TemplateMode.HTML);
  23. // ②设置前缀
  24. templateResolver.setPrefix(servletContext.getInitParameter("view-prefix"));
  25. // ③设置后缀
  26. templateResolver.setSuffix(servletContext.getInitParameter("view-suffix"));
  27. // ④设置缓存过期时间(毫秒)
  28. templateResolver.setCacheTTLMs(60000L);
  29. // ⑤设置是否缓存
  30. templateResolver.setCacheable(true);
  31. // ⑥设置服务器端编码方式
  32. templateResolver.setCharacterEncoding("utf-8");
  33. // 创建模板引擎
  34. this.templateEngine = new TemplateEngine();
  35. // 给模板引擎设置模板解析器
  36. this.templateEngine.setTemplateResolver(templateResolver);
  37. }
  38. protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp)
  39. throws IOException {
  40. // 1.设置响应体内容类型和字符集
  41. resp.setContentType("text/html;charset=UTF-8");
  42. // 2.创建WebContext对象
  43. WebContext webContext = new WebContext(req, resp, this.getServletContext());
  44. // 3.处理模板数据
  45. this.templateEngine.process(templateName, webContext, resp.getWriter());
  46. }
  47. }
  • Test1.java
package com.example.javaweb2;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2021-10-22 10:31
 */
@WebServlet(value = "/test1")
public class Test1 extends ViewBaseServlet {

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        // 创建Cookie
        Cookie cookie1 = new Cookie("cookie-name","cookie-Value");
        Cookie cookie2 = new Cookie("cookie-name2","cookie-Value2");

        // 响应给客户端
        response.addCookie(cookie1);
        response.addCookie(cookie2);

        this.processTemplate("demo", request, response);
    }
}

Cookie的创建和设置.png

1.2.2 Cookie的读取

  • Cookie的读取就是读取浏览器中携带的Cookie请求头。
  • ① 服务器端获取浏览器传递过来的Cookie的代码:request.getCookies()
  • ② 遍历Cookie数组,获取所有的Cookie信息。

  • 示例:

  • pom.xml
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.0.12.RELEASE</version>
</dependency>
  • index.html
<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/test1">test1</a>
</body>
</html>
  • Test1.java
package com.example.javaweb2;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2021-10-22 10:31
 */
@WebServlet(value = "/test1")
public class Test1 extends HttpServlet {

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 创建Cookie
        Cookie cookie1 = new Cookie("cookie-name", "cookie-Value");
        Cookie cookie2 = new Cookie("cookie-name2", "cookie-Value2");

        // 响应给客户端
        response.addCookie(cookie1);
        response.addCookie(cookie2);

        response.sendRedirect(request.getContextPath() + "/test2");

    }
}
  • Test2.java
package com.example.javaweb2;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Optional;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2021-10-22 10:31
 */
@WebServlet(value = "/test2")
public class Test2 extends HttpServlet {

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        Optional.ofNullable(cookies).ifPresent(c -> {
            for (Cookie cookie : c) {
                String name = cookie.getName();
                String value = cookie.getValue();
                System.out.println("name:" + name + ",value:" + value);
            }
        });

    }
}

1.2.3 Cookie值的修改

  • ① 服务器端获取浏览器传递过来的Cookie的代码:request.getCookies()
  • ② 遍历Cookie数组,获取所有的Cookie信息。
  • ③ 根据指定的Cookie的名称修改Cookie的值。
  • ④ 通知浏览器保存修改的Cookie。

  • 示例:

  • index.html
<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/test1">test1</a>
</body>
</html>
  • Test1.java
package com.example.javaweb2;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2021-10-22 10:31
 */
@WebServlet(value = "/test1")
public class Test1 extends HttpServlet {

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 创建Cookie
        Cookie cookie1 = new Cookie("cookie-name", "cookie-Value");
        Cookie cookie2 = new Cookie("cookie-name2", "cookie-Value2");

        // 响应给客户端
        response.addCookie(cookie1);
        response.addCookie(cookie2);

        response.sendRedirect(request.getContextPath() + "/test2");

    }
}
  • Test2.java
package com.example.javaweb2;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Optional;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2021-10-22 10:31
 */
@WebServlet(value = "/test2")
public class Test2 extends HttpServlet {

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 修改Cookie信息
        Cookie[] cookies = request.getCookies();
        Optional.ofNullable(cookies).ifPresent(c -> {
            for (Cookie cookie : c) {
                String name = cookie.getName();
                if("cookie-name".equals(name)){
                    cookie.setValue("cookie-Value1");
                    // 通知浏览器保存修改
                    response.addCookie(cookie);
                }
            }
        });

        response.sendRedirect(request.getContextPath()+"/test3");

    }
}
  • Test3.java
package com.example.javaweb2;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Optional;

@WebServlet( value = "/test3")
public class Test3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        Optional.ofNullable(cookies).ifPresent(c -> {
            for (Cookie cookie : c) {
                String name = cookie.getName();
                String value = cookie.getValue();
                System.out.println("name:" + name + ",value:" + value);
            }
        });
    }
}

1.2.4 Cookie的有效时间

  • 经过上面的介绍,我们知道Cookie是保存在浏览器端的,但是浏览器不可能永远保存一个Cookie,所以我们需要为一个Cookie设置一个有效时间。
  • Cookie默认是会话级别的,一旦关闭浏览器,Cookie会失效。
  • Cookie的实例方法setMaxAge()控制Cookie的存活时间,接收一个int类型的参数,单位是秒。
public void setMaxAge(int expiry)
  • 参数设置为0,Cookie立即失效。
  • 参数设置大于0,Cookie在设置的参数秒后失效。
  • 参数设置小于0,Cookie恢复会话级别。

  • 示例:

  • index.html
<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/test1">test1</a>
</body>
</html>
  • Test1.java
package com.example.javaweb2;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(value = "/test1")
public class Test1 extends HttpServlet {

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 创建Cookie
        Cookie cookie = new Cookie("cookie-name", "cookie-Value");
        // 设置Cookie在5秒后失效
        cookie.setMaxAge(5);

        // 响应给客户端
        response.addCookie(cookie);

        response.sendRedirect(request.getContextPath() + "/test2");

    }
}
  • Test2.java
package com.example.javaweb2;

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

@WebServlet(value = "/test2")
public class Test2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        Optional.ofNullable(cookies).ifPresent(c -> {
            for (Cookie cookie : c) {
                String name = cookie.getName();
                String value = cookie.getValue();
                System.out.println("name:" + name + ",value:" + value);
            }
        });
    }
}

1.2.5 Cookie的路径

  • Cookie的路径会保存浏览器访问那些地址应该携带该Cookie,我们知道浏览器会保存不同网站的Cookie,如:百度的Cookie、新浪的Cookie、腾讯的Cookie,但是我们不能访问百度的时候携带腾信的Cookie,也不可能访问每个网站的时候都带上所有的Cookie,这很明显不现实,所以我们通常会为Cookie设置一个Path属性,告诉浏览器何时携带该Cookie。
  • 我们可以通过Cookie的实例方法setPath(),来设置Cookie的Path的路径,这个路径是由浏览器解析的。

    • /:代表服务器的根目录。
    • 如果设置的有效路径是/demo/abc,那么
      • /demo/abc,能访问到Cookie。
      • /demo/abc.xxx,不能访问到Cookie。
      • /demo/abc/xxx.xxx,能访问到Cookie。
      • /demo/abc/a/b/c,能访问到Cookie。
    • 如果不设置,默认会在访问/项目名的资源的时候携带,如:/项目名/abc.html
  • 示例:

  • index.html
<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/test1">test1</a>
</body>
</html>
  • Test1.java
package com.example.javaweb2;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 许大仙
 * @version 1.0
 * @since 2021-10-22 10:31
 */
@WebServlet(value = "/test1")
public class Test1 extends HttpServlet {

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 创建Cookie
        Cookie cookie = new Cookie("cookie-name", "cookie-Value");
        // 设置Cookie的路径
        cookie.setPath(request.getContextPath() + "/abc");
        // 响应给客户端
        response.addCookie(cookie);

        response.sendRedirect(request.getContextPath() + "/test2");

    }
}
  • Test2.java
package com.example.javaweb2;

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

@WebServlet(value = "/test2")
public class Test2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cookie[] cookies = request.getCookies();
        Optional.ofNullable(cookies).ifPresent(c -> {
            for (Cookie cookie : c) {
                String name = cookie.getName();
                String value = cookie.getValue();
                String path = cookie.getPath();

                System.out.println("name:" + name + ",value:" + value + ",path:" + path);
            }
        });
    }
}

1.3 Cookie的弊端

  • ① Cookie的value是String类型,存储不灵活(实际开发中,可能需要存储对象)。
  • ② Cookie数量过多,会浪费数据流量,但是浏览器对Cookie数量有限制,限制数据大小为200~500个,容量为2kb~5kb
  • ③ Cookie存储在浏览器端,相对不安全。

第二章:Session

2.1 Session的简介

2.1.1 为什么需要Session?

  • 使用Cookie有一个非常大的局限,就是如果Cookie很多,则无形的增加了客户端与服务端的数据传输量,而且由于浏览器对Cookie数量的限制,注定我们不能再Cookie中保存过多的信息,于是Session出现。
  • Session的作用就是在服务器端保存一些用户的数据,然后传递给用户一个名字为JSESSIONID的Cookie,这个JESSIONID对应这个服务器中的一个Session对象,通过它就可以获取到保存用户信息的Session。

2.1.2 Session是什么?

  • Session是一个域对象,同时也是Thymeleaf或JSP中的内置对象。
  • Session是在服务器端保存用户数据的一种技术,并且Session是基于Cookie的。

2.1.3 Session的工作原理

  • 前提:浏览器能正常访问服务器。
  • 服务器端没有调用request.getSession()方法,则什么都不会发生。
  • 服务器端调用了request.getSession()方法,服务器端会检查当前请求中是否携带了JSESSIONID的Cookie:
    • 如果有,根据JSESSIONID在服务器端查找对应的HttpSession对象,如果找到,将找到的HttpSession对象作为request.getSession()方法的返回值返回;如果没有找到,则服务器端创建一个HttpSession对象作为request.getSession()方法的返回值返回。
    • 如果没有,服务器创建一个HttpSession对象作为request.getSession()方法的返回值返回。

Session的工作原理.jpg

2.2 Session的使用

2.2.1 Session的创建和获取

  • Session的创建时机是在request.getSession()方法第一次调用的时候。
  • Session被创建后,同时还会有一个JSESSIONID的Cookie被创建。
  • 这个Cookie的默认时效就是当前会话。

  • 示例:

  • pom.xml
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.0.12.RELEASE</version>
</dependency>
  • index.html
<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/test1">test1</a>
</body>
</html>
  • ViewBaseServlet.java
package com.example.javaweb2;

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;

    @Override
    public void init() throws ServletException {
        // 获取ServletContext对象
        ServletContext servletContext = this.getServletContext();
        // 创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
        // 给解析器设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);
        // ②设置前缀
        templateResolver.setPrefix(servletContext.getInitParameter("view-prefix"));
        // ③设置后缀
        templateResolver.setSuffix(servletContext.getInitParameter("view-suffix"));
        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);
        // ⑤设置是否缓存
        templateResolver.setCacheable(true);
        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");
        // 创建模板引擎
        this.templateEngine = new TemplateEngine();
        // 给模板引擎设置模板解析器
        this.templateEngine.setTemplateResolver(templateResolver);
    }

    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp)
        throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, this.getServletContext());

        // 3.处理模板数据
        this.templateEngine.process(templateName, webContext, resp.getWriter());
    }

}
  • Test1.java
package com.example.javaweb2;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet(value = "/test1")
public class Test1 extends ViewBaseServlet {

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        String id = session.getId();
        System.out.println("id = " + id);
        this.processTemplate("demo", request, response);
    }
}
  • /WEB-INF/view/demo.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p th:text="${#session.id}"></p>
</body>
</html>

2.2.2 Session数据的存取

  • 向Session对象域中存储数据:
public void setAttribute(String name, Object value);
  • 从Session对象域中获取数据:
public Object getAttribute(String name);
  • 示例:
  • index.html
<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/test1">test1</a>
</body>
</html>
  • Test1.java
package com.example.javaweb2;


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

@WebServlet(value = "/test1")
public class Test1Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        // 存储数据
        session.setAttribute("abc", "123");

        response.sendRedirect(request.getContextPath() + "/test2");
    }
}
  • Test2.java
package com.example.javaweb2;


import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet(value = "/test2")
public class Test2Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        // 获取数据
        Object abc = session.getAttribute("abc");
        System.out.println("abc = " + abc);
    }
}

2.2.3 Session的有效时间(空闲时间)

  • Session的有效时间:Session对象在服务器端是不能长期保存的,它是有时间限制的,超过一定时间没有被访问过的Session对象就应该被释放掉,以节省其内存,所以Session的有效时间并不是从创建对象开始计时的,到指定时间后释放;而是从最后一次访问开始计时统计其空闲的时间
  • 默认有效时间(Tomcat的web.xml):全局
<!-- ==================== Default Session Configuration ================= -->
  <!-- You can set the default session timeout (in minutes) for all newly   -->
  <!-- created sessions by modifying the value below.                       -->

<session-config>
    <session-timeout>30</session-timeout>
</session-config>

Session对象的默认有效时间是30分钟。

  • 手动设置(在工程的web.xml中配置Session的超时时间):全局
<!-- 设置Session默认的过期时间  -->
<session-config>
    <!-- 以分钟为单位。10分钟超时  -->
    <session-timeout>10</session-timeout>
</session-config>
  • 手动设置:局部

    • 获取超时时间,单位是秒

      public int getMaxInactiveInterval();
      
    • 设置用户多久时间没有操作就会Session过期,单位为秒

      // 如果是正数,则表示用户在指定的时间内没有任何操作,Session就会过期失效
      // 如果是负数,则表示Session永不过期
      public void setMaxInactiveInterval(int interval);
      
  • 强制失效:

public void invalidate();

2.3 Session对象的失效情况

  • Session对象空闲时间达到了目标设置的最大值,自动释放。
  • Session对象被强制失效。
  • Web应用卸载。
  • 服务器进程停止。

2.4 Session的活化和钝化

  • Session机制很好的解决了Cookie的不足,但是当访问应用的用户很多时,服务器上就会创建非常多的Session对象,如果不对这些Session对象进行处理,那么在Session失效之前,这些Session一直都会在服务器的内存中存在,此时,就出现了Session活化和钝化的机制。

Session的钝化和活化.png

  • Session钝化:Session在一段时间内没有被使用或关闭服务器时,会将当前存在的Session对象及Session对象中的数据从内存序列化到磁盘的过程,称之为钝化。
  • Session活化:Session被钝化后,服务器再次调用Session对象或重启服务器时,将Session对象及Session对象中的数据从磁盘反序列化到内存的过程,称之为活化。
  • 如果希望Session域中的对象也能够随Session钝化过程一起序列化到磁盘上,则对象的实现类也必须实现java.io.Serializable接口。不仅如此,如果对象中还包含其他对象的引用,则被关联的对象也必须支持序列化,否则会抛出异常:java.io.NotSerializableException。

2.5 浏览器和Session关联的技术内幕

  • 我们发现一旦浏览器关闭之后,我们再去获取Session对象就会创建一个新的Session对象,这是为什么?

浏览器和Session关联的技术内幕.png

  • 当浏览器关闭之后,因为浏览器无法再通知服务器,之前创建的session的id是多少,所以服务器也没办法找到对应的Session对象,就以为是第一次访问,就创建了新的Session对象并返回。