当前位置:   article > 正文

Springboot整合Mybatis-Plus

springboot整合mybatis-plus

1.概述

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。--单表操作的都不需要自己在写sql语句。--

愿景

我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。

2.特点

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑

  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作

  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现-单表大部分 CRUD 操作,更有强大的条件构造器[条件封装成一个条件类],满足各类使用需求

  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错

  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题

  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作

  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )

  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用

  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询。

  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库.

  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询

  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作.

3.快速使用

快速开始 | MyBatis-Plus (baomidou.com)https://baomidou.com/pages/226c21/(1)创建数据库和表

  1. DROP TABLE IF EXISTS user;
  2. CREATE TABLE user
  3. (
  4. id BIGINT(20) NOT NULL COMMENT '主键ID',
  5. name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
  6. age INT(11) NULL DEFAULT NULL COMMENT '年龄',
  7. email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
  8. PRIMARY KEY (id)
  9. );
  10. DELETE FROM user;
  11. INSERT INTO user (id, name, age, email) VALUES
  12. (1, 'Jone', 18, 'test1@baomidou.com'),
  13. (2, 'Jack', 20, 'test2@baomidou.com'),
  14. (3, 'Tom', 28, 'test3@baomidou.com'),
  15. (4, 'Sandy', 21, 'test4@baomidou.com'),
  16. (5, 'Billie', 24, 'test5@baomidou.com');

(2)添加依赖

  1. <!--mp的依赖-->
  2. <dependency>
  3. <groupId>com.baomidou</groupId>
  4. <artifactId>mybatis-plus-boot-starter</artifactId>
  5. <version>3.5.1</version>
  6. </dependency>

(3)创建实体类

  1. package com.wzh.entity;
  2. import com.baomidou.mybatisplus.annotation.TableField;
  3. import com.baomidou.mybatisplus.annotation.TableId;
  4. import com.baomidou.mybatisplus.annotation.TableName;
  5. import lombok.Data;
  6. /**
  7. * @ProjectName: springboot-mp
  8. * @Package: com.wzh.entity
  9. * @ClassName: User
  10. * @Author: 王振华
  11. * @Description:
  12. * @Date: 2022/7/25 19:22
  13. * @Version: 1.0
  14. */
  15. @Data
  16. //如果表明和实体类名不一致,
  17. @TableName(value = "user")
  18. public class User {
  19. //标记该属性为主键。value:标记列名和属性名的对应
  20. @TableId(value = "id")
  21. private Integer id;
  22. //如果属性名和列名不一样
  23. @TableField(value = "name")
  24. private String name;
  25. private Integer age;
  26. private String email;
  27. }

(4)mapper操作层

  1. package com.wzh.mapper;
  2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  3. import com.wzh.entity.User;
  4. //BaseMapper接口中提供了单表的所有操作,连表不行,需要自己实现
  5. // @Mapper
  6. public interface UserMapper extends BaseMapper<User> {
  7. }

(5)测试

  1. package com.wzh;
  2. import com.wzh.entity.User;
  3. import com.wzh.mapper.UserMapper;
  4. import org.junit.jupiter.api.Test;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.boot.test.context.SpringBootTest;
  7. @SpringBootTest
  8. class SpringbootMpApplicationTests {
  9. @Autowired
  10. private UserMapper userMapper;
  11. @Test
  12. void contextLoads() {
  13. User user = userMapper.selectById(2);
  14. System.out.println(user);
  15. }
  16. }

1.mybatis-plus不需要引入数据源jdbc jar包,因为它默认集成了jdbc 

2.mybatis-plus不需要配置映射路径,因为有默认配置

 3.逻辑列可以在application.properties自定义配置,有默认配置 0表示未删除 1表示删除

  1. # 配置日志
  2. mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
  3. # 配置逻辑删除
  4. mybatis-plus.global-config.db-config.logic-delete-value=1
  5. mybatis-plus.global-config.db-config.logic-not-delete-value=0

4.mp-增加


       主键mp提供相应的生成策略:
         AUTO(0),递增策略,如果使用该策略必须要求数据表的列也是递增。
         NONE(1),没有策略,必须人为的输入id值
         INPUT(2),没有策略,必须人为的输入id值
         ASSIGN_ID(3), 随机生成一个Long类型的值。该值一定是唯一。而且每次生成都不会相同。算法:雪花算法。 适合分布式主键。
         ASSIGN_UUID(4); 随机产生一个String类型的值。该值也是唯一的。
     

  1. @Test
  2. public void testInsert(){
  3. User user = new User();
  4. user.setName("李四");
  5. user.setAge(22);
  6. user.setEmail("12051256@qq.com");
  7. System.out.println("添加前:==="+user);
  8. int row = userMapper.insert(user);
  9. System.out.println("添加后:==="+user);
  10. }

5.mp-删除


     *  实际开发中: 我们的删除可能是逻辑删除所谓的逻辑删除就是修改功能把某个列修改以删除的状态值
     *  只对自动注入的 sql 起效:
             * 插入: 不作限制---
             * 查找: 追加 where 条件过滤掉已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
             * 更新: 追加 where 条件防止更新到已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
             * 删除: 转变为 更新
     * (1)增加一个逻辑字段: isdeleted  0表示未删除 1表示删除.
     * (2)实体类上的字段isdeleted上添加   @TableLogic.
     

(1)添加列 

(2)实体类添加属性并添加注解@TableLogic 

(3)测试 

  1. @Test
  2. public void testDelete(){
  3. //根据主键删除
  4. int i = userMapper.deleteById(1);
  5. System.out.println(i);
  6. }

6.mp-修改

  *   自动填充功能:
     *     在阿里规则中我们的每一张表必须具备的三个字段 id,create_time,update_time.
     *     这两个字段要不要自己添加。
     *
     *    (1)在需要自动填充属性上@TableField(fill=”“)
     *    (2)创建mp自动填充类

 (1)user表添加列gmt_created,gmt_updated

(2)user实体类添加属性

(3)自定义实现类 MyMetaObjectHandler

  1. package com.wzh.config;
  2. import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.apache.ibatis.reflection.MetaObject;
  5. import org.springframework.stereotype.Component;
  6. import java.time.LocalDateTime;
  7. @Slf4j
  8. @Component
  9. public class MyMetaObjectHandler implements MetaObjectHandler {
  10. //当添加时自动填充的值
  11. @Override
  12. public void insertFill(MetaObject metaObject) {
  13. log.info("start insert fill ....");
  14. //this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
  15. // 切记这里是表的列名 不是实体类的属性名
  16. this.strictInsertFill(metaObject, "gmtCreated", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
  17. this.strictInsertFill(metaObject, "isdeleted", () -> 0, Integer.class);
  18. // 或者
  19. //this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
  20. }
  21. //当修改时自动填充的值
  22. @Override
  23. public void updateFill(MetaObject metaObject) {
  24. log.info("start update fill ....");
  25. //this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)
  26. // 或者
  27. this.strictUpdateFill(metaObject, "gmtUpdated", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
  28. // 或者
  29. //this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
  30. }
  31. }

列名如果是 如is_deleted格式的,这里会自动转换驼峰命名isDeleted,所以这里用驼峰命名

(4)测试

  1. @Test
  2. public void testUpdate(){
  3. User user = new User();
  4. user.setId(2L);
  5. user.setName("张学友");
  6. //根据主键进行修改
  7. int i = userMapper.updateById(user);
  8. System.out.println(i);
  9. }

7.mp-查询

7.1.根据主键查询

  1. @Test
  2. public void testSelectById(){
  3. User user = userMapper.selectById(2);
  4. System.out.println(user);
  5. }

7.2.根据各种条件查询

Wrapper:封装了关于查询的各种条件方法。

有三个子类最常用: QueryWrapper查询条件  UpdateWrapper修改条件  LambdaQueryWrapper查询使用lambda表达式条件

  1. @Test
  2. public void testSelectByCondition(){
  3. QueryWrapper<User> wrapper=new QueryWrapper<>();
  4. wrapper.between("age", 15, 25); //age在15-25
  5. wrapper.select("name","age"); //查询name,age这两列
  6. //wrapper.or(); //默认中间都是and连接
  7. wrapper.like("name","a"); //name like %a%
  8. System.out.println(userMapper.selectList(wrapper));
  9. }

7.3.根据条件查询一条记录

  1. @Test
  2. public void testSelectOne(){
  3. QueryWrapper<User> wrapper = new QueryWrapper<>();
  4. wrapper.eq("name","李四");
  5. wrapper.gt("age",15); //age大于15
  6. wrapper.lt("age",30); //age小于30
  7. //wrapper.ge("age",20); age大于等于20
  8. //wrapper.le("age",30); age小于等于30
  9. //String sqlSelect = wrapper.getSqlSelect(); //要查询的字段列
  10. User user = userMapper.selectOne(wrapper);
  11. System.out.println(user);
  12. }

7.4 分页查询

  (1)添加分页拦截器

  1. package com.wzh.config;
  2. import com.baomidou.mybatisplus.annotation.DbType;
  3. import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
  4. import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
  5. import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
  6. import org.mybatis.spring.annotation.MapperScan;
  7. import org.springframework.context.annotation.Bean;
  8. import org.springframework.context.annotation.Configuration;
  9. @Configuration
  10. public class MybatisPlusConfig {
  11. /**
  12. * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
  13. */
  14. @Bean
  15. public MybatisPlusInterceptor mybatisPlusInterceptor() {
  16. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  17. interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); //数据库类型
  18. return interceptor;
  19. }
  20. }

 (2)调用分页方法

  1. @Test
  2. public void testPage(){
  3. //P page, 分页对象 Page
  4. // @Param("ew") Wrapper<T> queryWrapper
  5. IPage<User> page = new Page<>(1,5);
  6. QueryWrapper<User> wrapper = new QueryWrapper<>();
  7. wrapper.eq("age",22);
  8. IPage<User> page1 = userMapper.selectPage(page, wrapper);//把查询的结果自动封装到Page对象中
  9. System.out.println("总页码:"+page.getPages());
  10. System.out.println("总条数:"+page.getTotal());
  11. System.out.println("当前页记录:"+page.getRecords());
  12. }

7.5 联表查询也使用mp的分页

(1)实体类添加对象属性并添加注解@TableField(exist = false),并在user表中添加连表列did

 

 (2)创建实体类Dept 

  1. @Data
  2. @TableName(value = "tb_dept")
  3. public class Dept {
  4. @TableId
  5. private Integer id;
  6. private String name;
  7. private String imgUrl;
  8. }

(3)UserMapper写连表方法(根据单表查询的分页方法模仿写)

  1. package com.wzh.mapper;
  2. import com.baomidou.mybatisplus.core.conditions.Wrapper;
  3. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  4. import com.baomidou.mybatisplus.core.metadata.IPage;
  5. import com.wzh.entity.User;
  6. import org.apache.ibatis.annotations.Param;
  7. /**
  8. * @ProjectName: springboot-mp
  9. * @Package: com.wzh.mapper
  10. * @ClassName: UserMapper
  11. * @Author: 王振华
  12. * @Description:
  13. * @Date: 2022/7/25 20:43
  14. * @Version: 1.0
  15. */
  16. //BaseMapper接口中提供了单表的所有操作,连表不行,需要自己实现
  17. // @Mapper
  18. public interface UserMapper extends BaseMapper<User> {
  19. //连表查询
  20. IPage<User> selectUserWithDept(IPage<User> page, @Param("ew") Wrapper<User> wrapper);
  21. }

(4)UserMapper.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="com.wzh.mapper.UserMapper">
  4. <resultMap id="baseMaper" type="com.wzh.entity.User" autoMapping="true">
  5. <id property="id" column="uid"/>
  6. <result property="name" column="uname"/>
  7. <association property="dept" javaType="com.wzh.entity.Dept" autoMapping="true">
  8. <id column="did" property="id"/>
  9. <result column="dname" property="name"/>
  10. </association>
  11. </resultMap>
  12. <sql id="selectCondition">
  13. u.id uid,u.name uname,age,email,d.id did,d.name dname,imgUrl
  14. </sql>
  15. <select id="selectUserWithDept" resultMap="baseMaper">
  16. select <include refid="selectCondition"/> from user u join tb_dept d on u.did=d.id where u.isdeleted = 0
  17. <if test="ew!=null">
  18. and ${ew.sqlSegment}
  19. </if>
  20. </select>
  21. </mapper>

(5)测试

  1. @Test
  2. public void testPage() {
  3. //P page, 分页对象 Page
  4. // @Param("ew") Wrapper<T> queryWrapper
  5. IPage<User> page = new Page<>(1, 5);
  6. QueryWrapper<User> wrapper = new QueryWrapper<>();
  7. wrapper.eq("age", 22);
  8. IPage<User> page1 = userMapper.selectPage(page, wrapper);//把查询的结果自动封装到Page对象中
  9. System.out.println("总页码:" + page.getPages());
  10. System.out.println("总条数:" + page.getTotal());
  11. System.out.println("当前页记录:" + page.getRecords());
  12. }

 ${ew.sqlSegment}必须用${},不能用#{}

8. mp的代码生成器

8.1.旧版本

(1)引入依赖

  1. <dependency>
  2. <groupId>com.baomidou</groupId>
  3. <artifactId>mybatis-plus-generator</artifactId>
  4. <version>3.4.1</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.apache.velocity</groupId>
  8. <artifactId>velocity-engine-core</artifactId>
  9. <version>2.3</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.freemarker</groupId>
  13. <artifactId>freemarker</artifactId>
  14. <version>2.3.30</version>
  15. </dependency>

(2)创建类并配置代码生成器

  1. import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
  2. import com.baomidou.mybatisplus.core.toolkit.StringPool;
  3. import com.baomidou.mybatisplus.generator.AutoGenerator;
  4. import com.baomidou.mybatisplus.generator.InjectionConfig;
  5. import com.baomidou.mybatisplus.generator.config.*;
  6. import com.baomidou.mybatisplus.generator.config.po.TableInfo;
  7. import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
  8. import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
  9. import java.util.ArrayList;
  10. import java.util.List;
  11. // 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
  12. public class CodeGenerator {
  13. public static void main(String[] args) {
  14. // 代码生成器
  15. AutoGenerator mpg = new AutoGenerator();
  16. // 全局配置
  17. GlobalConfig gc = new GlobalConfig();
  18. String projectPath = System.getProperty("user.dir");
  19. gc.setOutputDir(projectPath + "/src/main/java");
  20. gc.setAuthor("wzh");
  21. gc.setOpen(false);
  22. gc.setSwagger2(true); //实体属性 Swagger2 注解
  23. mpg.setGlobalConfig(gc);
  24. // 数据源配置
  25. DataSourceConfig dsc = new DataSourceConfig();
  26. dsc.setUrl("jdbc:mysql://localhost:3306/mycc?serverTimezone=Asia/Shanghai");
  27. // dsc.setSchemaName("public");
  28. dsc.setDriverName("com.mysql.cj.jdbc.Driver");
  29. dsc.setUsername("root");
  30. dsc.setPassword("123456");
  31. mpg.setDataSource(dsc);
  32. // 包配置
  33. PackageConfig pc = new PackageConfig();
  34. pc.setModuleName(("system"));
  35. pc.setParent("com.wzh");
  36. mpg.setPackageInfo(pc);
  37. // 自定义配置
  38. InjectionConfig cfg = new InjectionConfig() {
  39. @Override
  40. public void initMap() {
  41. // to do nothing
  42. }
  43. };
  44. // 如果模板引擎是 freemarker
  45. String templatePath = "/templates/mapper.xml.ftl";
  46. // 如果模板引擎是 velocity
  47. // String templatePath = "/templates/mapper.xml.vm";
  48. // 自定义输出配置
  49. List<FileOutConfig> focList = new ArrayList<>();
  50. // 自定义配置会被优先输出
  51. focList.add(new FileOutConfig(templatePath) {
  52. @Override
  53. public String outputFile(TableInfo tableInfo) {
  54. // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
  55. return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
  56. + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
  57. }
  58. });
  59. /*
  60. cfg.setFileCreate(new IFileCreate() {
  61. @Override
  62. public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
  63. // 判断自定义文件夹是否需要创建
  64. checkDir("调用默认方法创建的目录,自定义目录用");
  65. if (fileType == FileType.MAPPER) {
  66. // 已经生成 mapper 文件判断存在,不想重新生成返回 false
  67. return !new File(filePath).exists();
  68. }
  69. // 允许生成模板文件
  70. return true;
  71. }
  72. });
  73. */
  74. cfg.setFileOutConfigList(focList);
  75. mpg.setCfg(cfg);
  76. // 配置模板
  77. TemplateConfig templateConfig = new TemplateConfig();
  78. // 配置自定义输出模板
  79. //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
  80. // templateConfig.setEntity("templates/entity2.java");
  81. // templateConfig.setService();
  82. // templateConfig.setController();
  83. templateConfig.setXml(null);
  84. mpg.setTemplate(templateConfig);
  85. // 策略配置
  86. StrategyConfig strategy = new StrategyConfig();
  87. strategy.setNaming(NamingStrategy.underline_to_camel);
  88. strategy.setColumnNaming(NamingStrategy.underline_to_camel);
  89. strategy.setEntityLombokModel(true);
  90. strategy.setRestControllerStyle(true);
  91. // 公共父类
  92. // 写于父类中的公共字段
  93. strategy.setTablePrefix("tb_");
  94. strategy.setControllerMappingHyphenStyle(true);
  95. mpg.setStrategy(strategy);
  96. mpg.setTemplateEngine(new FreemarkerTemplateEngine());
  97. mpg.execute();
  98. }
  99. }

8.2.新版本

仅适用 3.5.1 以上版本,对历史版本的不兼容

(1)添加依赖

  1. <dependency>
  2. <groupId>com.baomidou</groupId>
  3. <artifactId>mybatis-plus-generator</artifactId>
  4. <version>3.5.2</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.freemarker</groupId>
  8. <artifactId>freemarker</artifactId>
  9. <version>2.3.31</version>
  10. </dependency>

(2)创建类并配置代码生成器

  1. package com.wzh;
  2. import com.baomidou.mybatisplus.generator.FastAutoGenerator;
  3. import com.baomidou.mybatisplus.generator.config.OutputFile;
  4. import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
  5. import java.util.Collections;
  6. /**
  7. * @ProjectName: springboot-mp
  8. * @Package: com.wzh
  9. * @ClassName: CodeGeneratorNew
  10. * @Author: 王振华
  11. * @Description:
  12. * @Date: 2022/7/26 12:28
  13. * @Version: 1.0
  14. */
  15. public class CodeGeneratorNew {
  16. public static void main(String[] args) {
  17. FastAutoGenerator.create("jdbc:mysql://localhost:3306/mycc?serverTimezone=Asia/Shanghai", "root", "123456")
  18. .globalConfig(builder -> {
  19. builder.author("王振华") // 设置作者
  20. .enableSwagger() // 开启 swagger 模式
  21. .fileOverride() // 覆盖已生成文件
  22. .outputDir(".\\src\\main\\java\\"); // 指定输出目录
  23. })
  24. .packageConfig(builder -> {
  25. builder.parent("com.wzh") // 设置父包名
  26. .moduleName("system2") // 设置父包模块名
  27. .pathInfo(Collections.singletonMap(OutputFile.xml, ".\\src\\main\\resources\\mapper")); // 设置mapperXml生成路径
  28. })
  29. .strategyConfig(builder -> {
  30. builder.addInclude("user") // 设置需要生成的表名
  31. .addTablePrefix("t_", "c_"); // 设置过滤表前缀
  32. })
  33. .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
  34. .execute();
  35. }
  36. }

MyBatis-Plus——代码自动生成器_一心同学的博客-CSDN博客_mybatisplus代码生成器https://blog.csdn.net/Huang_ZX_259/article/details/122540801

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/665638
推荐阅读
相关标签
  

闽ICP备14008679号