Skip to content

MyBatisPlus增强 (mybatis)

模块简介

ruoyi-common-mybatis 是 Ruoyi-Plus-Uniapp 框架的数据访问增强模块,基于 MyBatis-Plus 进行深度定制和功能扩展。该模块提供了强大的查询增强、数据权限控制、分页支持等功能,极大简化了数据访问层的开发。

核心特性

🚀 查询增强 (Query Enhancement)

  • PlusQuery: 字符串列名查询增强器,支持聚合函数和智能条件处理
  • PlusLambdaQuery: Lambda表达式查询增强器,类型安全的查询构建
  • 智能条件处理: 自动过滤 null 值和空集合,避免无效查询条件

🛡️ 数据权限控制 (Data Permission)

  • 注解式权限控制: 通过 @DataPermission 注解轻松实现数据权限
  • 多种权限类型: 支持部门权限、角色权限、用户权限等
  • 动态权限策略: 基于当前用户上下文动态生成权限SQL

📄 分页增强 (Pagination Enhancement)

  • PageQuery: 统一的分页查询参数封装
  • PageResult: 标准化分页结果返回格式
  • 自动分页: 无需手动处理分页逻辑,框架自动注入分页参数

🏗️ 三层架构支持 (Three-Layer Architecture)

  • IBaseService: 通用服务接口,支持 Entity、BO、VO 三层转换
  • BaseServiceImpl: 基础服务实现类,减少80%样板代码
  • BaseMapperPlus: 增强的Mapper接口,提供更多便捷方法

⚡ 性能优化 (Performance Optimization)

  • 字段自动填充: 创建时间、更新时间、创建人等字段自动填充
  • 数据库监控: 集成数据源监控,实时了解数据库性能
  • SQL注入防护: 内置SQL注入检测和防护机制

模块架构

text
ruoyi-common-mybatis/
├── annotation/              # 注解定义
│   ├── DataPermission      # 数据权限注解
│   └── DataColumn          # 数据列权限注解
├── aspect/                 # 切面处理
│   └── DataPermissionAspect # 数据权限切面
├── config/                 # 配置类
│   ├── MybatisPlusConfig   # MyBatis-Plus配置
│   └── MyBatisDataSourceMonitor # 数据源监控
├── core/                   # 核心组件
│   ├── domain/             # 领域模型
│   │   ├── BaseEntity      # 基础实体类
│   │   ├── PageQuery       # 分页查询参数
│   │   └── PageResult      # 分页结果封装
│   ├── mapper/             # Mapper接口
│   │   └── BaseMapperPlus  # 增强Mapper基类
│   ├── query/              # 查询增强
│   │   ├── PlusQuery       # 字符串查询增强
│   │   └── PlusLambdaQuery # Lambda查询增强
│   └── service/            # 服务接口
│       ├── IBaseService    # 基础服务接口
│       └── impl/
│           └── BaseServiceImpl # 基础服务实现
├── enums/                  # 枚举定义
│   ├── DataBaseType        # 数据库类型
│   └── DataScopeType       # 数据权限类型
├── handler/                # 处理器
│   ├── InjectionMetaObjectHandler    # 字段自动填充
│   ├── PlusDataPermissionHandler     # 数据权限处理
│   ├── PlusPostInitTableInfoHandler  # 表信息初始化
│   └── MybatisExceptionHandler       # 异常处理
├── helper/                 # 辅助工具
│   ├── DataBaseHelper      # 数据库工具
│   └── DataPermissionHelper # 数据权限工具
└── interceptor/            # 拦截器
    └── PlusDataPermissionInterceptor # 数据权限拦截器

核心组件详解

1. 查询增强器 (Query Enhancement)

PlusQuery - 字符串列名查询

java
// 基础查询
PlusQuery<User> query = PlusQuery.of(User.class)
    .eq("user_name", "张三")
    .like("nick_name", "admin")
    .gt("create_time", DateUtils.beginOfDay(new Date()));

// 聚合查询支持
PlusQuery<User> query = PlusQuery.of(User.class)
    .select("dept_id")
    .sum("age", "total_age")
    .count("*", "user_count")
    .groupBy("dept_id");

// 智能条件处理 - 自动过滤无效值
PlusQuery<User> query = PlusQuery.of(User.class)
    .eq("status", null)     // 自动忽略
    .in("dept_id", List.of()) // 自动忽略
    .between("age", 18, null); // 自动转为 >= 18

PlusLambdaQuery - Lambda表达式查询

java
// 类型安全的查询构建
PlusLambdaQuery<User> query = PlusLambdaQuery.of(User.class)
    .eq(User::getUserName, "张三")
    .like(User::getNickName, "admin")
    .gt(User::getCreateTime, DateUtils.beginOfDay(new Date()));

// 链式调用,流畅API
List<User> users = PlusLambdaQuery.of(User.class)
    .eq(User::getStatus, "0")
    .orderByDesc(User::getCreateTime)
    .list();

2. 三层架构支持 (Three-Layer Architecture)

IBaseService - 通用服务接口

java
/**
 * 用户服务实现三层架构
 * T: User (Entity) - 数据库实体
 * B: UserBo (Business Object) - 业务对象
 * V: UserVo (View Object) - 视图对象
 */
@Service
public class UserServiceImpl extends BaseServiceImpl<UserMapper, User, UserBo, UserVo> 
    implements IUserService {

    // 继承大量通用方法,无需重复实现
    // - get(id) - 根据ID查询并返回VO
    // - list(bo) - 根据BO条件查询并返回VO列表  
    // - page(bo, pageQuery) - 分页查询
    // - add(bo) - 新增
    // - update(bo) - 更新
    // - delete(id) - 删除
}

使用示例

java
@RestController
public class UserController {

    @Autowired
    private IUserService userService;

    // 分页查询用户
    @PostMapping("/page")
    public R<PageResult<UserVo>> page(@RequestBody UserBo bo, PageQuery pageQuery) {
        PageResult<UserVo> result = userService.page(bo, pageQuery);
        return R.ok(result);
    }

    // 新增用户
    @PostMapping
    public R<Long> add(@Validated(AddGroup.class) @RequestBody UserBo bo) {
        Long userId = userService.add(bo);
        return R.ok(userId);
    }

    // 更新用户
    @PutMapping
    public R<Void> update(@Validated(EditGroup.class) @RequestBody UserBo bo) {
        boolean result = userService.update(bo);
        return R.status(result);
    }

    // 删除用户
    @DeleteMapping("/{id}")
    public R<Void> delete(@PathVariable Long id) {
        boolean result = userService.delete(id);
        return R.status(result);
    }
}

3. 数据权限控制 (Data Permission)

注解式权限控制

java
@Service
public class UserServiceImpl extends BaseServiceImpl<UserMapper, User, UserBo, UserVo> {

    // 部门数据权限 - 只能查看本部门及下级部门数据
    @DataPermission({
        @DataColumn(key = "deptName", value = "dept_id")
    })
    @Override
    public List<UserVo> list(UserBo bo) {
        return super.list(bo);
    }

    // 用户数据权限 - 只能查看自己创建的数据
    @DataPermission({
        @DataColumn(key = "userName", value = "create_by")
    })
    public List<UserVo> listMyCreated(UserBo bo) {
        return super.list(bo);
    }
}

权限配置

java
// 数据权限类型枚举
public enum DataScopeType {
    ALL(1, "全部数据权限"),
    CUSTOM(2, "自定数据权限"), 
    DEPT(3, "部门数据权限"),
    DEPT_AND_CHILD(4, "部门及以下数据权限"),
    SELF(5, "仅本人数据权限");
}

4. 分页增强 (Pagination Enhancement)

PageQuery - 分页查询参数

java
public class UserBo extends PageQuery {
    private String userName;
    private String status;
    // ... 其他查询条件
}

// 控制器中使用
@PostMapping("/page") 
public R<PageResult<UserVo>> page(@RequestBody UserBo bo) {
    // 自动处理分页参数,无需手动设置
    PageResult<UserVo> result = userService.page(bo);
    return R.ok(result);
}

PageResult - 分页结果封装

java
// 标准分页结果格式
{
    "code": 200,
    "msg": "操作成功",
    "data": {
        "records": [...],      // 数据列表
        "total": 100,         // 总记录数
        "size": 10,           // 每页大小
        "current": 1,         // 当前页
        "pages": 10           // 总页数
    }
}

5. BaseEntity - 基础实体类

java
@Data
@EqualsAndHashCode(callSuper = false)
public class User extends BaseEntity {
    
    // 业务字段
    private String userName;
    private String nickName;
    private String status;
    
    // BaseEntity 已包含以下通用字段:
    // - id: 主键ID
    // - createDept: 创建部门  
    // - createBy: 创建者
    // - createTime: 创建时间
    // - updateBy: 更新者
    // - updateTime: 更新时间
    // - remark: 备注
    // - version: 乐观锁版本号
    // - delFlag: 删除标志
    // - tenantId: 租户ID
}

6. 字段自动填充 (Auto Fill)

java
// 字段自动填充配置
@Component
public class InjectionMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        // 新增时自动填充
        this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
        this.strictInsertFill(metaObject, "createBy", String.class, getLoginUserId());
        this.strictInsertFill(metaObject, "createDept", String.class, getLoginDeptId());
        // ...
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // 更新时自动填充
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
        this.strictUpdateFill(metaObject, "updateBy", String.class, getLoginUserId());
        // ...
    }
}

配置与使用

1. 添加依赖

xml
<dependency>
    <groupId>plus.ruoyi</groupId>
    <artifactId>ruoyi-common-mybatis</artifactId>
    <version>${ruoyi.version}</version>
</dependency>

2. 数据库配置

yaml
# application.yml
spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/ruoyi_plus
          username: root
          password: root

3. MyBatis-Plus配置

java
@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        
        // 分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        
        // 数据权限插件
        interceptor.addInnerInterceptor(new DataPermissionInterceptor());
        
        // 乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        
        return interceptor;
    }
}

最佳实践

1. 服务层开发

java
// 继承BaseServiceImpl,获得丰富的通用方法
@Service
public class UserServiceImpl extends BaseServiceImpl<UserMapper, User, UserBo, UserVo> 
    implements IUserService {

    // 只需实现特殊的业务逻辑
    @Override
    public boolean resetPassword(Long userId, String newPassword) {
        return lambdaUpdate()
            .eq(User::getId, userId)
            .set(User::getPassword, SecurityUtils.encryptPassword(newPassword))
            .set(User::getUpdateTime, new Date())
            .update();
    }
    
    // 使用查询增强器构建复杂查询
    @Override
    public List<UserVo> listActiveUsers(String deptId) {
        return of()
            .eq(User::getStatus, "0")
            .eq(User::getDeptId, deptId)
            .orderByDesc(User::getCreateTime)
            .list();
    }
}

2. 复杂查询构建

java
// 使用PlusLambdaQuery构建复杂查询
public List<UserVo> searchUsers(UserSearchBo bo) {
    return PlusLambdaQuery.of(User.class)
        .like(StringUtils.isNotBlank(bo.getUserName()), User::getUserName, bo.getUserName())
        .eq(StringUtils.isNotBlank(bo.getStatus()), User::getStatus, bo.getStatus())
        .in(CollUtil.isNotEmpty(bo.getDeptIds()), User::getDeptId, bo.getDeptIds())
        .between(Objects.nonNull(bo.getStartTime()) && Objects.nonNull(bo.getEndTime()),
                User::getCreateTime, bo.getStartTime(), bo.getEndTime())
        .orderByDesc(User::getCreateTime)
        .list();
}

3. 数据权限使用

java
// 在Service方法上添加数据权限注解
@DataPermission({
    @DataColumn(key = "deptName", value = "dept_id"),
    @DataColumn(key = "userName", value = "create_by")
})
public PageResult<UserVo> page(UserBo bo, PageQuery pageQuery) {
    // 框架会自动在SQL中添加数据权限条件
    return super.page(bo, pageQuery);
}

4. 错误处理

java
// 统一异常处理
@ControllerAdvice
public class MybatisExceptionHandler {

    @ExceptionHandler(DuplicateKeyException.class)
    public R<Void> handleDuplicateKeyException(DuplicateKeyException e) {
        log.error("数据库操作异常", e);
        return R.fail("数据重复,请检查后重试");
    }
    
    @ExceptionHandler(DataAccessException.class)
    public R<Void> handleDataAccessException(DataAccessException e) {
        log.error("数据访问异常", e);
        return R.fail("数据操作失败");
    }
}

注意事项

1. 性能注意事项

  • 大量数据查询: 使用分页查询避免一次性加载过多数据
  • N+1问题: 合理使用关联查询或批量查询解决
  • 索引优化: 确保查询条件字段建立合适的索引

2. 数据权限注意事项

  • 权限范围: 明确每个数据权限注解的作用范围
  • 性能影响: 数据权限会增加SQL复杂度,注意性能影响
  • 权限测试: 充分测试各种权限场景,确保数据安全

3. 事务管理

  • 事务边界: 在Service层方法上合理设置事务边界
  • 异常回滚: 确保异常情况下事务能正确回滚
  • 只读事务: 查询操作使用只读事务提高性能

4. 代码规范

  • 命名规范: 遵循Java命名规范,保持代码可读性
  • 注释规范: 重要方法添加完整的JavaDoc注释
  • 异常处理: 合理处理数据访问异常,提供友好的错误信息

通过使用 ruoyi-common-mybatis 模块,可以显著提高数据访问层的开发效率,减少样板代码,同时提供强大的数据权限控制和查询增强功能。