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

Springboot - Web

Spring Boot 是一个用于简化 Spring 应用程序配置和部署的框架。它提供了一种快速开发的方式,通过默认配置、自动化配置等特性,使得开发者能够更快捷地构建和部署基于 Spring 的应用。
在这里插入图片描述

Spring Boot Web 是 Spring Boot 的一个子模块,它专注于 Web 应用的构建。它简化了创建 Web 应用的过程,包括 RESTful 服务、Web 层的支持、嵌入式服务器等功能。Spring Boot Web 是 Spring Boot 中处理 Web 相关应用的一个功能模块,通常包含 Spring MVC、嵌入式 Tomcat、Jetty 或 Undertow 服务器等。

Spring Boot 是一个完整的框架,而 Spring Boot Web 是其中一个子模块,专注于 Web 开发。

文章目录

  • 一、创建SpringBoot 工程
  • 二、 HTTP协议
    • 2.1 请求协议
    • 2.2 响应协议
      • 2.2.1 状态码 描述
  • 三、分层解耦
    • 3.1 三层架构
      • 1. 表示层
      • 2. 业务逻辑层
      • 3. 数据访问层
      • 组件之间的协作
      • 完整流程示例:
    • 3.2 各层中的职责和关系
      • 各层的职责和关系:
      • 工作流程:
    • 3.3 IOC(控制反转)和DI(依赖注入)
  • 四、自写一个案例
    • 4.1 数据库结构
    • 4.2 服务端代码
      • 4.2.0 在测试阶段的问题发现
      • 4.2.1 POJO
      • 4.2.2 Mapper
      • 4.2.3 Controller
      • 4.2.4 Service
      • 4.2.5 Apipost调试

一、创建SpringBoot 工程

在这里插入图片描述

在这里插入图片描述

package com.itdt.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello() {
        System.out.println("sout Hello World");
        return "return Hello World";
    }
}

在这里插入图片描述
在其中内嵌了tomcat服务器
在这里插入图片描述
查看依赖
在这里插入图片描述

二、 HTTP协议

HTTP(Hypertext Transfer Protocol)是一种用于传输超文本的应用层协议。它是Web的基础,用于在Web浏览器和Web服务器之间传输数据。

2.1 请求协议

  1. 请求行(Request Line):包括请求方法(GET、POST 等)、请求的URL和使用的HTTP协议版本。
  2. 请求头部(Headers):包含了各种标识信息,如Accept、User-Agent、Content-Type 等。
  3. 请求体(Body):对于 POST 请求,请求体中包含了实际要发送给服务器的数据。对于 GET 请求,通常为空

image-20241224114002773

<!DOCTYPE html>
<html>
<head>
    <title>Test Hello Controller</title>
</head>
<body>
    <form action="http://localhost:8081/hello" method="POST">
        <label for="name">Name:</label>
        <input type="text" id="name" name="name">
        <button type="submit">Submit</button>
    </form>
</body>
</html>

  1. GET请求数据格式

    • GET请求将数据附加在URL之后,以?分隔URL和传输数据。

    • 参数之间使用&连接,由键值对组成,如key1=value1&key2=value2

    • GET请求适合传输少量数据,因为数据会暴露在URL中,有长度限制。

      (1)从服务器获取数据,且数据量较小且不敏感时,可以使用GET请求。

      (2)向服务器请求资源,如获取网页、图片等。

      (3)通过URL直接传递参数,方便在浏览器中进行测试和调试。

  2. POST请求数据格式

    • POST请求的数据在请求体中,不会暴露在URL中。
    • 请求头中会包含Content-Type: application/x-www-form-urlencoded来指示数据格式。
    • 参数同样以键值对的形式传输,但不会显示在URL中。
    • POST请求适合传输大量数据或敏感信息,如表单提交等。
  • 例如GET:

GET请求的

  • 例如POST:(POST请求,将请求的参数放入请求体中)

    `Accept`: 指定客户端能够接收的内容类型,如`text/html`、`application/json`等。
    `Content-Type`: 指定请求体中的数据类型,如`application/json`、`application/x-www-form-urlencoded`等。
    `User-Agent`: 包含了客户端的应用程序、操作系统、版本等信息,用于标识客户端身份。
    `Host`: 指定请求的目标主机和端口号。
    `Cookie`: 包含了客户端的Cookie信息,用于在客户端和服务器之间保持状态。
     `Referer`: 指定了当前请求的来源页面URL。
    `Origin`: 指定了发起请求的源。
    

post请求的、、

2.2 响应协议

image-20241224135445071

2.2.1 状态码 描述

状态码英文描述中文描述
1xxInformational信息性状态码。服务器收到请求,需要请求者继续操作
100Continue客户端应继续其请求
101Switching Protocols服务器根据客户端的请求切换协议
2xxSuccess成功状态码。请求成功被服务器接收和理解
200OK请求已成功处理
201Created请求已经成功,并且服务器创建了新资源
202Accepted已接受。请求已接受,但尚未处理
203Non-Authoritative Information非权威信息。服务器已成功处理请求,但返回的信息可能来自另一来源
204No Content服务器成功处理请求,但未返回任何内容
205Reset Content重置内容。服务器成功处理请求,需要重置视图
206Partial Content服务器成功处理了部分GET请求
3xxRedirection重定向状态码。需要客户端采取进一步操作以完成请求
300Multiple Choices请求的资源存在多种选择,服务器返回列表供选择
301Moved Permanently请求的资源已被永久移动到新位置
302Found找到。请求的资源临时从不同位置响应
303See Other查看其他。请求的资源存在另一个URI,应使用GET、POST方法获取
304Not Modified资源未被修改,客户端可使用缓存数据
305Use Proxy使用代理。请求必须通过指定的代理才能访问
307Temporary Redirect临时重定向。请求的资源临时从不同位置响应
4xxClient Error客户端错误状态码。请求包含语法错误或无法完成请求
400Bad Request错误请求。服务器无法理解请求的语法
401Unauthorized未授权。请求要求用户的身份认证
403Forbidden禁止访问。服务器理解请求,但拒绝执行
404Not Found未找到。服务器无法找到请求的资源
405Method Not Allowed方法不允许。请求中指定的方法不被允许
406Not Acceptable不可接受。服务器无法根据请求的内容特性完成请求
407Proxy Authentication Required需要代理身份验证。客户端必须先使用代理认证
408Request Timeout服务器等待请求时发生超时
409Conflict请求导致服务器上的冲突
410Gone消失。请求的资源不再可用
411Length Required需要长度。缺少Content-Length头信息
412Precondition Failed请求头中指定的前提条件无法满足
413Payload Too Large请求的负载过大,服务器拒绝处理
414URI Too Long请求的URI长度超过服务器能处理的长度
415Unsupported Media Type不支持的媒体类型。请求的格式不受支持
416Range Not Satisfiable范围不符合要求。服务器无法满足请求的Range头信息
417Expectation Failed服务器无法满足请求中Expect请求头信息
418I’m a teapot我是茶壶。服务器拒绝尝试用茶壶煮咖啡
421Misdirected Request误导的请求。服务器无法生成适用于请求的响应
422Unprocessable Entity无法处理的实体。请求格式正确,但无法处理请求
423Locked已锁定。资源被锁定,当前操作无法完成
424Failed Dependency依赖关系失败。请求失败,因为请求的先决条件失败
425Too Early服务器不愿意处理请求,因为可能导致重放
426Upgrade Required需要升级。客户端应切换到TLS/1.0
428Precondition Required需要前提条件。请求失败,因为缺少必需的前提条件
429Too Many Requests请求过多。客户端发送的请求过多
431Request Header Fields Too Large请求头字段太大。服务器无法处理请求,因为请求头字段太大
451Unavailable For Legal Reasons由于法律原因不可用。资源因法律原因不可用
5xxServer Error服务器错误状态码。服务器无法完成请求
500Internal Server Error服务器内部错误。服务器遇到意外情况,无法完成请求
501Not Implemented未实现。服务器不支持请求的功能
502Bad Gateway错误网关。服务器作为网关或代理,从上游服务器接收到无效响应
503Service Unavailable服务不可用。服务器当前无法处理请求
504Gateway Timeout网关超时。服务器作为网关或代理,但未及时从上游服务器收到响应
505HTTP Version Not SupportedHTTP版本不支持。服务器不支持请求中所用的HTTP版本
507Insufficient Storage存储空间不足。服务器无法存储完成请求所必须的内
510Not Extended未扩展。客户端需要对请求进一步扩展
511Network Authentication Required需要网络身份验证。客户端需要进行身份验证才能获得网络访问权限

三、分层解耦

image-20241224195413883

  • 耦合是指不同模块(或类、组件)之间的依赖关系。它衡量的是模块之间的紧密程度。低耦合意味着模块之间的依赖关系较少,模块之间的变化不会相互影响,这通常是设计中的目标。高耦合则意味着模块之间的依赖关系过多,任何一个模块的变化都会影响到其他模块,增加了维护和修改的难度。
  • 内聚是指一个模块内部的各个元素之间的紧密程度。它衡量的是模块内部元素的相关性,或者说是模块内部各个功能的联系度。高内聚意味着模块内部的功能高度相关,模块内部的代码是为了实现一个单一的、明确的功能而组织的。低内聚则意味着模块内部的功能没有明确的目标,模块中的各个元素职责分散,缺乏相关性。

3.1 三层架构

在软件开发中,三层架构(Three-Tier Architecture)是一种常见的设计模式,用于将应用程序的不同职责分离,以提高系统的可维护性、可扩展性和重用性。三层架构通常分为 表示层业务逻辑层数据访问层

1. 表示层

  • 职责:表示层负责处理用户的输入和输出。它是与用户交互的部分,通常通过 Web 页面(前端)来展示信息,接收用户的请求并返回响应。
  • 组件:通常包含 Controller(或 RestController),它负责接收 HTTP 请求并将其委派给业务逻辑层(Service)。Controller 会根据用户的请求调用相应的服务,并返回响应结果。
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        User user = userService.getUserById(id);
        return ResponseEntity.ok(user);
    }
}

2. 业务逻辑层

  • 职责:业务逻辑层负责处理应用程序的核心业务逻辑,它充当了表示层和数据访问层之间的中介。所有复杂的计算、规则判断和数据转换等任务都在这一层进行。业务逻辑层通常包含接口和其实现类(如 ServiceServiceImpl),它们负责调用数据访问层(Mapper)来进行数据库操作,并处理返回结果。
  • 组件Service(接口)和 ServiceImpl(实现类),Service 定义了业务操作的接口,ServiceImpl 提供实际的业务逻辑实现。
  • 技术:Spring Service、业务逻辑编写等。
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public User getUserById(Long id) {
        return userMapper.findById(id);
    }
}

3. 数据访问层

  • 职责:数据访问层负责与数据库进行交互,执行 CRUD 操作(创建、读取、更新、删除)等。它直接与数据库进行通信,封装了所有的 SQL 操作。数据访问层通常由 MapperDAO(Data Access Object)类组成。Mapper 是 MyBatis 中的接口,而 DAO 在其他框架中通常代表数据访问的类。
  • 组件MapperDAO,这些类负责数据持久化操作,定义数据库查询语句,并将数据库结果返回给业务逻辑层。
  • 技术:MyBatis、JPA(Hibernate)、JDBC、Spring Data JPA 等。
@Mapper
public interface UserMapper {
    User findById(Long id);
}

组件之间的协作

  1. 表示层 (Controller) 接收用户请求,调用业务逻辑层 (Service) 进行处理。
  2. 业务逻辑层 (ServiceImpl) 通过调用数据访问层 (Mapper) 来获取或更新数据。
  3. 数据访问层 (Mapper) 负责与数据库进行交互,执行 SQL 操作。
  4. 处理结果返回到 表示层 (Controller),最终响应给用户。
层级主要职责主要组件(类)主要技术
表示层处理用户请求和响应Controller、RestControllerSpring MVC、JSP、Thymeleaf
业务逻辑层处理业务逻辑Service、ServiceImplSpring Service
数据访问层与数据库交互,执行数据操作Mapper、DAOMyBatis、JPA、JDBC

完整流程示例:

  1. 前端发起请求:用户通过 Web 浏览器或其他客户端发起请求(如 GET 或 POST)。
  2. Controller 处理请求Controller 接收请求,调用相应的业务逻辑层 (Service) 来处理业务。
  3. Service 进行业务逻辑处理ServiceImpl 处理复杂的业务逻辑,并可能需要通过 Mapper 与数据库进行交互。
  4. Mapper 查询数据库Mapper 执行 SQL 查询,获取数据并返回。
  5. 业务层处理数据ServiceImpl 对数据库返回的数据进行处理和转换。
  6. Controller 返回响应Controller 将处理结果(通常是数据)返回给前端。

3.2 各层中的职责和关系

+-----------+        +-----------+        +----------------+        +-------------+        +-------------+
| Controller| -----> |   Service | -----> |   ServiceImpl  | -----> |   Mapper    | -----> |     POJO    |
+-----------+        +-----------+        +----------------+        +-------------+        +-------------+
      ↑                     ↑                      ↑                      ↑                    ↑
    (调用接口)         (调用实现)          (调用数据库操作)         (持久化数据)          (封装数据)

各层的职责和关系:

  1. Controller: – 负责接收请求,调用 Service 层的接口。

    • 职责:接收前端请求,调用 Service 层进行处理,并返回处理结果给前端。
    • 与其他组件的关系Controller 接收到前端请求后,调用 Service 接口中的方法进行业务处理,最终返回处理结果。
  2. Service (业务层接口): – 定义业务逻辑的接口。

    • 职责:定义业务逻辑的抽象接口。Service 层提供了一系列业务方法,用于业务操作的声明,但不包含具体实现。
    • 与其他组件的关系Service 层由 ServiceImpl 实现,Controller 调用 Service 接口提供的业务方法。Service 只定义接口,不涉及具体的业务实现细节。
  3. ServiceImpl (服务实现类): – 实现业务逻辑,调用 Mapper 层的数据库操作。

    • 职责ServiceImplService 接口的具体实现,负责处理具体的业务逻辑。它可以调用 Mapper 层进行数据库操作,并封装业务操作。
    • 与其他组件的关系ServiceImpl 调用 Mapper 进行数据库操作,获取或更新数据,并将结果返回给 Controller。它的作用是将数据库访问与业务逻辑分开。
  4. Mapper (数据访问层): – 负责数据库的操作,将数据存取到 POJO 中。

    • 职责Mapper 是与数据库交互的层,通常定义了数据库的查询、插入、更新和删除操作。实现通常MyBatis
  5. POJO (数据模型): – 表示数据模型,封装数据。

    • 职责:POJO 是普通的 Java 对象,通常用于表示数据库中的一行记录或者某些数据结构。它封装了数据,并为这些数据提供 getter 和 setter 方法。
    • 与其他组件的关系:POJO 作为数据模型,通常用于与数据库交互,它由 Mapper 来操作,ServiceImpl 会将 POJO 作为处理结果传递给 Controller

工作流程:

  1. 用户请求:用户通过前端发起请求,Controller 接收请求。
  2. 调用 Service 接口Controller 调用 Service 接口定义的方法来执行业务操作。
  3. 业务实现ServiceImpl 作为 Service 接口的实现,负责具体的业务逻辑,并调用 Mapper 进行数据操作。
  4. 数据库操作Mapper 执行数据库操作,将数据从数据库加载到 POJO 中,或者将 POJO 中的数据保存到数据库。
  5. 返回结果ServiceImpl 将结果(通常是 POJO 对象或集合)返回给 ControllerController 将处理结果返回给前端。

3.3 IOC(控制反转)和DI(依赖注入)

  • IOC(控制反转)是一种设计原则,它将控制权从应用程序代码中转移出来,由框架或容器来管理对象之间的依赖关系。在IOC中,对象的创建、组装和管理都由框架来完成,而不是由程序员手动管理。

    控制反转:指将对象的控制权交给IOC容器,由IOC容器来创建和管理这些对象,IOC里的这些对象也被称为Bean对象。

    将Dao 及 Service层的实现类,交给IOC容器管理;为Controller 及 Service注入运行时所依赖的对象。

    声明bean的注解有:@Controller、@Service、@Repository、@Component

  • DI(依赖注入)是IOC的一种实现方式,它指的是通过外部注入的方式来提供一个对象所依赖的其他对象。依赖注入可以通过构造函数、属性或方法来实现,目的是减少类之间的耦合度,使代码更易于维护和测试。

    DI:IOC容器要为应用程序提供运行时所依赖的资源。资源,指的是对象。

    @Autowired注解,默认是按照类型进行注入的。

    如果存在多个相同类型的bean,将会报出如下错误:方案一:@Primary、方案二:@Qualifier、方案三:@Resource

    @Resource 与 @Autowired区别 ?
    @Autowired是Spring框架提供的注解,而@Resource是JavaEE规范提供的
    @Autowired默认是按照类型注入,而@Resource默认是按照名称注入

总的来说,IOC是一种设计原则,而DI是实现这一原则的具体方式之一。通过使用IOC和DI,可以使代码更加灵活、可扩展和易于测试。

四、自写一个案例

4.1 数据库结构

create table users
(
    id         int auto_increment
        primary key,
    username   varchar(50)                            not null comment '用户名',
    password   varchar(255) default '12345678'        not null comment '加密后的密码',
    email      varchar(100)                           not null comment '用户邮箱',
    phone      varchar(11)                            not null,
    user_type  int                                    not null comment '用户类型(''landlord'', ''tenant'', ''buyer'', ''seller'')',
    created_at timestamp    default CURRENT_TIMESTAMP not null comment '创建时间',
    updated_at timestamp    default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
    avatar_url varchar(255)                           null comment '用户头像URL',
    gender     int                                    null comment '用户性别(男、女)'
)
    comment '用户表,存储所有用户信息';


下面是模拟数据

image-20241224230427418

4.2 服务端代码

  • POM 安装分页查询分页插件PageHelper,JAXBJava类映射到XML表示形式

    创建项目

image-20241224215438168

我的application.yml

spring:
  application:
    name: GraduationPro
  datasource:
    url:  填写你的实际url
    driver-class-name: com.mysql.cj.jdbc.Driver
    username:填写你的实际username
    password: 填写你的实际password
  servlet:
    multipart:
      #最大单个文件大小
      max-file-size: 10MB
      #最大请求大小(包括所有文件和表单数据)
      max-request-size: 100MB

#Mybatis的相关配置
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    #开启驼峰命名映射开关
    map-underscore-to-camel-case: true

#配置事务管理日志级别
logging:
  level:
    org.springframework.jdbc.support.JdbcTransactionManager: debug

server:
  port: 8081

4.2.0 在测试阶段的问题发现

image-20241225000128644

这是由于pom.xml,把下面的这个删去,然后在右侧的maven配置中clean一下重新刷maven,最终重新build一下代码即可

image-20241225000315108

4.2.1 POJO

package com.example.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;

import java.sql.Timestamp;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Integer id;
    private String username;
    private String password;
    private String email;
    private String phone;
    private Integer userType;
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Timestamp createdAt;
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Timestamp updatedAt;
    private String avatarUrl;
    private Integer gender;
}

统一相应结果

public class Result {

    private Integer code; //编码:1成功,0为失败
    private String msg; //错误信息
    private Object data; //数据

    public static Result success() {
        Result result = new Result();
        result.code = 1;
        result.msg = "success";
        return result;
    }

    public static Result success(Object object) {
        Result result = new Result();
        result.data = object;
        result.code = 1;
        result.msg = "success";
        return result;
    }

    public static Result error(String msg) {
        Result result = new Result();
        result.msg = msg;
        result.code = 0;
        return result;
    }

}

4.2.2 Mapper

package com.example.mapper;

import com.example.pojo.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface UserMapper {
    @Select("select * from user where id = #{id}")
    User getUserById(Integer id);

    void save(User user);
}

在resoucrs资源下,新建一个同级的包,切记是以‘/'分割的

image-20250103205506529

在其中同名的xml写(此为复杂情况使用mybatis)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
    <!--    批量分隔符-->
<!-- UserMapper.xml -->
<insert id="save" parameterType="com.example.pojo.User">
    INSERT INTO user (
        username, password, email, phone, user_type, created_at, updated_at, avatar_url, gender
    ) VALUES (
        #{username}, #{password}, #{email}, #{phone}, #{userType}, #{createdAt}, #{updatedAt}, #{avatarUrl}, #{gender}
    )
</insert>

</mapper>

image-20250103205705415

4.2.3 Controller

package com.example.controller;

import com.example.pojo.Result;
import com.example.pojo.User;
import com.example.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserService userService;
//    查询指定用户
    @GetMapping("/{id}")
    public Result getUserById(@PathVariable Integer id) {
        log.info("正在查询id为{}的用户", id);
        User user = userService.getUserById(id);
        return Result.success(user);
    }


    @PostMapping
    public Result save(@RequestBody User user) {
        log.info("用户{}注册", user);
        userService.save(user);
        return Result.success();
    }

}

4.2.4 Service

package com.example.service;

import com.example.pojo.User;

public interface UserService {
    void save(User user);

    User getUserById(Integer id);
}

其实现类

package com.example.service.impl;

import java.time.LocalDateTime;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public void save(User user) {
        user.setCreatedAt(LocalDateTime.now());
        user.setUpdatedAt(LocalDateTime.now());
        userMapper.save(user);
    }

    @Override
    public User getUserById(Integer id) {
        return userMapper.getUserById(id);
    }

}

4.2.5 Apipost调试

image-20250103205908908

还有json格式的新增用户

image-20250103210021510


http://www.kler.cn/a/466079.html

相关文章:

  • 基于 Node.js 的 ORM(对象关系映射)工具——Sequelize介绍与使用,并举案例分析
  • 『SQLite』几种向表中插入数据的方法
  • JavaWeb开发(六)XML介绍
  • 【AutoSAR】【底软自动化】Arxml自动配置平台
  • 三、GIT与Github推送(上传)和克隆(下载)
  • 【paddle】初次尝试
  • C++STL中bitset的介绍与使用
  • 数据库软考历年上午真题与答案解析(2018-2024)
  • 点击<el-dropdown>中某一项跳转页面时,控制台报错的问题
  • 基于海豚调度功能开发——推送下游系统数据库连接信息批量修改方案与实现
  • 算法-10进制转换成16进制,负数用补码表示
  • 一、二极管(模电理论篇)
  • ubuntu安装firefox
  • aardio —— 改变按钮文本颜色
  • Node.js应用程序遇到了内存溢出的问题
  • IP5385应用于移动电源快充方案的30W到100W大功率电源管理芯片
  • 服务器开发 的编程环境(programming environment)核心知识
  • Linux下部署ElasticSearch集群
  • 基于SpringBoot和Thymeleaf的仿小米电商系统源码下载与安装指南-幽络源
  • Win11+WLS Ubuntu 鸿蒙开发环境搭建(二)
  • DVWA靶场文件上传漏洞全级别通关及源码深度解析
  • 使用rknn进行yoloV8部署(C++)
  • 六种主流服务器的选择与使用
  • 【机器学习】由浅入深学习网格搜索
  • 158页精品PPT | 大型研发制造集团信息化IT规划整体方案
  • React 中结合 antd 的 Input 组件实现防抖输入