• SpringBoot整合JUnit、MyBatis、MyBatis-plus、Druid详解


    本专栏将从基础开始,循序渐进,以实战为线索,逐步深入SpringBoot相关知识相关知识,打造完整的云原生学习步骤,提升工程化编码能力和思维能力,写出高质量代码。希望大家都能够从中有所收获,也请大家多多支持。
    专栏地址:SpringBoot专栏
    本文涉及的代码都已放在gitee上:gitee地址
    如果文章知识点有错误的地方,请指正!大家一起学习,一起进步。


    ​ SpringBoot之所以好用,就是它能方便快捷的整合其他技术,这一部分咱们就来聊聊一些技术的整合方式,通过本文的学习,大家能够感受到SpringBoot到底有多酷炫。本文将学习如下技术的整合方式:

    • 整合JUnit
    • 整合MyBatis
    • 整合MyBatis-Plus
    • 整合Druid

    1 整合JUnit

    ​ SpringBoot技术的定位用于简化开发,再具体点是简化Spring程序的开发。所以在整合任意技术的时候,如果你想直观感触到简化的效果,你必须先知道使用非SpringBoot技术时对应的整合是如何做的,然后再看基于SpringBoot的整合是如何做的,才能比对出来简化在了哪里。

    ​ 我们先来看一下不使用SpringBoot技术时,Spring整合JUnit的使用方式

    //加载spring整合junit专用的类运行器
    @RunWith(SpringJUnit4ClassRunner.class)
    //指定对应的配置信息
    @ContextConfiguration(classes = SpringConfig.class)
    public class AccountServiceTestCase {
        //注入你要测试的对象
        @Autowired
        private AccountService accountService;
        @Test
        public void testGetById(){
            //执行要测试的对象对应的方法
            System.out.println(accountService.findById(2));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    ​ 其中核心代码是前两个注解,第一个注解@RunWith是设置Spring专用的测试类运行器,简单说就是Spring程序执行程序有自己的一套独立的运行程序的方式,不能使用JUnit提供的类运行方式了,必须指定一下,但是格式是固定的,琢磨一下,每次都指定一样的东西,这个东西写起来没有技术含量啊,第二个注解@ContextConfiguration是用来设置Spring核心配置文件或配置类的,简单说就是加载Spring的环境你要告诉Spring具体的环境配置是在哪里写的,虽然每次加载的文件都有可能不同,但是仔细想想,如果文件名是固定的,这个貌似也是一个固定格式。既然有可能是固定格式,那就有可能每次都写一样的东西,也是一个没有技术含量的内容书写。

    ​ SpringBoot就抓住上述两条没有技术含量的内容书写进行开发简化,能走默认值的走默认值,能不写的就不写,具体格式如下

    @SpringBootTest
    class Springboot04JunitApplicationTests {
        //注入你要测试的对象
        @Autowired
        private BookDao bookDao;
        @Test
        void contextLoads() {
            //执行要测试的对象对应的方法
            bookDao.save();
            System.out.println("two...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    ​ 看看这次简化成什么样了,一个注解就完成了,而且还没有参数,再体会SpringBoot整合其他技术的优势在哪里,就两个字——简化。使用一个注解@SpringBootTest替换了前面两个注解。至于内部是怎么回事?和之前一样,只不过都走默认值。

    ​ 这个时候有人就问了,你加载的配置类或者配置文件是哪一个?就是我们前面启动程序使用的引导类。如果想手工指定引导类有两种方式,第一种方式使用属性的形式进行,在注解@SpringBootTest中添加classes属性指定配置类

    @SpringBootTest(classes = Springboot04JunitApplication.class)
    class Springboot04JunitApplicationTests {
        //注入你要测试的对象
        @Autowired
        private BookDao bookDao;
        @Test
        void contextLoads() {
            //执行要测试的对象对应的方法
            bookDao.save();
            System.out.println("two...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    ​ 第二种方式回归原始配置方式,仍然使用@ContextConfiguration注解进行,效果是一样的

    @SpringBootTest
    @ContextConfiguration(classes = Springboot04JunitApplication.class)
    class Springboot04JunitApplicationTests {
        //注入你要测试的对象
        @Autowired
        private BookDao bookDao;
        @Test
        void contextLoads() {
            //执行要测试的对象对应的方法
            bookDao.save();
            System.out.println("two...");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    温馨提示

    ​ 使用SpringBoot整合JUnit需要保障导入test对应的starter,由于初始化项目时此项是默认导入的,所以此处没有提及,其实和之前学习的内容一样,用什么技术导入对应的starter即可。

    总结

    1. 导入测试对应的starter
    2. 测试类使用@SpringBootTest修饰
    3. 使用自动装配的形式添加要测试的对象
    4. 测试类如果存在于引导类所在包或子包中无需指定引导类
    5. 测试类如果不存在于引导类所在的包或子包中需要通过classes属性指定引导类

    2 整合MyBatis

    2.1 Spring整合MyBatis

    ​ 整合完JUnit下面再来说一下整合MyBatis,这个技术是大部分公司都要使用的技术,务必掌握。如果对Spring整合MyBatis不熟悉的小伙伴好好复习一下,下面列举出原始整合的全部内容,以配置类的形式为例进行

    • 导入坐标,MyBatis坐标不能少,Spring整合MyBatis还有自己专用的坐标,此外Spring进行数据库操作的jdbc坐标是必须的,剩下还有mysql驱动坐标,本例中使用了Druid数据源,这个倒是可以不要

      <dependencies>
          <dependency>
              <groupId>com.alibaba</groupId>
              <artifactId>druid</artifactId>
              <version>1.1.16</version>
          </dependency>
          <dependency>
              <groupId>org.mybatis</groupId>
              <artifactId>mybatis</artifactId>
              <version>3.5.6</version>
          </dependency>
          <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <version>5.1.47</version>
          </dependency>
          <!--导入mybatis与spring整合的jar包-->
          <dependency>
              <groupId>org.mybatis</groupId>
              <artifactId>mybatis-spring</artifactId>
              <version>1.3.0</version>
          </dependency>
          <!--导入spring操作数据库必选的包-->
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-jdbc</artifactId>
              <version>5.2.10.RELEASE</version>
          </dependency>
      </dependencies>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
    • Spring核心配置

      @Configuration
      @ComponentScan("com.hashnode")
      @PropertySource("jdbc.properties")
      public class SpringConfig {
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • MyBatis要交给Spring接管的bean

      //定义mybatis专用的配置类
      @Configuration
      public class MyBatisConfig {
      //    定义创建SqlSessionFactory对应的bean
          @Bean
          public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
              //SqlSessionFactoryBean是由mybatis-spring包提供的,专用于整合用的对象
              SqlSessionFactoryBean sfb = new SqlSessionFactoryBean();
              //设置数据源替代原始配置中的environments的配置
              sfb.setDataSource(dataSource);
              //设置类型别名替代原始配置中的typeAliases的配置
              sfb.setTypeAliasesPackage("com.itheima.domain");
              return sfb;
          }
      //    定义加载所有的映射配置
          @Bean
          public MapperScannerConfigurer mapperScannerConfigurer(){
              MapperScannerConfigurer msc = new MapperScannerConfigurer();
              msc.setBasePackage("com.itheima.dao");
              return msc;
          }
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
    • 数据源对应的bean,此处使用Druid数据源

      @Configuration
      public class JdbcConfig {
          @Value("${jdbc.driver}")
          private String driver;
          @Value("${jdbc.url}")
          private String url;
          @Value("${jdbc.username}")
          private String userName;
          @Value("${jdbc.password}")
          private String password;
      
          @Bean("dataSource")
          public DataSource dataSource(){
              DruidDataSource ds = new DruidDataSource();
              ds.setDriverClassName(driver);
              ds.setUrl(url);
              ds.setUsername(userName);
              ds.setPassword(password);
              return ds;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
    • 数据库连接信息(properties格式)

      jdbc.driver=com.mysql.jdbc.Driver
      jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false
      jdbc.username=root
      jdbc.password=root
      
      • 1
      • 2
      • 3
      • 4

      上述格式基本上是最简格式了,要写的东西还真不少。下面看看SpringBoot整合MyBaits格式

    2.2 SpringBoot整合MyBatis

    步骤①:使用Spring Initializr创建模块,可以将ServerURL设置成https://start.aliyun.com:

    步骤②:勾选要使用的技术,MyBatis,由于要操作数据库,还要勾选对应数据库

    ​ 或者手工导入对应技术的starter,和对应数据库的坐标

    <!--导入mybatis与spring整合的jar包-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.4</version>
            </dependency>
    
            <!--导入mysql-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    步骤③:配置数据源相关信息,没有这个信息你连接哪个数据库都不知道

    spring:
      application:
        name: springboot_0004_mybatis
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        name: defaultDataSource
        url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDateTimeCode=false&serverTimezone=GMT%2B8
        username: root
        password: root
    
    mybatis:
      mapper-locations: classpath:mapper/*.xml
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    ​ 结束了,就这么多,没了。有人就很纳闷,这就结束了?对,这就结束了,SpringBoot把配置中所有可能出现的通用配置都简化了。下面写一个MyBatis程序运行需要的Dao(或者Mapper)就可以运行了

    实体类

    package com.hashnode.springboot_0004_mybatis.model;
    
    public class Student {
        private Integer id;
    
        private String name;
    
        private Integer age;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    映射接口(Mapper)

    package com.hashnode.springboot_0004_mybatis.mapper;
    
    import com.hashnode.springboot_0004_mybatis.model.Student;
    
    public interface StudentMapper {
        int deleteByPrimaryKey(Integer id);
    
        int insert(Student record);
    
        int insertSelective(Student record);
    
        Student selectByPrimaryKey(Integer id);
    
        int updateByPrimaryKeySelective(Student record);
    
        int updateByPrimaryKey(Student record);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Service类

    package com.hashnode.springboot_0004_mybatis.service;
    
    
    import com.hashnode.springboot_0004_mybatis.mapper.StudentMapper;
    import com.hashnode.springboot_0004_mybatis.model.Student;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class StudentService {
        @Autowired
        StudentMapper studentMapper;
    
        public int insertTest(Student record){
            return studentMapper.insert(record);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    测试类

    package com.hashnode.springboot_0004_mybatis;
    
    import com.hashnode.springboot_0004_mybatis.model.Student;
    import com.hashnode.springboot_0004_mybatis.service.StudentService;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    @SpringBootTest
    class Springboot0004MybatisApplicationTests {
    
        @Autowired
        StudentService studentService;
    
        @Test
        void contextLoads() {
            Student student = new Student();
            student.setAge(18);
            student.setName("aaa");
            System.out.println(studentService.insertTest(student));
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    ​ 完美,开发从此变的就这么简单。再体会一下SpringBoot如何进行第三方技术整合的,是不是很优秀?

    3 整合MyBatis-Plus

    ​ 做完了两种技术的整合了,各位小伙伴要学会总结,我们做这个整合究竟哪些是核心?总结下来就两句话

    • 导入对应技术的starter坐标

    • 根据对应技术的要求做配置

      虽然看起来有点虚,但是确实是这个理儿,下面趁热打铁,再换一个技术,看看是不是上面这两步。

    ​ 接下来在MyBatis的基础上再升级一下,整合MyBaitsPlus(简称MP),国人开发的技术,符合中国人开发习惯,谁用谁知道。来吧,一起做整合

    步骤①:导入对应的starter

    <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.5.2</version>
            </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    ​ 关于这个坐标,此处要说明一点,之前我们看的starter都是spring-boot-starter-???,也就是说都是下面的格式

    Spring-boot-start-***
    
    • 1

    ​ 而MyBatis与MyBatisPlus这两个坐标的名字书写比较特殊,是第三方技术名称在前,boot和starter在后。此处简单提一下命名规范,后期原理篇会再详细讲解

    starter所属命名规则示例
    官方提供spring-boot-starter-技术名称spring-boot-starter-web
    spring-boot-starter-test
    第三方提供第三方技术名称-spring-boot-startermybatis-spring-boot-starter
    druid-spring-boot-starter
    第三方提供第三方技术名称-boot-starter(第三方技术名称过长,简化命名)mybatis-plus-boot-starter

    步骤②:配置数据源相关信息

    spring:
      application:
        name: springboot_0005_mybatis_plus
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        name: defaultDataSource
        url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDateTimeCode=false&serverTimezone=GMT%2B8
        username: root
        password: root
    
    mybatis-plus:
      mapper-locations: classpath:mapper/*.xml
      global-config:
        db-config:
          table-prefix: t_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    ​ 没了,就这么多,剩下的就是写MyBaitsPlus的程序了

    映射接口(Dao)

    package com.hashnode.springboot_0004_mybatis.mapper;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.hashnode.springboot_0004_mybatis.model.Student;
    import org.apache.ibatis.annotations.Mapper;
    
    @Mapper
    public interface StudentMapper extends BaseMapper<Student> {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ​ 核心在于Dao接口继承了一个BaseMapper的接口,这个接口中帮助开发者预定了若干个常用的API接口,简化了通用API接口的开发工作。

    ​ 下面就可以写一个测试类进行测试了。

    public class StudentService {
        @Autowired
        StudentMapper studentMapper;
    
        public void insertTest(Student record){
            System.out.println(studentMapper.selectById(1));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    温馨提示

    ​ 目前数据库的表名定义规则是t_模块名称,为了能和实体类相对应,需要做一个配置,在配置application.yml文件添加如下配置即可,设置所有表名的通用前缀名

    mybatis-plus:
      global-config:
        db-config:
          table-prefix: t_		#设置所有表的通用前缀名称为t_
    
    • 1
    • 2
    • 3
    • 4

    总结

    1. 手工添加MyBatis-Plus对应的starter
    2. 数据层接口使用BaseMapper简化开发
    3. 需要使用的第三方技术无法通过勾选确定时,需要手工添加坐标

    4 整合Druid

    ​ 使用SpringBoot整合了3个技术了,发现套路基本相同,导入对应的starter,然后做配置,各位小伙伴需要一直强化这套思想。下面再整合一个技术,继续深入强化此思想。

    ​ 前面整合MyBatis和MyBatisPlus的时候,使用的数据源对象都是SpringBoot默认的数据源对象,下面我们手工控制一下,自己指定了一个数据源对象,Druid。

    ​ 在没有指定数据源时,我们的配置如下:

    #2.配置相关信息
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=Asia/Shanghai
        username: root
        password: root
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ​ 此时虽然没有指定数据源,但是根据SpringBoot的德行,肯定帮我们选了一个它认为最好的数据源对象,这就是HiKari。通过启动日志可以查看到对应的身影。

    2021-11-29 09:39:15.202  INFO 12260 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
    2021-11-29 09:39:15.208  WARN 12260 --- [           main] com.zaxxer.hikari.util.DriverDataSource  : Registered driver with driverClassName=com.mysql.jdbc.Driver was not found, trying direct instantiation.
    2021-11-29 09:39:15.551  INFO 12260 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
    
    • 1
    • 2
    • 3

    ​ 上述信息中每一行都有HiKari的身影,如果需要更换数据源,其实只需要两步即可。

    1. 导入对应的技术坐标

    2. 配置使用指定的数据源类型

      下面就切换一下数据源对象

    步骤①:导入对应的坐标(注意,是坐标,此处不是starter)

    <!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.2.8</version>
            </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    步骤②:修改配置,在数据源配置中有一个type属性,专用于指定数据源类型

    spring:
      application:
        name: springboot_0005_mybatis_plus
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        name: defaultDataSource
        url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDateTimeCode=false&serverTimezone=GMT%2B8
        username: root
        password: root
        type: com.alibaba.druid.pool.DruidDataSource
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    ​ 在这里要提出一个问题,目前的数据源配置格式是一个通用格式,不管你换什么数据源都可以用这种形式进行配置。但是新的问题又来了,如果对数据源进行个性化的配置,例如配置数据源对应的连接数量,这个时候就有新的问题了。每个数据源技术对应的配置名称都不一样吗,各个厂商不可能提前商量好都写一样的名字,所以就要使用专用的配置格式了。这个时候上面这种通用格式就不能使用了,怎么办?按照SpringBoot整合其他技术的通用规则来套啊,导入对应的starter,进行相应的配置即可。

    步骤①:导入对应的starter

    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.6</version>
        </dependency>
    </dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    步骤②:修改配置

    spring:
      application:
        name: springboot_0005_mybatis_plus
      datasource:
        druid:
          driver-class-name: com.mysql.cj.jdbc.Driver
          name: defaultDataSource
          url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDateTimeCode=false&serverTimezone=GMT%2B8
          username: root
          password: root
    
    
    
    mybatis-plus:
      mapper-locations: classpath:mapper/*.xml
      global-config:
        db-config:
          table-prefix: t_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    ​ 注意观察,配置项中,在datasource下面并不是直接配置url这些属性的,而是先配置了一个druid节点,然后再配置的url这些东西。言外之意,url这个属性是druid下面的属性,那你能想到什么?除了这4个常规配置外,还有druid专用的其他配置。通过提示功能可以打开druid相关的配置查阅

    ​ 与druid相关的配置超过200条以上,这就告诉你,如果想做druid相关的配置,使用这种格式就可以了,这里就不展开描述了,太多了。

    ​ 这是我们做的第4个技术的整合方案,还是那两句话:导入对应starter,使用对应配置

  • 相关阅读:
    【技术】视频汇聚/视频云存储/视频监控管理平台EasyCVR安全检查相关问题及解决方法2.0
    11.7 校招 实习 内推 面经
    【linux】shell脚本调试
    低代码搭建质量管理解决方案,为企业管理提速降本
    解锁新姿势,揭秘如何通过公众号迁移方式给自己的爱号开通留言板功能
    【YOLOv8分割】在 预测阶段 如何预测整个目录并输出二值mask图像
    canal同步Mariadb到Mysql
    查找外文文献的几种方式
    图论算法总结
    金仓数据库 KingbaseES 插件dbms_session
  • 原文地址:https://blog.csdn.net/Learning_xzj/article/details/125427716