从0开始,手搓Tomcat

 一、什么是Tomcat

Tomcat 是一款开源的、轻量级的 Web 服务器,它不仅能够提供 HTTP 服务,还能够运行 Java Servlet 和 JavaServer Pages(JSP)。对于许多开发者来说,理解 Tomcat 的目录结构以及如何在该结构中组织应用,往往是入门的第一步。

1、Tomcat目录结构

Tomcat 的目录结构相对简单,但每个目录和文件都有其明确的用途。

1. bin 目录

bin 目录包含启动和停止 Tomcat 所需的脚本。它的内容包括:

startup.sh/startup.bat:启动 Tomcat。

shutdown.sh/shutdown.bat:停止 Tomcat。

catalina.sh/catalina.bat:Tomcat 启动时的核心脚本,包含了一些启动参数的设置。

setenv.sh/setenv.bat:用于设置 Tomcat 环境变量,通常用于配置 Java 堆大小、日志设置等。

2. conf 目录

conf 目录包含 Tomcat 的核心配置文件,这些文件直接影响 Tomcat 的行为。常见的配置文件有:

server.xml:Tomcat 的主要配置文件,定义了服务器的端口、连接器、虚拟主机等。

web.xml:Web 应用的默认部署描述符。

context.xml:为每个 Web 应用提供额外的配置。

3. lib 目录

lib 目录存放 Tomcat 运行时所需要的 Java 类库和 JAR 包,包括:

servlet-api.jar:Java Servlet API 的实现。

jsp-api.jar:Java Server Pages(JSP)API 的实现。

其他第三方库和 Tomcat 特有的库文件。

4. logs 目录

logs 目录用于存储 Tomcat 启动、运行过程中的日志文件。常见的日志文件有:

catalina.out:Tomcat 启动和运行时的主要日志文件。

localhost_access_log.*.txt:记录每个请求的访问日志。

5. webapps 目录

webapps 目录是 Tomcat 的应用目录,所有部署的 Web 应用都应该放在此目录下。每个应用通常以一个文件夹的形式存在,目录中包含了应用的 WEB-INF 和 META-INF 等文件夹。

6. work 目录

work 目录用于存放 Tomcat 编译 JSP 文件后的中间文件。每当 Tomcat 运行一个 JSP 文件时,都会将其编译成 Java 类文件并存放在这个目录中。

7. temp 目录

temp 目录是 Tomcat 用来存放临时文件的地方。例如,Tomcat 会将文件上传的内容存放在该目录中,处理过程中生成的临时数据也会保存在这里。

2、Tomcat的工作目录

在apache的Tomcat中,工作目录可以简化成上图,即在webapps中进行资源的访问。资源的访问可以简单的理解为对网页的操作。

二、Tomcat工作原理简介

1、Tomcat中Servlet的生命周期

在一个实现具体操作的Servlet类中,具有如下图的继承关系

javax.servlet.Servlet 是所有 Servlet 的基本接口。任何自定义的 Servlet 都必须实现这个接口或者继承一个实现了它的类。该接口定义了 Servlet 的生命周期方法,例如 init(), service(), 和 destroy(),这些方法体现了Servlet的生命周期

init(..):当servlet第一次被请求时,Servlet容器就会开始调用这个方法来初始化一个Servlet对象出来

service(...):每当请求Servlet时,Servlet容器就会调用这个方法service(...)

destroy(...):当要销毁Servlet时,Servlet容器就会调用这个方法

getservletInfo(...):这个方法会返回Servlet的一段描述,可以返回一段字符串。

getServletconfig(...):这个方法会返回由Servlet容器传给init()方法的Servletconfig对象。

javax.servlet.GenericServlet 是 Servlet 接口的一个抽象实现类。它实现了 Servlet 接口,但提供了空实现的 service() 方法。通常,自定义的 Servlet 会继承 GenericServlet,并重写 service() 方法来处理客户端请求。

javax.servlet.http.HttpServlet 是处理 HTTP 请求的抽象类,继承自 GenericServlet。大多数 Web 应用中的 Servlet 会继承 HttpServlet,因为它提供了简化的 HTTP 请求处理方法,如 doGet(), doPost(), doPut() 和 doDelete(),这些方法可以根据请求类型进行重写。同时 HttpServlet 中重写了service() 方法,对于不同的请求进行判断并划分到不同的操作中,将其拆分成doGet()方法和doPost()等七种方法,其目的是为了更好的匹配http请求。

2、Tomcat对待资源

Tomcat将资源分为动态资源和静态资源。

1.静态资源

指内容在服务器上不会发生变化的资源,通常这些资源由服务器直接提供给客户端,不需要任何动态处理。常见的静态资源有:

  • HTML 文件:静态的网页内容,直接通过浏览器访问即可展示。
  • CSS 文件:样式表文件,用于定义网页的外观。
  • JavaScript 文件:脚本文件,用于网页的交互行为。
  • 图片文件:如 PNG、JPEG、GIF、SVG 等图片文件。
  • 字体文件:例如 .woff, .ttf 等字体文件。
  • 视频文件:如 .mp4, .avi 等文件。

Tomcat 处理静态资源的方式:

Tomcat 会直接通过文件系统(例如 /webapps/ROOT 目录)读取静态资源,然后返回给客户端。静态资源通常会被配置在 Web 应用的 webapps 目录下。

默认情况下,Tomcat 会直接将这些资源返回给客户端,除非配置了 URL 映射或者过滤器,否则不涉及任何额外的处理逻辑。

2.动态资源

动态资源 是指在客户端请求时,服务器需要根据请求的不同,动态生成或者处理后才返回的内容。这类资源的内容是可变的,通常与用户的输入、数据库等外部数据源有关。动态资源的常见形式包括:

  • Servlet:通过 Java 编写的后端代码,接收客户端请求并生成响应内容。
  • JSP (JavaServer Pages):与 Servlet 类似,但通过模板方式生成 HTML 内容。JSP 是动态生成 HTML 页面的一种方法。
  • RESTful API:通常由 Servlet 或其他 Java 后端框架实现,用于为前端应用提供数据接口。
  • WebSocket:允许在客户端与服务器之间进行双向通信的技术。

Tomcat 处理动态资源的方式

Tomcat 会将动态请求交给相应的 Servlet 或 JSP 进行处理。Servlet/JSP 会根据请求生成动态内容。请求 URL 会映射到特定的 Servlet 或 JSP,Tomcat 通过 web.xml 或注解来配置这些映射。

动态资源通常通过 Servlet 或 JSP 来生成 HTTP 响应,这些响应可以是 HTML、JSON、XML 等格式,具体取决于请求和后端代码的逻辑。

3.两种资源的区别

资源类型

需要服务器处理

变化性

典型示例

静态资源

不变

HTML、CSS、JavaScript、图片、视频等

动态资源

需要处理

可变

Servlet、JSP、REST API、WebSocket 等

静态资源 直接由 Tomcat 提供,客户端请求时无需任何额外的动态处理。

动态资源 需要通过 Servlet 或 JSP 等方式在服务器端进行处理,然后生成响应内容返回给客户端。

3、Tomcat的核心——Servlet容器

Tomcat的核心是servlet容器,本质是一个hashmap,Key值是servlet的访问路径,Value值是一般为servlet对象。在启动tomcat时,动态资源加载到servlet容器中

http请求打到servlet容器中,进行key值对比,如果访问动态资源,则调用servlet对象

需要注意的一点是,在Tomcat启动时,就需要把动态资源加载到Servlet容器中。

4、Tomcat处理http请求

Tomcat 生成一个socket对象,用于接收和处理http请求,从请求中解析出请求类型和需要的资源,交给Servlet容器中的Servlet对象去处理

三、简易Tomcat实现

1、目录结构

这样设计为区分不同功能的Java文件。

需要指出的是,这里创建项目不是普通的Java项目,需要选择Maven项目,只需设置项目名称即可,其他默认即可,项目名不要有中文。

2、实现继承关系

Servlet接口

package com.tom2.servlet;

import com.tom2.servlet.Re.HttpRequest;
import com.tom2.servlet.Re.HttpResponse;

public interface Servlet {
    public abstract void init();
    public abstract void destory();
    public abstract void service(HttpRequest request, HttpResponse response) throws Exception;
}

GenericServlet抽象类

package com.tom2.servlet;

import com.tom2.servlet.Re.HttpRequest;
import com.tom2.servlet.Re.HttpResponse;

public abstract class GenericServlet implements Servlet{

    @Override
    public void init() {
        System.out.println("genservlet 的init");
    }

    @Override
    public void destory() {
        System.out.println("genservlet 的destory");
    }
}

HttpServlet 抽象类

package com.tom2.servlet;

import com.tom2.servlet.Re.HttpRequest;
import com.tom2.servlet.Re.HttpResponse;

public abstract class HttpServlet extends GenericServlet{
    @Override
    public void service(HttpRequest request, HttpResponse response) throws Exception {
        if(request.getMethod().equals("GET")){
            doGet(request,response);
        }else if(request.getMethod().equals("POST")){
            doPost(request,response);
        }
    }

    public abstract void doGet(HttpRequest request, HttpResponse response) throws Exception;
    public abstract void doPost(HttpRequest request, HttpResponse response) throws Exception;

}

HttpRequest 和 HttpResponse

package com.tom2.servlet.Re;

public class HttpRequest {
    private String path;
    private String method;

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    @Override
    public String toString() {
        return "HttpRequest{" +
                "path='" + path + '\'' +
                ", method='" + method + '\'' +
                '}';
    }
}

package com.tom2.servlet.Re;

import java.io.IOException;
import java.io.OutputStream;

public class HttpResponse {
    private OutputStream outputStream;

    public  HttpResponse(OutputStream outputStream){
        this.outputStream=outputStream;
    }

    public void writeResponse(String context) throws IOException {
        outputStream.write(context.getBytes());
    }

}

3、工具类

SearchClassUtil :利用反射进行类信息的查找。扫描指定的 Java 包目录,查找所有 .class 文件,并提取每个 .class 文件的全类名,将这些类名存储在一个 List 列表中。

package com.tom2.Util;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * 扫描 com.qcby.webapps 目录下的 Java 文件并获取每个类的全名
 */
public class SearchClassUtil {
    public static List<String> classPaths = new ArrayList<String>();
    public static List<String> searchClass() {
        // 需要扫描的包名
        String basePack = "com.tom2.webapps";
        // 将包名转换为路径格式
        String classPath = SearchClassUtil.class.getClassLoader().getResource("").getPath();

        basePack = basePack.replace(".", File.separator);

        if(classPath.startsWith("file:")){
            classPath.substring(5);
        }
        String searchPath = classPath + basePack;

        // 确保路径在开发环境和打包后的环境下都能正确处理
        File searchDir = new File(searchPath);
        if (!searchDir.exists()) {
            // 如果路径不存在,尝试扫描 target/classes 目录
            searchPath = "target/classes"+File.separator+basePack;
            searchDir = new File(searchPath);
        }

        // 调用 doPath 方法递归扫描文件
        doPath(searchDir, classPath);

        // 返回扫描到的类路径列表
        return classPaths;
    }

    /**
     * 递归处理文件,找到 .class 文件并将其全类名添加到 classPaths 列表中
     */
    private static void doPath(File file, String classpath) {
        if (file.isDirectory()) {
            // 如果是目录,递归处理子目录
            File[] files = file.listFiles();
            if (files != null) {
                for (File f1 : files) {
                    doPath(f1, classpath);
                }
            }
        } else {
            // 如果是 .class 文件,提取类名
            if (file.getName().endsWith(".class")) {
                // 修正路径替换:不使用 replaceFirst,而直接使用 replace
                String path = file.getPath()
                        .replace(classpath, "") // 直接使用 classpath,不再替换 "/" 为 File.separator
                        .replace(File.separator, ".")
                        .replace(".class", "");
                if(path.startsWith("targetes.")){
                    path = path.substring("targetes.".length());
                }

                // 将类名添加到 classPaths 列表
                classPaths.add(path);
            }
        }
    }

    public static void main(String[] args) {
        List<String> classes = SearchClassUtil.searchClass();
        for (String s : classes) {
            System.out.println(s);
        }
    }
}

WebServlet:注解

package com.tom2.Util;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface WebServlet {
    String urlMapping() default "";
}

ResponseUtil

package com.tom2.Util;

public class ResponseUtil {
    public  static  final String responseHeader200 = "HTTP/1.1 200 \r\n"+
            "Content-Type:text/html; charset=utf-8 \r\n"+"\r\n";

    public static String getResponseHeader404(){
        return "HTTP/1.1 404 \r\n"+
                "Content-Type:text/html; charset=utf-8 \r\n"+"\r\n" + "404";
    }

    public static String getResponseHeader200(String context){
        return "HTTP/1.1 200 \r\n"+
                "Content-Type:text/html; charset=utf-8 \r\n"+"\r\n" + context;
    }
}

5、模拟Servlet容器

SearchServlet

package com.tom2;

import com.tom2.Util.SearchClassUtil;
import com.tom2.Util.WebServlet;
import com.tom2.servlet.HttpServlet;
import java.util.*;

public class SearchServlet {
    public static Map<String, HttpServlet> servletmap = new HashMap<>();

    static {
        List<String> classpath = SearchClassUtil.searchClass();
        for(String path:classpath){
            System.out.println(path);
        }
        for(String path:classpath){
            try{
                Class clazz = Class.forName(path);
                WebServlet webServlet = (WebServlet) clazz.getDeclaredAnnotation(WebServlet.class);
                HttpServlet httpServlet = (HttpServlet) clazz.getDeclaredConstructor().newInstance();
                servletmap.put(webServlet.urlMapping(),httpServlet);
            }catch(Exception e){
                e.printStackTrace();
            }

        }
    }

}

6、动态资源

Login

package com.tom2.webapps.myweb;

import com.tom2.Util.WebServlet;
import com.tom2.servlet.HttpServlet;
import com.tom2.servlet.Re.HttpRequest;
import com.tom2.servlet.Re.HttpResponse;
@WebServlet(urlMapping = "/login")
public class Login extends HttpServlet {
    @Override
    public void doGet(HttpRequest request, HttpResponse response) throws Exception {
        System.out.println("俺是login的doGet");
    }

    @Override
    public void doPost(HttpRequest request, HttpResponse response) throws Exception {

    }
}

Show

package com.tom2.webapps.myweb;
import com.tom2.Util.ResponseUtil;
import com.tom2.Util.WebServlet;
import com.tom2.servlet.HttpServlet;
import com.tom2.servlet.Re.HttpRequest;
import com.tom2.servlet.Re.HttpResponse;
@WebServlet(urlMapping = "/show")
public class Show extends HttpServlet {
    @Override
    public void doGet(HttpRequest request, HttpResponse response) throws Exception {
        response.writeResponse(ResponseUtil.getResponseHeader200("俺是Show的doGet"));
    }

    @Override
    public void doPost(HttpRequest request, HttpResponse response) throws Exception {

    }
}

7、主方法

MyTomcat

package com.tom2;

import com.tom2.servlet.HttpServlet;
import com.tom2.servlet.Re.HttpRequest;
import com.tom2.servlet.Re.HttpResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class MyTomcat {
    private static HttpRequest httpRequest = new HttpRequest();

    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(8080);
        while(true){
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();
            HttpResponse httpResponse = new HttpResponse(outputStream);

            int len = 0;
            while(len==0){
                len = inputStream.available();
            }
            byte[] bytes = new byte[len];
            inputStream.read(bytes);
            String context = new String(bytes);
            System.out.println(context);
            if(context.equals("")){
                System.out.println("空请求");
            }else{
                String line1 = context.split("\\n")[0];
                String method = line1.split("\\s")[0];
                String path = line1.split("\\s")[1];
                httpRequest.setMethod(method);
                httpRequest.setPath(path);
            }
            System.out.println(SearchServlet.servletmap.containsKey(httpRequest.getPath()));
            if(SearchServlet.servletmap.containsKey(httpRequest.getPath())){
                HttpServlet httpServlet = SearchServlet.servletmap.get(httpRequest.getPath());
                httpServlet.service(httpRequest,httpResponse);
            }
        }
    }
}

8、模拟效果

在浏览器地址栏中输入:localhost:8080/login

在浏览器地址栏中输入:localhost:8080/show

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu虚拟机中使用QEMU搭建ARM64环境

Ubuntu虚拟机中使用QEMU搭建ARM64环境 通过本实验学习如何编译一个 ARM64 版本的内核 image&#xff0c;并且在QEMU 上运行起来。 文章目录 Ubuntu虚拟机中使用QEMU搭建ARM64环境一、安装aarch64交叉编译工具二、安装QEMU三、制作根文件系统1、根文件系统简介2、BusyBox构建根…

java 重点知识 — JVM存储模块与类加载器

1 jvm主要模块 方法区 存储了由类加载器从.class文件中解析的类的元数据&#xff08;类型信息、域信息、方法信息&#xff09;及运行时常量池&#xff08;引用符号及字面量&#xff09;。 所有线程共享&#xff1b;内存不要求连续&#xff0c;可扩展&#xff0c;可能发生垃圾回…

Windows 如何开启和使用FTP服务

在Windows 系统开启FTP的服务方式有很多种&#xff0c;最快速的就是使用Windows自身的FTP服务了。 Windows 搭建FTP服务的方式 在Windows 中搭建FTP的方式有很多种&#xff0c;有商用收费的&#xff0c;也有开源免费的&#xff0c;除此之外&#xff0c; Windows本身也内置了F…

ASP.NET Core 6 MVC 文件上传

概述 应用程序中的文件上传是一项功能&#xff0c;用户可以使用该功能将用户本地系统或网络上的文件上传到 Web 应用程序。Web 应用程序将处理该文件&#xff0c;然后根据需要对文件进行一些验证&#xff0c;最后根据要求将该文件存储在系统中配置的用于保存文件的存储中&#…

计算机毕业设计SpringBoot+Vue.js制造装备物联及生产管理ERP系统(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

yoloV5训练visDrone2019-Det无人机视觉下目标检测

一、visDrone2019数据集详解 visDrone2019数据集是无人机视角下最具挑战性的目标检测基准数据集之一&#xff0c;由天津大学机器学习与数据挖掘实验室联合其他研究机构共同构建。该数据集采集自中国14个不同城市&#xff0c;覆盖复杂城市场景、交通枢纽、密集人群等多种环境。…

Unity开发——CanvasGroup组件介绍和应用

CanvasGroup是Unity中用于控制UI的透明度、交互性和渲染顺序的组件。 一、常用属性的解释 1、alpha&#xff1a;控制UI的透明度 类型&#xff1a;float&#xff0c;0.0 ~1.0&#xff0c; 其中 0.0 完全透明&#xff0c;1.0 完全不透明。 通过调整alpha值可以实现UI的淡入淡…

C语言学习笔记-进阶(7)字符串函数3

1. strstr的使用和模拟实现 char * strstr ( const char * str1, const char * str2); Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1. &#xff08;函数返回字符串str2在字符串str1中第⼀次出现的位置&#x…

如何利用数字校园平台提升职业竞争力

现在我们来探讨如何借助数字校园平台来增强自身的职业竞争力。当今之时代&#xff0c;技术与数据堪称热门领域&#xff0c;略懂编程语言及数据分析&#xff0c;于求职之际&#xff0c;实能增添诸多优势&#xff01; 首先&#xff0c;咱们得说说编程语言。现在很多学校都有提供在…

使用 Arduino 的 WiFi 控制机器人

使用 Arduino 的 WiFi 控制机器人 这次我们将使用 Arduino 和 Blynk 应用程序制作一个 Wi-Fi 控制的机器人。这款基于 Arduino 的机器人可以使用任何支持 Wi-Fi 的 Android 智能手机进行无线控制。 为了演示 Wi-Fi 控制机器人,我们使用了一个名为“Blynk”的 Android 移动应…

动态ip和静态ip适用于哪个场景?有何区别

在数字化浪潮席卷全球的今天&#xff0c;IP地址作为网络世界的“门牌号”&#xff0c;其重要性不言而喻。然而&#xff0c;面对动态IP与静态IP这两种截然不同的IP分配方式&#xff0c;许多用户往往感到困惑&#xff1a;它们究竟有何区别&#xff1f;又分别适用于哪些场景呢&…

求最大公约数【C/C++】

大家好啊&#xff0c;欢迎来到本博客( •̀ ω •́ )✧&#xff0c;我将带领大家详细的了解最大公约数的思想与解法。 一、什么是公约数 公约数&#xff0c;也称为公因数&#xff0c;是指两个或多个整数共有的因数。具体来说&#xff0c;如果一个整数能被两个或多个整数整除&…

conda 配置新环境时package will be install 和 package will be download 的区别

install 和 download 的区别 package will be downloaded下的包&#xff1a;这一类显示的是需要从 conda 仓库或其他指定的源下载的软件包。这些软件包通常是 .tar.bz2、.tar.xz 或 .conda 格式的压缩包。这些包会被下载到本地缓存目录&#xff08;通常是 ~/.conda 或 C:\Users…

【2025小黑课堂】计算机二级WPS精选系列20G内容(可下载:真题+预测卷+软件+选择题)

2025年3月全国计算机等级考试即将于3月29日至31日举行。为了帮助广大考生高效备考&#xff0c;小编特意收集并整理了最新版&#xff08;备考2025年3月&#xff09;的小黑课堂计算机二级WPS 电脑题库软件&#xff0c;助力考生在考试中游刃有余&#xff0c;轻松通关&#xff01; …

C++编写Redis客户端

目录 安装redis-plus-plus库 ​编辑 编译Credis客户端 redis的通用命令使用 get/set exists del keys expire /ttl type string类型核心操作 set和get set带有超时时间 set带有NX string带有XX mset mget getrange和setrange incr和decr list类型核心操作…

①EtherCAT转Modbus485RTU网关多路同步高速采集无需编程串口服务器

EtherCAT转Modbus485RTU网关多路同步高速采集无需编程串口服务器https://item.taobao.com/item.htm?ftt&id798036415719 型号 1路总线EC网关 MS-A2-1011 2路总线EC网关 MS-A2-1021 4路总线EC网关 MS-A2-1041 EtherCAT 串口网关 EtherCAT 转 RS485 技术规格 …

C++ Primer 交换操作

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

TDengine 服务无法启动常见原因

taosd 是 TDengine 的核心服务进程&#xff0c;如果无法启动将导致整个数据库无法使用&#xff0c;了解常导致无法启动的原因&#xff0c;可以帮你快速解决问题。 1. 如何查找日志 无法启动的原因记录在日志中&#xff0c;日志文件默认在 /var/log/taos 的 taosdlog.0 或者 t…

一周学会Flask3 Python Web开发-SQLAlchemy连接Mysql数据库

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili app.py下&#xff0c;我们先配置数据库连接&#xff0c;然后写一个简单sql测试。 连接配置&#xff0c;包括用户名&#xff…

【NLP 32、文本匹配任务 —— 深度学习】

大劫大难以后&#xff0c;人不该失去锐气&#xff0c;不该失去热度&#xff0c;你镇定了却依旧燃烧&#xff0c;你平静了却依旧浩荡&#xff0c;致那个从绝望中走出来的自己&#xff0c;共勉 —— 25.1.31 使用深度学习在文本匹配任务上主要有两种方式&#xff1a;① 表示型 ②…