为了账号安全,请及时绑定邮箱和手机立即绑定

MyBatisPlus资料:新手入门与常用操作详解

概述

MyBatisPlus是一个强大的MyBatis增强工具,提供了许多开箱即用的功能,如CRUD增强、逻辑删除和分页插件等,极大简化了开发人员的工作。本文将详细介绍MyBatisPlus的环境搭建、基本操作以及一些高级特性,帮助开发者更好地理解和使用MyBatisPlus。

MyBatisPlus简介与环境搭建
MyBatisPlus的基本介绍

MyBatisPlus是一个MyBatis的增强工具,它主要在MyBatis的基础上提供了大量开箱即用的功能,以简化开发人员的工作。其主要特性包括:

  1. CRUD增强:简化了基础的增删改查操作。
  2. 逻辑删除:提供逻辑删除功能,减少了物理删除的复杂性。
  3. 自动填充:在实体类中使用注解可以实现创建和更新时的自动填充。
  4. 分页插件:提供了强大的分页功能。
  5. 连接池配置:提供了多种连接池配置选项。
  6. 缓存:支持多种缓存配置。
  7. 条件构造器:支持复杂的查询条件构造。
开发环境的搭建步骤

以下是搭建MyBatisPlus开发环境的步骤:

  1. 创建一个新的Spring Boot项目

    • 使用慕课网提供的教程创建一个新的Spring Boot项目。
    • 确保项目中有Spring Boot和MyBatis的相关依赖。
  2. 添加MyBatisPlus依赖

    • 在项目的pom.xml文件中添加MyBatisPlus的依赖。
    • 示例代码如下:
    <dependency>
       <groupId>com.baomidou</groupId>
       <artifactId>mybatis-plus-boot-starter</artifactId>
       <version>3.4.1</version>
    </dependency>
  3. 配置数据库连接

    • application.propertiesapplication.yml文件中配置数据库连接信息。
    • 示例代码如下:
    spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    spring.datasource.username=root
    spring.datasource.password=root
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
  4. 创建实体类

    • 创建一个代表数据库表的Java实体类。
    • 示例代码如下:
    @Table(name = "user")
    public class User {
       @TableId(value = "id", type = IdType.AUTO)
       private Long id;
       private String name;
       private Integer age;
       private String email;
       // 省略getters和setters
    }
  5. 创建Mapper接口

    • 创建一个继承自BaseMapper的接口,用于定义对用户表的操作。
    • 示例代码如下:
    @Mapper
    public interface UserMapper extends BaseMapper<User> {
    }
  6. 启动项目
    • 启动Spring Boot项目,确保数据库连接成功。
快速入门实例

添加数据

  1. 使用Mapper接口插入数据

    • 通过UserMapper接口中的insert方法插入一条数据。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void insertUser() {
           User user = new User();
           user.setName("张三");
           user.setAge(20);
           user.setEmail("zhangsan@example.com");
           userMapper.insert(user);
       }
    }
  2. 运行结果
    • 查看数据库中的user表,会看到插入的新用户记录。

查询数据

  1. 使用Mapper接口查询数据

    • 通过UserMapper接口中的selectById方法查询指定ID的用户。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void queryUserById() {
           User user = userMapper.selectById(1L);
           System.out.println(user.getName());
       }
    }
  2. 运行结果
    • 控制台将输出查询到的用户名称。

更新数据

  1. 使用Mapper接口更新数据

    • 通过UserMapper接口中的updateById方法更新指定ID的用户。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void updateUser() {
           User user = new User();
           user.setId(1L);
           user.setName("李四");
           user.setAge(22);
           user.setEmail("lisi@example.com");
           userMapper.updateById(user);
       }
    }
  2. 运行结果
    • 查看数据库中的user表,会看到ID为1的用户信息已被更新。

删除数据

  1. 使用Mapper接口删除数据

    • 通过UserMapper接口中的deleteById方法删除指定ID的用户。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void deleteUser() {
           userMapper.deleteById(1L);
       }
    }
  2. 运行结果
    • 查看数据库中的user表,会发现ID为1的用户已经被删除。
基本CRUD操作
增加数据

使用Mapper接口插入数据

  1. 定义实体类

    • 之前已经定义了User实体类,需要确保该类已经包含必要的字段和注解。
  2. 创建Mapper接口

    • 已经定义了UserMapper接口,继承了BaseMapper接口。
  3. 插入数据

    • 通过UserMapper接口中的insert方法插入一条数据。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void insertUser() {
           User user = new User();
           user.setName("王五");
           user.setAge(25);
           user.setEmail("wangwu@example.com");
           userMapper.insert(user);
       }
    }
  4. 运行结果
    • 查看数据库中的user表,会看到新插入的用户记录。

批量插入数据

  1. 定义实体类列表

    • 创建一个User对象列表,每个对象代表一条数据。
  2. 插入数据

    • 通过UserMapper接口中的insertBatch方法批量插入数据。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void insertBatchUser() {
           List<User> users = new ArrayList<>();
           User user1 = new User();
           user1.setName("赵六");
           user1.setAge(28);
           user1.setEmail("zhaoliu@example.com");
           User user2 = new User();
           user2.setName("钱七");
           user2.setAge(30);
           user2.setEmail("qianqi@example.com");
           users.add(user1);
           users.add(user2);
           userMapper.insertBatch(users);
       }
    }
  3. 运行结果
    • 查看数据库中的user表,会看到新插入的两条用户记录。
查询数据

查询单条记录

  1. 定义Mapper接口

    • 通过UserMapper接口中的selectById方法查询单条记录。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void queryUserById() {
           User user = userMapper.selectById(1L);
           if (user != null) {
               System.out.println(user.getName());
           }
       }
    }
  2. 运行结果
    • 控制台将输出查询到的用户名称。

查询多条记录

  1. 定义Mapper接口

    • 通过UserMapper接口中的selectList方法查询多条记录。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void queryUserList() {
           List<User> users = userMapper.selectList(null);
           for (User user : users) {
               System.out.println(user.getName());
           }
       }
    }
  2. 运行结果
    • 控制台将输出查询到的所有用户名称。

条件查询

  1. 定义Mapper接口

    • 通过UserMapper接口中的selectList方法配合条件查询。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void queryUserByCondition() {
           QueryWrapper<User> queryWrapper = new QueryWrapper<>();
           queryWrapper.eq("age", 20);
           List<User> users = userMapper.selectList(queryWrapper);
           for (User user : users) {
               System.out.println(user.getName());
           }
       }
    }
  2. 运行结果
    • 控制台将输出年龄为20的所有用户名称。
更新数据

更新单条记录

  1. 定义实体类

    • 创建一个User对象,设置要更新的字段。
  2. 更新数据

    • 通过UserMapper接口中的updateById方法更新单条记录。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void updateUser() {
           User user = new User();
           user.setId(1L);
           user.setName("张三");
           user.setAge(21);
           userMapper.updateById(user);
       }
    }
  3. 运行结果
    • 查看数据库中的user表,会看到ID为1的用户信息已被更新。

更新多条记录

  1. 定义更新条件

    • 使用update方法配合QueryWrapper进行批量更新。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void batchUpdateUser() {
           QueryWrapper<User> queryWrapper = new QueryWrapper<>();
           queryWrapper.eq("age", 20);
           User user = new User();
           user.setAge(21);
           userMapper.update(user, queryWrapper);
       }
    }
  2. 运行结果
    • 查看数据库中的user表,会看到所有年龄为20的用户信息已被更新。
删除数据

删除单条记录

  1. 定义Mapper接口

    • 通过UserMapper接口中的deleteById方法删除单条记录。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void deleteUser() {
           userMapper.deleteById(1L);
       }
    }
  2. 运行结果
    • 查看数据库中的user表,会发现ID为1的用户已经被删除。

删除多条记录

  1. 定义删除条件

    • 使用delete方法配合QueryWrapper进行批量删除。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void batchDeleteUser() {
           QueryWrapper<User> queryWrapper = new QueryWrapper<>();
           queryWrapper.eq("age", 20);
           userMapper.delete(queryWrapper);
       }
    }
  2. 运行结果
    • 查看数据库中的user表,会发现所有年龄为20的用户已经被删除。
条件构造器与分页插件
使用条件构造器构建复杂查询条件

条件构造器是MyBatisPlus提供的用于构建复杂查询条件的工具。它提供了多种条件组合的方法,使得构建复杂的查询条件变得简单。

定义条件构造器

使用QueryWrapper类来构建查询条件。QueryWrapper提供了一系列的方法来构建各种查询条件。

  1. 基本的条件组合

    • 使用eqnegtlt等方法构建基本的查询条件。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void queryUserByCondition() {
           QueryWrapper<User> queryWrapper = new QueryWrapper<>();
           queryWrapper.eq("name", "张三").and(wrapper -> wrapper.ne("age", 20));
           List<User> users = userMapper.selectList(queryWrapper);
           for (User user : users) {
               System.out.println(user.getName());
           }
       }
    }
  2. 复杂条件组合

    • 使用andor等方法进行复杂的条件组合。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void queryUserByComplexCondition() {
           QueryWrapper<User> queryWrapper = new QueryWrapper<>();
           queryWrapper.eq("name", "张三").and(wrapper -> wrapper.or(wrapper2 -> wrapper2.gt("age", 20).lt("age", 30)));
           List<User> users = userMapper.selectList(queryWrapper);
           for (User user : users) {
               System.out.println(user.getName());
           }
       }
    }
分页插件的基本使用

分页插件是MyBatisPlus提供的一个非常实用的功能。它可以方便地实现分页查询。

开启分页插件

  1. 在配置文件中开启分页插件

    • application.propertiesapplication.yml文件中开启分页插件。
    • 示例代码如下:
    mybatis-plus.plugin.pagination.enabled=true
  2. 配置分页插件

    • 在配置类中配置分页插件。
    • 示例代码如下:
    @Configuration
    public class MyBatisPlusConfig {
       @Bean
       public MybatisPlusInterceptor mybatisPlusInterceptor() {
           MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
           interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
           return interceptor;
       }
    }

分页查询的实例

  1. 定义分页参数

    • 使用Page对象传递分页参数。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void queryUserByPage() {
           Page<User> page = new Page<>(1, 10); // 页码从1开始,每页10条数据
           IPage<User> result = userMapper.selectPage(page, null);
           int totalPages = result.getPages();
           int totalRecords = result.getTotal();
           List<User> userRecords = result.getRecords();
           // 输出结果
           System.out.println("总页数:" + totalPages);
           System.out.println("总记录数:" + totalRecords);
           for (User user : userRecords) {
               System.out.println(user.getName());
           }
       }
    }
  2. 运行结果
    • 查看查询结果,会看到当前页的用户记录列表。
自动填充与逻辑删除
如何使用实体类的注解实现自动填充

自动填充是MyBatisPlus提供的一个非常实用的功能,可以在插入或更新数据时自动填充某些字段。

创建实体类

在实体类中,使用@TableField注解来定义自动填充字段。

  1. 创建实体类

    • 定义一个实体类,并在其字段上添加@TableField注解。
    • 示例代码如下:
    @Table(name = "user")
    public class User {
       @TableId(value = "id", type = IdType.AUTO)
       private Long id;
       private String name;
       private Integer age;
       private String email;
       @TableField(fill = FieldFill.INSERT)
       private LocalDateTime gmtCreate;
       @TableField(fill = FieldFill.INSERT_UPDATE)
       private LocalDateTime gmtModified;
       // 省略getters和setters
    }
  2. 定义自动填充逻辑

    • 创建一个实现MetaObjectHandler接口的类来实现自动填充逻辑。
    • 示例代码如下:
    @Component
    public class MyMetaObjectHandler implements MetaObjectHandler {
       @Override
       public void insertFill(MetaObject metaObject) {
           metaObject.setValue("gmtCreate", LocalDateTime.now());
           metaObject.setValue("gmtModified", LocalDateTime.now());
       }
    
       @Override
       public void updateFill(MetaObject metaObject) {
           metaObject.setValue("gmtModified", LocalDateTime.now());
       }
    }
逻辑删除的原理与配置

逻辑删除是指在删除时并不物理删除数据,而是通过一个字段来标记该数据已被删除。这样可以在需要时恢复数据。

配置逻辑删除

  1. 在实体类中定义逻辑删除字段

    • 使用@TableLogic注解来定义逻辑删除字段。
    • 示例代码如下:
    @Table(name = "user")
    public class User {
       @TableId(value = "id", type = IdType.AUTO)
       private Long id;
       private String name;
       private Integer age;
       private String email;
       @TableField(fill = FieldFill.INSERT)
       private LocalDateTime gmtCreate;
       @TableField(fill = FieldFill.INSERT_UPDATE)
       private LocalDateTime gmtModified;
       @TableLogic
       private Integer deleted;
       // 省略getters和setters
    }
  2. 配置逻辑删除的值

    • 在配置文件中配置逻辑删除的值。
    • 示例代码如下:
    mybatis-plus.global-config.db-config.logic-delete-value=1
    mybatis-plus.global-config.db-config.logic-not-delete-value=0

逻辑删除的使用示例

  1. 删除数据

    • 使用deleteById方法删除数据,实际会将deleted字段设置为逻辑删除的值。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void deleteUser() {
           userMapper.deleteById(1L);
       }
    }
  2. 查询数据

    • 查询时,MyBatisPlus会自动过滤掉逻辑删除的记录。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void queryUserList() {
           List<User> users = userMapper.selectList(null);
           for (User user : users) {
               System.out.println(user.getName());
           }
       }
    }
Lambda表达式与链式操作
Lambda表达式在MyBatisPlus中的使用方法

Lambda表达式使得MyBatisPlus的操作更加简洁。它可以在查询条件中使用,也可以在更新和删除操作中使用。

使用Lambda表达式构建查询条件

  1. 查询单条记录

    • 使用eq方法配合Lambda表达式查询单条记录。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void queryUserById() {
           User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getId, 1L));
           System.out.println(user.getName());
       }
    }
  2. 查询多条记录

    • 使用eq方法配合Lambda表达式查询多条记录。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void queryUserByCondition() {
           List<User> users = userMapper.selectList(new LambdaQueryWrapper<User>().eq(User::getAge, 20));
           for (User user : users) {
               System.out.println(user.getName());
           }
       }
    }

使用Lambda表达式更新数据

  1. 更新单条记录

    • 使用updateById方法配合Lambda表达式更新单条记录。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void updateUser() {
           User user = new User();
           user.setId(1L);
           user.setName("张三");
           userMapper.update(user, new LambdaUpdateWrapper<User>().eq(User::getId, 1L));
       }
    }
  2. 更新多条记录

    • 使用update方法配合Lambda表达式更新多条记录。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void batchUpdateUser() {
           userMapper.update(null, new LambdaUpdateWrapper<User>().eq(User::getAge, 20).set(User::getAge, 21));
       }
    }

使用Lambda表达式删除数据

  1. 删除单条记录

    • 使用deleteById方法配合Lambda表达式删除单条记录。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void deleteUser() {
           userMapper.deleteById(1L);
       }
    }
  2. 删除多条记录

    • 使用delete方法配合Lambda表达式删除多条记录。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void batchDeleteUser() {
           userMapper.delete(new LambdaQueryWrapper<User>().eq(User::getAge, 20));
       }
    }
链式调用的优势与使用示例

链式调用使得代码更加简洁和易读,尤其是在构造复杂的查询条件时。

链式调用的使用示例

  1. 构建复杂的查询条件

    • 使用lambdaQueryWrapper构建复杂的查询条件。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void queryUserByComplexCondition() {
           List<User> users = userMapper.selectList(new LambdaQueryWrapper<User>()
               .eq(User::getName, "张三")
               .gt(User::getAge, 20)
               .or(wrapper -> wrapper.eq(User::getEmail, "zhangsan@example.com"))
           );
           for (User user : users) {
               System.out.println(user.getName());
           }
       }
    }
  2. 链式操作的优势

    • 链式操作使得代码具有更好的可读性和可维护性。
    • 示例代码如下:
    @Service
    public class UserService {
       @Autowired
       private UserMapper userMapper;
    
       public void updateUser() {
           userMapper.update(null, new LambdaUpdateWrapper<User>()
               .eq(User::getId, 1L)
               .set(User::getName, "李四")
               .set(User::getAge, 21)
           );
       }
    }
MyBatisPlus的配置与优化
MyBatisPlus的核心配置项解析

MyBatisPlus提供了丰富的配置项,可以帮助开发人员更好地配置和优化数据库访问。

配置文件中的配置项

  1. 全局配置

    • application.ymlapplication.properties中配置全局配置项。
    • 示例代码如下:
    mybatis-plus.global-config.db-config.id-type=assign_id
    mybatis-plus.global-config.db-config.logic-delete-value=0
    mybatis-plus.global-config.db-config.logic-not-delete-value=1
    mybatis-plus.global-config.db-config.id-type=assign_id
    mybatis-plus.mapper-locations=classpath*:mapper/*Mapper.xml
    mybatis-plus.configuration.useGeneratedKeys=true
    mybatis-plus.configuration.cacheEnabled=true
    mybatis-plus.configuration.defaultSqlDialect=MYSQL
    mybatis-plus.configuration.localCacheScope=STATEMENT
  2. Mapper配置

    • 配置Mapper的扫描路径。
    • 示例代码如下:
    mybatis-plus.mapper-locations=classpath*:mapper/*Mapper.xml
  3. SQL配置

    • 配置SQL的方言、缓存等。
    • 示例代码如下:
    mybatis-plus.configuration.defaultSqlDialect=MYSQL
    mybatis-plus.configuration.cacheEnabled=true
    mybatis-plus.configuration.localCacheScope=STATEMENT

其他配置项

  • MyBatisPlus的拦截器配置

    • 在配置文件中配置MyBatisPlus的拦截器。
    • 示例代码如下:
    mybatis-plus.plugin.pagination.enabled=true
  • MyBatisPlus的缓存配置

    • 配置缓存的属性,例如缓存的级别。
    • 示例代码如下:
    mybatis-plus.configuration.cacheEnabled=true
    mybatis-plus.configuration.localCacheScope=STATEMENT
性能优化的常见手段

性能优化是提高应用性能的重要手段之一。MyBatisPlus提供了多种方式来优化数据库访问性能。

分页插件优化

  • 使用分页插件

    • 分页插件可以减少查询的数据量,提高查询性能。
    • 示例代码如下:
    @Configuration
    public class MyBatisPlusConfig {
      @Bean
      public MybatisPlusInterceptor mybatisPlusInterceptor() {
          MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
          interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
          return interceptor;
      }
    }

SQL优化

  • 优化查询语句

    • 使用索引、减少不必要的列等手段优化查询。
    • 示例代码如下:
    @Service
    public class UserService {
      @Autowired
      private UserMapper userMapper;
    
      public void queryUserByCondition() {
          QueryWrapper<User> queryWrapper = new QueryWrapper<>();
          queryWrapper.select("name", "age").eq("age", 20);
          List<User> users = userMapper.selectList(queryWrapper);
          for (User user : users) {
              System.out.println(user.getName());
          }
      }
    }
  • 减少不必要的查询

    • 通过缓存等方式减少不必要的数据库查询。
    • 示例代码如下:
    @Service
    public class UserService {
      @Autowired
      private UserMapper userMapper;
      @Autowired
      private CacheManager cacheManager;
    
      public User getUserById(Long id) {
          String key = "user_" + id;
          User user = cacheManager.get(key);
          if (user == null) {
              user = userMapper.selectById(id);
              cacheManager.put(key, user);
          }
          return user;
      }
    }
日志配置与异常处理

日志配置

  • 配置日志框架

    • 使用Log4j、Logback等日志框架输出MyBatisPlus的日志。
    • 示例代码如下:
    logging.level.com.baomidou.mybatisplus=DEBUG
    logging.level.cn.dev.base=DEBUG
  • 配置MyBatisPlus日志

    • 在配置文件中配置MyBatisPlus的日志级别。
    • 示例代码如下:
    mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

异常处理

  • 全局异常处理

    • 使用全局异常处理器捕获MyBatisPlus的异常。
    • 示例代码如下:
    @ControllerAdvice
    public class GlobalExceptionHandler {
      @ExceptionHandler(value = Exception.class)
      public ModelAndView handleException(Exception e) {
          ModelAndView modelAndView = new ModelAndView("error");
          modelAndView.addObject("exception", e);
          return modelAndView;
      }
    }
  • 自定义异常处理器

    • 为特定类型的异常编写自定义处理器。
    • 示例代码如下:
    @ControllerAdvice
    public class MyBatisPlusExceptionHandler {
      @ExceptionHandler(value = MybatisPlusException.class)
      public ResponseEntity<String> handleMybatisPlusException(MybatisPlusException e) {
          return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
      }
    }

通过以上配置和优化,可以显著提高MyBatisPlus的性能和稳定性。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消