手动实现Tomcat底层机制+自己设计Servlet

文章目录

    • 1.Tomcat整体架构分析
      • 自己理解
    • 2.第一阶段
        • 1.实现功能
        • 2.代码
          • 1.TomcatV1.java
        • 3.调试阶段
          • 1.阻塞在readLine导致无法返回结果
        • 4.结果演示
    • 3.第二阶段
        • 1.实现功能
        • 2.代码
          • 1.RequestHander.java
          • 2.TomcatV2.java
        • 3.调试阶段
          • 1.发现每次按回车会接受到两次请求
        • 4.结果演示
    • 4.第三阶段
        • 1.实现功能
        • 2.总体框架
        • 3.代码实现
          • ===1.封装Request
          • 1.Request.java
          • 2.RequestHander.java
            • 单元测试报错Sock is closed
            • 原因
            • 修改之后
          • ===2.封装Response
          • 3.Response.java
          • 4.RequestHander.java
            • 单元测试无误
          • ===3.设计servlet规范
          • 5.Servlet.java
          • 6.HttpServlet.java
          • 7.CalServlet.java
          • 8.WebUtils.java
          • 9.RequestHander.java
            • 单元测试无误
          • ===4.xml + 反射初始化容器
          • 10.web.xml
          • 11.TomcatV3.java
          • 12.RequestHander.java
        • 4.总体调试阶段
          • 1.空指针异常
        • 5.结果演示
    • 5.课后作业
        • 1.更新WebUtils.java
          • 添加方法
        • 2.修改RequestHander.java
        • 3.cal.html
        • 4.调试阶段
        • 5.结果展示

1.Tomcat整体架构分析

image-20240126204326055

image-20240126204409213

自己理解

pdf下载

image-20240128100508870

2.第一阶段

1.实现功能

编写自己的Tomcat能接受浏览器的请求并返回结果

2.代码
1.TomcatV1.java
package Tomcat;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;/*** @author 孙显圣* @version 1.0* 第一个版本的,可以接收浏览器的请求并返回信息*/
public class TomcatV1 {public static void main(String[] args) throws Exception {//在8080端口监听ServerSocket serverSocket = new ServerSocket(8081);System.out.println("Tomcat在8080端口监听");//只要不是手动关闭服务,则循环获取连接while (!serverSocket.isClosed()) {//获取连接Socket accept = serverSocket.accept();//获取输入流InputStream inputStream = accept.getInputStream();//使用转换流转为bufferedreader可以读取一行BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));//字符串缓冲区String buff = null;while ((buff = bufferedReader.readLine()) != null) {//readline()在网络编程中,只有客户端的连接关闭了才会返回null,所以如果不设置别的判定条件退出,则会阻塞//由于请求信息最后有一个\r\n,读到这个\r\n会返回一个"",就可以退出了if (buff.equals("")) {break;}System.out.println(buff);}//tomcat向浏览器发送http响应,\r\n是换行String respHead ="HTTP/1.1 200 OK\r\n" +"Content-Type: text/html;charset=utf-8\r\n\r\n"; //响应头下面要空一行才能写响应体所以两个换行String resp = respHead + "<h1>hello world!</h1>";//获取输出流OutputStream outputStream = accept.getOutputStream();//输出outputStream.write(resp.getBytes());//关闭outputStream.flush();outputStream.close();inputStream.close();accept.close();}}
}
3.调试阶段
1.阻塞在readLine导致无法返回结果
  1. 最开始我并没有添加,如果readLine()读到""就退出循环的逻辑
  2. 后来发现readLine()在网络编程中,只有浏览器端关闭连接才会返回null
  3. 当读到了请求的\r\n的时候就会返回一个""字符串,然后阻塞在这里等待输入
  4. 所以在循环中添加当读到\r\n即返回""的时候退出即可
4.结果演示

image-20240127133045568

image-20240127133105064

3.第二阶段

1.实现功能

BIO线程模型支持多线程

image-20240127133413354

2.代码
1.RequestHander.java
package Tomcat.handler;import java.io.*;
import java.net.Socket;/*** @author 孙显圣* @version 1.0* 处理http请求的线程类*/
public class RequestHander implements Runnable{//定义一个socket属性private Socket socket = null;public RequestHander(Socket socket) {this.socket = socket;}public void run() {//可以对客户端或浏览器进行交互try {//获取输入流InputStream inputStream = socket.getInputStream();//转换成BufferedReader,方便按行读取BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));System.out.println("tomcatV2接受到浏览器的数据如下:");//接受数据//设置缓冲String buff = null;//循环读取while ((buff = bufferedReader.readLine()) != null) {//判断是否读取到了\r\nif (buff.equals("")) {break; //读取完毕则退出循环,避免readLine阻塞}System.out.println(buff);}//获取输出流,返回信息到浏览器OutputStream outputStream = socket.getOutputStream();String respHead ="HTTP/1.1 200 OK\r\n" +"Content-Type: text/html;charset=utf-8\r\n\r\n"; //响应头下面要空一行才能写响应体所以两个换行String resp = respHead + "<h1>hello 孙显圣!</h1>";outputStream.write(resp.getBytes());//关闭outputStream.flush();outputStream.close();inputStream.close();socket.close();} catch (IOException e) {throw new RuntimeException(e);} finally {//确保关闭if (socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}
2.TomcatV2.java
package Tomcat;import Tomcat.handler.RequestHander;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** @author 孙显圣* @version 1.0*/
public class TomcatV2 {public static void main(String[] args) throws IOException {//在8080端口监听ServerSocket serverSocket = new ServerSocket(8080);System.out.println("TomcatV2在8080端口监听");//只要没有手动关闭则服务一直开启,循环监听while (!serverSocket.isClosed()) {Socket socket = serverSocket.accept();//将获取的socket交给线程类来处理RequestHander requestHander = new RequestHander(socket);Thread thread = new Thread(requestHander);thread.start(); //启动线程}}
}
3.调试阶段
1.发现每次按回车会接受到两次请求

image-20240127141739775

原因就是每次请求还要请求一下页面的小图标

image-20240127141931309

4.结果演示

image-20240127141956236

4.第三阶段

1.实现功能

image-20240127142230563

image-20240127142544134

2.总体框架

image-20240127215734459

3.代码实现
===1.封装Request
1.Request.java
package Tomcat.http;/*** @author 孙显圣* @version 1.0*/import java.io.*;
import java.util.HashMap;/*** 1.Request的作用就是封装http请求的数据 GET /tomcatv2?a=9&b=3 HTTP/1.1* 2.比如method(get), uri(/tomcat/cal),还有参数列表(num1&num2)* 3.相当于原生的HttpServletRequest*/
public class Request {private String method;private String uri;//存放参数列表private HashMap<String, String> parametersMapping = new HashMap<String, String>();//构造方法获取inputStream来封装信息public Request(InputStream inputStream) throws IOException {//转换成BufferedReaderBufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));//读取第一行String s = bufferedReader.readLine();//将内容封装到属性String[] split = s.split(" ");method = split[0];//判断是否有参数列表int index = split[1].indexOf("?");if (index == -1) { //没有参数列表uri = split[1];}else { //有参数列表uri = split[1].substring(0,index);String parameters = split[1].substring(index + 1, split[1].length());String[] split1 = parameters.split("&"); //分割参数//判断?后面是否有东西if (split1 != null && !"".equals(split1)) {//遍历参数for (String parameterPair : split1) {String[] split2 = parameterPair.split("=");parametersMapping.put(split2[0],split2[1]);}}}//不能关闭,否则socket也就关闭了
//        inputStream.close();}public String getMethod() {return method;}public String getUri() {return uri;}public String getParameter(String name) {if (parametersMapping.containsKey(name)) {return parametersMapping.get(name);}else {return null;}}}
2.RequestHander.java
package Tomcat.handler;import Tomcat.http.Request;import java.io.*;
import java.net.Socket;/*** @author 孙显圣* @version 1.0* 处理http请求的线程类*/
public class RequestHander implements Runnable {//定义一个socket属性private Socket socket = null;public RequestHander(Socket socket) {this.socket = socket;}public void run() {//可以对客户端或浏览器进行交互try {//获取输入流InputStream inputStream = socket.getInputStream();//封装到Request里Request request = new Request(inputStream);//获取数据System.out.println(request.getUri() + " " + request.getMethod());System.out.println(request.getParameter("num1") + " " + request.getParameter("num2")+ " " + request.getParameter("num3"));//获取输出流,返回信息到浏览器OutputStream outputStream = socket.getOutputStream();String respHead ="HTTP/1.1 200 OK\r\n" +"Content-Type: text/html;charset=utf-8\r\n\r\n"; //响应头下面要空一行才能写响应体所以两个换行String resp = respHead + "<h1>hello 孙显圣!</h1>";outputStream.write(resp.getBytes());//关闭outputStream.flush();outputStream.close();inputStream.close();socket.close();} catch (IOException e) {throw new RuntimeException(e);} finally {//确保关闭if (socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}
单元测试报错Sock is closed

image-20240127153426609

原因

在Request.java中获取完参数顺便把inputStream关闭了,导致了Socket也一起关闭了,使得主线程在使用socket的时候出现了已经关闭的错误

image-20240127153538511

修改之后

image-20240127153742457

image-20240127153750759

===2.封装Response
3.Response.java
package Tomcat.http;/*** @author 孙显圣* @version 1.0*/import java.io.OutputStream;/*** 1.这个response对象可以封装OutputSream* 2.即可以通过这个对象返回http响应给浏览器* 3.相当于原生的HttpServletResponse*/
public class Response {private OutputStream outputStream = null;//封装一个响应头public static final String respHeader = "HTTP/1.1 200 OK\r\n" +"Content-Type: text/html;charset=utf-8\r\n\r\n"; //响应头下面要空一行才能写响应体所以两个换行public Response(OutputStream outputStream) {this.outputStream = outputStream;}//以后再Servlet里面获取输出流public OutputStream getOutputStream() {return outputStream;}
}
4.RequestHander.java
package Tomcat.handler;import Tomcat.http.Request;
import Tomcat.http.Response;import java.io.*;
import java.net.Socket;/*** @author 孙显圣* @version 1.0* 处理http请求的线程类*/
public class RequestHander implements Runnable {//定义一个socket属性private Socket socket = null;public RequestHander(Socket socket) {this.socket = socket;}public void run() {//可以对客户端或浏览器进行交互try {//获取输入流InputStream inputStream = socket.getInputStream();//封装到Request里Request request = new Request(inputStream);//获取数据System.out.println(request.getUri() + " " + request.getMethod());System.out.println(request.getParameter("num1") + " " + request.getParameter("num2")+ " " + request.getParameter("num3"));//获取输出流,返回信息到浏览器OutputStream outputStream = socket.getOutputStream();//封装到Response对象中Response response = new Response(outputStream);//获取输出流输出信息OutputStream outputStream1 = response.getOutputStream();outputStream1.write((response.respHeader + "<h1>response响应:你好,孙显圣</h1>").getBytes());//关闭outputStream.flush();outputStream.close();inputStream.close();socket.close();} catch (IOException e) {throw new RuntimeException(e);} finally {//确保关闭if (socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}
单元测试无误

image-20240127161328146

image-20240127161334862

===3.设计servlet规范
5.Servlet.java
package Tomcat.servlet;import Tomcat.http.Request;
import Tomcat.http.Response;import java.io.IOException;/*** @author 孙显圣* @version 1.0* 保留三个核心方法*/
public interface Servlet {void init() throws Exception;void service(Request request, Response response) throws IOException;void destroy();
}
6.HttpServlet.java
package Tomcat.servlet;import Tomcat.http.Request;
import Tomcat.http.Response;import java.io.IOException;/*** @author 孙显圣* @version 1.0*/
public abstract class HttpServlet implements Servlet {public void service(Request request, Response response) throws IOException {//抽象模板设计模式,判断类型来决定调用什么方法if ("GET".equalsIgnoreCase(request.getMethod())) {//以后会反射创建子类实例,调用子类的service方法,子类没有,就从父类找,然后再使用动态绑定到子类的doGet方法this.doGet(request, response);} else if ("POST".equalsIgnoreCase(request.getMethod())) {this.doPost(request, response);}}public abstract void doGet(Request request, Response response);public abstract void doPost(Request request, Response response);}
7.CalServlet.java
package Tomcat.servlet;import Tomcat.http.Request;
import Tomcat.http.Response;
import Tomcat.utils.WebUtils;import java.io.IOException;
import java.io.OutputStream;/*** @author 孙显圣* @version 1.0*/
public class CalServlet extends HttpServlet {public void doGet(Request request, Response response) {//完成计算任务int num1 = WebUtils.parseInt(request.getParameter("num1"), 0);int num2 = WebUtils.parseInt(request.getParameter("num2"), 0);int sum = num1 + num2;//返回计算结果给浏览器OutputStream outputStream = response.getOutputStream();String resp = Response.respHeader + "<h1>" + num1 + " + " + num2 + " = " + sum + "</h1>";try {outputStream.write(resp.getBytes());//关闭outputStream.flush();outputStream.close();} catch (IOException e) {throw new RuntimeException(e);}}public void doPost(Request request, Response response) {this.doGet(request, response);}public void init() throws Exception {}public void destroy() {}
}
8.WebUtils.java
package Tomcat.utils;/*** @author 孙显圣* @version 1.0*/
public class WebUtils {//把String类型转换成int类型,如果是非整数则返回默认值public static int parseInt(String str, int defaultVal) {try {return Integer.parseInt(str);} catch (NumberFormatException e) {System.out.println("转换失败");}return defaultVal;}}
9.RequestHander.java
package Tomcat.handler;import Tomcat.http.Request;
import Tomcat.http.Response;
import Tomcat.servlet.CalServlet;import java.io.*;
import java.net.Socket;/*** @author 孙显圣* @version 1.0* 处理http请求的线程类*/
public class RequestHander implements Runnable {//定义一个socket属性private Socket socket = null;public RequestHander(Socket socket) {this.socket = socket;}public void run() {//可以对客户端或浏览器进行交互try {//获取输入流InputStream inputStream = socket.getInputStream();//封装到Request里Request request = new Request(inputStream);//获取输出流,返回信息到浏览器OutputStream outputStream = socket.getOutputStream();//封装到Response对象中Response response = new Response(outputStream);CalServlet calServlet = new CalServlet();calServlet.service(request,response); //这个会调用他抽象父类的service方法inputStream.close();socket.close();} catch (IOException e) {throw new RuntimeException(e);} finally {//确保关闭if (socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}
单元测试无误

image-20240127170622206

===4.xml + 反射初始化容器

image-20240127172419183

10.web.xml

image-20240127200603422

image-20240127200517652

11.TomcatV3.java
package Tomcat;import Tomcat.handler.RequestHander;
import Tomcat.servlet.HttpServlet;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;/*** @author 孙显圣* @version 1.0*/
public class TomcatV3 {//设置两个hashmap容器,在启动的Tomcat的时候就初始化//存放名字和实例public static final ConcurrentHashMap<String, HttpServlet>servletMapping = new ConcurrentHashMap<String, HttpServlet>();//存放路径和名字public static final ConcurrentHashMap<String, String>servletUrlMapping = new ConcurrentHashMap<String, String>();public static void main(String[] args) throws MalformedURLException, DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException {TomcatV3 tomcatV3 = new TomcatV3();tomcatV3.init();tomcatV3.run();}//启动TomcatV3容器public void run() {try {ServerSocket serverSocket = new ServerSocket(8080);System.out.println("TomcatV3在8080端口监听");while (!serverSocket.isClosed()) { //只要没有手动关闭服务,就循环获取连接Socket socket = serverSocket.accept();//将socket交给线程处理RequestHander requestHander = new RequestHander(socket);new Thread(requestHander).start(); //启动线程}} catch (IOException e) {throw new RuntimeException(e);}}private void init() throws MalformedURLException, DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException {//获取该类的路径String path = TomcatV3.class.getResource("/").getPath();//使用dom4j读取web.xml文件//获取解析器SAXReader saxReader = new SAXReader();//读取文件Document read = saxReader.read(new File(path + "web.xml"));//获取根元素Element rootElement = read.getRootElement();//获取所有二级元素List<Element> servlet = rootElement.elements();//遍历所有二级元素,根据不同类型做处理for (Element element : servlet) {if ("servlet".equalsIgnoreCase(element.getName())) {//获取名字和全类名Element servletName = element.element("servlet-name");Element servletClass = element.element("servlet-class");//通过反射创建实例Class<?> aClass = Class.forName(servletClass.getText().trim()); //trim是清除空格HttpServlet httpServlet = (HttpServlet) aClass.newInstance();//将其放到容器中去servletMapping.put(servletName.getText(), httpServlet);} else if ("servlet-mapping".equalsIgnoreCase(element.getName())) {//获取名字和urlElement servletName = element.element("servlet-name");Element servletUrl = element.element("url-pattern");//将其放到容器中去servletUrlMapping.put("/tomcat" + servletUrl.getText(), servletName.getText());}}}}
12.RequestHander.java
package Tomcat.handler;import Tomcat.TomcatV3;
import Tomcat.http.Request;
import Tomcat.http.Response;
import Tomcat.servlet.CalServlet;
import Tomcat.servlet.HttpServlet;import java.io.*;
import java.net.Socket;/*** @author 孙显圣* @version 1.0* 处理http请求的线程类*/
public class RequestHander implements Runnable {//定义一个socket属性private Socket socket = null;public RequestHander(Socket socket) {this.socket = socket;}public void run() {//可以对客户端或浏览器进行交互try {//获取输入流InputStream inputStream = socket.getInputStream();//封装到Request里Request request = new Request(inputStream);//获取输出流,返回信息到浏览器OutputStream outputStream = socket.getOutputStream();//封装到Response对象中Response response = new Response(outputStream);String uri = request.getUri();String servletName = TomcatV3.servletUrlMapping.get(uri);if (servletName == null) {servletName = "";}HttpServlet httpServlet = TomcatV3.servletMapping.get(servletName);//判断是否得到了这个对象if (httpServlet != null) {httpServlet.service(request, response);} else {//没有得到则返回404String resp = Response.respHeader + "<h1>404 not found</h1>";response.getOutputStream().write(resp.getBytes());}inputStream.close();socket.close();} catch (IOException e) {throw new RuntimeException(e);} finally {//确保关闭if (socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}
4.总体调试阶段
1.空指针异常

image-20240127195609800

image-20240127200135939

5.结果演示

image-20240127200406441

image-20240127200413877

image-20240127200437664

5.课后作业

image-20240127201804124

image-20240127201735945

1.更新WebUtils.java
添加方法
    //判断是不是html格式的文件,如果是就直接读取文件内容并且返回truepublic static boolean isHtml(String uri, Response response) {//使用正则表达式匹配html文件String regStr = "(/.*)*/(.*\\.html)";Pattern compile = Pattern.compile(regStr);Matcher matcher = compile.matcher(uri);if (!matcher.find()) { //没匹配到就直接返回falsereturn false;}//得到html文件的路径String path = "D:\\Intelij IDEA Project\\java_web\\tomcat\\target\\classes\\" + matcher.group(2);System.out.println(path);//根据路径读取文件并存放到StringBuilder中StringBuilder stringBuilder = new StringBuilder();try {BufferedReader bufferedReader = new BufferedReader(new FileReader(path));String buf = null;while ((buf = bufferedReader.readLine()) != null) {stringBuilder.append(buf); //存放到stringBuilder中}//将stringBuilder的内容响应给浏览器String resp = Response.respHeader + stringBuilder.toString();response.getOutputStream().write(resp.getBytes());}catch (Exception e) {System.out.println("文件找不到!");return false; //返回false之后就会继续进行原来的逻辑,弹出404}//如果不出异常则说明响应成功return true;}
2.修改RequestHander.java

image-20240127215107134

3.cal.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form action="/tomcat/CalServlet" method="get">num1:<input type="text" name="num1">num2:<input type="text" name="num2"><input type="submit" value="提交">
</form>
</body>
</html>
4.调试阶段
  1. 一直显示我的cal.html文件找不到,调了半个小时
  2. 原因是String path = TomcatV3.class.getResource("/").getPath();使用这个来获取的路径没有空格,而我的资源路径是这个D:\\Intelij IDEA Project\\java_web\\tomcat\\target\\classes\\,中间带了空格,真的是醉了,深刻体会到文件夹起名不要带空格的重要性了
5.结果展示

image-20240127215627956

image-20240127215633496

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

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

相关文章

Redis常见数据类型(2)

String字符串 字符串是Redis最基础的数据类型, 关于字符串需要特别注意: (1)首先Redis中所有的键的类型都是字符串类型, 而且其它几种数据结构也是在字符串类型的基础上构建的, 例如列表和集合的元素都是字符串类型, 所以字符串类型能为其它4种数据结构的学习奠定基础. (2)其次…

基于Unet的BraTS 3d 脑肿瘤医学图像分割,从nii.gz文件中切分出2D图片数据

1、前言 3D图像分割一直是医疗领域的难题&#xff0c;在这方面nnunet已经成为了标杆&#xff0c;不过nnunet教程较少&#xff0c;本人之前跑了好久&#xff0c;一直目录报错、格式报错&#xff0c;反正哪里都是报错等等。并且&#xff0c;nnunet对于硬件的要求很高&#xff0c…

Java23种设计模式

本文主要是对Java中一些常用的设计模式进行讲解 后期会进行不断的更新&#xff0c;欢迎浏览 23种设计模式 创建型模式&#xff0c;共五种&#xff1a;工厂方法模式、抽象工厂模式、建造者模式、原型模式、单例模式。结构型模式&#xff0c;共七种&#xff1a;适配器模式、桥接…

Allavsoft for Mac v3.27.0.8852注册激活版 优秀的视频下载工具

Allavsoft for Mac是一款功能强大的多媒体下载和转换工具&#xff0c;支持从各种在线视频网站和流媒体服务下载视频、音频和图片。它具备批量下载和转换功能&#xff0c;可将文件转换为多种格式&#xff0c;以适应不同设备的播放需求。此外&#xff0c;Allavsoft还提供视频编辑…

彩虹易支付接口配置

支付通道配置 基本概念 彩虹易支付系统有强大的支付接口扩展能力&#xff0c;首先需要明白以下几个概念。 支付方式&#xff1a; 支付方式用于定义发起支付的调用值&#xff08;在前台开发文档里面显示&#xff09;与支付方式名称。目前系统自带6种支付方式&#xff0c;它们的…

【C++】map set 底层刨析

文章目录 1. 红黑树的迭代器2. 改造红黑树3. map 的模拟实现4. set 的模拟实现 在 C STL 库中&#xff0c;map 与 set 的底层为红黑树&#xff0c;那么在不写冗余代码的情况下使用红黑树同时实现 map 与 set 便是本文的重点。 1. 红黑树的迭代器 迭代器的好处是可以方便遍历&…

openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警

文章目录 openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警 openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警 Plan Hint的结果会体现在计划的变化上&#xff0c;可以通过explain来查看变化。 …

Flutter Don‘t use ‘BuildContext‘s across async gaps.

Flutter提示Don‘t use ‘BuildContext‘s across async gaps.的解决办法—flutter里state的mounted属性

JAVAEE之Spring Boot日志

1. 日志概述 1.1 学习日志的原因 ⽇志对我们来说并不陌生, 从JavaSE部分, 我们就在使用 System.out.print 来打印日志了. 通过打印日志来发现和定位问题, 或者根据日志来分析程序的运行过程. 在Spring的学习中, 也经常根据控制台的日志来分析和定位问题. 随着项⽬的复杂…

【图论】【分类讨论】LeetCode3017按距离统计房屋对数目

本文涉及的知识点 图论 分类讨论 本题同解 【差分数组】【图论】【分类讨论】【整除以2】3017按距离统计房屋对数目 LeetCode3017按距离统计房屋对数目 给你三个 正整数 n 、x 和 y 。 在城市中&#xff0c;存在编号从 1 到 n 的房屋&#xff0c;由 n 条街道相连。对所有 …

Python 基于列表实现的通讯录管理系统(有完整源码)

目录 通讯录管理系统 PersonInformation类 ContactList类 menu函数 main函数 程序的运行流程 完整代码 运行示例 通讯录管理系统 这是一个基于文本的界面程序&#xff0c;用户可以通过命令行与之交互&#xff0c;它使用了CSV文件来存储和读取联系人信息&#xff0c;这…

Docker实战教程 第1章 Linux快速入门

2-1 Linux介绍 为什么要学Linux 三个不得不学习 课程需要&#xff1a;Docker开发最好在Linux环境下。 开发需要&#xff1a;作为一个后端程序员&#xff0c;是必须要掌握Linux的&#xff0c;这是找工作的基础门槛。 运维需要&#xff1a;在服务器端&#xff0c;主流的大型服…

Java栈和队列的实现

目录 一.栈(Stack) 1.1栈的概念 1.2栈的实现及模拟 二.队列(Queue) 2.1队列的概念 2.2队列的实现及模拟 2.3循环队列 2.4双端队列&#xff08;Deque&#xff09; 一.栈(Stack) 1.1栈的概念 栈:一种特殊的线性表&#xff0c;其 只允许在固定的一端进行插入和删除元素操作…

element-ui result 组件源码分享

今日简单分享 result 组件的源码实现&#xff0c;主要从以下三个方面&#xff1a; 1、result 组件页面结构 2、result 组件属性 3、result 组件 slot 一、result 组件页面结构 二、result 组件属性 2.1 title 属性&#xff0c;标题&#xff0c;类型 string&#xff0c;无默…

11-1(2)-CSS 背景+CSS 精灵图

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 一、CSS 背景1 背景颜色2 背景色半透明3 背景图片4 背景平铺5 背景图片位置6 …

linux操作系统安装及命令初识,上岸蚂蚁金服

310 包&#xff09; desktop 1800个包左右 内容必须大于 768M 系统设置 分区设置 挂载点 /boot / swap 交换分区–占用磁盘容量 网络配置 网卡配置 设置为ON 主机名配置 Begin installation 设置 root 用户密码 命令初识 命令 选项 参数&#xff1a; 命令选项参数…

JavaEE 初阶篇-生产者与消费者模型(线程通信)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 生产者与消费者模型概述 2.0 在生产者与消费者模型中涉及的关键概念 2.1 缓冲区 2.2 生产者 2.3 消费者 2.4 同步机制 2.5 线程间通信 3.0 实现生产者与消费者模…

iOS开发进阶(十三):脚手架创建iOS项目

文章目录 一、前言二、xcode-select 命令三、拓展阅读 一、前言 项目初期&#xff0c;需要搭建项目基本框架&#xff0c;为此离不开辅助工具&#xff0c;即脚手架。当然&#xff0c;IDE也可以实现新建空白项目&#xff0c;但是其新建后的项目结构可能不符合预期设计&#xff0…

AWS-EKS 给其他IAM赋予集群管理权限

AWS EKS 设计了权限管理系统&#xff0c;A用户创建的集群 B用户是看不到并且不能管理和使用kubectl的&#xff0c;所以我们需要共同管理集群时就需要操场共享集群访问给其他IAM用户。 两种方式添加集群控制权限&#xff08;前提&#xff1a;使用有管理权限的用户操作&#xff…

顺序表相关习题

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;python从入门到精通&#xff0c;魔法指针&#xff0c;进阶C&#xff0c;C语言&#xff0c;C语言题集&#xff0c;C语言实现游戏&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文…