网站去掉index.html/找回原来的百度
目录
一、Tomcat底层整体架构
1.简介 :
2.分析图 :
3.基于Socket开发服务端的流程 :
4.打通服务器端和客户端的数据通道 :
二、多线程模型的实现
1.思路分析 :
2.处理HTTP请求 :
3.自定义Tomcat :
三、自定义Servlet规范
1. HTTP请求和响应 :
1° CyanServletRequest
2° CyanServletResponse
2.Servlet规范 :
1° CyanServlet
2° CyanHttpServlet
3° CyanLoginServlet
3.容器实现 :
1° 思路分析
2° web.xml配置文件
3° 最终版自定义Tomcat
4° 最终版自定义线程类
5° 容器启动测试
一、Tomcat底层整体架构
1.简介 :
Tomcat 有三种运行模式 (BIO[阻塞], NIO[非阻塞], APR),这里采用 BIO 线程模型来模拟实现。
2.分析图 :
如下图所示 :
浏览器请求servlet资源后,Tomcat底层会通过Socket网络编程来接收请求,每次请求,都会创建一个新的线程去调用相应的Web资源,并返回。
3.基于Socket开发服务端的流程 :
如下图所示 :
通过获取的Socket对象,来获取Socket对象对应的字节输入流和字节输出流。
可以利用对象转换流将字节流转换为字符流对象(InputStreamReader实现了Reader抽象类),然后再通过BufferedReader的包装,将节点流转换成包装流(处理流)。
4.打通服务器端和客户端的数据通道 :
PS :
Maven配置Web应用,运行出现jakarta.servlet.ServletException:
因为tomcat10之后不是javax.servlet,而是jakarta.servlet,所以Web的依赖应该换成如下所示 : (pom.xml配置文件)
<!--jar包的依赖--><dependency><groupId>jakarta.servlet</groupId><artifactId>jakarta.servlet-api</artifactId><version>5.0.0</version><scope>provided</scope></dependency><!--jsp的依赖--><dependency><groupId>jakarta.servlet.jsp</groupId><artifactId>jakarta.servlet.jsp-api</artifactId><version>3.0.0</version><scope>provided</scope></dependency>
MyTomcat类代码如下 : (服务端;自定义的Tomcat)
package tomcat;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;/**服务器端*/
public class MyTomcat {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8080);System.out.println("Tomcat在8080端口进行监听...");System.out.println("--------------------------------------");while (!serverSocket.isClosed()) {//获取Socket对象Socket socket = serverSocket.accept();//接收来自浏览器端的信息InputStream inputStream = socket.getInputStream();BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));String content = null; //局部变量在使用前必须赋初值。while ((content = bufferedReader.readLine()) != null) {//判断content是否是空串儿if (content.length() == 0) {break;}System.out.println(content);}//服务器向浏览器回送消息OutputStream outputStream = socket.getOutputStream();//设置一个HTTP响应包的响应头// "/r/n"表示换行String respHeader ="HTTP/1.1 200\r\n" +"Content-Type: text/html;charset=utf-8\r\n\r\n";//设置HTTP响应的响应体String respBody = respHeader + "<h1>你好!</h1>";/*注意这里不能使用字符包装流来写数据!!!。*/outputStream.write(respBody.getBytes());System.out.println("--------------------------------------");System.out.println(respBody);//释放资源outputStream.flush();outputStream.close();inputStream.close();socket.close();
// serverSocket.close();}}
}
在浏览器地址栏访问本机8080端口。
login.html代码如下 :
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>login</title><style>table, tr, td {border:2px cornflowerblue solid;border-collapse: collapse;padding: 10px;background-color: lightcyan}#tr01 {text-align: center}</style>
</head>
<body>
<form action="/Cyan_Tomcat/login" methods="get"><table><tr><th colspan="2">User Logging</th></tr><tr><td>Username: </td><td><input type="text" name="username"/></td></tr><tr><td>Password: </td><td><input type="password" name="password"/></td></tr><tr id="tr01"><td><input type="submit" value="Submit"/></td><td><input type="reset" value="Reset"/></td></tr></table>
</form>
</body>
</html>
LoginServlet类代码如下 :
package servlet;import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** @author : Cyan_RA9* @version : 21.0*/
@WebServlet(urlPatterns = {"/login"})
public class LoginServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("LoginServlet's doPost is invoked~");resp.setContentType("text/html; charset=utf-8");PrintWriter writer = resp.getWriter();req.setCharacterEncoding("utf-8");String username = req.getParameter("username");String password = req.getParameter("password");if ("Cyan".equals(username) && "123".equals(password)) {writer.print("<h1>登录成功!</h1>");} else {writer.print("<h1>登录失败!请重新尝试!</h1>");}}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}
}
运行效果 :
如果以Web工程配置好的Tomcat运行,就会按照LoginServlet类的代码逻辑来处理业务,如下图所示 : (GIF)
如果以自定义的Tomcat运行,就会以MyTomcat类中的代码逻辑来处理业务。
如下图所示 : (GIF)
二、多线程模型的实现
1.思路分析 :
当服务器端接收到浏览器端的HTTP请求后,启动一个新的线程,令该线程持有浏览器对应的Socket对象,完成线程和浏览器的对接。
可通过实现Runnable接口的方式定义线程类HttpRequestHandler,线程对象用于处理来自浏览器的HTTP请求。
2.处理HTTP请求 :
线程类HttpRequestHandler类代码如下 :
package tomcat.handler;import tomcat.http.CyanServletRequest;
import tomcat.http.CyanServletResponse;
import tomcat.servlet.CyanLoginServlet;import java.io.*;
import java.net.Socket;public class HttpRequestHandler implements Runnable {private Socket socket;public HttpRequestHandler(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {//接收客户端的信息InputStream inputStream = socket.getInputStream();/* 以下代码已在CyanServletRequest类中实现BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(inputStream, "utf-8"));//BIO,每次请求都对应一个新的线程System.out.println("当前线程 = " + Thread.currentThread().getName());String content = null; //局部变量在使用前必须赋初值。while ((content = bufferedReader.readLine()) != null) {//判断是否读到了空字符串if (content.length() == 0) {break;}System.out.println(content);}
*///Die first and live second//获取客户端的信息(利用了CyanServletRequest中封装好的方法)//以下代码已在CyanLoginServlet中实现
/* CyanServletRequest cyanServletRequest = new CyanServletRequest(inputStream);String username = cyanServletRequest.getParameter("username");String password = cyanServletRequest.getParameter("password");System.out.println("username = " + username);System.out.println("password = " + password);System.out.println(cyanServletRequest);*///给客户端回送信息//以下代码已在CyanLoginServlet类中实现。
/* CyanServletResponse cyanServletResponse = new CyanServletResponse(socket.getOutputStream());String resp = CyanServletResponse.respHeader + "<h1>CyanServletResponse!</h1>";OutputStream outputStream = cyanServletResponse.getOutputStream();outputStream.write(resp.getBytes());outputStream.flush();outputStream.close();*/CyanServletRequest cyanServletRequest = new CyanServletRequest(inputStream);CyanServletResponse cyanServletResponse = new CyanServletResponse(socket.getOutputStream());CyanLoginServlet cyanLoginServlet = new CyanLoginServlet();cyanLoginServlet.doPost(cyanServletRequest, cyanServletResponse);//释放资源inputStream.close();socket.close();/* 以下代码已在CyanServletResponse类中实现 :String respHeader = "HTTP/1.1 200\r\n" +"Content-Type: text/html;charset=utf-8\r\n\r\n";String respHttp = respHeader + "<h1>Cyan_RA9</h1>";System.out.println("-----------------------------------------------");System.out.println("回送的信息如下:(回显)");System.out.println(respHttp);OutputStream outputStream = socket.getOutputStream();outputStream.write(respHttp.getBytes());//释放资源outputStream.flush();outputStream.close();inputStream.close();socket.close(); */} catch (IOException e) {throw new RuntimeException(e);} finally {//确保Socket关闭if (socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}
3.自定义Tomcat :
在MyTomcat_EX类中实现线程的分发。
MyTomcat_EX类代码如下 :
package tomcat;import tomcat.handler.HttpRequestHandler;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;/*** @author : Cyan_RA9* @version : 21.0*/
public class MyTomcat_EX {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8080);System.out.println("MyTomcat_EX在8080端口进行监听...");while (!serverSocket.isClosed()) {Socket socket = serverSocket.accept();HttpRequestHandler httpRequestHandler = new HttpRequestHandler(socket);Thread thread = new Thread(httpRequestHandler);thread.start();}}
}
运行效果 : (GIF)
三、自定义Servlet规范
1. HTTP请求和响应 :
1° CyanServletRequest
CyanServletRequest类的作用等同于原始的HttpServletRequest,该类用于封装HTTP请求中的数据,eg : method, URI, 以及表单数据的参数列表等。
CyanServletRequest类代码如下 :
package tomcat.http;import java.io.*;
import java.util.HashMap;/*** @author : Cyan_RA9* @version : 21.0* @function : like the original HttpServletRequest.*/
public class CyanServletRequest {private String method;private String URI;private HashMap<String, String> parametersMapping = new HashMap<>();private InputStream inputStream;/*此处传入的InputStream对象是和Socket关联的InputStream.*/public CyanServletRequest(InputStream inputStream) {this.inputStream = inputStream;//完成对HTTP请求数据的封装this.init();}private void init() {System.out.println("\nCyanServletRequest's init is invoked~");try {//注意转换流的形参列表BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(inputStream, "utf-8"));//首先读取HTTP请求的请求行/* eg : GET /Cyan/cyan.html HTTP/1.1 */String requestLine = bufferedReader.readLine();String[] requestLineArr = requestLine.split(" ");//获取methodmethod = requestLineArr[0];//获取URIint index = requestLineArr[1].indexOf("?");if (index == -1) { //if判断成立,说明请求行中没有参数列表URI = requestLineArr[1];} else {URI = requestLineArr[1].substring(0, index);//获取参数列表String parameters = requestLineArr[1].substring(index + 1);String[] parameterPairs = parameters.split("&");//兼容性处理,防止?后啥都没有。if (null != parameterPairs && !"".equals(parameterPairs)) {for (String parameterPair : parameterPairs) {String[] parameter = parameterPair.split("=");if (parameter.length == 2) { //判断是否为一对完整的"name=value".parametersMapping.put(parameter[0],parameter[1]);}}}}//!!! 直接关闭Socket关联的InputStream,会引起Socket的关闭。//inputStream.close();} catch (UnsupportedEncodingException e) {throw new RuntimeException(e);} catch (IOException e) {throw new RuntimeException(e);}}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;}//重要public String getParameter(String name) {if (parametersMapping.containsKey(name)) { //注意此处API的使用!return parametersMapping.get(name);} else {return null;}}@Overridepublic String toString() {return "CyanServletRequest{" +"method='" + method + '\'' +", URI='" + URI + '\'' +", parametersMapping=" + parametersMapping +'}';}
}
CyanServletRequest类测试,运行效果如下GIF :
2° CyanServletResponse
CyanServletResponse类的作用等同于原始的HttpServletResponse,用于封装HTTP响应的相关信息。
CyanServletResponse类代码如下 :
package tomcat.http;import java.io.OutputStream;/*** @author : Cyan_RA9* @version : 21.0* @function : like the original HttpServletResponse*/
public class CyanServletResponse {private OutputStream outputStream;//设置一个HTTP响应头public static final String respHeader = "HTTP/1.1 200\r\n" +"Content-Type: text/html;charset=utf-8\r\n\r\n";//传入与Socket关联的OutputStream对象public CyanServletResponse(OutputStream outputStream) {this.outputStream = outputStream;}public OutputStream getOutputStream() {return outputStream;}
}
运行测试(如下GIF图):
2.Servlet规范 :
1° CyanServlet
CyanServlet仅保留原生Servlet的init, destroy, service方法,其中,service方法供将来CyanServlet的抽象实现类CyanHttpServlet去重写。注意,service方法的形参列表,要使用自定义的CyanServletRequest 和 CyanServletResponse.
CyanServlet接口,代码如下 :
package tomcat.servlet;import tomcat.http.CyanServletRequest;
import tomcat.http.CyanServletResponse;import java.io.IOException;public interface CyanServlet {void init() throws Exception;void service(CyanServletRequest req, CyanServletResponse resp) throws IOException;void destroy();
}
2° CyanHttpServlet
CyanHttpServlet的作用,类似于原生的HttpServlet;在CyanHttpServlet中实现CyanServlet接口中的service方法,在service方法中,要对HTTP请求的method类型进行判断。
CyanHttpServlet抽象类代码如下 :
package tomcat.servlet;import tomcat.http.CyanServletRequest;
import tomcat.http.CyanServletResponse;import java.io.IOException;public abstract class CyanHttpServlet implements CyanServlet{@Overridepublic void service(CyanServletRequest req, CyanServletResponse resp) throws IOException {//忽略大小写if ("GET".equalsIgnoreCase(req.getMethod())) {this.deGet(req, resp);} else if ("POST".equalsIgnoreCase(req.getMethod())) {this.doPost(req, resp);}}//模板设计模式public abstract void deGet(CyanServletRequest req, CyanServletResponse resp);public abstract void doPost(CyanServletRequest req, CyanServletResponse resp);
}
3° CyanLoginServlet
CyanLoginServlet是一个简单的servlet实例,用于继承CyanHttpServlet抽象类,并实现CyanHttpServlet类中的doGet和doPost抽象方法。之后,在HttpRequestHandler线程类中先尝试直接调用CyanLoginServlet实例。
CyanLoginServlet代码如下 :
package tomcat.servlet;import tomcat.http.CyanServletRequest;
import tomcat.http.CyanServletResponse;import java.io.IOException;
import java.io.OutputStream;public class CyanLoginServlet extends CyanHttpServlet{@Overridepublic void deGet(CyanServletRequest req, CyanServletResponse resp) {doPost(req, resp);}@Overridepublic void doPost(CyanServletRequest req, CyanServletResponse resp) {String username = req.getParameter("username");String password = req.getParameter("password");//获取与当前Socket相关联的OutputStream对象OutputStream outputStream = resp.getOutputStream();String respInfo = CyanServletResponse.respHeader + "<h1>username = " +username + "</h1><br/> " + "<h1>password = " + password + "</h1>" + "<br/>" +"<h3>Cyan_RA9</h3>";try {outputStream.write(respInfo.getBytes());outputStream.flush();outputStream.close();} catch (IOException e) {throw new RuntimeException(e);}}@Overridepublic void init() throws Exception {}@Overridepublic void destroy() {}
}
此外,还需要更新HttpServletHandler类中的类型,将已封装好的代码注释掉,HttpServletHandler类已更新,在上文“多线程模型实现”的HTTP请求处理模块。
运行效果如下图所示 :
3.容器实现 :
1° 思路分析
Tomcat中维护有至少两个大的HashMap容器。以web.xml配置文件的方式为例,其中一个HashMap容器,key存放<url-pattern>,value存放<servlet-name>;另一个HashMap容器,key存放<servlet-name>,value存放通过<servlet-class>来反射生成的servlet实例。
2° web.xml配置文件
web.xml配置文件如下 :
<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><!--xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"-->
<!--IDEA报错——因为这是我们自定义的servlet,IDEA无法识别;无所谓!继续用!-->
<web-app><display-name>Archetype Created Web Application</display-name><servlet><servlet-name>CyanLoginServlet</servlet-name><servlet-class>tomcat.servlet.CyanLoginServlet</servlet-class></servlet><servlet-mapping><servlet-name>CyanLoginServlet</servlet-name><url-pattern>/cyanLogin</url-pattern></servlet-mapping>
</web-app>
3° 最终版自定义Tomcat
在MyTomcat_Pro类中定义两个CurrentHashMap对象;定义init方法完成对两个CurrentHashMap对象的初始化(使用Dom4J读取web.xml配置文件)。
首先,需要在Maven的pom.xml配置文件中,引入dom4j依赖,如下图所示 :
然后,将web.xml配置文件拷贝到/target/classes/目录下一份,如下图所示 :
MyTomcat_Pro代码如下 :
package tomcat;import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import tomcat.handler.HttpRequestHandler;
import tomcat.servlet.CyanHttpServlet;import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;/*** The final own custom Tomcat.*/
public class MyTomcat_Pro {//Tomcat维护的第一个容器//String --> <servlet-name>//CyanHttpServlet --> 可存放它的子类(即各种servlet实例)public static final ConcurrentHashMap<String, CyanHttpServlet> servletMapping =new ConcurrentHashMap<>();//Tomcat维护的第二个容器//String --> <url-patterns>//String --> <servlet-name>public static final ConcurrentHashMap<String, String> servletURLMapping =new ConcurrentHashMap<>();public static void main(String[] args) {MyTomcat_Pro myTomcat_pro = new MyTomcat_Pro();myTomcat_pro.init();myTomcat_pro.run();}public void run() {try {ServerSocket serverSocket = new ServerSocket(8080);System.out.println("MyTomcat_Pro在8080端口进行监听...");while (!serverSocket.isClosed()) {Socket socket = serverSocket.accept();Thread thread = new Thread(new HttpRequestHandler(socket));thread.start();}} catch (IOException e) {throw new RuntimeException(e);}}public void init() {String path = MyTomcat_Pro.class.getResource("/").getPath();//path = "/javaProject/Servlet/Cyan_Tomcat/target/classes/"//使用Dom4J技术解析web.xml文件SAXReader saxReader = new SAXReader();try {//注意文件名Document document = saxReader.read(new File(path + "web.xml"));System.out.println("document = " + document);//获取根元素<web-app>Element rootElement = document.getRootElement();//得到根元素下面的所有子元素List<Element> elements = rootElement.elements();//遍历并判断for (Element element : elements) {if ("servlet".equals(element.getName())) {Element servlet_name = element.element("servlet-name");Element servlet_class = element.element("servlet-class");//反射机制创建servlet实例 (注意getText()方法的使用!)Class<?> clazz = Class.forName(servlet_class.getText().trim());Constructor<?> constructor = clazz.getConstructor();CyanHttpServlet o = (CyanHttpServlet) constructor.newInstance();servletMapping.put(servlet_name.getText(), o);} else if ("servlet-mapping".equals(element.getName())) {Element url_pattern = element.element("url-pattern");Element servlet_name = element.element("servlet-name");servletURLMapping.put(url_pattern.getText(), servlet_name.getText());}}} catch (Exception e) {throw new RuntimeException(e);}}
}
4° 最终版自定义线程类
package tomcat.handler;import tomcat.MyTomcat_Pro;
import tomcat.http.CyanServletRequest;
import tomcat.http.CyanServletResponse;
import tomcat.servlet.CyanHttpServlet;
import tomcat.servlet.CyanLoginServlet;import java.io.*;
import java.net.Socket;public class HttpRequestHandler implements Runnable {private Socket socket;public HttpRequestHandler(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {//接收客户端的信息CyanServletRequest cyanServletRequest = new CyanServletRequest(socket.getInputStream());CyanServletResponse cyanServletResponse = new CyanServletResponse(socket.getOutputStream());String uri = cyanServletRequest.getURI();System.out.println("uri = " + uri);String servlet_name = MyTomcat_Pro.servletURLMapping.get(uri);/*这里的servlet_name可能为空。解决方式一 : 将CurrentHashMap替换为HashMap解决方式二 : 增加一个是否为null的判断。*/if (servlet_name == null) {servlet_name = "";}//多态 --> 动态绑定CyanHttpServlet cyanHttpServlet = MyTomcat_Pro.servletMapping.get(servlet_name);if (cyanHttpServlet != null) { //判断是否正常得到servlet实例cyanHttpServlet.service(cyanServletRequest, cyanServletResponse);} else {//如果没有找到servlet,返回404String resp = CyanServletResponse.respHeader + "<h1>404 Not Found!</h1>";OutputStream outputStream = cyanServletResponse.getOutputStream();outputStream.write(resp.getBytes());outputStream.flush();outputStream.close();}//释放资源socket.close();} catch (IOException e) {throw new RuntimeException(e);} finally {//确保Socket关闭if (socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}
5° 容器启动测试
如下图所示(GIF):
相关文章:

JavaWeb 手写Tomcat底层机制
目录 一、Tomcat底层整体架构 1.简介 : 2.分析图 : 3.基于Socket开发服务端的流程 : 4.打通服务器端和客户端的数据通道 : 二、多线程模型的实现 1.思路分析 : 2.处理HTTP请求 : 3.自定义Tomcat : 三、自定义Servlet规范 1. HTTP请求和响应 : 1 CyanServletRequest …...

Gof23设计模式之组合模式
1.定义 组合模式又名部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。 2.结构 组合模式主要包含三种…...

龙芯积极研发二进制翻译,提升软硬件兼容性,提高LoongArch架构
根据8月8日Phoronix报道,龙芯正在积极研发龙芯二进制翻译功能(Loongson Binary Translationm,LBT)以提高LoongArch架构与其他处理器(如MIPS/x86/Arm)的二进制翻译能力,这重要举措将显著提升龙芯…...

3天爆肝整理,自动化测试-YAML文件读写实战(超细总结)
目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 YAML 简介 YAML&…...

算法通关村——透彻理解二分查找
1. 循环法 public static int binarySearch(int[] arr, int low, int high, int target) {while (low < high) {// 这样写主要是避免溢出的情况,以及>>优先级小于,避免出现死循环int mid low ((high - low) >> 1);if (arr[mid] target…...

PAT(Advanced Level)刷题指南 —— 第六弹(⭐有点难度⭐)
一、1010 Radix 1. 问题重述 2. Sample Input1 6 110 1 103. Sample Output1 24. Sample Input 2 1 ab 1 25. Sample Output 2...

个人对智能家居平台选择的思考
本人之前开发过不少MicroPython程序,其中涉及到自动化以及局域网控制思路,也可以作为智能家居的实现方式。而NodeMCUESPHome的方案具有方便添加硬件、容易更新程序和容量占用小的优势,本人也查看过相关教程后感觉部署ESPHome和编译固件的步骤…...

无涯教程-Lua - while语句函数
只要给定条件为真,Lua编程语言中的 while 循环语句就会重复执行目标语句。 while loop - 语法 Lua编程语言中 while 循环的语法如下- while(condition) dostatement(s) end while loop - 流程图 在这里,需要注意的关键是 while 循环可能根本不执行。…...

MySql学习3:常用函数
常用字符串函数 CHAR_LENGTH(s):返回字符串的长度 select *, char_length(name) as nameLength from emp;CONCAT(s1,s2…sn):字符串拼接 select name,concat(name,入职时间:,entrydata) as 入职时间 from emp;CONCAT_WS(x, s1,s2…sn)&a…...

24届近5年江南大学自动化考研院校分析
今天给大家带来的是江南大学控制考研分析 满满干货~还不快快点赞收藏 一、江南大学 学校简介 江南大学(Jiangnan University)是国家“双一流”建设高校,“211工程”、“985工程优势学科创新平台”重点建设高校,入选…...

C++ 数组
数组是具有一定顺序关系的若干对象的集合体,组成数组的对象称为该数组的元素。 数组元素用数组名与带方括号的下标表示,同一数组的各个元素具有相同的类型。数组可以由除void型以外的任何一种类型构成,构成数组的类型和数组之间的关系&#x…...
Android LinearLayout dynamic add child ImageView,Glide load,kotlin
Android LinearLayout dynamic add child ImageView,Glide load,kotlin images.xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"andro…...

HTML 是什么?它的全称是什么?
聚沙成塔每天进步一点点 专栏简介HTML是什么?HTML的全称是什么?写在最后 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对We…...

ATF(TF-A)安全通告
目录计划如下,相关内容补充中,待完成后进行超链接,敬请期待,欢迎关注 1、Advisory TFV-1 (CVE-2016-10319) 2、Advisory TFV-2 (CVE-2017-7564) 3、Advisory TFV-3 (CVE-2017-7563) 4、Advisory TFV-4 (CVE-2017-9607) 5、Adviso…...

LVS—DR集群的搭建
目录 lvs-dr模式工作原理: 搭建结构: 1、RS: 1)两台RS准备好httpd环境和测试文件 2)添加虚拟IP(vip)、添加访问本地vip的静态路由 并抑制ARP 2、DS: 1)安装ipvasadm…...

如何理解容量测试?如何做容量测试?
1、如何理解容量测试? 容量测试,是性能测试里的一部分,它的目的是测量系统的最大容量,为系统扩容、性能优化提供参考,节省成本投入,提高资源利用率。就是运用各种方法和工具在这种复杂的情况下去不断验证容…...

文件上传漏洞(webshell)
一、防护 1、防护 1、判断文件后缀,为图片的话才让上传成功。 2、解析文件内容(文件幻数)判断文件头和文件尾部是否一致 幻数 常见的 3、隐藏按钮(带上code唯一值) 4、二次渲染(类似拿着你的图片ÿ…...

.net几行代码音乐API各排行榜 热搜 入库
对比了几家大厂的音乐API的接口 这家相对规范些 现在开始从零开始 net6敏捷开发对接 入库吧 关键技术工具和思维 1 json 生成类 2 分析类 规划表设计3 sqlsuger codefirst 生成表 4 封装get post 连接5 类映射automapper6 sqlsuger 插入数据 1 json 生成类 宇宙 第 一的…...

使用gpt对对话数据进行扩增,对话数据扩增,数据增强
我们知道一个问题可以使用很多方式问,但都可以使用完全一样的回答,基于这个思路,我们可以很快的扩增我们的数据集。思路就是使用chatgpt或者gpt4生成类似问题,如下: 然后我们可以工程化这个过程,从而快速扩…...

算法练习工程1.2
题目要求: * 问题标题:删除有序数组中的重复项: * 题意说明: * 给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。 * …...

数字IC流片经历有多重要?怎样才能有流片机会?
都说拥有流片经验可以显示你在实际项目中的实践能力和对整个设计流程的了解程度,流片经历的重要性不言而喻。 什么是芯片流片 像流水线一样通过一系列工艺步骤制造芯片,这就是流片。在芯片制造过程中一般有两段时间可以叫作流片。 流片:英…...

fontfaceobserver 第三方字体加载优化方案
fontfaceobserver 第三方字体加载优化方案 1. github地址 https://github.com/bramstein/fontfaceobserver 2. 基础使用方法 const font new FontFaceObserver(My Family, {weight: 400 });font.load().then(function () {console.log(Font is available); }, function ()…...

laravel安装composer依赖
一.问题描述 拉取的新项目没有依赖 项目根目录没有vendor目录 报错 二.安装composer,拉取依赖 1.如果没有composer先去下载 官网地址:Packagist / Composer 中国全量镜像 我的博客安装composer:composer最新版本安装_荒-漠的博客-CSDN博客 2.进入项目根目录cmd或者在项目中…...

问题聚集度Hive SQL
问题聚集度:最小的分母占比,贡献最多的分子占比,即小规模贡献大问题。 selectcity_name,user_id,rf_type,deal_ord_cnt,sale_amt,rf_ord_cnt,rf_amt,rf_ra,rf_amt_ra,rf_all,ord_cnt_all,rf_gx,ord_cnt_gx,del_gx,row_number() over(partiti…...

Windows11右键菜单
刚开始使用Windows11时,新的右键菜单用起来很不习惯。 记录一下修改和恢复Windows11的右键菜单的方法。 1.Win11切换到旧版右键菜单: 方法:WinR打开CMD,运行下面的命令行 添加注册列表重启Windows资源管理器 reg add "HKC…...

篇十四:观察者模式:对象间的通知与更新
篇十四:“观察者模式:对象间的通知与更新” 设计模式是软件开发中的重要知识,观察者模式(Observer Pattern)是一种行为型设计模式,用于在对象间建立一种一对多的依赖关系,当一个对象的状态发生…...

Hadoop知识点总结
1. MapReduce中Shuffle的执行流程是什么样的? - 阶段:Map端Shuffle、Reduce端Shuffle - 功能:分区、排序、分组 Map端Shuffle 分区(Partition):在这个阶段,Map任务会调用分区器,根据Key的Hash值取模&a…...

相关搜索量激增10000%!“芭比周边”产品火爆亚马逊!
据外媒报道,芭比娃娃是今年夏天最热的话题。今年7月份,“芭比娃娃”是亚马逊上搜索最多的词。第二季度,Shopify上的芭比娃娃销量激增了56%。知名玩具制造商美泰(Mattel)预计,受电影的推动,在未来…...

C高级第四讲
1、思维导图 2、写一个shell函数,获取用户的uid和gid并使用变量接收 #!/bin/bash function get_id() {uidid -u ubuntugidid -g ubuntu } get_id echo "uid:$uid" echo "gid:$gid"运行结果 3、排序 冒泡排序 /* ------------------------…...

Idea小操作
Idea操作 idea提取内容构成一个方法 idea提取内容构成一个方法...