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

本文档用于指导在目标项目中完成
digitalhainan-mybatis模块集成。执行顺序:
- 先完成「6.1.2 快速集成」的全部步骤(必须)
- 根据业务需求,查阅「功能集成决策索引」选择对应路径,逐项实现
- 遇到配置问题时参考「6.1.3 配置属性参考」
- 出现异常时查阅「6.1.6 常见问题」
代码约定: 所有代码示例均包含完整
import路径和类声明,可直接用于代码生成。
digitalhainan-mybatis(artifactId: mybatis-spring-boot-starter)是数字海南框架的数据层增强组件,基于 MyBatis Plus 封装,提供:
Maven 坐标:
<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
目标: 完成以下 4 个步骤后,项目即具备 MyBatis Plus 增强能力。
<parent>
<groupId>cn.com.digitalhainan</groupId>
<artifactId>digitalhainan-pom</artifactId>
<version>3.1.0-SNAPSHOT</version>
</parent><dependencies>
<dependency>
<groupId>cn.com.digitalhainan</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
</dependencies>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创建验证类:
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 可用 → 分页转换能力就绪
}| 配置键 | 类型 | 默认值 | 说明 |
|---|---|---|---|
digitalhainan.component.mybatis.basePackages | List<String> | — | Mapper 扫描包路径(可选,默认扫描启动类所在包) |
digitalhainan.component.mybatis.column.encrypt.sm4Encrypt.encryptionMode | Enum | — | SM4 加密模式:CBC / ECB |
digitalhainan.component.mybatis.column.encrypt.sm4Encrypt.secretKey | String | — | SM4 密钥(16 位) |
digitalhainan.component.mybatis.column.encrypt.sm4Encrypt.iv | String | — | SM4 CBC 模式 IV 向量(16 位) |
digitalhainan.component.mybatis.druid.enable | boolean | false | 是否启用慢 SQL 监控 |
digitalhainan.component.mybatis.druid.slowSqlMillis | long | 500 | 慢 SQL 阈值(毫秒) |
digitalhainan.component.mybatis.druid.alertType | String | — | 告警方式 |
digitalhainan.component.mybatis.druid.dingTalk.webhook | String | — | 钉钉机器人 Webhook |
digitalhainan.component.mybatis.druid.dingTalk.secret | String | — | 钉钉机器人加签密钥 |
digitalhainan.component.mybatis.druid.authors | Set<String> | — | 告警接收人 |
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.Driverspring:
datasource:
dynamic:
primary: master
datasource:
master:
url: jdbc:kingbase8://localhost:54321/your_db
username: system
password: your_password
driver-class-name: com.kingbase8.Driverspring:
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| 需求场景 | 参考章节 |
|---|---|
| 创建实体类(自动填充时间/操作人/逻辑删除/乐观锁) | 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 监控 |
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;
}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 方法
}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;
}
}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);
}
}自定义数据权限规则:
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}'";
}
});
};
}
}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);
}
}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);
}
}1. 配置 SM4 加密参数(application.yml):
digitalhainan:
component:
mybatis:
column:
encrypt:
sm4Encrypt:
encryptionMode: ECB # ECB 或 CBC
secretKey: 4370780c9a8c43e5 # 16 位密钥
# iv: UISwD9fW6cFh9SNS # CBC 模式需要配置 IV2. 在实体类字段上使用 TypeHandler:
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 密文
}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原因: 未配置数据源。 解决: 在 application.yml 中配置 spring.datasource.dynamic.datasource.master 的 url/username/password/driver-class-name。
原因: 数据库字段名与 Java 属性名不匹配。 解决: 确保数据库表包含 create_time、update_time、creator、updator、disable、version 字段(下划线命名)。
原因: MDC 中没有 _U_ID_ 值。 解决: 确保在请求链路中(如 Filter/Interceptor)将当前用户 ID 放入 MDC:MDC.put("_U_ID_", userId)。
原因: 需要在方法或类上添加 @DataPermission 注解,且用户上下文(UserInfoContext)中必须有当前用户信息。 解决: 确保 digitalhainan-user 模块已集成,且请求链路中用户上下文已设置。
原因: 方法被同类内部调用(AOP 代理未生效)。 解决: 确保 @DS 注解的方法被不同 Bean 调用,或将 @DS 放在类级别。
原因: 密钥长度不是 16 位,或数据库中已有明文数据。 解决: 确保 secretKey 为 16 位字符串,历史数据需先手动加密后再使用 TypeHandler。
| mybatis-spring-boot-starter | Spring Boot | JDK | MyBatis Plus | 说明 |
|---|---|---|---|---|
| 3.1.0-SNAPSHOT | 3.x | 21 | 3.5.14 | 当前版本,支持数据权限 |
| 3.0.0 ~ 3.0.1 | 3.x | 21 | 3.5.x | Spring Boot 3.x 适配 |
| 2.0.0 ~ 2.1.0 | 2.x | 8/11 | 3.4.x | javax 命名空间 |