当前位置: 首页 > news >正文

深入核心:一步步手撕Tomcat搭建自己的Web服务器

介绍:

        servlet:处理 http 请求

        tomcat:服务器

Servlet

  1.  servlet 接口:
    1. 定义 Servlet 声明周期
    2. 初始化:init
    3. 服务:service
    4. 销毁:destory
  2. 继承链:

Tomcat

  1. Tomcat 和 servlet 原理:
    1. 浏览器向服务器发送 http 请求
    2. socket 接收请求,发送给请求解析器
    3. 请求解析器再解析自己想要的信息
      1. 请求地址
      2. 请求方式
      3. 浏览器类型
      4. Cookie
      5. ··········
    4. 解析器解析到的信息发送给映射器
    5. 映射器中存放:
      1. Web 地址
      2. 内存地址
    6. 根据请求解析器中解析的信息,找到映射器中相对应的网络地址和内存地址,根据请求方式去访问对应的程序
  2. Socket 交互以及解析阶段:
    package com.Tomcat;import com.sun.corba.se.spi.activation.Server;import java.io.IOException;
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;public class myTomcat {Request request = new Request();    //创建解析请求的对象public void startUP() throws IOException {//监听端口号ServerSocket serverSocket = new ServerSocket(7421);while(true){Socket socket = serverSocket.accept();      //阻塞监听System.out.println("有请求!!!!!!!");//将每个请求开启一个线程new Thread(new Runnable() {@Overridepublic void run() {try {handler(socket);    //调用处理信息方法}catch (Exception e){e.printStackTrace();}}}).start();}}//处理信息public void handler(Socket socket) throws IOException {InputStream inputStream = socket.getInputStream();//将bit流转换为文字信息int count = 0;while(count == 0){count = inputStream.available();        //统计输入流的长度}//打印数据byte[] bytes = new byte[count];inputStream.read(bytes);    //将bit信息写入到byte数组String Context = new String(bytes);     //将 byte 数组转换为字符串System.out.println(Context);    //输出信息//拆解字符串,获取想要的信息String[] list = Context.split("\\n");   //根据换行切割字符串String Methed = list[0].split(" ")[0];  //在拆分的第一行中以空格再次拆分,获取第一个数据String Path = list[0].split(" ")[1];    //在拆分的第一行中以空格再次拆分,获取第二个数据//把截取的数据传给 Request 类request.setMethod(Methed);request.setPath(Path);}
    }
  3. Request 存储解析信息 ==> 继承 HttpservletRequest,为方便访问同一变量
    public class Request implements HttpservletRequast {private String Method;private String Path;public String getMethod() {return Method;}public void setMethod(String method) {Method = method;}public String getPath() {return Path;}public void setPath(String path) {Path = path;}@Overridepublic String toString() {return "Request{" +"Method='" + Method + '\'' +", Path='" + Path + '\'' +'}';}}
  4. 扫包:
    /*** 扫描指定包,获取该包下所有的类的全路径信息*/
    public class SearchClassUtil {//存放文件的绝对路径public static  List<String> classPaths = new ArrayList<String>();/*** 扫描固定包下面的类* @return*/public static List<String> searchClass(){//需要扫描的包名String basePack = "com.servlet";      //写需要获取包名的路径//将获取到的包名转换为路径//getResource():是获取类对象的方法, "/" :表示在根目录开始//getPath():是将对象的路径转为字符串String classPath = SearchClassUtil.class.getResource("/").getPath();//将包名转换为文件系统路径  --->  把 "." 替换成 系统的路径分隔符(系统不一样,分隔符也不一样)basePack =  basePack.replace(".", File.separator);//把两个路径合并为文件的 绝对路径String searchPath = classPath + basePack;//调用doPath()方法,把路径写入路径数组中doPath(new File(searchPath),classPath);//这个时候我们已经得到了指定包下所有的类的绝对路径了。我们现在利用这些绝对路径和java的反射机制得到他们的类对象return classPaths;}/*** 该方法会得到所有的类,将类的绝对路径写入到classPaths中* @param file*/private static void doPath(File file,String classpath) {if (file.isDirectory()) {//当前为文件夹//文件夹我们就递归  --->  筛出文件夹File[] files = file.listFiles();for (File f1 : files) {doPath(f1,classpath);}} else {//标准文件//标准文件我们就判断是否是class文件if (file.getName().endsWith(".class")) {//各级拆解字符串,替换分隔符String path = file.getPath().replace(classpath.replace("/","\\").replaceFirst("\\\\",""),"").replace("\\",".").replace(".class","");//如果是class文件我们就放入我们的集合中。classPaths.add(path);}}}public static void main(String[] args) {List<String> classes = SearchClassUtil.searchClass();for (String s: classes) {//System.out.println(s);}}
    }
  5. 注解:设置文件的访问地址 ==> HashMap 中的 key 值
    @Retention(RetentionPolicy.RUNTIME)     //在运行期间保留
    @Target(ElementType.TYPE)       //作用于类上面
    public @interface Webservlet {String url() default "";
    }
  6. 创建 Httpservlet 实现 Service 服务:
    public abstract class HttpServlet {   //HttpServerlet只实现了父类的service服务,其他方法没有实现,此时该类为抽象类//子类需要使用doGet或doPost方法,在这里直接让子类去实现两个发给发//这里需要获取Request中被解析出来的数据,//要想访问的是同一个Request对象,这里用到接口,让Request实现这个接口,传参时就会向上转型,此时request对象为同一个对象public abstract void doGet(HttpServletRequast requast, HttpServletResponse response) throws Exception;public abstract void doPost(HttpServletRequast requast,HttpServletResponse response);//在服务中判断用户的请求方式,让子类实现向对应的方法public void service(HttpServletRequast requast,HttpServletResponse response) throws Exception {if(requast.getMethod().equals("GET")){doGet(requast,response);}else if(requast.getMethod().equals("POST")){doPost(requast,response);}}
    }
  7. HttpservletRequast:为 Httpservlet 访问对象为统一对象,让 Request 实现这个接口
    public interface HttpservletRequast {String getMethod();void setMethod(String method);String getPath();void setPath(String path);
    }
  8. 自己创建 servlet,继承 Httpservlet 实现 service 服务  ==>  实现相关的访问方式
    @WebServerlet(url = "OneServerlet")
    public class FirstServlet extends HttpServlet {@Overridepublic void doGet(HttpServletRequast requast, HttpServletResponse response) throws Exception {}@Overridepublic void doPost(HttpServletRequast requast, HttpServletResponse response) {}
    }
  9. 获取访问地址:HashMap 中的 key 值
    public class getMessageUtil {public static String fund(String path) throws Exception {//创建类对象Class clazz = Class.forName(path);//根据类对象调用 getDeclaredAnnotation() 方法找到该类的访问地址(@Webservlet()中的内容)Webservlet webservlet = (Webservlet) clazz.getDeclaredAnnotation(Webservlet.class);return webservlet.url();}public static void main(String[] args) throws Exception {//fund();}
    }
  10. 映射器:底层由 HashMap 容器存储
    public class ServletConfigMapping {//将执行逻辑写入static代码块中,以便更好加载//定义Servlet容器public static Map<String,Class<HttpServlet>> classMap = new HashMap<>();//该静态代码块应放在启动tomcat前运行static {List<String> classPaths = SearchClassUtil.searchClass();for (String classPath : classPaths){try {InitClassMap(classPath);}catch (Exception e){e.printStackTrace();}}}//将key val 值插入到HashMap中public static void InitClassMap(String classPath) throws Exception {//获取类对象Class clazz = Class.forName(classPath);//获取访问地址String url = getMessageUtil.fundUrl(classPath);//将值插入HashMap树当中classMap.put(url,clazz);}
    }

Response 返回数据:

  1. 设置返回头工具类:
    /*** 设置返回头*/
    public class ResponseUtil {public  static  final String responseHeader200 = "HTTP/1.1 200 \r\n"+"Content-Type:text/html \r\n"+"\r\n";public  static  final String responseHeader200JSON = "HTTP/1.1 200 \r\n"+"Content-Type:application/json \r\n"+"\r\n";public static String getResponseHeader404(){return "HTTP/1.1 404 \r\n"+"Content-Type:text/html \r\n"+"\r\n" + "404";}public static String getResponseHeader200(String context){return "HTTP/1.1 200 \r\n"+"Content-Type:text/html \r\n"+"\r\n" + context;}
    }
  2. 读取文件:根据提供的地址转化为文件完整地址
    /*** 该类的主要作用是进行读取文件*/
    public class FileUtil {public  static  boolean witeFile(InputStream inputStream, OutputStream outputStream){boolean success = false ;BufferedInputStream bufferedInputStream ;BufferedOutputStream bufferedOutputStream;try {bufferedInputStream = new BufferedInputStream(inputStream);bufferedOutputStream = new BufferedOutputStream(outputStream);bufferedOutputStream.write(ResponseUtil.responseHeader200.getBytes());int count = 0;while (count == 0){count = inputStream.available();}int fileSize = inputStream.available();long written = 0;int beteSize = 1024;byte[] bytes = new byte[beteSize];while (written < fileSize){if(written + beteSize > fileSize){beteSize = (int)(fileSize - written);bytes = new byte[beteSize];}bufferedInputStream.read(bytes);bufferedOutputStream.write(bytes);bufferedOutputStream.flush();written += beteSize;}success = true;} catch (IOException e) {e.printStackTrace();}return success;}public static boolean writeFile(File file,OutputStream outputStream) throws Exception{return witeFile(new FileInputStream(file),outputStream);}/*** 根据提供的地址转换为文件完整地址* @param path* @return*/public static String getResoucePath(String path){String resource = FileUtil.class.getResource("/").getPath();return resource + "\\" + path;}}
  3. response 返回数据:
    public class Response implements HttpServletResponse {//输出流private OutputStream outputStream;public Response(OutputStream outputStream){this.outputStream = outputStream;}/**** 返回动态文字信息* @param context* @throws IOException*/public void write(String context) throws IOException {outputStream.write(context.getBytes());     //将文字信息转换为 byte流 形式}public void WriteHtml(String Path) throws Exception {//得到文件全路径String resoucePath = FileUtil.getResoucePath(Path);//创建文件File file = new File(resoucePath);if(file.exists()){System.out.println("静态资源存在");//输出静态资源FileUtil.writeFile(file,outputStream);}else {System.out.println("静态资源不存在");}}
    }
  4. HttpServletResponse 接口:
    public interface HttpServletResponse {void write(String context) throws IOException;
    }
  5. 输出资源:
    Response response = new Response(socket.getOutputStream());if(request.getPath().equals("") || request.getPath().equals("/")){      //空访问response.WriteHtml("404.html");     //抛出404页面response.write(ResponseUtil.getResponseHeader404());    //抛出404文字信息} else if (ServerletConfigMapping.classMap.get(request.getPath()) == null) {        //静态资源response.WriteHtml(request.getPath());}else {     //动态资源Class<HttpServlet> httpServletClass = ServerletConfigMapping.classMap.get(request.getPath());   //获取类对象if(httpServletClass != null){       //有类对象HttpServlet httpServlet = httpServletClass.newInstance();   //多态创建对象httpServlet.service(request,response);      //启动service服务}else{      //没有动态资源response.WriteHtml("404.html");     //抛出 404页面}
    }
  6. 整合后 Tomcat:
    public class myTomcat {Request request = new Request();    //创建解析请求的对象//提前加载容器(HashMap)static {List<String> classPaths = SearchClassUtil.searchClass();for (String classPath : classPaths){try {ServerletConfigMapping.InitClassMap(classPath);}catch (Exception e){e.printStackTrace();}}}public static void main(String[] args) throws IOException {myTomcat myTomcat = new myTomcat();myTomcat.startUP();}public void startUP() throws IOException {//监听端口号ServerSocket serverSocket = new ServerSocket(8080 );while(true){Socket socket = serverSocket.accept();      //阻塞监听System.out.println("有请求!!!!!!!");//将每个请求开启一个线程new Thread(new Runnable() {@Overridepublic void run() {try {handler(socket);    //调用处理信息方法}catch (Exception e){e.printStackTrace();}}}).start();}}//处理信息public void handler(Socket socket) throws Exception {InputStream inputStream = socket.getInputStream();//将bit流转换为文字信息int count = 0;while(count == 0){count = inputStream.available();        //统计输入流的长度}//打印数据byte[] bytes = new byte[count];inputStream.read(bytes);    //将bit信息写入到byte数组String Context = new String(bytes);     //将 byte 数组转换为字符串System.out.println(Context);    //输出信息//拆解字符串,获取想要的信息String[] list = Context.split("\\n");   //根据换行切割字符串String Methed = list[0].split(" ")[0];  //在拆分的第一行中以空格再次拆分,获取第一个数据String Path = list[0].split(" ")[1];    //在拆分的第一行中以空格再次拆分,获取第二个数据//把截取的数据传给 Request 类request.setMethod(Methed);request.setPath(Path);//判断资源类型Response response = new Response(socket.getOutputStream());if(request.getPath().equals("") || request.getPath().equals("/")){      //空访问response.WriteHtml("404.html");     //抛出404页面response.write(ResponseUtil.getResponseHeader404());    //抛出404文字信息} else if (ServerletConfigMapping.classMap.get(request.getPath()) == null) {        //静态资源response.WriteHtml(request.getPath());}else {     //动态资源Class<HttpServlet> httpServletClass = ServerletConfigMapping.classMap.get(request.getPath());   //获取类对象if(httpServletClass != null){       //有类对象HttpServlet httpServlet = httpServletClass.newInstance();   //多态创建对象httpServlet.service(request,response);      //启动service服务}else{      //没有动态资源response.WriteHtml("404.html");     //抛出 404页面}}}
    }

Tomcat 运行原理:

  1. 原理:
    1. 浏览器发起请求
    2. Socket 解析输入流,获取请求头信息
    3. 分析请求的地址是动态资源还是静态资源
      1. 首先判断 HashMap 中有没有这个 Key 值
      2. 如果有就去访问动态资源,如果没有就去查看静态资源
      3. 如果也不是静态资源就返回 404
    4. Servlet 容器(HashMap):
      1. 将 @WebServlet 中的值作为 key 值,将对象作为 value 值,存入 HashMap 中
  2. Servlet 容器加载时期:
    1. 在 Socket 启动之前启动 Servlet 容器
      1. 缺点:程序启动时间变长
      2. 优点:不易出现空指针
    2. 在 Socket 启动之后启动 Servlet 容器
    3. 在浏览器访问的同时启动 Servlet 容器

相关文章:

深入核心:一步步手撕Tomcat搭建自己的Web服务器

介绍&#xff1a; servlet&#xff1a;处理 http 请求 tomcat&#xff1a;服务器 Servlet servlet 接口&#xff1a; 定义 Servlet 声明周期初始化&#xff1a;init服务&#xff1a;service销毁&#xff1a;destory 继承链&#xff1a; Tomcat Tomcat 和 servlet 原理&#x…...

ASP.NET Core与配置系统的集成

目录 配置系统 默认添加的配置提供者 加载命令行中的配置。 运行环境 读取方法 User Secrets 注意事项 Zack.AnyDBConfigProvider 案例 配置系统 默认添加的配置提供者 加载现有的IConfiguration。加载项目根目录下的appsettings.json。加载项目根目录下的appsettin…...

在 Ubuntu 上安装 Node.js 23.x

在 Ubuntu 上安装 Node.js 23.x 前提条件安装步骤1. 下载设置脚本2. 运行设置脚本3. 安装 Node.js4. 验证安装 参考链接总结 在现代 web 开发中&#xff0c;Node.js 是一个不可或缺的工具。它提供了一个强大的 JavaScript 运行时环境&#xff0c;使得开发人员可以在服务器端使用…...

《 C++ 点滴漫谈: 二十五 》空指针,隐秘而危险的杀手:程序崩溃的真凶就在你眼前!

摘要 本博客全面解析了 C 中指针与空值的相关知识&#xff0c;从基础概念到现代 C 的改进展开&#xff0c;涵盖了空指针的定义、表示方式、使用场景以及常见注意事项。同时&#xff0c;深入探讨了 nullptr 的引入及智能指针在提升代码安全性和简化内存管理方面的优势。通过实际…...

SpringBoot中Excel表的导入、导出功能的实现

文章目录 一、easyExcel简介二、Excel表的导出2.1 添加 Maven 依赖2.2 创建导出数据的实体类4. 编写导出接口5. 前端代码6. 实现效果 三、excel表的导出1. Excel表导入的整体流程1.1 配置文件存储路径 2. 前端实现2.1 文件上传组件 2.2 文件上传逻辑3. 后端实现3.1 文件上传接口…...

CodeGPT使用本地部署DeepSeek Coder

目前NV和github都托管了DeepSeek&#xff0c;生成Key后可以很方便的用CodeGPT接入。CodeGPT有三种方式使用AI&#xff0c;分别时Agents&#xff0c;Local LLMs&#xff08;本地部署AI大模型&#xff09;&#xff0c;LLMs Cloud Model&#xff08;云端大模型&#xff0c;从你自己…...

SpringBoot 整合 SpringMVC:配置嵌入式服务器

修改和 server 相关的配置(ServerProperties)&#xff1a; server.port8081 server.context‐path/tx server.tomcat.uri‐encodingUTF‐8 注册 Servlet 三大组件&#xff1a;Servlet、Fileter、Listener SpringBoot 默认是以 jar 包的方式启动嵌入式的 Servlet 容器来启动 Spr…...

浅谈Linux 权限、压缩、进程与服务

概述 放假回家&#xff0c;对Linux系统的一些知识进行重新的整理&#xff0c;做到温故而知新&#xff0c;对用户权限管理、文件赋权、压缩文件、进程与服务的知识进行了一次梳理和总结。 权限管理 Linux最基础的权限是用户和文件&#xff0c;先了解基础的用户权限和文件权限…...

LeetCode 0040.组合总和 II:回溯 + 剪枝

【LetMeFly】40.组合总和 II&#xff1a;回溯 剪枝 力扣题目链接&#xff1a;https://leetcode.cn/problems/combination-sum-ii/ 给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates…...

springCload快速入门

原作者&#xff1a;3. SpringCloud - 快速通关 前置知识&#xff1a; Java17及以上、MavenSpringBoot、SpringMVC、MyBatisLinux、Docker 1. 分布式基础 1.1. 微服务 微服务架构风格&#xff0c;就像是把一个单独的应用程序开发为一套小服务&#xff0c;每个小服务运行在自…...

实现使用K210单片机进行猫脸检测,并在检测到猫脸覆盖屏幕50%以上时执行特定操作

要实现使用K210单片机进行猫脸检测&#xff0c;并在检测到猫脸覆盖屏幕50%以上时执行特定操作&#xff0c;以及通过WiFi上传图片到微信小程序&#xff0c;并在微信小程序中上传图片到开发板进行训练&#xff0c;可以按照以下步骤进行&#xff1a; 1. 硬件连接 确保K210开发板…...

FlashAttention v1 论文解读

论文标题&#xff1a;FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness 论文地址&#xff1a;https://arxiv.org/pdf/2205.14135 FlashAttention 是一种重新排序注意力计算的算法&#xff0c;它无需任何近似即可加速注意力计算并减少内存占用。…...

Kafka 副本机制(包含AR、ISR、OSR、HW 和 LEO 介绍)

文章目录 Kafka 副本机制&#xff08;包含AR、ISR、OSR、HW 和 LEO 介绍&#xff09;1. 副本的基本概念2. 副本同步和一致性2.1 AR&#xff08;Assigned Replicas&#xff09;2.2 ISR&#xff08;In-Sync Replicas&#xff09;2.3 OSR&#xff08;Out-of-Sync Replicas&#xf…...

QtCreator在配置Compilers时,有一个叫ABI的选项,那么什么是ABI?

问题提出 QtCreator在配置Compilers时,有一个叫ABI的选项,那么什么是ABI&#xff1f; ABI&#xff08;Application Binary Interface&#xff09;介绍 ABI&#xff08;Application Binary Interface&#xff0c;应用二进制接口&#xff09;是指应用程序与操作系统或其他程序…...

ResNet--深度学习中的革命性网络架构

一、引言 在深度学习的研究和应用中&#xff0c;网络架构的设计始终是一个关键话题。随着计算能力和大数据的不断提升&#xff0c;深度神经网络逐渐成为解决复杂任务的主流方法。然而&#xff0c;随着网络层数的增加&#xff0c;训练深度神经网络往往面临梯度消失或梯度爆炸的…...

【 软件测试项目实战】 以淘宝网购物车管理功能为例

一、测试功能模块分析 选择淘宝网购物车管理功能进行测试&#xff0c;核心子功能包含&#xff1a; 单商品添加/删除购物车商品数量修改多商品勾选与批量删除失效商品识别与处理 二、测试用例设计方法论应用 1. 等价类划分法&#xff08;商品添加操作&#xff09; 分析&…...

Go 中 defer 的机制

文章目录 Go 语言中 defer 的底层机制与实战解析一、defer 的执行顺序&#xff1a;后进先出&#xff08;LIFO&#xff09;示例 &#xff1a;多个 defer 的执行顺序 二、defer 的参数预计算&#xff1a;值拷贝的陷阱示例 &#xff1a;参数预计算的影响 三、defer 与闭包&#xf…...

智能小区物业管理系统推动数字化转型与提升用户居住体验

内容概要 在当今快速发展的社会中&#xff0c;智能小区物业管理系统的出现正在改变传统的物业管理方式。这种系统不仅仅是一种工具&#xff0c;更是一种推动数字化转型的重要力量。它通过高效的技术手段&#xff0c;将物业管理与用户居住体验紧密结合&#xff0c;无疑为社区带…...

【memgpt】letta 课程4:基于latta框架构建MemGpt代理并与之交互

Lab 3: Building Agents with memory 基于latta框架构建MemGpt代理并与之交互理解代理状态,例如作为系统提示符、工具和agent的内存查看和编辑代理存档内存MemGPT 代理是有状态的 agents的设计思路 每个步骤都要定义代理行为 Letta agents persist information over time and…...

HTML DOM 对象

HTML DOM 对象 引言 HTML DOM(文档对象模型)是现代网页开发的核心技术之一。DOM 将 HTML 或 XML 文档结构化,使其成为可编程的对象。通过 DOM,开发者可以轻松地操作网页内容、样式和结构。本文将详细介绍 HTML DOM 对象的相关知识,包括其概念、结构、操作方法以及在实际…...

高温环境对电机性能的影响与LabVIEW应用

电机在高温环境下的性能可能受到多种因素的影响&#xff0c;尤其是对于持续工作和高负荷条件下的电机。高温会影响电机的效率、寿命以及可靠性&#xff0c;导致设备出现过热、绝缘损坏等问题。因此&#xff0c;在设计电机控制系统时&#xff0c;特别是在高温环境下&#xff0c;…...

【09-电源线布线与覆铜 GND与转孔】

走线 从接触点处走线 TYPEC画线-加铜皮 1.关闭不需要的层(锡膏层和阻焊层和机械层) 紫色阻焊层 L: 顶层锡膏 底层锡膏 顶层阻焊 底层阻焊 2.修改线框或者贴铜 3.顶层走不过去:打四个孔 核心:走线-打孔-贴铜皮 设置孔的参数:大小和人为盖有 挨一下其他才会有网络 4个孔也要贴…...

算法题(48):反转链表

审题&#xff1a; 需要我们将链表反转并返回头结点地址 思路&#xff1a; 一般在面试中&#xff0c;涉及链表的题会主要考察链表的指向改变&#xff0c;所以一般不会允许我们改变节点val值。 这里是单向链表&#xff0c;如果要把指向反过来则需要同时知道前中后三个节点&#x…...

C++ 泛型编程指南02 (模板参数的类型推导)

文章目录 一 深入了解C中的函数模板类型推断什么是类型推断&#xff1f;使用Boost TypeIndex库进行类型推断分析示例代码关键点解析 2. 理解函数模板类型推断2.1 指针或引用类型2.1.1 忽略引用2.1.2 保持const属性2.1.3 处理指针类型 2.2 万能引用类型2.3 传值方式2.4 传值方式…...

穷举vs暴搜vs深搜vs回溯vs剪枝系列一>单词搜索

题解如下 题目&#xff1a;解析决策树&#xff1a;代码设计&#xff1a; 代码&#xff1a; 题目&#xff1a; 解析 决策树&#xff1a; 代码设计&#xff1a; 代码&#xff1a; class Solution {private boolean[][] visit;//标记使用过的数据int m,n;//行&#xff0c;列char…...

9 点结构模块(point.rs)

一、point.rs源码 use super::UnknownUnit; use crate::approxeq::ApproxEq; use crate::approxord::{max, min}; use crate::length::Length; use crate::num::*; use crate::scale::Scale; use crate::size::{Size2D, Size3D}; use crate::vector::{vec2, vec3, Vector2D, V…...

基于vue船运物流管理系统设计与实现(源码+数据库+文档)

船运物流管理系统目录 目录 基于springboot船运物流管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员登录 2、货运单管理 3、公告管理 4、公告类型管理 5、新闻管理 6、新闻类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考…...

海思ISP开发说明

1、概述 ISP&#xff08;Image Signal Processor&#xff09;图像信号处理器是专门用于处理图像信号的硬件或处理单元&#xff0c;广泛应用于图像传感器&#xff08;如 CMOS 或 CCD 传感器&#xff09;与显示设备之间的信号转换过程中。ISP通过一系列数字图像处理算法完成对数字…...

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.12 连续数组:为什么contiguous这么重要?

2.12 连续数组&#xff1a;为什么contiguous这么重要&#xff1f; 目录 #mermaid-svg-wxhozKbHdFIldAkj {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-wxhozKbHdFIldAkj .error-icon{fill:#552222;}#mermaid-svg-…...

Chromium132 编译指南 - Android 篇(一):编译前准备

1. 引言 欢迎来到《Chromium 132 编译指南 - Android 篇》系列的第一部分。本系列指南将引导您逐步完成在 Android 平台上编译 Chromium 132 版本的全过程。Chromium 作为一款由 Google 主导开发的开源浏览器引擎&#xff0c;为众多现代浏览器提供了核心驱动力。而 Android 作…...

Jenkins未在第一次登录后设置用户名,第二次登录不进去怎么办?

Jenkins在第一次进行登录的时候&#xff0c;只需要输入Jenkins\secrets\initialAdminPassword中的密码&#xff0c;登录成功后&#xff0c;本次我们没有修改密码&#xff0c;就会导致后面第二次登录&#xff0c;Jenkins需要进行用户名和密码的验证&#xff0c;但是我们根本就没…...

#define,源文件与头文件,赋值表达式

1.#define 1.1定义 #define 是一个预处理指令&#xff0c;用于定义宏 宏&#xff0c;是预处理阶段&#xff08;在编译之前&#xff09;由预处理器处理的代码片段 1.2使用 1.2.1 #define 可以定义常量 #define PI 3.14159 1.2.2 #define 可以定义宏函数 #define SQUARE(x) ((…...

wordpress外贸独立站常用询盘软件

LiveChat LiveChat是一家提供实时聊天软件的公司&#xff0c;帮助企业通过其平台与客户进行即时通讯&#xff0c;提高客户满意度和忠诚度。他们的产品允许企业在网站、应用程序或电子邮件等多个渠道与客户互动&#xff0c;从而提升客户体验并促进销售增长。 LiveChat的软件特…...

网络爬虫学习:应用selenium获取Edge浏览器版本号,自动下载对应版本msedgedriver,确保Edge浏览器顺利打开。

一、前言 我从24年11月份开始学习网络爬虫应用开发&#xff0c;经过2个来月的努力&#xff0c;于1月下旬完成了开发一款网络爬虫软件的学习目标。这里对本次学习及应用开发进行一下回顾总结。 前几天我已经发了一篇日志&#xff08;网络爬虫学习&#xff1a;应用selenium从搜…...

Zookeeper入门部署(单点与集群)

本篇文章基于docker方式部署zookeeper集群&#xff0c;请先安装docker 目录 1. docker初期准备 2.启动zookeeper 2.1 单点部署 2.2 集群部署 3. Linux脚本实现快速切换启动关闭 1. docker初期准备 拉取zookeeper镜像 docker pull zookeeper:3.5.6 如果拉取时间过长&#xf…...

2025最新在线模型转换工具onnx转换ncnn,mnn,tengine等

文章目录 引言最新网址地点一、模型转换1. 框架转换全景图2. 安全的模型转换3. 网站全景图 二、转换说明三、模型转换流程图四、感谢 引言 在yolov5&#xff0c;yolov8&#xff0c;yolov11等等模型转换的领域中&#xff0c;时间成本常常是开发者头疼的问题。最近发现一个超棒的…...

文件读写操作

写入文本文件 #include <iostream> #include <fstream>//ofstream类需要包含的头文件 using namespace std;void test01() {//1、包含头文件 fstream//2、创建流对象ofstream fout;/*3、指定打开方式&#xff1a;1.ios::out、ios::trunc 清除文件内容后打开2.ios:…...

AJAX XML

AJAX XML 引言 随着互联网技术的不断发展,Web应用对用户交互性和实时性的要求越来越高。AJAX(Asynchronous JavaScript and XML)技术的出现,为Web应用开发提供了强大的支持。AJAX技术允许Web应用在不重新加载整个页面的情况下,与服务器进行异步通信。XML作为数据传输格式…...

Linux文件原生操作

Linux 中一切皆文件&#xff0c;那么 Linux 文件是什么&#xff1f; 在 Linux 中的文件 可以是&#xff1a;传统意义上的有序数据集合&#xff0c;即&#xff1a;文件系统中的物理文件 也可以是&#xff1a;设备&#xff0c;管道&#xff0c;内存。。。(Linux 管理的一切对象…...

JavaScript常用的内置构造函数

JavaScript作为一种广泛应用的编程语言&#xff0c;提供了丰富的内置构造函数&#xff0c;帮助开发者处理不同类型的数据和操作。这些内置构造函数在创建和操作对象时非常有用。本文将详细介绍JavaScript中常用的内置构造函数及其用途。 常用内置构造函数概述 1. Object Obj…...

Shell篇-字符串处理

目录 1.变量引用 2.获取字符串长度 3.字符串截取 4.删除子字符串 5.字符串替换 总结&#xff1a; Bash&#xff08;Shell 脚本&#xff09;中的字符串处理语法。以下是对其的介绍和总结&#xff1a;Bash 变量可以使用不同的语法来获取、修改和删除字符串的内容。图片中列…...

Arduino大师练成手册 -- 控制 AS608 指纹识别模块

要在 Arduino 上控制 AS608 指纹识别模块&#xff0c;你可以按照以下步骤进行&#xff1a; 硬件连接 连接指纹模块&#xff1a;将 AS608 指纹模块与 Arduino 连接。通常&#xff0c;AS608 使用 UART 接口进行通信。你需要将 AS608 的 TX、RX、VCC 和 GND 引脚分别连接到 Ardu…...

C++ Primer 命名空间的using声明

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…...

C#,入门教程(12)——数组及数组使用的基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(11)——枚举&#xff08;Enum&#xff09;的基础知识和高级应用https://blog.csdn.net/beijinghorn/article/details/123917587https://blog.csdn.net/beijinghorn/article/details/123917587 数组是一种数据集合&#xff0c;是一组…...

深入浅出并查集(不相交集合实现思路)

引言 并查集&#xff08;Disjoint Set Union&#xff0c;简称DSU&#xff09;是一种用于处理一些不交集的合并及查询问题。它主要支持两种操作&#xff1a;查找&#xff08;Find&#xff09;和合并&#xff08;Union&#xff09;。 查找&#xff1a;确定某个元素属于哪一个子…...

M|哪吒之魔童闹海

rating: 8.5 豆瓣: 8.5 上映时间: “2025” 类型: M动画 导演: 饺子 主演: 国家/地区: 中国大陆 片长/分钟: 144分钟 M&#xff5c;哪吒之魔童闹海 制作精良&#xff0c;除了剧情逻辑有一点瑕疵&#xff0c;各方面都很到位。总体瑕不掩瑜。 上映时间&#xff1a; &…...

【c++】类与对象详解

目录 面向过程思想和面向对象思想类的定义引入类的关键字类定义的两种方式类的访问限定符类的作用域类大小的计算封装 this指针类的6个默认成员函数构造函数初步理解构造函数深入理解构造函数初始化列表单参数构造函数引发的隐式类型转换 析构函数拷贝构造函数赋值运算符重载运…...

LabVIEW如何有效地进行数据采集?

数据采集&#xff08;DAQ&#xff09;是许多工程项目中的核心环节&#xff0c;无论是测试、监控还是控制系统&#xff0c;准确、高效的数据采集都是至关重要的。LabVIEW作为一个图形化编程环境&#xff0c;提供了丰富的功能来实现数据采集&#xff0c;确保数据的实时性与可靠性…...

Golang 并发机制-4:用Mutex管理共享资源

并发性是Go的强大功能之一&#xff0c;它允许多个线程&#xff08;并发线程&#xff09;同时执行。然而&#xff0c;权力越大&#xff0c;责任越大。当多个例程并发地访问和修改共享资源时&#xff0c;可能会导致数据损坏、竞争条件和不可预测的程序行为。为了解决这些问题&…...

如何用微信小程序写春联

​ 生活没有模板,只需心灯一盏。 如果笑能让你释然,那就开怀一笑;如果哭能让你减压,那就让泪水流下来。如果沉默是金,那就不用解释;如果放下能更好地前行,就别再扛着。 一、引入 Vant UI 1、通过 npm 安装 npm i @vant/weapp -S --production​​ 2、修改 app.json …...