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

参考文章以及视频

文章:

都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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overridepublic 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 {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//得到请求URLStringBuffer requestURL = request.getRequestURL();System.out.println("请求的URL是:" + requestURL);//得到请求URIString requestURI = request.getRequestURI();System.out.println("请求的URI是:" + requestURI);//得到主机名HostString host = request.getHeader("Host");System.out.println("请求的主机名是:" + host);//得到请求的ipString 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);}@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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.mzph.cn/news/880001.shtml

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

相关文章

yolov8旋转目标检测之绝缘子检测-从数据加载到模型训练、部署

YOLOv8 是 YOLO (You Only Look Once) 系列目标检测算法的最新版本&#xff0c;以其高速度和高精度而著称。在电力行业中&#xff0c;绝缘子是电力传输线路上的重要组件之一&#xff0c;它们用于支撑导线并保持电气绝缘。由于长期暴露在户外环境中&#xff0c;绝缘子容易出现损…

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

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

【25.6】C++智能交友系统

常见错误总结 const-1 如下代码会报错 原因如下&#xff1a; man是一个const修饰的对象&#xff0c;即man不能修改任何内容&#xff0c;但是man所调用的play函数只是一个普通的函数&#xff0c;所以出现了报错。我们需要在play函数中加上const修饰&#xff0c;或者删除man对…

【计算机网络 - 基础问题】每日 3 题(十八)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

SpringBoot环境配置(Spring Boot Profile)

一、介绍 在Spring Boot中&#xff0c;spring.profiles 配置用于定义不同环境下的配置文件。这使得应用可以在不同的环境中使用不同的配置&#xff0c;比如开发环境、测试环境和生产环境等。这种方式可以避免在代码中硬编码配置信息&#xff0c;并且能够更灵活地管理应用的环境…

SpringBootWeb增删改查入门案例

前言 为了快速入门一个SpringBootWeb项目&#xff0c;这里就将基础的增删改查的案例进行总结&#xff0c;作为对SpringBootMybatis的基础用法的一个巩固。 准备工作 需求说明 对员工表进行增删改查操作环境搭建 准备数据表 -- 员工管理(带约束) create table emp (id int …

计算机毕业设计公交站点线路查询网站登录注册搜索站点线路车次/springboot/javaWEB/J2EE/MYSQL数据库/vue前后分离小程序

选题背景‌&#xff1a; 随着城市化进程的加快&#xff0c;公共交通成为城市居民出行的重要方式。然而&#xff0c;传统的公交站点线路查询方式往往依赖于纸质地图或简单的电子显示屏&#xff0c;查询效率低下且信息更新不及时。因此&#xff0c;开发一个功能全面、易于使用的…

OpenMV学习第一步安装IDE_2024.09.20

用360浏览器访问星瞳科技官网&#xff0c;一直提示访问不了。后面换了IE浏览器就可以访问。第一个坑。

基于springboot的智慧社区微信小程序

文未可获取一份本项目的java源码和数据库参考。 本课题研究目标 本文主要对小区生活服务平台的功能和非功能需求进行了分析&#xff0c;系统除了提供物业保修、小区资讯、投诉留言、常用电话等基础功能外&#xff0c;为了满足用户的多样化需求&#xff0c;还提供邻里圈子和有…

238 除自身以外数组的乘积

解题思路&#xff1a; \qquad 这道题要求在 O ( n ) O(n) O(n) 时间内解决&#xff0c;但是不能使用除法。仅使用乘法的话&#xff0c;看上去很难在一次遍历中得出想要的结果&#xff0c;但是没关系&#xff0c;一次遍历不行的话那就试试两次、三次&#xff0c;重要的是分析在…

Python--TCP/UDP通信

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.客户端与服务端通信原理 1. 服务器端 服务器端的主要任务是监听来自客户端的连接请求&#xff0c;并与之建立连接&#xff0c;然后接收和发送数据。 创建套接字&#xff1a;首先&#xff0…

【数据库】常用数据库简介

目录 &#x1f354; 常用的关系型数据库 &#x1f354; Mysql简介 &#x1f354; SQL 简介 SQL语句的分类 SQL 写法 SQL 常用的数据类型 &#x1f354; DDL语句 对数据库的操作 对数据表的操作 &#x1f354; DML语句 插入数据 insert into 修改数据 update 删除数…

css基础知识笔记

一言&#xff1a; “放任误解就是撒谎。” 文章目录 前言文章有误敬请斧正 不胜感恩&#xff01;CSS基础教程0.文本样式基础1. CSS选择器2. CSS布局技巧3. 响应式设计4. Emmet语法 总结 前言 写在开始&#xff1a; 今天来看一眼CSS基础知识。 好几天没更新了 先更一篇 文章有…

DataGrip在Windows和MacOS平台上的快捷键

0. 背景信息 No.说明1测试DataGrip版本号 : 2024.2.2 1. Windows下快捷键 2. MacOS下快捷键

Java流程控制语句——跳转语句详解:break 与 continue 有什么区别?

&#x1f310;在Java编程中&#xff0c;break和continue是两个重要的控制流语句&#xff0c;它们允许开发者根据特定条件改变程序的执行流程。虽然两者都用于中断当前的行为&#xff0c;但它们的作用方式不同。本文将通过生动的例子来详细解释这两个语句&#xff0c;并使用流程…

C++/Qt 集成 AutoHotkey

C/Qt 集成 AutoHotkey 前言AutoHotkey 介绍 方案一&#xff1a;子进程启动编写AutoHotkey脚本准备 AutoHotkey 运行环境编写 C/Qt 代码 方案二&#xff1a;显式动态链接方案探索编译动态链接库集成到C工程关于AutoHotkeyDll.dll中的函数原型 总结 前言 上一篇介绍了AutoHotkey…

系统架构设计师 需求分析篇一

&#x1f4d8; 结构化分析SA 思想 自顶向下&#xff1a;像剥洋葱一样&#xff0c;层层深入&#xff0c;大问题拆成小问题&#xff0c;再拆成更小的问题。 核心模型 数据字典 &#x1f4d4;&#xff1a;记录数据元素的点点滴滴&#xff0c;从属性到使用方式&#xff0c;无所…

Spring自定义参数解析器

在这篇文章中&#xff0c;我们认识了参数解析器和消息转换器&#xff0c;今天我们来自定义一个参数解析器。 自定义参数解析器 实现HandlerMethodArgumentResolver的类&#xff0c;并注册到Spring容器。 Component&#xff0f;&#xff0f;注册到Spring public class UserAr…

C#解决方案的各种操作

C#开发编程软件下载安装 C#开发编程软件下载安装_c#下载安装-CSDN博客文章浏览阅读208次。。。。_c#下载安装https://rxxw-control.blog.csdn.net/article/details/140879228 C#和S7-1200PLC S7.NET通信 C#和S7-1200PLC S7.NET通信_c# s1200 s7协议设置-CSDN博客文章浏览阅读…

【Python】探索 TensorFlow:构建强大的机器学习模型

TensorFlow 是一个开源的深度学习框架&#xff0c;由 Google 开发&#xff0c;广泛应用于机器学习和人工智能领域。自从 2015 年推出以来&#xff0c;它已成为研究人员、开发者和数据科学家们不可或缺的工具。TensorFlow 提供了灵活、高效的工具集&#xff0c;可以帮助我们构建…