mybaitsPlus 封装的工具类

对mybatisPlus进行封装 实现单查询sql自动拼装

建表语句

create table student
(
    id           bigint auto_increment comment '主键' primary key,
    creator      int                                  null comment '创建用户',
    updator      int                                  null comment '更新用户',
    version      int(5)                               not null comment '乐观锁',
    data_status  tinyint(1) default 1                 null comment '逻辑删除标志位(0删除)',
    created_time datetime   default CURRENT_TIMESTAMP null comment '创建时间',
    updated_time datetime   default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
    name         varchar(128)                         null comment '姓名',
    age          int                                  null comment '年纪',
    birthday     datetime                             null comment '生日'
)
    comment '学生表';

两个比较重要的工具类
MapperUtils.java

package top.fuly.mybatis_plus_swagger.common.sqlbase.utils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import top.fuly.mybatis_plus_swagger.common.sqlbase.bean.CreateBaseDO;
import top.fuly.mybatis_plus_swagger.common.sqlbase.bean.QueryBaseDTO;
import top.fuly.mybatis_plus_swagger.common.sqlbase.exceptions.UtilsException;
import java.util.List;

/**
 * @author Fuly.Zhao
 * @date 2021/5/14/20:33
 */
public class MapperUtils {

    //查总数
    public static <E extends CreateBaseDO> Integer selectDtoCount(BaseMapper<E> mapper) {
        return mapper.selectCount(new QueryWrapper<>());
    }

    //按条件查总数
    public static <E extends CreateBaseDO, Q> Integer selectDtoCount(BaseMapper<E> mapper, Q objDto, Class<E> genericClass) {
        return mapper.selectCount(QueryWrapperUtils.getQueryWrapper(objDto, genericClass));
    }

    //按条件查一个
    public static <E extends CreateBaseDO, Q> E selectDtoOne(BaseMapper<E> mapper, Q objDto, Class<E> genericClass) {
        return mapper.selectOne(QueryWrapperUtils.getQueryWrapper(objDto, genericClass));
    }

    //按条件分页查
    public static <E extends CreateBaseDO, Q extends QueryBaseDTO> Page<E> selectDtoPage(BaseMapper<E> mapper, Q objDto, Class<E> genericClass) {
        return mapper.selectPage(new Page<>(objDto.getCurrent(), objDto.getSize()), QueryWrapperUtils.getQueryWrapper(objDto, genericClass));
    }

    // 查全部
    public static <E extends CreateBaseDO> List<E> selectDtoList(BaseMapper<E> mapper) {
        return mapper.selectList(new QueryWrapper<>());
    }

    public static <E extends CreateBaseDO,Q extends QueryBaseDTO> List<E> selectDtoList(BaseMapper<E> mapper, Q objDto, Class<E> genericClass) {
        Integer current = objDto.getCurrent();
        Integer size = objDto.getSize();
        return mapper.selectList(QueryWrapperUtils.getQueryWrapper(objDto, genericClass).last("limit " + (current-1)*size + " , " + size));
    }

    //根据某一条件查
    public static <E extends CreateBaseDO> List<E> selectPageByColumn(BaseMapper<E> mapper, String column, Object value) {
        return mapper.selectList(new QueryWrapper<E>().eq(column, value));
    }




    //按条件删除
    public static <E extends CreateBaseDO, D> Integer deleteByDto(BaseMapper<E> mapper, D objDto, Class<E> genericClass) {
        return mapper.delete(QueryWrapperUtils.getQueryWrapper(objDto, genericClass));
    }


    //根据id删除
    public static <E extends CreateBaseDO> Integer deleteByDtoId(BaseMapper<E> mapper, Long id) {
        return mapper.deleteById(id);
    }


    // 改  实际是根据id修改的
    public static <E extends CreateBaseDO, U> Integer updateById(BaseMapper<E> mapper, U objDto, Class<E> genericClass) {
        E upEntity = QueryWrapperUtils.getNewInstance(objDto, genericClass);
        if (upEntity.getId() == null) {
            throw new UtilsException("id不合法");
        }
        return mapper.updateById(upEntity);
    }

    public static <E extends CreateBaseDO, U> Integer updateByDto(BaseMapper<E> mapper, U objDto, Class<E> genericClass) {
        return mapper.update(QueryWrapperUtils.getNewInstance(objDto, genericClass),QueryWrapperUtils.getUpdateWrapper(objDto));
    }
}

QueryWrapperUtils.java

package top.fuly.mybatis_plus_swagger.common.sqlbase.utils;


import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import top.fuly.mybatis_plus_swagger.common.sqlbase.annotation.*;
import top.fuly.mybatis_plus_swagger.common.sqlbase.annotation.constantenum.LikeConstantEnum;
import top.fuly.mybatis_plus_swagger.common.sqlbase.annotation.constantenum.OrderConstantEnum;
import top.fuly.mybatis_plus_swagger.common.sqlbase.exceptions.UtilsException;

import java.lang.reflect.Field;
import java.util.List;

/**
 * @author Fuly.Zhao
 * @date 2021/5/13/15:01
 */
@Slf4j
public class QueryWrapperUtils {


    public static <Q, E> QueryWrapper<E> getQueryWrapper(Q objDto, Class<E> genericClass) {
        E targetDo = getNewInstance(objDto, genericClass);
        QueryWrapper<E> queryWrapper = createQueryWrapper(new QueryWrapper<>(targetDo), objDto);
        return queryWrapper;
    }


    public static <Q, E> E getNewInstance(Q objDto, Class<E> genericClass) {
        E target = null;
        try {
            target = ((Class<E>) genericClass).newInstance();
            BeanUtils.copyProperties(objDto, target);
        } catch (ReflectiveOperationException roe) {

        }
        initEntity(target);
        return target;
    }


    @SneakyThrows
    private static <Q, E> QueryWrapper<E> createQueryWrapper(QueryWrapper<E> queryWrapper, Q queryDto)  {
        Class queryDtoClazz = queryDto.getClass();
        Field[] declaredFields = queryDtoClazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            if (declaredField.getAnnotations().length > 0) {
                declaredField.setAccessible(true);
                Object obj = declaredField.get(queryDto);
                if (ObjectUtils.isEmpty(obj) && ObjectUtils.isEmpty(declaredField.getDeclaredAnnotation(OrderBy.class))) {
                    return queryWrapper;
                }
                if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(Ge.class))) {
                    ge(queryWrapper, declaredField, obj);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(Gt.class))) {
                    gt(queryWrapper, declaredField, obj);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(Le.class))) {
                    le(queryWrapper, declaredField, obj);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(Lt.class))) {
                    lt(queryWrapper, declaredField, obj);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(In.class))) {
                    in(queryWrapper, declaredField, obj);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(Like.class))) {
                    like(queryWrapper, declaredField, obj);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(Not.class))) {
                    not(queryWrapper, declaredField, obj);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(OrderBy.class))) {
                    order(queryWrapper, declaredField);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(NotIn.class))) {
                    notIn(queryWrapper, declaredField,obj);
                }
            }
        }
        return queryWrapper;
    }

    @SneakyThrows
    private static <E> void initEntity(E targetDo) {
        Class<?> aClass = targetDo.getClass();
        do {
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                declaredField.setAccessible(true);
                Object object = declaredField.get(targetDo);
                //为了过滤 ""
                if (object != null &&
                        ObjectUtils.isEmpty(declaredField.get(targetDo))
                        && (declaredField.getDeclaredAnnotation(TableField.class) == null)) {
                    declaredField.set(targetDo, null);
                }
            }
            aClass = aClass.getSuperclass();
        } while (aClass != Object.class);
    }



    private static String getXiaHuaXian(String str) {
        StringBuilder sb = new StringBuilder();
        if (str.length() < 3) {
            sb.append(str.toLowerCase());
        } else {
            for (int i = 0; i < str.length(); i++) {
                if (Character.isUpperCase(str.charAt(i))) {
                    sb.append("_").append(Character.toLowerCase(str.charAt(i)));
                } else {
                    sb.append(str.charAt(i));
                }
            }
        }
        return sb.toString();
    }

    //大于等于
    @SneakyThrows
    private static <E> QueryWrapper<E> ge(QueryWrapper<E> queryWrapper, Field declaredField, Object obj) {
        Ge Ge = declaredField.getDeclaredAnnotation(Ge.class);
        String fieldName = Ge.fieldName();
        if (ObjectUtils.isNotEmpty(fieldName)) {
            queryWrapper.ge(getXiaHuaXian(fieldName), obj);
        }
        return queryWrapper;
    }

    @SneakyThrows
    private static <E> QueryWrapper<E> gt(QueryWrapper<E> queryWrapper, Field declaredField, Object obj) {
        Gt Gt = declaredField.getDeclaredAnnotation(Gt.class);
        String fieldName = Gt.fieldName();
        queryWrapper.gt(getXiaHuaXian(fieldName), obj);
        return queryWrapper;
    }

    @SneakyThrows
    private static <E> QueryWrapper<E> in(QueryWrapper<E> queryWrapper, Field declaredField, Object obj) {
        In In = declaredField.getDeclaredAnnotation(In.class);
        String fieldName = In.fieldName();
        if (ObjectUtils.isEmpty(fieldName)) {
            return queryWrapper;
        }
        if (obj.getClass().isArray()) {
            Object[] objArr = (Object[]) obj;
            queryWrapper.in(getXiaHuaXian(fieldName), objArr);
        } else if (obj instanceof List) {
            List objList = (List) obj;
            queryWrapper.in(getXiaHuaXian(fieldName), objList);
        }
        return queryWrapper;
    }

    @SneakyThrows
    private static <E> QueryWrapper<E> notIn(QueryWrapper<E> queryWrapper, Field declaredField, Object obj) {
        NotIn notIn = declaredField.getDeclaredAnnotation(NotIn.class);
        String fieldName = notIn.fieldName();
        if (ObjectUtils.isEmpty(fieldName)) {
            return queryWrapper;
        }
        if (obj.getClass().isArray()) {
            Object[] objArr = (Object[]) obj;
            queryWrapper.notIn(getXiaHuaXian(fieldName), objArr);
        } else if (obj instanceof List) {
            List objList = (List) obj;
            queryWrapper.notIn(getXiaHuaXian(fieldName), objList);
        }
        return queryWrapper;
    }


    @SneakyThrows
    private static <E> QueryWrapper<E> le(QueryWrapper<E> queryWrapper, Field declaredField, Object obj) {
        Le Le = declaredField.getDeclaredAnnotation(Le.class);
        String fieldName = Le.fieldName();
        if (ObjectUtils.isNotEmpty(fieldName)) {
            queryWrapper.le(getXiaHuaXian(fieldName), obj);
        }
        return queryWrapper;
    }

    @SneakyThrows
    private static <E> QueryWrapper<E> like(QueryWrapper<E> queryWrapper, Field declaredField, Object obj) {
        Like Like = declaredField.getDeclaredAnnotation(Like.class);
        String fieldName = Like.fieldName();
        if (ObjectUtils.isEmpty(fieldName)) {
            return queryWrapper;
        }
        LikeConstantEnum LikeConstantEnum = Like.likeType();
        switch (LikeConstantEnum) {
            case LEFT: {
                queryWrapper.likeLeft(getXiaHuaXian(fieldName), obj);
                break;
            }
            case RIGHT: {
                queryWrapper.likeRight(getXiaHuaXian(fieldName), obj);
                break;
            }
            case ALL: {
                queryWrapper.like(getXiaHuaXian(fieldName), obj);
                break;
            }
            default: {
            }
        }
        return queryWrapper;
    }

    @SneakyThrows
    private static <E> QueryWrapper<E> lt(QueryWrapper<E> queryWrapper, Field declaredField, Object obj) {
        Lt Lt = declaredField.getDeclaredAnnotation(Lt.class);
        String fieldName = Lt.fieldName();
        if (ObjectUtils.isNotEmpty(fieldName)) {
            queryWrapper.lt(getXiaHuaXian(fieldName), obj);
        }
        return queryWrapper;
    }

    @SneakyThrows
    private static <E> QueryWrapper<E> not(QueryWrapper<E> queryWrapper, Field declaredField, Object obj) {
        Not Ne = declaredField.getDeclaredAnnotation(Not.class);
        String fieldName = Ne.fieldName();
        if (ObjectUtils.isNotEmpty(fieldName)) {
            queryWrapper.ne(getXiaHuaXian(fieldName), obj);
        }
        return queryWrapper;
    }


    @SneakyThrows
    private static <E> QueryWrapper<E> order(QueryWrapper<E> queryWrapper, Field declaredField) {
        OrderBy Order = declaredField.getDeclaredAnnotation(OrderBy.class);
        OrderConstantEnum OrderConstantEnum = Order.orderType();
        switch (OrderConstantEnum) {
            case ASC: {
                queryWrapper.orderByAsc(getXiaHuaXian(declaredField.getName()));
                break;
            }
            case DESC: {
                queryWrapper.orderByDesc(getXiaHuaXian(declaredField.getName()));
                break;
            }
            default: {
                break;
            }
        }
        return queryWrapper;
    }


    @SneakyThrows
    public static <U, E> QueryWrapper<E> getUpdateWrapper(U updateDto) {
        return createUpdateWrapper(new QueryWrapper<>(), updateDto);
    }

    private static <U, E> QueryWrapper<E> createUpdateWrapper(QueryWrapper<E> updateWrapper, U updateDto) throws IllegalAccessException {
        Class queryDtoClazz = updateDto.getClass();
        Field[] declaredFields = queryDtoClazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            if (declaredField.getAnnotations().length > 0
                    && ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(UpdateBy.class))) {
                declaredField.setAccessible(true);
                Object obj = declaredField.get(updateDto);
                if (ObjectUtils.isEmpty(obj)) {
                    throw new UtilsException("限定条件为空");
                }
                if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(Ge.class))) {
                    ge(updateWrapper, declaredField, obj);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(Gt.class))) {
                    gt(updateWrapper, declaredField, obj);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(Le.class))) {
                    le(updateWrapper, declaredField, obj);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(Lt.class))) {
                    lt(updateWrapper, declaredField, obj);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(In.class))) {
                    in(updateWrapper, declaredField, obj);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(Like.class))) {
                    like(updateWrapper, declaredField, obj);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(Not.class))) {
                    not(updateWrapper, declaredField, obj);
                } else if (ObjectUtils.isNotEmpty(declaredField.getDeclaredAnnotation(NotIn.class))) {
                    notIn(updateWrapper, declaredField,obj);
                } else {
                    updateBy(updateWrapper, declaredField, obj);
                }
            }
        }
        return updateWrapper;
    }

    @SneakyThrows
    private static < E> QueryWrapper<E> updateBy(QueryWrapper<E> queryWrapper, Field declaredField, Object obj) {
        UpdateBy updateBy = declaredField.getDeclaredAnnotation(UpdateBy.class);
        String fieldName = updateBy.fieldName();
        if (ObjectUtils.isNotEmpty(fieldName)) {
            queryWrapper.eq(getXiaHuaXian(fieldName), obj);
        }
        return queryWrapper;
    }
}

service接口是这样的

public interface IStudentService extends IService<StudentEntity> {

    //查总数
    Integer selectDtoCount();

    //按条件查总数
    Integer selectDtoCount(StudentQueryDTO queryDTO);

    //按条件查一个
    StudentEntity selectDtoOne(StudentQueryDTO queryDTO);

    //按条件分页查
    Page<StudentEntity> selectDtoPage(StudentQueryDTO queryDTO);

    // 查全部
    List<StudentEntity> selectDtoList();

    // 按条件查
    List<StudentEntity> selectDtoList(StudentQueryDTO queryDTO);

    //根据某一条件查
    List<StudentEntity> selectPageByColumn(String column, Object value);

    //根据id删除
    Integer deleteByDtoId(long id);

    // 改  实际是根据id修改的
    Integer updateById(StudentUpdateDTO updateDTO);

    //按条件修改
    Integer updateByDto(StudentUpdateDTO updateDTO);

    //增
    Boolean insertDto(StudentAddDTO addDto);

    // 批量新增
    Boolean batchInsertDto(List<StudentAddDTO> addDtoList);

    //按条件删除
    //  Integer deleteByDto(StudentDeleteDTO queryDTO);

}

ServiceImpl实现类是这样的

@Service("studentService")
public class StudentServiceImpl extends ServiceImpl<StudentMapper, StudentEntity> implements IStudentService {

    @Autowired
    private StudentMapper studentMapper;

    /**
     * 查总数
     */
    @Override
    public Integer selectDtoCount() {
        return MapperUtils.selectDtoCount(studentMapper);
    }
    
    /**
     * 按条件查总数
     */
    @Override
    public Integer selectDtoCount(StudentQueryDTO queryDTO) {
        return MapperUtils.selectDtoCount(studentMapper, queryDTO, StudentEntity.class);
    }

    /**
     * 按条件查一个
     */
    @Override
    public StudentEntity selectDtoOne(StudentQueryDTO queryDTO) {
        return MapperUtils.selectDtoOne(studentMapper, queryDTO, StudentEntity.class);
    }
    
    /**
     * 按条件分页查
     */
    @Override
    public Page<StudentEntity> selectDtoPage(StudentQueryDTO queryDTO) {
        return MapperUtils.selectDtoPage(studentMapper, queryDTO, StudentEntity.class);
    }

    /**
     * 查全部
     */
    @Override
    public List<StudentEntity> selectDtoList() {
        return MapperUtils.selectDtoList(studentMapper);
    }
    
    /**
     * 按条件查
     */
    @Override
    public List<StudentEntity> selectDtoList(StudentQueryDTO queryDTO) {
        return MapperUtils.selectDtoList(studentMapper, queryDTO, StudentEntity.class);
    }

    /**
     * 根据某一条件查
     */
    @Override
    public List<StudentEntity> selectPageByColumn(String column, Object value) {
        return MapperUtils.selectPageByColumn(studentMapper, column, value);
    }

    /**
     * 根据id删除
     */
    @Override
    public Integer deleteByDtoId(long id) {
        return MapperUtils.deleteByDtoId(studentMapper, id);
    }

    /**
     * 修改  实际是根据id修改的
     */
    @Override
    public Integer updateById(StudentUpdateDTO updateDTO) {
        return MapperUtils.updateById(studentMapper, updateDTO, StudentEntity.class);
    }

    /**
     * 按条件修改
     */
    @Override
    public Integer updateByDto(StudentUpdateDTO updateDTO) {
        return MapperUtils.updateByDto(studentMapper, updateDTO, StudentEntity.class);
    }
    
    /**
     * 新增
     */
    @Override
    public Boolean insertDto(StudentAddDTO addDto) {
        return save(QueryWrapperUtils.getNewInstance(addDto, StudentEntity.class));
    }
    
    /**
     * 批量新增
     */
    @Override
    public Boolean batchInsertDto(List<StudentAddDTO> addDtoList) {
        List<StudentEntity> plottingInfoEntities = BeanUtils.copyCollectionObjects(addDtoList, StudentEntity::new);
        return saveBatch(plottingInfoEntities);
    }
    
    /**
     * 按条件删除
     */
    //  @Override
    // public Integer deleteByDto(StudentDeleteDTO deleteDTO) {
    //     return MapperUtils.deleteByDto(studentMapper,deleteDTO,StudentEntity.class);
    // }
}

Mapper接口是空的

@Mapper
public interface StudentMapper extends BaseMapper<StudentEntity> {
}

代码地址: https://gitee.com/Fuly1024/study-demo
启动后swagger 访问地址 http://localhost:8200/doc.html#/home

这些东西是可以写使用easycode直接生成的
easycode插件离线安装 https://plugins.jetbrains.com/plugin/10954-easy-code/versions

Mybatis-plus是MyBatis增强工具包,用于简化CRUD操作。该工具包为MyBatis提供了一些高效,有用,即用的功能,使用它可以有效地节省您的开发时间。Mybatis-plus特征与MyBatis完全兼容 启动时自动配置 开箱即用的用于操作数据库的界面 强大而灵活的条件包装器 生成主键的多种策略 Lambda样式的API 全能和高度可定制的代码生成器 自动分页操作 SQL注入防御 支持活动记录 支持可插拔的自定义界面 内置许多有用的扩展Mybatis-plus功能1、单表CURD(简单 + 批量)操作,自动完成(支持 like 比较等查询)。 2、分页插件,Count查询自动或自定义SQL查询。 3、Spring根据不同环境加载不同配置支持(支持typeAliasesPackage通配符扫描)。 【自动生成Entity Mapper Service文件】Mybatis-plus(Mybatis增强工具包) v3.3.2更新日志分页参数提取,单元测试用例修复 达梦数据库代码生成器表过滤支持 微软数据库代码生成器表过滤支持 修复代码生成器属性字段规则错误 SelectById 支持自定义方法名 修复分页插件获取数据库类型问题 Json转换器空值处理 bugfix(mybatis-plus-generator):SQL类型返回错误问题 调整未知方言异常,自动识别url转换小写匹配. fix: 初始化TableInfo中遇到多个字段有@TableId注解时未能抛出异常的问题 SuperController有Class参数的set方法 增加方法StrategyConfig.setSuperServiceImplClass(java.lang.Class<?>). 代码生成器命名策略调整. 扩展分页缓存key值计算. 去除方法推测,直接访问属性字段. 修正枚举处理器类型不匹配比较. 修改表前缀匹配方式 修改在Mybatis全局配置文件中设置分页插件参数不生效问题 修改在Mybatis全局配置文件中设置分页插件参数不生效问 修复PR未指定解析器的时候引发空指针 增加分页插件limit参数配置 修复指定superEntityClass重复生成父类字段问题 无主键的情况无需导入IdType与TableId包 调整生成BaseResultMap格式 支持lombok模式下选择是否进行链式set生成 修复解析器for update错误 过滤PG约束列(只留下主键约束) 增加生成器禁用模板生成 fix(kotlin): 修复动态表名BUG,最大努力替换表名 修复PG约束生成重复属性字段问题 fix(kotlin): 将LambdaUtils中缓存的key改为String 代码生成器增加数据库关键字处理接口 fix github/issues/2454 支持注解可继承 新增 AES 加密数据库用户名密码 优化方法入参泛型,支持更多类型 修复代码生成器开启移除is前缀生成实体缺少包导入 fixed github issues/2470Mybatis-plus截图
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值