整合多方大佬博客以及视频 一文读懂 servlet

news2024/12/31 6:07:14

参考文章以及视频

文章:

都2023年了,Servlet还有必要学习吗?一文带你快速了解Servlet_servlet用得多吗-CSDN博客

【计算机网络】HTTP 协议详解_3.简述浏览器请求一个网址的过程中用到的网络协议,以及协议的用途(写关键点即可)-CSDN博客

【从理论到应用】HTTP请求响应详解 (请求数据格式,请求方式,Web开发中的体现)_apifox 如何转换htt请求-CSDN博客

HTTP响应是什么?_响应内容-CSDN博客

Servlet的生命周期-CSDN博客

HttpServletRequest介绍和使用-CSDN博客

【Servlet】请求转发与重定向_servlet请求转发可以访问其它应用的资源吗-CSDN博客

https://blog.csdn.net/qq_41264674/article/details/80472666

cookie详解-CSDN博客

什么是Session的销毁方式?_销毁session-CSDN博客

ServletContext详解-CSDN博客

【JavaWeb】会话管理 cookie session 三大域对象总结_cookie登录时效性-CSDN博客

视频:

【可能是B站讲的最好的Servlet教程,一天打通Servlet全套教程丨2022最新版,轻松掌握servlet基础+案例实操】https://www.bilibili.com/video/BV1kt4y157xd?p=15&vd_source=bb412cc25ca27e171f8e17085daad038

1、主旨大纲

在这里插入图片描述

2、Http协议

介绍

在这里插入图片描述

浏览器的书写格式

在这里插入图片描述

Http之url

在这里插入图片描述

Http请求

介绍

HTTP请求格式是由三部分组成:

  • 请求行(Request line):包括请求方法、URL和协议版本。
  1. 请求方法(Request method):表示要执行的操作,常见的方法有GET、POST、PUT、DELETE等。
  2. URL(Uniform Resource Locator):表示要访问的资源路径。
  3. 协议版本(Protocol version):表示使用的HTTP协议版本,如HTTP/1.1。
  • 请求头部(Request headers):包括一些关于请求的额外信息,如User-Agent、Content-Type、Authorization等。
  • 请求体(Request body):用于传输请求的数据,对于GET请求来说,请求体通常为空。

示例

以下是一个示例HTTP请求的格式:

GET /index.html HTTP/1.1    
​
Host: www.example.com
​
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 
Safari/537.3
​
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
​
Accept-Encoding: gzip, deflate, br
​
Accept-Language: en-US,en;q=0.9

在这个示例中:

请求行包括GET方法URL为/index.html协议版本为HTTP/1.1

请求头部包括HostUser-AgentAcceptAccept-EncodingAccept-Language等字段。

请求体为空,因为这是一个GET请求。

在上述实例中,申明了该请求是GET请求,我们最常用的请求方式就是GET和POST请求,二者在请求参数的传递中有很大不同,正如上述实例中所说:

GET请求的请求参数在请求行中,没有请求体

POST请求的请求参数在请求体中

格式

在这里插入图片描述

Http响应

介绍

当客户端发起一个请求后,一般都会得到一个服务器的响应,断网或者服务器宕机的情况下除外。服务器发送给客户端的 HTTP 响应用于向客户端提供其请求的资源,以及客户端请求的执行结果。

与请求类似,HTTP 响应同样由四个部分组成,分别为响应行(状态行)、响应头、空行和响应体,如下图所示:

在这里插入图片描述

响应行

响应行以 HTTP 协议版本表示响应状态的状态码形容这个状态的一个短语组成,每个部分使用空格分隔,如下所示:

HTTP/1.1 200 OK

其中,HTTP/1.1 为 HTTP 协议版本,200 为响应的状态码,OK 为状态文本。注意:响应行中的字母都是大写的。

HTTP 响应的状态码是一个三位的整数,其中状态码的第一位用来表示响应的类别,状态码一共有 5 类,如下表所示;
在这里插入图片描述

响应头

响应头与 HTTP 请求中的请求头类似,同样由头部字段名、冒号、空格和值组成,例如Date: Tue, 22 Sep 2020 02:00:55 GMT。响应头中包含了一系列服务器的信息,以及服务器对请求的响应。

HTTP 协议的响应头中常用的头部字段名以及含义如下表所示:

在这里插入图片描述
在这里插入图片描述

空行与响应体

与 HTTP 请求中的空行相同,HTTP 响应中同样使用空行来表示响应头结束。响应体则是服务器根据客户端的请求返回给客户端的具体数据。

示例

HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache/2.2.14 (Win32)
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
Content-Length: 88
Content-Type: text/html
Connection: Closed
​
<html>
<body>
<h1>Hello, CSDN!</h1>
</body>
</html>

3、Servlet

介绍

Servlet 是 JavaEE 的规范之一,通俗的来说就是 Java 接口,将来我们可以定义 Java 类来实现这个接口,并由 Web 服务器运行 Servlet ,所以 TomCat 又被称作 Servlet 容器。

Servlet 提供了动态 Web 资源开发技术,一种可以将网页数据提交到 Java 代码,并且将 Java 程序的数据返回给网页的技术,使用 Servlet 技术实现了不同用户登录之后在页面上动态的显示不同内容等的功能。

简单实现Servlet


@WebServlet("/servlet01")
public class servlet01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest rep, HttpServletResponse resp) throws IOException {
        System.out.println("hello servlet");
        resp.getWriter().write("hello servlet?");
    }
}

在这里插入图片描述

  • 1、创建普通的类
  • 2、继承HttpServlet
  • 3、重写service方法,用来处理请求
  • 4、设置@WebServlet注解,指定访问路径

Servlet的工作流程

在这里插入图片描述

Servlet的实现方式

第一种:继承HttpServlet

@WebServlet("/servlet01")
public class servlet01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest rep, HttpServletResponse resp) throws IOException {
        System.out.println("hello servlet");
        resp.getWriter().write("hello servlet?");
    }
}

第二种:继承GenericServlet

@WebServlet("/serlet02")
public class servlet02 extends GenericServlet {
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
​
    }
}

第三种:实现Servlet接口

在这里插入图片描述

补充:

除了去实现相应的service方法,实际上我们还可以直接去使用doget,dopost等方法

我们查看Httpservice的源码,看看它的service方法

  protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);<---------------------------------------------
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader("If-Modified-Since");
                } catch (IllegalArgumentException var9) {
                    ifModifiedSince = -1L;
                }
​
                if (ifModifiedSince < lastModified / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);<--------------------------------------
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);<-------------------------------
        } else if (method.equals("POST")) {
            this.doPost(req, resp);<--------------------------------------
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);<---------------------------------------
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);<----------------------------------
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);<------------------------------------
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);<-------------------------------------
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);<----------------------------------
        }
    }

我打标记,这里发现,实质就是先去获取你是什么请求方法,然后去调用对应的doget,dopost等方法

Servlet的生命周期

介绍

在这里插入图片描述

Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

  • Servlet 初始化后调用 init () 方法。
  • Servlet 调用 service() 方法来处理客户端的请求。
  • Servlet 销毁前调用 destroy() 方法。
  • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

架构图:

下图显示了一个典型的 Servlet 生命周期方案。

  • 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。

  • Servlet 容器在调用 service() 方法之前加载 Servlet。

  • 然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。

在这里插入图片描述

init() 方法

init 方法被设计成只调用一次。它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用。因此,它是用于一次性初始化,就像 Applet 的 init 方法一样。

Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,但是您也可以指定 Servlet 在服务器第一次启动时被加载。

当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。

init 方法的定义如下:

public void init() throws ServletException {
  // 初始化代码...
}

service() 方法

service() 方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。

每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。

下面是该方法的特征:

public void service(ServletRequest request, 
                    ServletResponse response) 
      throws ServletException, IOException{
}

service() 方法由容器调用,service 方法在适当的时候调用 doGet、doPost、doPut、doDelete 等方法。所以,您不用对 service() 方法做任何动作,您只需要根据来自客户端的请求类型来重写 doGet() 或 doPost() 即可。

doGet() 和 doPost() 方法是每次服务请求中最常用的方法。下面是这两种方法的特征。

doGet() 方法

GET 请求来自于一个 URL 的正常请求,或者来自于一个未指定 METHOD 的 HTML 表单,它由 doGet() 方法处理。

public void doGet(HttpServletRequest request,
                  HttpServletResponse response)
    throws ServletException, IOException {
    // Servlet 代码
}
doPost() 方法

POST 请求来自于一个特别指定了 METHOD 为 POST 的 HTML 表单,它由 doPost() 方法处理。

public void doPost(HttpServletRequest request,
                   HttpServletResponse response)
    throws ServletException, IOException {
    // Servlet 代码
}

destroy() 方法

destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。

在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。destroy 方法定义如下所示:

  public void destroy() {
    // 终止化代码...
  }

补充:tomocat与servlet工作的时序

在这里插入图片描述

HttpservletRequest

介绍:

httpServletRequest对象对http请求进行了封装,我们使用这个对象就可以方便快捷的获取http中的信息。HttpServletRequest 对象代表客户端的请求,在里面就包含了所有的客服端信息,我们通过这个对象的方法便可以获取所有的客服端信息,包括请求头和请求体中的所有数据。

常见方法:

  1. getRequestURL():得到请求的URI
  2. getRequestURL():得到请求的URL
  3. getHeader(String s):getHeader表示得到请求头,参数s表示想要获取请求头中的什么数据
  4. getHeader("Host"):获取请求的主机
  5. getHeader("Referer"):获取请求来自于哪里,一般用来做防盗链
  6. getRemotetAddr():得到请求的ip
  7. getParameter(String s):得到请求参数的值
  8. getParameterValues(String s):得到请求参数的值,用于参数有多个值,返回一个数组

案例演示:

前端:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<form action="http://localhost:8080/servlet/requestTest" method="post">
    用户名:<input type="text" name="username"> <br>
    密 码:<input type="password" name="password"><br>
    爱好 <input type="checkbox" name="hobby" value="lq">篮球
    <input type="checkbox" name="hobby" value="zq">足球
    <input type="checkbox" name="hobby" value="pq">排球<br>
    <input type="submit" value="注册">
</form>
</body>
</html>
后端:
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Arrays;
 
@WebServlet("/requestTest")
public class HttpServletRequestTest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //得到请求URL
        StringBuffer requestURL = request.getRequestURL();
        System.out.println("请求的URL是:" + requestURL);
        //得到请求URI
        String requestURI = request.getRequestURI();
        System.out.println("请求的URI是:" + requestURI);
        //得到主机名Host
        String host = request.getHeader("Host");
        System.out.println("请求的主机名是:" + host);
        //得到请求的ip
        String ip = request.getRemoteAddr();
        System.out.println(ip);
        //得到请求参数,分别得到用户名,密码还有爱好
        //如果参数中有中文,需要设置编码
        request.setCharacterEncoding("utf-8");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String[] hobbies = request.getParameterValues("hobby");
        System.out.println("用户名为:" + username);
        System.out.println("密码:" + password);
        System.out.println("爱好为:" + Arrays.toString(hobbies));
        //得到访问来自哪里
        String referer = request.getHeader("Referer");
        System.out.println("请求来自于:" + referer);
    }
 
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}
发送请求

在这里插入图片描述

抓包

请求头:


POST /servlet/requestTest HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 60
Cache-Control: max-age=0
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: http://localhost:8080
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:8080/servlet/register_request.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=ABEC5EA43080A0BFA70C2AABDF39BB7C; Pycharm-cb145b54=bac13d99-2d7f-4b5f-9c85-e783571ee72d; Idea-8cd34e8b=1bf6d6e0-14ee-4950-96ec-48105743bb40

请求体:
在这里插入图片描述

控制台输出:

在这里插入图片描述

请求转发

介绍

在这里插入图片描述
在这里插入图片描述

request作用域(实际就是service方法里面的HttpServletRequest rep)

在这里插入图片描述


@WebServlet("/s05")
public class servlet03 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest rep, HttpServletResponse resp) throws IOException, ServletException {
        System.out.println("Servlet05");
        rep.setAttribute("name","admin");
       rep.getRequestDispatcher("s06").forward(rep,resp);
    }
}

@WebServlet("/s06")
public class servlet04 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest rep, HttpServletResponse resp) throws IOException {
        System.out.println("Servlet06");
        String name =(String) rep.getAttribute("name");
        System.out.println("name"+name);
    }
}

当我们访问/s05时,请求转发会去跳转到/s06/s06获取到/s05的传送过来的rep里面的name对应的数据

在这里插入图片描述

HttpServletResponse

介绍

在这里插入图片描述

响应数据

响应字符数据

通过response对象,将你想要响应到客户端的字符型数据发送到浏览器里面。只用两步就可以实现:1、先通过response对象获取字符输出流:PrintWriter writer = resp.getWriter();2、将你想要写的数据通过write()方法响应到客户端:writer.write()。

public class HttpServletResponse001 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();
        writer.write("hello servlet!!!");
    }
}

在这里插入图片描述

需要注意的几点:

1.response不仅可以返回纯文本,还可以HTML的各个标签。在返回标签时要注意先把响应响应头的ContentType属性改成text/html格式,不然浏览器会默认把相应的内容当成纯文本解析。


public class HttpServletResponse001 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        PrintWriter writer = resp.getWriter();
        writer.write("hello servlet!!!");
        writer.write("<br/>name:<input type = 'text'/>");
    }
}

在这里插入图片描述

2.如果响应的是中文的内容,需要把响应头字体类型改成UTF-8。因为服务器默认的字体类型是ISO-8859-1,如果不修改会导致浏览器解析乱码。
在这里插入图片描述


public class HttpServletResponse001 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        resp.setContentType("text/html");
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        writer.write("我的servlet程序!!!");
        writer.write("<br/>姓名:<input type = 'text'/>");
    }
}

3.修改响应头等信息需要在通过response对象获取字符输出流就完成,在后面才修改没有效果。

4.响应结束后,相应的字符流不需要关闭。他不需要向像Java基础里面字节输入流那种最后需要手动关闭流节省资源。因为在响应结束后,response对象自动销毁,服务器会对其关闭。

响应字节数据

通过response对象,将你想要响应到客户端的字符型数据发送到浏览器里面。大致需要3步完成:1、读取文件(图片,音频,视频等二进制输入输出数据)2、获取字节输出流3、通过write()方法响应给客户端


public class HttpServletResponse002 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.读物文件
        FileInputStream inputStream = new FileInputStream("C:\Users\cx\Desktop\1.png");
        //2.获取字节输出流
        ServletOutputStream outputStream = resp.getOutputStream();
        //3.打印文件
        byte []b = new byte[2048];
        int len = 0;
        while ((len = inputStream.read(b))!=0){
            outputStream.write(b,0,len);
        }
        inputStream.close();
    }
}
补充:响应乱码问题

在这里插入图片描述

重定向

介绍

在这里插入图片描述

注:通常服务器发送一个302状态码以及一个Location消息头(该消息头的值是一个地址,即重定向地址),浏览器收到之后,会立即向重定向地址发送请求。

如何重定向

response.sendRedirect(String url)。
注:url即重定向地址。

重定向与请求转发

重定向:

在这里插入图片描述

请求转发:

在这里插入图片描述

不同:

在这里插入图片描述

Cookie

介绍:

cookie用户标记用户信息,现代浏览器有时会有这样的功能,当我们第一次登录某个系统后,再次登录时,就会直接进入到系统内部,不需要再次输入用户名和密码,就可以直接登录。这是因为我们的浏览器存储了该网站的cookie,当我们向网站发送请求时,网站检测到了cookie,识别出我们的身份,于是就不需要我们再次输入用户名和密码认证了。除此之外,我们在登录网站后,进行一些操作的时候,也会在请求数据包中携带cookie信息,这样可以帮助网站识别这些操作究竟是哪个用户的操作。使用cookie(或者session)识别用户身份是当前网站使用的主流手段。目前网站使用的HTTP协议,是一种无状态的协议,简单来说,就是客户端发送请求,服务器根据请求处理后给予应答。因此,服务器很难判断这些请求究竟是哪个用户发送过来的,通过IP地址等方式无法真正的区分不同的用户,因此我们必须使用cookie(或者session)。

事实上,cookie由服务器产生,发送给客户端,并且要求客户端保留cookie,并且在数据包发送时携带。如下所示:

在这里插入图片描述

上图中的set-cookie属性,就是服务器给客户端发送的cookie。

当然你也可以通过一下路径查看cookie
在这里插入图片描述

Cookie的表示

一般情况下,cookie是以键值对进行表示的(key-value),例如name=jack,这个就表示cookie的名字是name,cookie携带的值是jack。

Cookie的创建与发送

在这里插入图片描述


@RestController
public class servlet05 extends HttpServlet {
    @GetMapping("/cook01")
    protected void service(HttpServletRequest rep, HttpServletResponse resp) throws IOException {
       //Cookie的创建
        Cookie cookie = new Cookie("name","admin");
        //发送和响应Cookie对象
        resp.addCookie(cookie);
    }
}

在这里插入图片描述

Cookie的获取

在这里插入图片描述


@RestController
public class servlet06 extends HttpServlet {
    @GetMapping("/cook02")
    protected void service(HttpServletRequest rep, HttpServletResponse resp) throws IOException {
        //获取Cookie数组
        Cookie[] cookies = rep.getCookies();
        //判断Cookie是否为空
        if(cookies !=null&&cookies.length>0){
            //遍历
            for(Cookie cookie:cookies){
                //获取名称和值
                String name = cookie.getName();
                String value = cookie.getValue();
                System.out.println(name);
                System.out.println(value);
            }
        }
    }
}

注意:因为我没有本地自己装tomcat,所以我就换了种方法实现

Cookie设置到期时间

介绍

除了Cookie的名称和内容外,我们还需要关心一个信息,到期时间,到期时间用来指定该cookie 何时失效。默认为当前浏览器关闭即失效。我们可以手动设定cookie的有效时间(通过到期时间计算),通过setMaxAge(int time);方法设定 cookie 的最大有效时间,以秒为单位。

到期时间的取值
负整数

若为负数,表示不存储该 cookie。cookie的 maxAge 属性的默认值就是-1,表示只在浏览器内存中存活,一旦关闭浏览器窗口,那么 cookie 就会消失。

正整数

若大于0的整数,表示存储的秒数。表示cookie对象可存活指定的秒数。当生命大于O时,浏览器会把Cookie保存到硬盘上,就算关闭浏览器,就算重启客户端电脑,cookie也会存活相应的时间。

若为0,表示删除该 cookie。cookie 生命等于0是一个特殊的值,它表示cookie被作废!也就是说,如果原来浏览器已经保存了这个Cookie,那么可以通过Cookie的 setMaxAge(O)来删除这个Cookie。无论是在浏览器内存中,还是在客户端硬盘上都会删除这个Cookie。

实战

@RestController
public class servlet07 extends HttpServlet {
    @GetMapping("/cook03")
    protected void service(HttpServletRequest rep, HttpServletResponse resp) throws IOException {
        //Cookie的创建
        Cookie cookie = new Cookie("name1","admin1");
        //Cookie到期时间设置
        cookie.setMaxAge(-1);//关闭浏览器失效
        //发送和响应Cookie对象
        resp.addCookie(cookie);
​
        //Cookie的创建
        Cookie cookie2 = new Cookie("name2","admin2");
        //Cookie到期时间设置
        cookie2.setMaxAge(30);//存活30秒
        //发送和响应Cookie对象
        resp.addCookie(cookie2);
​
        //Cookie的创建
        Cookie cookie3 = new Cookie("name3","admin3");
        //Cookie到期时间设置
        cookie3.setMaxAge(0);//删除cookie3
        //发送和响应Cookie对象
        resp.addCookie(cookie3);
​
    }
}

分析:

在这里插入图片描述

你发现只有两个,原因就是当到期时间设置为0时,就是删除了这个cookie

当我们30s后重新去访问(Cookie的获取哪里写的路径:目的时后台打印)时会发现,只剩下

在这里插入图片描述

当我们关闭浏览器后,再次去访问(Cookie的获取哪里写的路径:目的时后台打印)时会发现,全没了

在这里插入图片描述

注意:之前在Cookie的创建与发送标题中的Cookie这里已经被我提前删除了,所以并没有它。

Cookie的注意点

1、Cookie保存在当前浏览器中。在一般的站点中常常有记住用户名这样一个操作,该操作只是将信息保存在本机上,换电脑以后这些信息就无效了。而且cookie 还不能跨浏览器。

2、Cookie存中文问题Cookie 中不能出现中文,如果有中文则通过URLEncoder.encode()来进行编码,获取时通过URLDecoder.decode()来进行解码。


String name = “姓名"
String value = "张三";
// 通过 URLEncoder.encode()来进行编码
name = URLEncoder.encode(name);
value = URLEncoder.encode(value) ;
// 创建cookie对象
Cookie cookie = new Cookie(name,value) ;
//发送cookie对象
 response.addcookie(cookie);

//获取时通过uRLDecoder.decode()来进行解码
URLDecoder.decode(cookie.getName()) ;
URLDecoder.decode(cookie.getValue()) ;

3、同名Cookie问题如果服务器端发送重复的Cookie那么会覆盖原有的Cookie。

4、浏览器存放Cookie的数量不同的浏览器对Cookie也有限定,Cookie的存储有是上限的。Cookie是存储在客户端(浏览器)的,而且一般是由服务器端创建和设定。后期结合Session来实现回话跟踪。

Cookie的路径

介绍:

Cookie的setPath设置cookie的路径,这个路径直接决定服务器的请求是否会从浏览器中加载某些cookie。

情景一:当前服务器下任何项目的任意资源都可获取Cookie对象

/*当前项目路径为:s01*/
Cookie cookie = new Cookie("xxx","xxx");
//设置路径为"/",表示在当前服务器下任何项目都可访问到cookie对象
cookie.setPath("/");
response.addcookie(cookie) ;
情景二:当前项目下的资源可获取Cookie对象(默认不设置Cookie的path)

/*当前项目路径为:s01*/
Cookie cookie = new Cookie("xxx","xxx") ;
//设置路径为"/s01",表示在当前项目下任何项目都可访问到cookie对象
cookie.setPath("/s01");//默认情况,可不设置path的值
response.addcookie(cookie) ;
情景三:指定项目下的资源可获取Cookie对象

/*当前项目路径为:s01*/
Cookie cookie = new Cookie("xxx","xxx");
//设置路径为"/s02",表示在s02项目下才可访问到cookie对象
cookie.setPath("/s02");//只能在s02项目下获取cookie,就算cookie是s01产生的,s01也不能获取它
response.addcookie(cookie) ;
情景四:指定目录下的资源可获取Cookie对象

/*当前项目路径为:s01*/
Cookie cookie = new Cookie("xxx","xxx");
//设置路径为"/s01/cook",表示在s02/cook目录下才可访问到cookie对象
cookie.setPath("/s01/cook") ;
 response.addcookie(cookie) ;
总结:

如果我们设置path,如果当前访问的路径包含了cookie的路径(当前访问路径在cookie路径基础上要比cookie的范围小)cookie就会加载到request对象之中。cookie的路径指的是可以访问该cookie的顶层目录,该路径的子路径也可以访问该cookie。总结:当访问的路径包含了cookie的路径时,则该请求将带上该cookie;如果访问路径不包含cookie路径,

HttpSession

介绍

Session技术是将数据存储在服务器端的技术,会为每个客户端都创建一块内存空间 存储客户的数据,但客户端需要每次都携带一个标识ID去服务器中寻找属于自己的内 存空间。所以说Session的实现是基于Cookie,Session需要借助于Cookie存储客 户的唯一性标识JSESSIONID;

使用场景

我们先来想一个问题,这个问题就是我们在游览购物网站时,我们并没有登录,但是我们任然可以将商品加入购物车,并且进行查看,当我们退出游览器后再打开游览器进行查看时,购物车中依然有我们选择的商品,这该怎么实现呢?

​ 当然,我们可以使用cookie,但是cookie能存放大量数据吗?这时,我们就需要一种新的技术,Session。session是存储于服务器端的特殊对象,服务器会为每一个游览器(客户端)创建一个唯一的session。这个session是服务器端共享,每个游览器(客户端)独享的。我们可以在session存储数据,实现数据共享。

原理示意图

在这里插入图片描述

简单使用


@RestController
public class servlet08 extends HttpServlet {
    @GetMapping("/session01")
    protected void service(HttpServletRequest rep, HttpServletResponse resp) throws IOException {
       //获取session对象
        HttpSession session = rep.getSession();
        //获取session的会话标识符
        String id =session.getId();
        System.out.println(id);
        //获取session创建时间
        long creationTime = session.getCreationTime();
        System.out.println(creationTime);
        //获取最后一次访问时间
        long lastAccessedTime = session.getLastAccessedTime();
        System.out.println(lastAccessedTime);
        // 判断是否是新的session对象
        boolean aNew = session.isNew();
        System.out.println(aNew);
    }
}

在这里插入图片描述

标识符JSESSIONID

​ Session既然是为了标识一次会话,那么此次会话就应该有一个唯一的标志,这个标志就是sessionld。

每当一次请求到达服务器,如果开启了会话(访问了session),服务器第一步会查看是否从客户端回传一个

名为JSESSIONID的cookie,如果没有则认为这是一次新的会话,会创建一个新的 session对象,并用唯一的

seSSionld为此次会话做一个标志。如果有JESSIONID这个cookie回传,服务器则会根据JSESSIONID 这个值去查

看是否含有id为JSESSION值的session对象,如果没有则认为是一个新的会话,重新创建一个新的session对象,

并标志此次会话;如果找到了相应的 session对象,则认为是之前标志过的一次会话,返回该session对象,数

据达到共享。

这里提到一个叫做JSESSIONID的cookie,这是一个比较特殊的cookie,当用户请求服务器时,如果访问了

session,则服务器会创建一个名为JSESSIONID,值为获取到的 session(无论是获取到的还是新创建的)的

sessionld 的 cookie 对象,并添加到 response 对象中,响应给客户端,有效时间为关闭浏览器。

所以 Session的底层依赖Cookie来实现。

Session域对象


@RestController
public class servlet09 extends HttpServlet {
    @GetMapping("/session02")
    protected void service(HttpServletRequest rep, HttpServletResponse resp) throws IOException {
       //获取session对象
        HttpSession session = rep.getSession();
        //获取域对象
        session.setAttribute("uname","upwd");
        session.setAttribute("uname1","upwd1");
        //移除域对象
        session.removeAttribute("uname");
    }
}

Session对象的销毁

大纲
  • 默认时间到期
  • 自己设定到期时间
  • 立刻失效
  • 关闭浏览器
  • 关闭服务器
默认时间到期

当客户端第一次请求 servlet 并且操作 session 时,session 对象生成,以 Tomcat 为例,Tomcat 中 session 默认的存活时间为 30min,即你不操作界面的时间,一旦有操作,session 会重新计时。那么 session 的默认时间可以改么?答案是肯定的。可以在 Tomcat 中的 web.xml 文件中进行修改。如下图:

在这里插入图片描述

自己设定到期时间

当然除了以上的修改方式外,我们也可以在程序中自己设定 session 的生命周期,通过 session.setMaxInactiveInterval(int); 来设定 session 的最大不活动时间,单位为秒。

HttpSession session = req.getSession();
session.setMaxInactiveInterval(5);

当然我们也可以通过 getMaxInactiveInterval(); 方法来查看当前 Session 对象的最大不活动时间。

立刻失效

或者我们也可以通过 session.invalidate(); 方法让 session 立刻失效。

session.invalidate();
关闭浏览器

session 的底层依赖 cookie 实现,因为不同用户访问服务器要判别到底是使用哪个 session,所以当用户第一次访问服务器的时候往往会把一个 session id 通过 cookie 存储到用户端,并且该 cookie 的有效时间为关闭浏览器,从而 session 在浏览器关闭时也相当于失效了(因为没有 session id 再与之对应)。如下图,关闭后再打开,重新给浏览器分配了个 session id。

在这里插入图片描述

需要注意的是这里只是 cookie 失效了,你再访问相当于服务器把你当成了新用户,又给你创建了一个 session,并没有把之前的 session 对象销毁。

关闭服务器

当非正常关闭服务器时,session 销毁;当正常关闭服务器时,session 将被序列化到磁盘上,在工作空间 work 目录下的 SESSION.ser 文件中,如果对象被保存在了 session 中,服务器在关闭时要把对象序列化到硬盘,这个对象就必须实现 Serializable 接口,下次启动服务时,自动加载到内存。如下图,正常关闭后可以看到文件夹中多了一个 SESSIONS.ser 文件,再次启动服务器则文件消失。

在这里插入图片描述

ServletContext

介绍:

ServletContext是Servlet规范中的一个对象,它代表了当前Web应用程序的上下文(Context)。这个上下文包括了整个Web应用程序的信息,可以被Web应用中的所有Servlet共享。可以将ServletContext看作是一个全局存储区,用于存储和访问Web应用中的全局数据和资源。

我们将ServletContext和Cookie、Session做一个简单对比,如下图:
在这里插入图片描述

我们可以把ServletContext当成一个公用的空间,可以被所有的客户访问,如上图,A、B、C三个客户端都可以访问。WEB容器在启动时,它会为每个Web应用程序都创建一个对应的ServletContext,它代表当前Web应用,并且它被所有客户端共享。

由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。公共聊天室就会用到它。

当web应用关闭、Tomcat关闭或者Web应用reload的时候,ServletContext对象会被销毁。

获取ServletContext

在这里插入图片描述

常用方法

获取当前服务器信息:
在这里插入图片描述

获取项目的真实路径:
在这里插入图片描述

效果:

在这里插入图片描述

三大域对象

在这里插入图片描述

三大域对象的数据作用范围图解 :

  • 请求域

客户端发送一次的请求,以及,请求转发

在这里插入图片描述

  • 会话域 :

同一个客户端,跨多个请求 传递信息,举例:servletA可以servletB、C、D也可以接受信息,只要拿到session对应的cookie

在这里插入图片描述

  • 应用域

跨客户端 , 另一个客户端也能取到数据
在这里插入图片描述

  • 所有域 合体

在这里插入图片描述

结言:

你好,我是Blue. 为帮助别人少走弯路而写博客 !!!

如果本篇文章帮到了你 不妨点个赞吧~ 我会很高兴的 😄 (^ ~ ^) 。想看更多 那就点个关注吧 我会尽力带来有趣的内容 😎。

如果你遇到了问题,自己没法解决,可以私信问我。

感谢订阅专栏 三连文章!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2156035.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[数据结构]无头单向非循环链表的实现与应用

文章目录 一、引言二、线性表的基本概念1、线性表是什么2、链表与顺序表的区别3、无头单向非循环链表 三、无头单向非循环链表的实现1、结构体定义2、初始化3、销毁4、显示5、增删查改 四、分析无头单向非循环链表1、存储方式2、优点3、缺点 五、总结1、练习题2、源代码 一、引…

Mysql----索引与事务

1.索引 1.1什么是MYSQL的索引 MySQL官方对于索引的定义&#xff1a;索引是帮助Mysql高效获取数据的数据结构 Mysql在存储数据之外&#xff0c;数据库系统中还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种引用&#xff08;指向&#xff09;表中的数据&…

萤石云平台接入SVMSPro平台

萤石云平台接入SVMSPro平台 步骤一&#xff1a;进入萤石云官网&#xff1a;https://open.ys7.com/ &#xff0c;点右上角的登陆&#xff0c;填写自己的用户名密码&#xff1b; 步骤二&#xff1a;登陆进去后&#xff0c;开发者服务—>我的账号—>应用信息&#xff0c;在…

电气自动化入门07:开关电源、三相异步电动机多地与顺序控制电路

视频链接&#xff1a;3.5 电工知识&#xff1a;三相交流异步电动机多地与顺序控制及开关电源选型_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1PJ41117PW?p9&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 1.开关电源功能与选型说明&#xff1a; 2.三相异步电动机…

数据结构与算法之间有何关系?

相信很多人都应该上个《数据结构与算法》这门课吧&#xff0c;而这两个概念也如孪生兄弟一样经常被拿出来一起讨论。那它们究竟是一个什么样子的关系呢&#xff1f; 听到数据结构与算法我第一反应是想到了Pascal 语言之父尼古拉斯沃斯在他的《Algorithms Data Structures Pro…

esp32s3分区表配置及读写

一、分区表介绍 每片 ESP32-S3 的 flash 可以包含多个应用程序&#xff0c;以及多种不同类型的数据&#xff08;例如校准数据、文件系统数据、参数存储数据等&#xff09;。因此&#xff0c;在 flash 的 默认偏移地址 0x8000 处烧写一张分区表。 分区表中的每个条目都包括以下…

【d47】【Java】【力扣】997.找到小镇的法官

思路 记录入度和出度 一个人可以连接多个&#xff0c;一个人也可以被多个人连接&#xff0c;就是图的性质 一个人可以信任多人&#xff0c;一个人也可以被多个人信任 统计入度出度&#xff0c; 法官&#xff1a;入度n-1,出度0 其他人&#xff1a;因为被所有其他人信任的 只能…

JS执行机制(同步和异步)

JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。 异步:在做这件事的同时&#xff0c;你还可以去处理其他事 他们的本质区别&#xff1a;这条流水线上各个流程的执行顺序不同。 同步任务 同步任务都在主线程上执行&#xff0c;形成一个执行栈。 异步…

7、论等保的必要性

数据来源&#xff1a;7.论等保的必要性_哔哩哔哩_bilibili 等级保护必要性 降低信息安全风险 等级保护旨在降低信息安全风险&#xff0c;提高信息系统的安全防护能力。 风险发现与整改 开展等级保护的最重要原因是通过测评工作&#xff0c;发现单位系统内外部的安全风险和脆弱…

【计网】从零开始掌握序列化 --- JSON实现协议 + 设计 传输\会话\应用 三层结构

唯有梦想才配让你不安&#xff0c; 唯有行动才能解除你的不安。 --- 卢思浩 --- 从零开始掌握序列化 1 知识回顾2 序列化与编写协议2.1 使用Json进行序列化2.2 编写协议 3 封装IOService4 应用层 --- 网络计算器5 总结 1 知识回顾 上一篇文章我们讲解了协议的本质是双方能够…

【JavaEE】多线程编程引入——认识Thread类

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯&#xff0c;你们的点赞收藏是我前进最大的动力&#xff01;&#xff01;希望本文内容能帮到你&#xff01; 目录 引入&#xff1a; 一&#xff1a;Thread类 1&#xff1a;Thread类可以直接调用 2&#xff1a;run方法 &a…

SpringBoot+thymeleaf竞赛报名系统

一、介绍 > 这是一个基于Spring Boot的后台管理系统。 > 使用了Mybatis Plus作为持久层框架&#xff0c;EasyExcel用于Excel操作&#xff0c;Thymeleaf作为前端模板引擎。 > 界面简洁&#xff0c;功能丰富&#xff0c;完成度比较高&#xff0c;适用于JAVA初学者作…

安国U盘量产工具系列下载地址

来源地址&#xff08;访问需要科学工具&#xff09;&#xff1a;AlcorMP (Последняя версия ALCOR U2 MP v23.08.07.00.H) – [USBDev.ru] 版本列表&#xff1a; AlcorMP&#xff08;最新版本的 ALCOR U2 MP v23.08.07.00.H&#xff09; AlcorMP是在Alcor Mic…

SpringBoot项目License证书生成与验证(TrueLicense) 【记录】

SpringBoot项目License证书生成与验证(TrueLicense) 【记录】 在非开源产品、商业软件、收费软件等系统的使用上&#xff0c;需要考虑系统的使用版权问题&#xff0c;不能随便一个人拿去在任何环境都能用。应用部署一般分为两种情况&#xff1a; 应用部署在开发者自己的云服务…

数据集-目标检测系列-火车检测数据集 train >> DataBall

数据集-目标检测系列-火车检测数据集 train >> DataBall 数据集-目标检测系列-火车检测数据集 数据量&#xff1a;1W 想要进一步了解&#xff0c;请联系 DataBall。 DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种数据集&#xff0c;不断增加…

跟李沐学AI:注意力机制、注意力分数

目录 不随意线索 随意线索 注意力机制 非参注意力池化层 参数化的注意力机制 注意力机制总结 注意力分数 拓展到高维度 加性模型&#xff08;Additive Attention&#xff09; 点积注意力机制&#xff08;Dot Product Attention&#xff09; 注意力分数总结 不随意线…

vscode 顶部 Command Center,minimap

目录 vscode 顶部 Command Center 设置显示步骤: minimap设置 方法一:使用设置界面 方法二:使用命令面板 方法三:编辑 settings.json 文件 左侧目录树和编辑器字体不一致: vscode 顶部 Command Center Visual Studio Code (VSCode) 中的 Command Center 是一个集中…

240912-设置WSL中的Ollama可在局域网访问

A. 最终效果 B. 设置Ollama&#xff08;前提&#xff09; sudo vim /etc/systemd/system/ollama.service[Unit] DescriptionOllama Service Afternetwork-online.target[Service] ExecStart/usr/bin/ollama serve Userollama Groupollama Restartalways RestartSec3 Environme…

Python redis 安装和使用介绍

python redis安装和使用 一、Redis 安装1.1、Windows安装 二、安装 redis 模块二、使用redis 实例1.1、简单使用1.2、连接池1.3、redis 基本命令 String1.3.1、ex - 过期时间&#xff08;秒&#xff09;1.3.2、nx - 如果设置为True&#xff0c;则只有name不存在时&#xff0c;当…

fiddler抓包08_抓Android手机请求

课程大纲 手机抓包&#xff0c;电脑端的设置和IOS端相同&#xff0c;设置一次即可&#xff0c;无需重复设置。 前提&#xff1a;电脑和手机连接同一个局域网 土小帽电脑和手机都连了自己的无线网“tuxiaomao”。 Step1. 电脑端设置 ① 打开Fiddler - 开启抓包&#xff08;F12…