MybatisPlus——快速入门、注解使用、插件使用、代码生成器

mybatis-plus学习过程笔记

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window) 的增强工具,在mybatis的基础上只做增强不做改变

一、快速开始

1、创建数据库
CREATE DATABASE mybatis_plus;
DROP TABLE IF EXISTS my_user;
CREATE TABLE my_user
(
    id BIGINT(20) NOT NULL COMMENT '主键ID',
    NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
    age INT(11) NULL DEFAULT NULL COMMENT '年龄',
    email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
    PRIMARY KEY (id)
);

INSERT INTO my_user (id, NAME, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
2、创建maven工程导入依赖包
<!--引入spring-starter父工程-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/>
    </parent>

    <dependencies>
        <!--spring-boot 启动类-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.0</version>
        </dependency>
        <!--数据库-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

    </dependencies>
3、添加application.yml配置文件
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis_plus? serverTimezone=GMT%2B8&characterEncoding=utf-8  #mysql8驱动需要添加时区
    driver-class-name: com.mysql.cj.jdbc.Driver #mysql8驱动

#mybatis日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  #数据访问层的xml位置
  mapper-locations: classpath:mappers/*.xml 
4、启动类
/**
 * @Author 李燕茹
 * @create 2022/1/20 13:43
 */
@SpringBootApplication  //启动类注解
@MapperScan("com.xyxy.mapper") //Mapper扫包
public class MybatisPlusApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusApplication.class,args);
    }
}
5、创建实体类
@Data
@TableName("my_user")  //数据库表名和类名不一致时添加注解
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
6、创建接口
//接口继承基类,有很多内置方法
public interface UserMapper extends BaseMapper<User> {

}
7、创建测试类测试Mapper接口
/**
 * @Author 李燕茹
 * @create 2022/1/20 13:47
 */
@SpringBootTest
public class MapperTest {
//    @Autowired  //默认按照类型自动装配,是spring的注解
    @Resource  //默认按照名字装配,找不到对应名称是按照类型装配,是J2EE的注解
    private UserMapper userMapper;

    @Test
    public void testFindAll(){
        //selectList()方法的参数:封装了查询条件
		//null:不加任何查询条件
        List<User> users = userMapper.selectList(null);
        public void testFindAll(){
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}

控制台打印结果:

User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)

二、基本CRUD

(一)通用Mapper

MP中的基本CRUD在内置的BaseMapper中已经实现

1、新增
@Test
public void testInsert(){
    User user = new User();
    user.setName("zhangsan");
    user.setAge(3);
    user.setEmail("zhansgsan@qq.com");
    int insert = userMapper.insert(user);
    System.out.println("返回受影响的行数:"+insert);
}
2、查询
@Test
public void testSelect(){
    //根据id查询结果
    User user = userMapper.selectById(1);
    System.out.println("根据id查询结果:"+user);

    //根据id的集合查找结果集
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3, 4));
    System.out.println("根据ids查询结果集:" +users);

    //根据条件查询
    Map map = new HashMap();
    map.put("name","zhangsan");
    map.put("age",3);
    List<User> userList = userMapper.selectByMap(map);
    System.out.println("根据条件map集合查询:"+userList);
}
3、修改
@Test
public void testUpdate(){
    User user = new User();
    user.setId(1L);
    user.setName("修改");
    //update时生成的SQL是动态语句,将传入的user不为空的数据进行修改
    int update = userMapper.updateById(user);
    System.out.println("受影响的行数:" +update);
}
4、delete
@Test
public void testDelete(){
    int delete = userMapper.deleteById(5);
    System.out.println("受影响的行数:"+delete);
}
(二)通用Service

MP中有接口IService和其实现类ServiceImpl封装了常见的业务层逻辑代码

1、创建service接口
public interface UserService extends IService<User> {
}
2、创建service实现类
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
3、测试查询记录条数
@Test
public void testCount(){
    long count = userService.count();
    System.out.println("数据记录条数:"+count);
}
4、测试批量插入
@Test
public void testSaveBatch(){

    // SQL长度有限制,海量数据插入单条SQL无法实行,
    // 因此MP将批量插入放在了通用Service中实现,而不是通用Mapper
    ArrayList<User> users = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        User user = new User();
        user.setName("Helen" + i);
        user.setAge(10 + i);
        users.add(user);
    }
    userService.saveBatch(users);
}
(三)自定义Mapper
1、写接口方法
public interface UserMapper extends BaseMapper<User> {
    List<User> selectAllByName(String name);
}
2、写xml方法
<select id="selectAllByName" resultType="com.xyxy.pojo.User">
        select * from my_user where name=#{name}
</select>
3、写测试方法
@Test
public void testSelectAllByName(){
    List<User> users = userMapper.selectAllByName("zhangsan");
    System.out.println(users);
}
(四)自定义Service
1、写接口方法
public interface UserService extends IService<User> {
    List<User> listAllByName(String name);
}
2、接口实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Override
    public List<User> listAllByName(String name) {
        // baseMapper对象指向当前业务的mapper对象
        return baseMapper.selectAllByName(name);
    }
}
3、测试方法
@Test
public void testSelectAllByName(){
    List<User> users = userService.listAllByName("zhangsan");
    System.out.println(users);
}

三、常用注解

1、@TableName

标注在实体类上

@TableName("my_user")  //数据库表名
public class User {
2、@TableId

type属性用来定义主键策略

  • **IdType.ASSIGN_ID:**使用基于雪花算法的策略生成数据id
  • 优点:整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率较高。
@TableId(type = IdType.ASSIGN_ID)
private Long id;

注意:当对象的id被明确赋值时,不会使用雪花算法

  • **IdType.AUTO:**使用数据库的自增策略
@TableId(type = IdType.AUTO)
private Long id;

注意:该类型请确保数据库设置了 ID自增 否则无效

  • **全局配置:**要想影响所有实体的配置,可以设置全局主键配置
#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto
3、@TableField

(1)value属性:将数据库字段与实体类属性名对应

(2)自动填充

阿里巴巴的开发手册中建议每个数据库表必须要有create_time 和 update_time字段,我们可以使用自动填充功能维护这两个字段

@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;

实现元对象处理器接口 -> 创建handler包,创建MyMetaObjectHandler类

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject,"createTime", LocalDateTime.class,LocalDateTime.now());
        this.strictInsertFill(metaObject,"updateTime", LocalDateTime.class,LocalDateTime.now());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject,"updateTime",LocalDateTime.class,LocalDateTime.now());
    }
}

测试添加和修改

4、@TableLogic

逻辑删除:只对自动注入的 sql 起效:

  • 插入: 不作限制
  • 查找: 追加 where 条件过滤掉已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
  • 更新: 追加 where 条件防止更新到已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
  • 删除: 转变为 更新

方法一:配置com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig

  • 例: application.yml
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

方法二:添加@TableLogic注解

 @TableLogic
 @TableField(value = "is_delete")
 private Integer isDelete;

测试删除

四、插件

(一)分页插件

1、创建配置类

@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

}

2、测试类

@Test
public void testPage(){
    //创建分页参数
    Page<User> pageParam = new Page<>(1,5);
    Page<User> page = userMapper.selectPage(pageParam, null);
    System.out.println(page.getTotal());//记录条数
    System.out.println(page.getRecords());//数据
}
(二)xml自定义分页

1、编写UserMapper接口

/**
     * 查询 : 根据年龄查询用户列表,分页显示
     * @param page 分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位
     * @param age 年龄
     * @return 分页对象
     */
    IPage<User> selectByPage(Page<?> page,Integer age);

2、xml

<select id="selectByPage" resultType="com.xyxy.pojo.User">
    select * from my_user where age > #{age}
</select>

3、测试类

@Test
public void testPage2(){
    //创建分页参数
    Page<User> pageParam = new Page<>(1,5);
    userMapper.selectByPage(pageParam,18);
    List<User> list = pageParam.getRecords();
    System.out.println(list);//数据
}
(三)乐观锁

1、配置文件

@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }

}

2、加注解

@Version
private Integer version;

五、条件构造器

(一)Wrapper家族

Wrapper : 条件构造抽象类,最顶端父类

AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件

 	QueryWrapper : 查询条件封装

​ UpdateWrapper : Update 条件封装

AbstractLambdaWrapper : 使用Lambda 语法

 	LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper

 	LambdaUpdateWrapper : Lambda 更新封装Wrapper
(二)QuerryWrapper
1、组装查询条件
@Test
public void test1() {
    //查询名字中包含n,年龄大于等于10且小于等于20,email不为空的用户
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper
        .like("name", "m")
        .between("age", 10, 20)
        .isNotNull("email");
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}
2、组装排序条件
@Test
public void test2() {
    //按年龄降序查询用户,如果年龄相同则按id升序排列
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper
        .orderByDesc("age")
        .orderByAsc("age");
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}
3、组装删除条件
@Test
public void test3() {
    //删除email为空的
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.isNull("email");
    int delete = userMapper.delete(queryWrapper);
    System.out.println("成功记录:" +delete);
}
4、条件的优先级
@Test
public void test4() {
    //查询名字中包含n,且(年龄小于18或email为空的用户),并将这些用户的年龄设置为18,
    // 邮箱设置为 user@atguigu.com
    QueryWrapper<User> queryWrapper  =new QueryWrapper<>();
    queryWrapper.like("name","n")
        .and(i -> i.lt("age",18).or().isNull("email"));
    User user = new User();
    user.setAge(18);
    user.setEmail("user@atguigu.com");
    int update = userMapper.update(user, queryWrapper);
    System.out.println("成功记录数:" + update);
}
5、组装select子句
@Test
public void test5() {
    //查询所有用户的用户名和年龄
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.select("name","age");
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}
6、实现子查询
@Test
public void test6() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.inSql("id","select id from my_user where id<3");
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}
(三)UpdateWrapper
@Test
public void test7() {
    
    //组装set子句
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    updateWrapper
        .set("age", 18)
        .set("email", "user@atguigu.com")
        .like("name", "n")
        .and(i -> i.lt("age", 18).or().isNull("email")); //lambda表达式内的逻辑优先运算

    //这里必须要创建User对象,否则无法应用自动填充。如果没有自动填充,可以设置为null
    User user = new User();
    int result = userMapper.update(user, updateWrapper);
    System.out.println(result);
}
(四)Condition

动态组装查询条件

@Test
    public void test8() {
        //查询名字中包含n,年龄大于10且小于20的用户,查询条件来源于用户输入,是可选的
        //定义查询条件,有可能为null(用户未输入)
        String name = null;
        Integer ageBegin = 10;
        Integer ageEnd = 20;

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//        if (StringUtils.isNotBlank(name)){
//            queryWrapper.like("name",name);
//        }
//        if (ageBegin != null){
//            queryWrapper.ge("age",ageBegin);
//        }
//        if (ageEnd != null){
//            queryWrapper.lt("age",ageEnd);
//        }
        queryWrapper
                .like(StringUtils.isNotBlank(name),"name",name)
                .ge(ageBegin != null,"age",ageBegin)
                .lt(ageEnd != null,"age",ageEnd);
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }
(五)LambdaXxxWrapper
LambdaQueryWrapper
@Test
public void test9() {
    //查询名字中包含n,年龄大于10且小于20的用户,查询条件来源于用户输入,是可选的
    //定义查询条件,有可能为null(用户未输入)
    String name = null;
    Integer ageBegin = 10;
    Integer ageEnd = 20;

    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper
        //避免使用字符串,防止运行时出错
        .like(StringUtils.isNotBlank(name),User::getName,name)
        .ge(ageBegin != null,User::getAge,ageBegin)
        .lt(ageEnd != null,User::getAge,ageEnd);
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}
LambdaUpdateWrapper
@Test
public void test10() {
    //查询名字中包含n,且(年龄小于18或email为空的用户),并将这些用户的年龄设置为18,
    // 邮箱设置为 user@atguigu.com
    LambdaUpdateWrapper<User> queryWrapper  =new LambdaUpdateWrapper<>();
    queryWrapper.like(User::getName,"n")
        .and(i -> i.lt(User::getAge,18).or().isNull(User::getEmail));
    User user = new User();
    user.setAge(18);
    user.setEmail("user@atguigu.com");
    int update = userMapper.update(user, queryWrapper);
    System.out.println("成功记录数:" + update);
}

六、代码生成器

(一)3.5.1及以上版本
<!-- mybatis plus代码生成器 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.1</version>
</dependency>

适用3.5.1以上版本

package com.xyxy.blog.utils;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.Collections;

/**
 * @Author 李燕茹
 * @create 2021/12/20 20:14
 * MybatisPlus代码生成器
 */
public class MPGenerator {
    public static void main(String[] args) {
        FastAutoGenerator.create("jdbc:mysql://localhost:3306/blog?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8&autoReconnect=true&useSSL=false&allowMultiQueries=true",
                "root", "123456")
                .globalConfig(builder -> {
                    builder.author("李燕茹") // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .commentDate("yyyy-MM-dd")
                            .outputDir(System.getProperty("user.dir")+"\\src\\main\\java"); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent("com.mp") // 设置父包名
                            .moduleName("blog") // 设置父包模块名
                            .entity("entity")
                            .service("service")
                            .serviceImpl("service.serviceImpl")
                            .controller("controller")
                            .mapper("mapper")
                            .xml("mapper")
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, System.getProperty("user.dir")+"\\src\\main\\resources\\")); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.addInclude("tb_menu") // 设置需要生成的表名
                            .addTablePrefix("tb_") //过滤表明前缀,
                            .serviceBuilder() //service生成策略
                            .formatServiceFileName("%sService")  //service类名,%s适配,根据表明替换
                            .formatServiceImplFileName("%sServiceImpl")  // service实现类
                            .entityBuilder()  //实体类生成策略
                            .enableLombok()  //开启lombok
                            .logicDeleteColumnName("deleted")  //说明逻辑删除是哪个字段
                            .enableTableFieldAnnotation()  // 属性加上说明注解
                            .controllerBuilder()  //controller生成策略
                            .formatFileName("%sController")
                            .enableRestStyle()  //开启RestController
                            .mapperBuilder()
                            .superClass(BaseMapper.class)  //dao层继承父类
                            .formatMapperFileName("%sMapper")
                            .enableMapperAnnotation() //@Mapper注解开启
                            .formatXmlFileName("%sMapper");
                })
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();

    }
}

(二)3.4.1版本
<!--mybatis-plus 代码生成器-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.4.1</version>
</dependency>
<!-- Mybatis Plus 代码生成器模板引擎,  -->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.0</version>
</dependency>
package com.atguigu.srb.core;

public class CodeGenerator {

    @Test
    public void genCode() {

        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("Helen");
        gc.setOpen(false); //生成后是否打开资源管理器
        gc.setServiceName("%sService");	//去掉Service接口的首字母I
        gc.setIdType(IdType.AUTO); //主键策略
        gc.setSwagger2(true);//开启Swagger2模式
        mpg.setGlobalConfig(gc);

        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/srb_core?serverTimezone=GMT%2B8&characterEncoding=utf-8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent("com.atguigu.srb.core");
        pc.setEntity("pojo.entity"); //此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
        mpg.setPackageInfo(pc);

        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略

        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok
        strategy.setLogicDeleteFieldName("is_deleted");//逻辑删除字段名
        strategy.setEntityBooleanColumnRemoveIsPrefix(true);//去掉布尔值的is_前缀(确保tinyint(1))
        strategy.setRestControllerStyle(true); //restful api风格控制器
        mpg.setStrategy(strategy);

        // 6、执行
        mpg.execute();
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值