Skip to content
返回

后端脚手架

脚手架

DigitalHainan Spring 微服务框架脚手架与集成指南,覆盖 POM、缓存、MyBatis、认证、OSS 等核心模块。

概述
后端脚手架

digitalhainan-mybatis ​

本文档用于指导在目标项目中完成 digitalhainan-mybatis 模块集成。

执行顺序:

  1. 先完成「6.1.2 快速集成」的全部步骤(必须)
  2. 根据业务需求,查阅「功能集成决策索引」选择对应路径,逐项实现
  3. 遇到配置问题时参考「6.1.3 配置属性参考」
  4. 出现异常时查阅「6.1.6 常见问题」

代码约定: 所有代码示例均包含完整 import 路径和类声明,可直接用于代码生成。


6.1.1 模块简介 ​

digitalhainan-mybatis(artifactId: mybatis-spring-boot-starter)是数字海南框架的数据层增强组件,基于 MyBatis Plus 封装,提供:

  • BaseMapper — 扩展 MPJBaseMapper,支持批量插入、批量更新、查询所有(含逻辑删除)
  • BaseDO — 基础实体类,自动填充 createTime/updateTime/creator/updator/version/disable
  • 分页工具 — PageUtils,将 PageHelper / MyBatis Plus 分页结果转为 PaginationInfoResDTO
  • 数据权限 — @DataPermission 注解 + SpEL 表达式,支持按用户/部门/角色动态拼接 SQL
  • 多数据源 — 基于 dynamic-datasource,支持 @DS 注解切换数据源
  • 读写分离 — RWSContextHolder 强制走主库控制
  • Druid 连接池 — 慢 SQL 监控 + 钉钉告警
  • 字段加密 — SM4/Base64 字段级加解密 TypeHandler
  • 乐观锁 — @Version 自动维护版本号
  • 自定义 MapperScan — 框架级 Mapper 扫描注解
  • 数据库兼容 — MySQL / 人大金仓 KingBase / 达梦 DM / Oracle / DB2 / H2

Maven 坐标:

xml
<dependency>
    <groupId>cn.com.digitalhainan</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>

前置依赖(项目 pom.xml 中必须已有):

依赖说明
digitalhainan-pom父 POM,统一管理版本号
digitalhainan-common通用基础组件
digitalhainan-tools工具集(SM4 加解密等)
digitalhainan-user(user-spring-boot-starter)用户上下文(数据权限依赖)

当前版本: 3.1.0-SNAPSHOT


6.1.2 快速集成 ​

目标: 完成以下 4 个步骤后,项目即具备 MyBatis Plus 增强能力。

6.1.2.1 确认父 POM 已引入 digitalhainan-pom ​

xml
<parent>
    <groupId>cn.com.digitalhainan</groupId>
    <artifactId>digitalhainan-pom</artifactId>
    <version>3.1.0-SNAPSHOT</version>
</parent>

6.1.2.2 添加依赖 ​

xml
<dependencies>
    <dependency>
        <groupId>cn.com.digitalhainan</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>
</dependencies>

6.1.2.3 配置数据源(application.yml) ​

yaml
spring:
  datasource:
    dynamic:
      primary: master
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/your_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
          username: root
          password: your_password
          driver-class-name: com.mysql.cj.jdbc.Driver

6.1.2.4 验证集成 ​

创建验证类:

java
package com.example;

import cn.com.digitalhainan.mybatis.mapper.BaseMapper;
import cn.com.digitalhainan.mybatis.model.BaseDO;
import cn.com.digitalhainan.mybatis.utils.PageUtils;

/**
 * 验证 digitalhainan-mybatis 集成
 * 编译通过即表示集成成功
 */
public class MybatisIntegrationVerify {
    // BaseMapper 可用 → 集成成功
    // BaseDO 可用 → 自动填充能力就绪
    // PageUtils 可用 → 分页转换能力就绪
}

Step 4 验证清单 ​

  • [ ] 项目编译通过
  • [ ] Spring Boot 启动时自动配置 MybatisPlusInterceptor(含分页、乐观锁、数据权限)
  • [ ] BaseDO 子类插入时自动填充 createTime/updateTime/disable/version
  • [ ] 数据源连接正常

6.1.3 配置属性参考 ​

6.1.3.1 框架自定义配置 ​

配置键类型默认值说明
digitalhainan.component.mybatis.basePackagesList<String>—Mapper 扫描包路径(可选,默认扫描启动类所在包)
digitalhainan.component.mybatis.column.encrypt.sm4Encrypt.encryptionModeEnum—SM4 加密模式:CBC / ECB
digitalhainan.component.mybatis.column.encrypt.sm4Encrypt.secretKeyString—SM4 密钥(16 位)
digitalhainan.component.mybatis.column.encrypt.sm4Encrypt.ivString—SM4 CBC 模式 IV 向量(16 位)
digitalhainan.component.mybatis.druid.enablebooleanfalse是否启用慢 SQL 监控
digitalhainan.component.mybatis.druid.slowSqlMillislong500慢 SQL 阈值(毫秒)
digitalhainan.component.mybatis.druid.alertTypeString—告警方式
digitalhainan.component.mybatis.druid.dingTalk.webhookString—钉钉机器人 Webhook
digitalhainan.component.mybatis.druid.dingTalk.secretString—钉钉机器人加签密钥
digitalhainan.component.mybatis.druid.authorsSet<String>—告警接收人

6.1.3.2 数据源配置(dynamic-datasource) ​

yaml
spring:
  datasource:
    dynamic:
      primary: master          # 主数据源名称
      strict: false            # 严格模式(未匹配到数据源是否报错)
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/your_db
          username: root
          password: your_password
          driver-class-name: com.mysql.cj.jdbc.Driver
        slave:                 # 从库(可选)
          url: jdbc:mysql://localhost:3307/your_db
          username: root
          password: your_password
          driver-class-name: com.mysql.cj.jdbc.Driver

6.1.3.3 人大金仓 KingBase 数据源示例 ​

yaml
spring:
  datasource:
    dynamic:
      primary: master
      datasource:
        master:
          url: jdbc:kingbase8://localhost:54321/your_db
          username: system
          password: your_password
          driver-class-name: com.kingbase8.Driver

6.1.3.4 达梦 DM 数据源示例 ​

yaml
spring:
  datasource:
    dynamic:
      primary: master
      datasource:
        master:
          url: jdbc:dm://localhost:5236/your_db
          username: SYSDBA
          password: your_password
          driver-class-name: dm.jdbc.driver.DmDriver

6.1.4 核心功能使用 ​

功能集成决策索引 ​

需求场景参考章节
创建实体类(自动填充时间/操作人/逻辑删除/乐观锁)4.1 BaseDO
创建 Mapper 接口(批量插入/更新)4.2 BaseMapper
分页查询结果转换4.3 PageUtils
数据权限控制(按用户/部门/角色)4.4 @DataPermission
多数据源切换(@DS 注解)4.5 多数据源
读写分离(强制走主库)4.6 RWSContextHolder
字段级 SM4 加解密4.7 SM4EncryptHandle
慢 SQL 监控 + 钉钉告警4.8 慢 SQL 监控

6.1.4.1 BaseDO — 基础实体类 ​

java
package com.example.entity;

import cn.com.digitalhainan.mybatis.model.BaseDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * 示例实体类,继承 BaseDO 后自动具备:
 * - createTime: 插入时自动填充当前时间
 * - updateTime: 插入/更新时自动填充当前时间
 * - creator: 插入时从 MDC("_U_ID_") 获取当前用户 ID
 * - updator: 更新时从 MDC("_U_ID_") 获取当前用户 ID
 * - disable: 逻辑删除标记(插入时默认 false)
 * - version: 乐观锁版本号(插入时默认 1)
 *
 * 对应数据库表需包含以下字段:
 * - create_time DATETIME
 * - update_time DATETIME
 * - creator VARCHAR(64)
 * - updator VARCHAR(64)
 * - disable TINYINT(1) DEFAULT 0
 * - version INT DEFAULT 1
 */
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("t_example")
public class ExampleDO extends BaseDO {
    private Long id;
    private String name;
    private String description;
}

6.1.4.2 BaseMapper — Mapper 接口 ​

java
package com.example.mapper;

import cn.com.digitalhainan.mybatis.mapper.BaseMapper;
import com.example.entity.ExampleDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

/**
 * 继承 BaseMapper 后具备:
 * - MyBatis Plus 全部 CRUD 方法
 * - MyBatis Plus Join 联表查询能力(MPJBaseMapper)
 * - insertList: 批量插入所有字段
 * - selectAll: 查询所有(包括逻辑删除的记录)
 * - batchUpdate: 根据主键批量更新所有字段
 * - batchUpdateSelective: 根据主键批量更新非空字段
 */
@Mapper
public interface ExampleMapper extends BaseMapper<ExampleDO> {
    // 自定义 SQL 方法
}

6.1.4.3 PageUtils — 分页结果转换 ​

java
package com.example.service;

import cn.com.digitalhainan.common.common.dto.PaginationInfoResDTO;
import cn.com.digitalhainan.mybatis.utils.PageUtils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.entity.ExampleDO;
import com.example.vo.ExampleVO;
import com.example.converter.ExampleConverter;
import org.springframework.stereotype.Service;

/**
 * PageUtils 使用示例
 * 将 MyBatis Plus 的 IPage 或 PageHelper 的 Page 转为统一的 PaginationInfoResDTO
 */
@Service
public class ExampleService {

    // 方式一:使用 BaseConverter 转换(推荐)
    public PaginationInfoResDTO<ExampleVO> getPageWithConverter(
            IPage<ExampleDO> page, ExampleConverter converter) {
        return PageUtils.transform(page, converter);
    }

    // 方式二:使用 Function 转换
    public PaginationInfoResDTO<ExampleVO> getPageWithFunction(
            IPage<ExampleDO> page) {
        return PageUtils.transform(page, records -> {
            // 手动转换逻辑
            return records.stream().map(this::toVO).toList();
        });
    }

    // 方式三:PageHelper 分页结果
    public PaginationInfoResDTO<ExampleVO> getPageHelperResult(
            java.util.List<ExampleDO> list, ExampleConverter converter) {
        return PageUtils.transform(list, converter);
    }

    private ExampleVO toVO(ExampleDO entity) {
        ExampleVO vo = new ExampleVO();
        vo.setId(entity.getId());
        vo.setName(entity.getName());
        return vo;
    }
}

6.1.4.4 @DataPermission — 数据权限 ​

java
package com.example.service;

import cn.com.digitalhainan.mybatis.data.permission.annotation.DataColumn;
import cn.com.digitalhainan.mybatis.data.permission.annotation.DataPermission;
import cn.com.digitalhainan.mybatis.data.permission.constants.JoinEnum;
import com.example.mapper.ExampleMapper;
import org.springframework.stereotype.Service;

/**
 * 数据权限使用示例
 *
 * 系统内置角色 SQL 模板:
 * - ADMIN: 无限制(管理员看所有数据)
 * - SELF: creator = 当前用户ID
 * - MAIN_DEPT: dept_id = 用户主部门ID
 * - MAIN_DEPT_TREE: dept_id IN (用户主部门及子部门ID列表)
 *
 * 数据权限基于用户角色自动匹配 SQL 模板,通过 SpEL 表达式动态拼接 WHERE 条件
 */
@Service
public class ExampleService {

    private final ExampleMapper exampleMapper;

    public ExampleService(ExampleMapper exampleMapper) {
        this.exampleMapper = exampleMapper;
    }

    // 示例 1:默认数据权限(按 creator 字段过滤)
    @DataPermission
    public void listByDefault() {
        exampleMapper.selectList(null);
    }

    // 示例 2:指定数据权限字段
    @DataPermission({
        @DataColumn(key = "creator", value = "create_by"),
        @DataColumn(key = "deptId", value = "dept_id")
    })
    public void listByCustomColumn() {
        exampleMapper.selectList(null);
    }

    // 示例 3:多条件 AND 组合
    @DataPermission(
        value = {
            @DataColumn(key = "creator", value = "create_by"),
            @DataColumn(key = "deptId", value = "dept_id")
        },
        mixRoleJoin = JoinEnum.AND
    )
    public void listWithAndJoin() {
        exampleMapper.selectList(null);
    }
}

自定义数据权限规则:

java
package com.example.config;

import cn.com.digitalhainan.mybatis.data.permission.conf.DataPermissionCustomizer;
import cn.com.digitalhainan.mybatis.data.permission.conf.SqlTempCodeConfiguration;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

/**
 * 自定义数据权限 SQL 模板
 * 实现 SqlTempCodeConfiguration 接口定义新的角色编码和 SQL 模板
 */
@Configuration
public class DataPermissionConfig {

    @Bean
    public DataPermissionCustomizer customDataPermission() {
        return sqlTemps -> {
            sqlTemps.add(new SqlTempCodeConfiguration() {
                @Override
                public String code() {
                    return "CUSTOM_ROLE";  // 角色编码,需与用户系统中的角色匹配
                }
                @Override
                public String sqlTemp() {
                    // SpEL 模板,支持 #userAccount、#creator、#deptId 等变量
                    return "#{#creator} = '#{#userAccount.getOriUserInfo().userId}'";
                }
            });
        };
    }
}

6.1.4.5 多数据源 — @DS 注解 ​

java
package com.example.service;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.example.mapper.ExampleMapper;
import com.example.mapper.SlaveMapper;
import org.springframework.stereotype.Service;

/**
 * 多数据源切换示例
 * 使用 @DS 注解指定数据源名称(对应 application.yml 中 spring.datasource.dynamic.datasource 下的 key)
 */
@Service
public class MultiDatasourceService {

    private final ExampleMapper exampleMapper;

    public MultiDatasourceService(ExampleMapper exampleMapper) {
        this.exampleMapper = exampleMapper;
    }

    // 默认使用主数据源
    public void queryFromMaster() {
        exampleMapper.selectList(null);
    }

    // 切换到从库
    @DS("slave")
    public void queryFromSlave() {
        exampleMapper.selectList(null);
    }
}

6.1.4.6 RWSContextHolder — 读写分离 ​

java
package com.example.service;

import cn.com.digitalhainan.mybatis.datasouce.rws.context.RWSContextHolder;
import com.example.mapper.ExampleMapper;
import org.springframework.stereotype.Service;

/**
 * 读写分离场景:某些查询即使在从库可用的情况下也需要强制走主库
 */
@Service
public class RWSService {

    private final ExampleMapper exampleMapper;

    public RWSService(ExampleMapper exampleMapper) {
        this.exampleMapper = exampleMapper;
    }

    public void forceReadFromMaster() {
        // 强制走主库(调用后自动清除,仅对下一次查询生效)
        RWSContextHolder.startEnforceMaster();
        exampleMapper.selectList(null);
    }
}

6.1.4.7 SM4EncryptHandle — 字段级 SM4 加解密 ​

1. 配置 SM4 加密参数(application.yml):

yaml
digitalhainan:
  component:
    mybatis:
      column:
        encrypt:
          sm4Encrypt:
            encryptionMode: ECB   # ECB 或 CBC
            secretKey: 4370780c9a8c43e5  # 16 位密钥
            # iv: UISwD9fW6cFh9SNS  # CBC 模式需要配置 IV

2. 在实体类字段上使用 TypeHandler:

java
package com.example.entity;

import cn.com.digitalhainan.mybatis.handlers.SM4EncryptHandle;
import cn.com.digitalhainan.mybatis.model.BaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * SM4 字段级加解密示例
 * 数据写入时自动加密,读取时自动解密
 */
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("t_sensitive")
public class SensitiveDO extends BaseDO {
    private Long id;

    @TableField(typeHandler = SM4EncryptHandle.class)
    private String idCard;  // 身份证号,数据库中存储为 SM4 密文

    @TableField(typeHandler = SM4EncryptHandle.class)
    private String phone;   // 手机号,数据库中存储为 SM4 密文
}

6.1.4.8 慢 SQL 监控 + 钉钉告警 ​

yaml
digitalhainan:
  component:
    mybatis:
      druid:
        enable: true
        slowSql-millis: 500        # 慢 SQL 阈值(毫秒)
        alert-type: DINGTALK       # 告警方式
        ding-talk:
          webhook: https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN
          secret: SECxxxxxx        # 加签密钥(可选)
        authors:                   # 告警消息中 @的人
          - admin

6.1.5 版本变更记录 ​

v3.1.0(当前版本) ​

  • 新增数据权限功能(@DataPermission 注解 + SpEL 动态 SQL)
  • 兼容未使用脚手架授权场景

v3.0.1 ​

  • 初始化 3.0.1

v3.0.0 ​

  • 新增乐观锁支持
  • 数据权限功能开发

v2.1.0 ​

  • 新增依赖
  • 驱动更新

v2.0.0 ​

  • strictUpdateFill 更新
  • 初始版本

6.1.6 常见问题 ​

Q1:启动报错 "Parameter 'spring.datasource.url' is required"? ​

原因: 未配置数据源。 解决: 在 application.yml 中配置 spring.datasource.dynamic.datasource.master 的 url/username/password/driver-class-name。

Q2:BaseDO 的 createTime/updateTime 没有自动填充? ​

原因: 数据库字段名与 Java 属性名不匹配。 解决: 确保数据库表包含 create_time、update_time、creator、updator、disable、version 字段(下划线命名)。

Q3:creator/updator 填充为空? ​

原因: MDC 中没有 _U_ID_ 值。 解决: 确保在请求链路中(如 Filter/Interceptor)将当前用户 ID 放入 MDC:MDC.put("_U_ID_", userId)。

Q4:数据权限不生效? ​

原因: 需要在方法或类上添加 @DataPermission 注解,且用户上下文(UserInfoContext)中必须有当前用户信息。 解决: 确保 digitalhainan-user 模块已集成,且请求链路中用户上下文已设置。

Q5:多数据源 @DS 注解不生效? ​

原因: 方法被同类内部调用(AOP 代理未生效)。 解决: 确保 @DS 注解的方法被不同 Bean 调用,或将 @DS 放在类级别。

Q6:SM4 字段加解密报错? ​

原因: 密钥长度不是 16 位,或数据库中已有明文数据。 解决: 确保 secretKey 为 16 位字符串,历史数据需先手动加密后再使用 TypeHandler。


6.1.7 版本兼容性矩阵 ​

mybatis-spring-boot-starterSpring BootJDKMyBatis Plus说明
3.1.0-SNAPSHOT3.x213.5.14当前版本,支持数据权限
3.0.0 ~ 3.0.13.x213.5.xSpring Boot 3.x 适配
2.0.0 ~ 2.1.02.x8/113.4.xjavax 命名空间

Power By 数字海南