Skip to content

BaseMapper 基础映射器

RuoYi-Plus 提供的增强型 MyBatis-Plus BaseMapper,扩展了更多实用的数据访问方法。

📋 基础用法

接口继承

java
// 实体类
@Data
@TableName("sys_user")
public class SysUser extends BaseEntity {

    @TableId(value = "user_id")
    private Long userId;

    @TableField("user_name")
    private String userName;

    @TableField("nick_name")
    private String nickName;

    @TableField("email")
    private String email;

    @TableField("status")
    private String status;
}

// Mapper接口
@Mapper
public interface SysUserMapper extends BaseMapperPlus<SysUser, UserVo> {

    // 继承BaseMapperPlus后,自动获得所有增强方法
    // 无需编写基础CRUD方法
}

// VO类
@Data
public class UserVo {
    private Long userId;
    private String userName;
    private String nickName;
    private String email;
    private String status;
    private String statusName; // 字典转换后的状态名称
    private Date createTime;
}

基础操作

java
@Service
public class UserServiceImpl implements IUserService {

    @Resource
    private SysUserMapper userMapper;

    public void basicOperations() {
        // 1. 插入数据
        SysUser user = new SysUser();
        user.setUserName("admin");
        user.setNickName("管理员");
        userMapper.insert(user);

        // 2. 根据ID查询
        SysUser found = userMapper.selectById(1L);

        // 3. 查询VO对象
        UserVo userVo = userMapper.selectVoById(1L);

        // 4. 条件查询
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getStatus, "0");
        List<SysUser> users = userMapper.selectList(wrapper);

        // 5. 查询VO列表
        List<UserVo> userVos = userMapper.selectVoList(wrapper);

        // 6. 分页查询
        Page<UserVo> page = new Page<>(1, 10);
        Page<UserVo> result = userMapper.selectVoPage(page, wrapper);

        // 7. 更新数据
        user.setNickName("超级管理员");
        userMapper.updateById(user);

        // 8. 删除数据
        userMapper.deleteById(1L);
    }
}

🎯 核心方法

BaseMapperPlus 接口

java
/**
 * 自定义 Mapper 接口, 实现 自定义扩展
 */
public interface BaseMapperPlus<T, V> extends BaseMapper<T> {

    /**
     * 根据 entity 条件,查询全部记录(并翻译)
     */
    default List<V> selectVoList(AbstractWrapper<T, String, ?> wrapper) {
        return selectVoList(wrapper, this.currentVoClass());
    }

    /**
     * 根据 entity 条件,查询全部记录(并翻译)
     */
    <C> List<C> selectVoList(AbstractWrapper<T, String, ?> wrapper, Class<C> clazz);

    /**
     * 根据 Wrapper 条件,查询总记录数
     */
    default Long selectVoCount(AbstractWrapper<T, String, ?> wrapper) {
        return selectCount(wrapper);
    }

    /**
     * 根据 ID 查询一条数据(并翻译)
     */
    default V selectVoById(Serializable id) {
        return selectVoById(id, this.currentVoClass());
    }

    /**
     * 根据 ID 查询一条数据(并翻译)
     */
    <C> C selectVoById(Serializable id, Class<C> clazz);

    /**
     * 根据 entity 条件,查询一条记录(并翻译)
     */
    default V selectVoOne(AbstractWrapper<T, String, ?> wrapper) {
        return selectVoOne(wrapper, this.currentVoClass());
    }

    /**
     * 根据 entity 条件,查询一条记录(并翻译)
     */
    <C> C selectVoOne(AbstractWrapper<T, String, ?> wrapper, Class<C> clazz);

    /**
     * 根据 entity 条件,分页查询记录(并翻译)
     */
    default Page<V> selectVoPage(IPage<T> page, AbstractWrapper<T, String, ?> wrapper) {
        return selectVoPage(page, wrapper, this.currentVoClass());
    }

    /**
     * 根据 entity 条件,分页查询记录(并翻译)
     */
    <C> Page<C> selectVoPage(IPage<T> page, AbstractWrapper<T, String, ?> wrapper, Class<C> clazz);

    /**
     * 批量新增数据,含主键返回
     */
    int insertBatch(Collection<T> entityList);

    /**
     * 批量新增或修改数据
     */
    int insertOrUpdateBatch(Collection<T> entityList);

    /**
     * 获取当前VO类型
     */
    Class<V> currentVoClass();
}

实现原理

java
/**
 * 自定义 Mapper 接口实现
 */
public class BaseMapperPlusImpl<T, V> implements BaseMapperPlus<T, V> {

    @Override
    public <C> List<C> selectVoList(AbstractWrapper<T, String, ?> wrapper, Class<C> clazz) {
        List<T> list = this.selectList(wrapper);
        if (CollUtil.isEmpty(list)) {
            return CollUtil.newArrayList();
        }
        return BeanUtil.copyToList(list, clazz);
    }

    @Override
    public <C> C selectVoById(Serializable id, Class<C> clazz) {
        T obj = this.selectById(id);
        if (ObjectUtil.isNull(obj)) {
            return null;
        }
        return BeanUtil.copyProperties(obj, clazz);
    }

    @Override
    public <C> Page<C> selectVoPage(IPage<T> page, AbstractWrapper<T, String, ?> wrapper, Class<C> clazz) {
        Page<T> result = this.selectPage(page, wrapper);
        return PageUtil.build(result, clazz);
    }

    @Override
    public int insertBatch(Collection<T> entityList) {
        // 使用MyBatis-Plus的批量插入
        return mybatisBatch(entityList, (sqlSession, entity) -> {
            String mapperName = this.getClass().getName();
            sqlSession.insert(mapperName + ".insert", entity);
        });
    }

    @Override
    public Class<V> currentVoClass() {
        return (Class<V>) ReflectUtil.getTypeArgument(this.getClass(), 1);
    }
}

🔧 高级功能

条件构造器

java
@Service
public class UserServiceImpl {

    @Resource
    private SysUserMapper userMapper;

    /**
     * 复杂条件查询
     */
    public List<UserVo> complexQuery(UserBo bo) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<SysUser>()
            // 等值查询
            .eq(StringUtils.isNotBlank(bo.getUserName()), SysUser::getUserName, bo.getUserName())
            .eq(StringUtils.isNotBlank(bo.getStatus()), SysUser::getStatus, bo.getStatus())

            // 模糊查询
            .like(StringUtils.isNotBlank(bo.getNickName()), SysUser::getNickName, bo.getNickName())

            // 范围查询
            .between(ObjectUtil.isAllNotEmpty(bo.getBeginTime(), bo.getEndTime()),
                SysUser::getCreateTime, bo.getBeginTime(), bo.getEndTime())

            // 排序
            .orderByDesc(SysUser::getCreateTime)
            .orderByAsc(SysUser::getUserId);

        return userMapper.selectVoList(wrapper);
    }

    /**
     * 动态条件查询
     */
    public List<UserVo> dynamicQuery(UserBo bo) {
        // 使用PlusLambdaQuery构建动态条件
        return userMapper.selectVoList(
            PlusLambdaQuery.lambdaQuery(SysUser.class)
                .like(SysUser::getUserName, bo.getUserName())
                .like(SysUser::getNickName, bo.getNickName())
                .eq(SysUser::getStatus, bo.getStatus())
                .between(SysUser::getCreateTime, bo.getBeginTime(), bo.getEndTime())
                .orderByDesc(SysUser::getCreateTime)
        );
    }
}

批量操作

java
@Service
public class UserServiceImpl {

    @Resource
    private SysUserMapper userMapper;

    /**
     * 批量插入
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchInsert(List<UserBo> boList) {
        List<SysUser> users = BeanUtil.copyToList(boList, SysUser.class);

        // 方式1:使用增强的批量插入
        int result = userMapper.insertBatch(users);

        // 方式2:使用MyBatis-Plus的saveBatch
        // return this.saveBatch(users);

        return result > 0;
    }

    /**
     * 批量更新
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchUpdate(List<UserBo> boList) {
        List<SysUser> users = BeanUtil.copyToList(boList, SysUser.class);

        // 批量更新
        return this.updateBatchById(users);
    }

    /**
     * 批量删除
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchDelete(List<Long> ids, Boolean isValid) {
        if (isValid) {
            // 业务验证
            for (Long id : ids) {
                SysUser user = userMapper.selectById(id);
                if (ObjectUtil.isNull(user)) {
                    throw new ServiceException("用户不存在");
                }
                if ("admin".equals(user.getUserName())) {
                    throw new ServiceException("系统管理员不能删除");
                }
            }
        }

        // 批量删除
        return userMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 批量插入或更新
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchInsertOrUpdate(List<UserBo> boList) {
        List<SysUser> users = BeanUtil.copyToList(boList, SysUser.class);

        // 使用增强的批量插入或更新
        int result = userMapper.insertOrUpdateBatch(users);

        return result > 0;
    }
}

分页查询

java
@Service
public class UserServiceImpl {

    @Resource
    private SysUserMapper userMapper;

    /**
     * 分页查询
     */
    public PageResult<UserVo> queryPageList(UserBo bo, PageQuery pageQuery) {
        // 构建查询条件
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<SysUser>()
            .like(StringUtils.isNotBlank(bo.getUserName()), SysUser::getUserName, bo.getUserName())
            .eq(StringUtils.isNotBlank(bo.getStatus()), SysUser::getStatus, bo.getStatus())
            .orderByDesc(SysUser::getCreateTime);

        // 分页查询并转换为VO
        Page<UserVo> result = userMapper.selectVoPage(pageQuery.build(), wrapper);

        return PageResult.build(result);
    }

    /**
     * 自定义分页查询
     */
    public PageResult<UserVo> customPageQuery(UserBo bo, PageQuery pageQuery) {
        // 构建分页对象
        Page<SysUser> page = pageQuery.build();

        // 设置不查询总数,提升性能
        page.setSearchCount(false);

        // 执行查询
        Page<UserVo> result = userMapper.selectVoPage(page,
            new LambdaQueryWrapper<SysUser>()
                .like(StringUtils.isNotBlank(bo.getUserName()), SysUser::getUserName, bo.getUserName())
                .orderByDesc(SysUser::getCreateTime)
        );

        return PageResult.build(result);
    }
}

🔄 数据转换

VO转换

java
// 自动转换配置
@Configuration
public class MapperConfig {

    /**
     * 自定义类型转换器
     */
    @Bean
    public DefaultConversionService conversionService() {
        DefaultConversionService conversionService = new DefaultConversionService();

        // 添加自定义转换器
        conversionService.addConverter(new StringToDateConverter());
        conversionService.addConverter(new DateToStringConverter());

        return conversionService;
    }
}

// VO转换示例
@Service
public class UserServiceImpl {

    /**
     * 实体转VO(自动字典翻译)
     */
    public UserVo convertToVo(SysUser user) {
        // 基础属性复制
        UserVo vo = BeanUtil.copyProperties(user, UserVo.class);

        // 字典翻译
        vo.setStatusName(DictUtils.getDictLabel("sys_user_status", user.getStatus()));
        vo.setSexName(DictUtils.getDictLabel("sys_user_sex", user.getSex()));

        // 关联数据查询
        if (ObjectUtil.isNotNull(user.getDeptId())) {
            SysDept dept = deptMapper.selectById(user.getDeptId());
            vo.setDeptName(dept.getDeptName());
        }

        return vo;
    }

    /**
     * 批量转换
     */
    public List<UserVo> convertToVoList(List<SysUser> users) {
        if (CollUtil.isEmpty(users)) {
            return CollUtil.newArrayList();
        }

        return users.stream()
            .map(this::convertToVo)
            .collect(Collectors.toList());
    }
}

字典翻译

java
// 字典翻译注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DictTranslate {

    /**
     * 字典类型
     */
    String dictType();

    /**
     * 翻译字段名(默认为当前字段名+Name)
     */
    String targetField() default "";
}

// VO类使用字典翻译
@Data
public class UserVo {

    private Long userId;
    private String userName;

    @DictTranslate(dictType = "sys_user_status")
    private String status;
    private String statusName; // 自动翻译字段

    @DictTranslate(dictType = "sys_user_sex", targetField = "sexLabel")
    private String sex;
    private String sexLabel; // 自定义翻译字段名
}

// 自动翻译处理器
@Component
public class DictTranslateProcessor {

    /**
     * 处理字典翻译
     */
    public <T> T translate(T obj) {
        if (ObjectUtil.isNull(obj)) {
            return obj;
        }

        Class<?> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            DictTranslate annotation = field.getAnnotation(DictTranslate.class);
            if (annotation != null) {
                try {
                    field.setAccessible(true);
                    Object value = field.get(obj);

                    if (ObjectUtil.isNotNull(value)) {
                        String dictLabel = DictUtils.getDictLabel(annotation.dictType(), String.valueOf(value));

                        // 确定目标字段名
                        String targetFieldName = StringUtils.isNotBlank(annotation.targetField())
                            ? annotation.targetField()
                            : field.getName() + "Name";

                        // 设置翻译值
                        Field targetField = clazz.getDeclaredField(targetFieldName);
                        targetField.setAccessible(true);
                        targetField.set(obj, dictLabel);
                    }
                } catch (Exception e) {
                    log.warn("字典翻译失败: {}", e.getMessage());
                }
            }
        }

        return obj;
    }

    /**
     * 批量翻译
     */
    public <T> List<T> translateList(List<T> list) {
        if (CollUtil.isEmpty(list)) {
            return list;
        }

        return list.stream()
            .map(this::translate)
            .collect(Collectors.toList());
    }
}

🔍 性能优化

查询优化

java
@Service
public class UserServiceImpl {

    /**
     * 只查询需要的字段
     */
    public List<UserVo> selectSpecificColumns() {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<SysUser>()
            .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getStatus)
            .eq(SysUser::getStatus, "0");

        return userMapper.selectVoList(wrapper);
    }

    /**
     * 避免N+1查询
     */
    public List<UserVo> avoidN1Query() {
        // 一次性查询所有用户
        List<SysUser> users = userMapper.selectList(null);

        // 一次性查询所有部门
        List<Long> deptIds = users.stream()
            .map(SysUser::getDeptId)
            .filter(ObjectUtil::isNotNull)
            .distinct()
            .collect(Collectors.toList());

        Map<Long, SysDept> deptMap = CollUtil.isNotEmpty(deptIds)
            ? deptMapper.selectBatchIds(deptIds).stream()
                .collect(Collectors.toMap(SysDept::getDeptId, Function.identity()))
            : new HashMap<>();

        // 组装VO
        return users.stream().map(user -> {
            UserVo vo = BeanUtil.copyProperties(user, UserVo.class);
            SysDept dept = deptMap.get(user.getDeptId());
            if (dept != null) {
                vo.setDeptName(dept.getDeptName());
            }
            return vo;
        }).collect(Collectors.toList());
    }

    /**
     * 使用缓存
     */
    @Cacheable(value = "user", key = "#id")
    public UserVo selectUserById(Long id) {
        return userMapper.selectVoById(id);
    }

    /**
     * 流式查询大数据量
     */
    public void processLargeData() {
        userMapper.selectList(new LambdaQueryWrapper<SysUser>()
            .eq(SysUser::getStatus, "0"))
            .stream()
            .forEach(user -> {
                // 处理每个用户
                processUser(user);
            });
    }

    private void processUser(SysUser user) {
        // 用户处理逻辑
    }
}

BaseMapper 为 RuoYi-Plus 提供了强大的数据访问能力,通过增强的方法和自动化转换,大大提升了开发效率和代码质量。