【JavaWeb学习笔记】10 - 手写Tomcat底层,Maven的初步使用

一、Maven

1.Maven示意图

类似Java访问数据库

2.创建Maven案例演示

配置阿里镜像

找到setting目录

但一开始配置不存在该文件

需要去Maven主目录下的conf拿到settings拷贝到上述目录

拷贝到admin/.m2后打开该settings

在<mirrors>内输入镜像地址

<mirror>
         <id>alimaven</id>
         <name>aliyun maven</name>
         <url>https://maven.aliyun.com/nexus/content/groups/publichttps://maven.aliyun.com/repository/publichttps://maven.aliyun.com/nexus/content/groups/public</url>
         <mirrorOf>central</mirrorOf>
     </mirror>

配置pom.xml文件

    </dependency><!--引入servlet.jar包--><!--1.入servlet-api.jar ,为J开发servlet2. dependency 标签是表示引入-一个包3. groupId包的公司/ 组织/开发团队/个人信息javax. servlet4. artifactId :项目名javax .servlet-api5. version 版本6. scope 表示引入的包的作用范围7. provided: 表示tomcat 本身有jar包,这里你引入的jar包,在编译,测试有效但是在打包的时候不要带上这个jar包8.下载的包在你指定的目录:C:\Users\Administrator\.m2\repository9.可以去修改我们要下载包的位置->10.我们可以去指定maven仓库,即配置maven镜像C:\Users\Administratorl.m2\settings.xml--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency>

3.实现计算器效果

创建Tomcat的时候不要使用xxx_war包而要使用explore的

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>计算器</title>
</head>
<body><form action="/yhtomcat/calServlet" method="post">num1:<input type="text" name="num1"><br/>num2:<input type="text" name="num2"><br/><input type="submit" value="submit"></form>
</body>
</html>
@WebServlet(name = "CalServlet",urlPatterns = "/calServlet")
public class CalServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String strnum1 = request.getParameter("num1");String strnum2 = request.getParameter("num2");int num1 = 0;int num2 = 0;int sum = -1;try {num1 = Integer.parseInt(strnum1);num2 = Integer.parseInt(strnum2);System.out.println("res = " + num1 + num2);sum = num1 + num2;} catch (NumberFormatException e) {System.out.println("form wrong , continue");}response.setContentType("text/html;charset=utf-8");PrintWriter writer = response.getWriter();if (!(sum == -1)) {writer.print("<h1> res = " + sum + "</h1>");}else{writer.print("<h1> wrong date please try again!!  </h1>");}writer.flush();writer.close();}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request,response);}
}

二、Tomcat架构分析

我们的目标:不用Tomcat,不用系统提供的Servlet,

模拟Tomcat底层实现并能调用我们自己设计的Servle,也能完成相同的功能

说明: Tomcat有三种运行模式(BIO, NIO, APR) ,因为老师核心讲解的是Tomcat如何接收客户端请求,解析请求,调用Servlet并返回结果的机制流程,采用BIO线程模型来模拟.

模拟Tomcat底层机制

一、编写自己Tomcat

1.基于socket开发服务端流程

1. ServerSocket

在服务端监听指定端口,如果浏览器/客户端连接该端口,则建立连接,返回Socket对象

2. Socket

表示服务端和客户端/浏览器间的连接,通过Socket可以得到InputStream和OutputStream流对象。
 

public class YhTomcatV1 {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8080);System.out.println("======yhtomcat 在8080端口监听");while (!serverSocket.isClosed()){//等待连接//如果有连接来,就创建一个socket//这socket就是服务端和浏觉器端的连接/通道Socket socket = serverSocket.accept();//先接受浏览器发来的数据//字节流InputStream inputStream = socket.getInputStream();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));String mes = null;System.out.println("=====接受到浏览器发送的数据======");while ((mes = bufferedReader.readLine()) != null){if(mes.length() == 0){//读到空字符串break;}System.out.println(mes);}//我们的tomcat会送-http响应方式OutputStream outputStream = socket.getOutputStream();//构建一个http响应的头//\r\n 表示回车换行//http响应体,需要前面有两个换行 \r\n\r\nString respHeader = "HTTP/1.1 200 OK\r\n" +"Content-Type: text/html;charset=utf-8\r\n\r\n";String resp = respHeader + "<h1>hi, 这是模拟Tomcat</h1>";System.out.println("========我们的tomcat 给浏览器会送的数据======");System.out.println(resp);outputStream.write(resp.getBytes());//将resp字符串以byte[] 方式返回outputStream.flush();outputStream.close();inputStream.close();socket.close();}}
}

2.使用BIO线程模型,支持多线程

BIO线程模型介绍

需求分析

浏览器请求http:/ /localhost:8080,服务端返回hi , hspedu,后台hsptomcat使用BIO线程模型,支持多线程=>对前面的开发模式进行改造

一个持有线程的对象

public class YhRequestHandler extends Thread {
/** 1. HspRequestHandler 对象是一个线程对象* 2. 处理一个http请求的*///定义Socketprivate Socket socket = null;public YhRequestHandler(Socket socket) {this.socket = socket;}@Overridepublic void run() {//这里我们可以对客户端/浏览器进行IO编程/交互try {//1.使用BIO线程模型,支持多线程InputStream inputStream = socket.getInputStream();// //把inputStream -> BufferedReader -> 方便进行按行读取BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(inputStream, "utf-8"));//// //不同的线程在和浏览器和客户端交互System.out.println("当前线程= " + Thread.currentThread().getName());System.out.println("=========hsptomcatv2 接收到的数据如下=========");String mes = null;// io - 网络 - 线程 - 反射 - 注解 - OOP [都会学会,也会学好]//while ((mes = bufferedReader.readLine()) != null) {//如果长度为0 ""if (mes.length() == 0) {break; //退出}System.out.println(mes);}//构建一下http响应头//返回的http的响应体和响应头之间有两个换行 \r\n\r\nString respHeader = "HTTP/1.1 200 OK\r\n" +"Content-Type: text/html;charset=utf-8\r\n\r\n";String resp = respHeader + "<h1>hi this is ThreadServlet</h1>";System.out.println("========Yhtomcatv2返回的数据是=========");System.out.println(resp);//返回数据给我们的浏览器/客户端-> 封装成http响应OutputStream outputStream = socket.getOutputStream();//resp.getBytes() 是把字符串转成字节数组outputStream.write(resp.getBytes());outputStream.flush();outputStream.close();inputStream.close();socket.close();} catch (IOException e) {e.printStackTrace();} finally {//最后一定确保socket要关闭if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}

Tomcat

public class YhTomcatV2 {public static void main(String[] args) throws IOException {//在8080端口监听ServerSocket serverSocket = new ServerSocket(8080);System.out.println("=======hsptomcatV2 在8080监听=======");//只要 serverSocket没有关闭,就一直等待浏览器/客户端的连接while (!serverSocket.isClosed()) {//1. 接收到浏览器的连接后,如果成功,就会得到socket//2. 这个socket 就是 服务器和 浏览器的数据通道Socket socket = serverSocket.accept();//3. 创建一个线程对象,并且把socket给该线程//  这个是java线程基础YhRequestHandler hspRequestHandler =new YhRequestHandler(socket);new Thread(hspRequestHandler).start();}}
}

问题分析: MyT omcat只是简单返回结果,没有和Servlet,web.xml关联

3.处理 Servlet 

Request处理请求信息

public class YhRequest {/*** 1. YhRequest 作用是封装http请求的数据* get /hspCalServlet?num1=10&num2=30* 2. 比如 method(get) 、 uri(/hspCalServlet) 、 还有参数列表 (num1=10&num2=30)* 3. HspRequest 作用就等价原生的servlet 中的HttpServletRequest 这里考虑的是GET请求*/private String method;private String uri;//存放参数列表 参数名-参数值 => HashMapprivate HashMap<String, String> parametersMapping =new HashMap<>();private InputStream inputStream = null;//构造器=> 对http请求进行封装 => 可以将老师写的代码封装成方法//inputStream 是和 对应http请求的socket关联public YhRequest(InputStream inputStream) {this.inputStream = inputStream;//完成对http请求数据的封装..encapHttpRequest();}/*** 将http请求的相关数据,进行封装,然后提供相关的方法,进行获取*/private void encapHttpRequest() {System.out.println("yhRequest init()");try {//inputstream -> BufferedReaderBufferedReader bufferedReader =new BufferedReader(new InputStreamReader(inputStream, "utf-8"));//读取第一行/*** GET /hspCalServlet?num1=10&num2=30 HTTP/1.1* Host: localhost:8080* User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Fi*/String requestLine = bufferedReader.readLine();//GET - /hspCalServlet?num1=10&num2=30 - HTTP/1.1String[] requestLineArr = requestLine.split(" ");//得到methodmethod = requestLineArr[0];//解析得到 /hspCalServlet//1. 先看看uri 有没有参数列表int index = requestLineArr[1].indexOf("?");if (index == -1) { //说明没有参数列表uri = requestLineArr[1];} else {//[0,index)uri = requestLineArr[1].substring(0, index);//获取参数列表->parametersMapping//parameters => num1=10&num2=30String parameters = requestLineArr[1].substring(index + 1);//num1=10 , num2=30 .... parametersPair= ["num1=10","num2=30" ]String[] parametersPair = parameters.split("&");//防止用户提交时 /hspCalServlet?if (null != parametersPair && !"".equals(parametersPair)) {//再次分割 parameterPair = num1=10for (String parameterPair : parametersPair) {//parameterVal ["num1", "10"]String[] parameterVal = parameterPair.split("=");if (parameterVal.length == 2) {//放入到 parametersMappingparametersMapping.put(parameterVal[0], parameterVal[1]);}}}}//这里不能关闭流 inputStream 和 socket关联//inputStream.close();} catch (Exception e) {e.printStackTrace();}}//request对象有一个特别重要方法public String getParameter(String name) {if (parametersMapping.containsKey(name)) {return parametersMapping.get(name);} else {return "";}}public String getMethod() {return method;}public void setMethod(String method) {this.method = method;}public String getUri() {return uri;}public void setUri(String uri) {this.uri = uri;}@Overridepublic String toString() {return "HspRequest{" +"method='" + method + '\'' +", uri='" + uri + '\'' +", parametersMapping=" + parametersMapping +'}';}
}

注意 这里不能关闭流 inputStream 和 socket关联

Response对象处理响应 持有socket

public class YhResponse {/*** 1. HspResponse对象可以封装OutputStream(是socket关联)* 2. 即可以通过 HspResponse对象 返回Http响应给浏览器/客户端* 3. HspResponse对象 的作用等价于原生的servlet的 HttpServletResponse*/private OutputStream outputStream = null;//写一个http的响应头 => 先死后活public static final String respHeader = "HTTP/1.1 200 OK\r\n" +"Content-Type: text/html;charset=utf-8\r\n\r\n";//说明同学们如果有兴趣, 在编写更多的方法//比如 setContentType//在创建 YhResponse 对象时,传入的outputStream是和Socket关联的public YhResponse(OutputStream outputStream) {this.outputStream = outputStream;}//当我们需要给浏览器返回数据时,可以通过HspResponse 的输出流完成//public OutputStream getOutputStream() {return outputStream;}}

设计Servlet规范类以及Servlet接口

public interface YhServlet {void init() throws Exception;void service(YhRequest request, YhResponse response) throws IOException;void destroy();
}
public abstract class YhHttpServlet implements YhServlet {@Overridepublic void service(YhRequest request, YhResponse response) throws IOException {//老师说明 equalsIgnoreCase 比较字符串内容是相同,不区别大小写if("GET".equalsIgnoreCase(request.getMethod())) {//这里会有动态绑定this.doGet(request,response);} else if("POST".equalsIgnoreCase(request.getMethod())) {this.doPost(request,response);}}//这里我们使用的了模板设计模式 => java 基础的 抽象类专门讲过模板设计模式//让HspHttpServlet 子类 HspCalServlet 实现public abstract void doGet(YhRequest request, YhResponse response);public abstract void doPost(YhRequest request, YhResponse response);
}

YhCalServlet实现该Servlet并写自己的业务代码 

public class YhCalServlet extends YhHttpServlet {@Overridepublic void doGet(YhRequest request, YhResponse response) throws IOException {doPost(request,response);}@Overridepublic void doPost(YhRequest request, YhResponse response) throws IOException {String strnum1 = request.getParameter("num1");String strnum2 = request.getParameter("num2");int num1 = 0;int num2 = 0;int sum = -1;try {num1 = Integer.parseInt(strnum1);num2 = Integer.parseInt(strnum2);System.out.println("res = " + num1 + num2);sum = num1 + num2;} catch (NumberFormatException e) {System.out.println("form wrong , continue");}// response.setContentType("text/html;charset=utf-8"); response内已经做了OutputStream outputStream = response.getOutputStream();if (!(sum == -1)) {outputStream.write((YhResponse.respHeader + "<h1> res = " + sum + "</h1>").getBytes());}else{outputStream.write((YhResponse.respHeader + "<h1> wrong date please try again!!  </h1>").getBytes());}outputStream.flush();outputStream.close();}@Overridepublic void init() {}@Overridepublic void destroy() {}
}

4.使用反射去处理查找哪个calServlet

handler管理线程代码 

            //=====================通过反射来实现==========// 先说明一把实现思路->【停一下】 -> 如果你自己完成?10min// 1. 得到 uri => 就是 servletUrlMapping 的 url-patternYhRequest yhRequest = new YhRequest(socket.getInputStream());YhResponse yhResponse = new YhResponse(socket.getOutputStream());String uri = yhRequest.getUri();String servletName = YhTomcatV3.servletUrlMapping.get(uri);if(servletName == null){servletName = "";}//2. 通过uri->servletName->servlet的实例 , 真正的运行类型是其子类 HspCalServletYhHttpServlet yhHttpServlet =YhTomcatV3.servletMapping.get(servletName);//3. 调用service , 通过OOP的动态绑定机制,调用运行类型的 doGet/doPostif (yhHttpServlet != null) {//得到yhHttpServlet.service(yhRequest, yhResponse);} else {//没有这个servlet , 返回404的提示信息String resp = YhResponse.respHeader + "<h1>404 Not Found</h1>";OutputStream outputStream = yhResponse.getOutputStream();outputStream.write(resp.getBytes());outputStream.flush();outputStream.close();}

模拟Tomcat利用反射和dom4j处理xml文件获取Servlet

public class YhTomcatV3 {//1. 存放容器 servletMapping// -ConcurrentHashMap// -HashMap// key            - value// ServletName    对应的实例public static final ConcurrentHashMap<String, YhHttpServlet>servletMapping = new ConcurrentHashMap<>();//2容器 servletUrlMapping// -ConcurrentHashMap// -HashMap// key                    - value// url-pattern       ServletNamepublic static final ConcurrentHashMap<String, String>servletUrlMapping = new ConcurrentHashMap<>();//你可以这里理解session, tomcat还维护一个容器public static final ConcurrentHashMap<String, HttpSession>sessionMapping = new ConcurrentHashMap<>();// //你可以这里理解filter, tomcat还维护了filter的容器// public static final ConcurrentHashMap<String, String>//         filterUrlMapping = new ConcurrentHashMap<>();//// public static final ConcurrentHashMap<String, Filter>//         filterMapping = new ConcurrentHashMap<>();public static void main(String[] args) throws MalformedURLException, DocumentException {YhTomcatV3 yhTomcatV3 = new YhTomcatV3();yhTomcatV3.init();//启动hsptomcat容器yhTomcatV3.startTomcatV3();}//启动HspTomcatV3容器public void startTomcatV3() {try {ServerSocket serverSocket = new ServerSocket(8080);System.out.println("=====hsptomcatv3在8080监听======");while (!serverSocket.isClosed()) {Socket socket = serverSocket.accept();YhRequestHandler yhRequestHandler =new YhRequestHandler(socket);new Thread(yhRequestHandler).start();}} catch (IOException e) {e.printStackTrace();}}//直接对两个容器进行初始化@Testpublic void init() throws MalformedURLException, DocumentException {//读取web.xml => dom4j =>//得到web.xml文件的路径 => 拷贝一份.String path = YhTomcatV3.class.getResource("/").getPath();System.out.println("path= " + path);//使用dom4j技术完成读取SAXReader saxReader = new SAXReader();//困难->真的掌握try {Document document = saxReader.read(new File(path + "web.xml"));System.out.println("document= " + document);//得到根元素Element rootElement = document.getRootElement();//得到根元素下面的所有元素List<Element> elements = rootElement.elements();//遍历并过滤到 servlet servlet-mappingfor (Element element : elements) {if ("servlet".equalsIgnoreCase(element.getName())) {//这是一个servlet配置//System.out.println("发现 servlet");//使用反射将该servlet实例放入到servletMappingElement servletName = element.element("servlet-name");Element servletClass = element.element("servlet-class");servletMapping.put(servletName.getText(),(YhHttpServlet) Class.forName(servletClass.getText().trim()).newInstance());} else if ("servlet-mapping".equalsIgnoreCase(element.getName())) {//这是一个servlet-mapping//System.out.println("发现 servlet-mapping");Element servletName = element.element("servlet-name");Element urlPatter = element.element("url-pattern");servletUrlMapping.put(urlPatter.getText(), servletName.getText());}}} catch (Exception e) {e.printStackTrace();}//老韩验证,这两个容器是否初始化成功System.out.println("servletMapping= " + servletMapping);System.out.println("servletUrlMapping= " + servletUrlMapping);}
}

二、课后作业

<html lang="en">
<head><meta charset="UTF-8"><title>计算器</title>
</head>
<body><form action="/yhCalServlet" method="GET">num1:<input type="text" name="num1"><br/>num2:<input type="text" name="num2"><br/><input type="submit" value="submit"></form>
</body>
</html>

在工具类内写方法判断  如果不是servlet 就判断是不是html

public static String readHtml(String filename) {String path = com.yinhai.utils.WebUtils.class.getResource("/").getPath();StringBuilder stringBuilder = new StringBuilder();try {BufferedReader bufferedReader = new BufferedReader(new FileReader(path + filename));String buf = "";while ((buf = bufferedReader.readLine()) != null) {stringBuilder.append(buf);}} catch (Exception e) {e.printStackTrace();}return stringBuilder.toString();}

如果是html 就走该if体 将方法返回 

 // ====================新增业务逻辑===========//(1) 判断uri是什么资源 => 工具方法//(2) 如果是静态资源,就读取该资源,并返回给浏览器 content-type text/html//(3) 因为目前老师并没有起到tomcat, 不是一个标准的web项目//(4) 把读取的静态资源放到 target/classes/cal.html//过滤,拦截 , 权限等待 => Handler.... => 分发if(WebUtils.isHtml(uri)) {//就是静态页面String content = WebUtils.readHtml(uri.substring(1));content = yhResponse.respHeader + content;//得到outputstream , 返回信息(静态页面)给浏览器OutputStream outputStream = yhResponse.getOutputStream();outputStream.write(content.getBytes());outputStream.flush();outputStream.close();socket.close();return;}//===========================================

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

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

相关文章

Docker--Docker镜像仓库

一、搭建私有镜像仓库 搭建镜像仓库可以基于Docker官方提供的DockerRegistry来实现。 官网地址&#xff1a;https://hub.docker.com/_/registry &#xff08;一&#xff09;简化版镜像仓库 Docker官方的Docker Registry是一个基础版本的Docker镜像仓库&#xff0c;具备仓库…

线下实体门店引流,百万私域电商高手都在用的实战营销引流技巧!

线下实体门店引流&#xff0c;百万私域电商高手都在用的实战营销引流技巧&#xff01; 无论是初创公司还是已经在步入正轨的实体门店&#xff0c;有个现实的实例告诉你&#xff1a;互联网上90%的引流技巧告诉你的方法&#xff0c;其实都是不挣钱的&#xff0c;辛辛苦苦折腾一整…

大数据技术之Shell(超级详细)

大数据技术之Shell&#xff08;超级详细&#xff09; 第1章 Shell概述 Shell 是一种脚本语言&#xff0c;用于在操作系统的命令行界面&#xff08;CLI&#xff09;下执行命令和脚本。在大数据领域&#xff0c;Shell 脚本常用于编写数据处理和分析任务的自动化脚本&#xff0c…

Redis设计与实现之对象处理机制

目录 一、前言 二、对象处理机制 1、redisObject 数据结构&#xff0c;以及 Redis 的数据类型 2、 命令的类型检查和多态 3、对象共享 4、引用计数以及对象的销毁 三、对象的处理 1、Redis是如何处理字符串对象的&#xff1f; 2、Redis是如何处理列表对象的&#xff1f…

十九)Stable Diffusion使用教程:ai室内设计案例

今天我们聊聊如何通过SD进行室内设计装修。 方式一:controlnet的seg模型 基础起手式: 选择常用算法,抽卡: 抽到喜欢的图片之后,拖到controlnet里: 选择seg的ade20k预处理器,点击爆炸按钮,得到seg语义分割图,下载下来: 根据语义分割表里的颜色值,到PS里进行修改: 语…

制作一个简单 的maven plugin

流程 首先&#xff0c; 你需要创建一个Maven项目&#xff0c;推荐用idea 创建项目 会自动配置插件 pom.xml文件中添加以下配置&#xff1a; <project> <!-- 项目的基本信息 --> <groupId>com.example</groupId> <artifactId>my-maven-plugi…

深入理解JVM设计的精髓与独特之处

这是Java代码的执行过程 从软件工程的视角去深入拆解&#xff0c;无疑极具吸引力&#xff1a;首个阶段仅依赖于源高级语言的细微之处&#xff0c;而第二阶段则仅仅专注于目标机器语言的特质。 不可否认&#xff0c;在这两个编译阶段之间的衔接&#xff08;具体指明中间处理步…

javacv的视频截图功能

之前做了一个资源库的小项目&#xff0c;因为上传资源文件包含视频等附件&#xff0c;所以就需要时用到这个功能。通过对视频截图&#xff0c;然后作为封面缩略图&#xff0c;达到美观效果。 首先呢&#xff0c;需要准备相关的jar包&#xff0c;之前我用的是低版本的1.4.2&…

极简Excel公式拆分合并单元格并自动填充

例如这个表格&#xff1a; 我们希望拆分合并单元格&#xff0c;并填充到E列。结果如&#xff1a; 步骤 1&#xff09;在E2输入公式如下&#xff1a; LOOKUP(2,1/($B$2:B2<>""),$B$2:B2) 2&#xff09;下拉E2至E9将公式填充即可 注意&#xff1a;公式中的$…

基于ssm游戏美术外包管理信息系统源码和论文

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;线下管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&…

[Linux] Apache的配置与运用

一、web虚拟主机的构台服务器上运行多个网站&#xff0c;每个网站实际上并不独立占用整个服务器&#xff0c;因此称为"虚拟"虚拟主机的虚拟主机服务可以让您充分利用服务器的硬件资源&#xff0c;大大降低了建立和运营网站的成本 Httpd服务使构建虚拟主机服务器变得容…

基于SSM的志愿者管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

6.23删除二叉搜索树中的节点(LC450-M)

算法&#xff1a; 一共有五种可能的情况&#xff1a; 第一种情况&#xff1a;没找到删除的节点&#xff0c;遍历到空节点直接返回了找到删除的节点 第二种情况&#xff1a;左右孩子都为空&#xff08;叶子节点&#xff09;&#xff0c;直接删除节点&#xff0c; 返回NULL为根…

基于springboot乐器视频学习网站设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。你想解决的问题&#xff0c;今天给大家介绍…

讲座 | 颠覆传统摄像方式乃至计算机视觉的“脉冲视觉”

传统相机拍摄视频时其实是以一定帧率进行采样&#xff0c;视频其实还是一串图片的集合&#xff0c;因此低帧率时会觉得视频卡&#xff0c;拍摄高速运动物体时会有运动模糊等等问题。然而你能想象这一切都可以被“脉冲视觉”这一前沿技术改变吗&#xff1f; 今天下午听了北京大学…

【从零开始学习JVM | 第七篇】深入了解 堆回收

前言&#xff1a; Java堆作为内存管理中最核心的一部分&#xff0c;承担着对象实例的存储和管理任务。堆内存的高效使用对于保障程序的性能和稳定性至关重要。因此&#xff0c;深入理解Java堆回收的原理、机制和优化策略&#xff0c;对于Java开发人员具有重要的意义。 本文旨在…

C++相关闲碎记录(16)

1、正则表达式 &#xff08;1&#xff09;regex的匹配和查找接口 #include <regex> #include <iostream> using namespace std;void out (bool b) {cout << ( b ? "found" : "not found") << endl; }int main() {// find XML/H…

ProroBuf C++笔记

一.什么是protobuf Protocol Buffers是Google的⼀种语⾔⽆关、平台⽆关、可扩展的序列化结构数据的⽅法&#xff0c;它可⽤于&#xff08;数据&#xff09;通信协议、数据存储等。Protocol Buffers 类⽐于XML&#xff0c;是⼀种灵活&#xff0c;⾼效&#xff0c;⾃动化机制的结…

SpringData自定义操作

一、JPQL和SQL 查询 package com.kuang.repositories;import com.kuang.pojo.Customer; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.PagingAndSortingR…

javaEE -17(13000字 CSS3 入门级教程)

一&#xff1a;CSS3 简介 CSS3 是 CSS2 的升级版本&#xff0c;它在 CSS2 的基础上&#xff0c;新增了很多强大的新功能&#xff0c;从而解决一些实际面临的问题&#xff0c;CSS3 在未来会按照模块化的方式去发展&#xff1a;https://www.w3.org/Style/CSS/current-work.html …