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

本文档用于指导在目标项目中完成
digitalhainan-log-starter模块集成。执行顺序:
- 先完成「8.1.2 快速集成」的全部步骤(必须)
- 根据业务需求,查阅「功能集成决策索引」选择对应路径,逐项实现
- 遇到配置问题时参考「8.1.3 配置属性参考」
- 出现异常时查阅「8.1.6 常见问题」
代码约定: 所有代码示例均包含完整
import路径和类声明,可直接用于代码生成。
digitalhainan-log-starter 是数字海南框架的 日志组件,提供:
@OperationLog 注解,AOP 拦截自动记录操作日志(入参/出参/耗时/异常)TraceUtils 工具类,创建本地 Span 并关联日志LoggerDecorator 模式,增强 SLF4J Logger,支持日志上报ILogReporter 接口,支持 Kafka 上报(可扩展其他渠道)Maven 坐标:
<dependency>
<groupId>cn.com.digitalhainan</groupId>
<artifactId>digitalhainan-log-starter</artifactId>
</dependency>前置依赖:
| 依赖 | 说明 |
|---|---|
digitalhainan-pom | 父 POM |
digitalhainan-tools | 工具集 |
spring-boot-starter-aop | AOP 支持 |
spring-kafka(可选) | Kafka 日志上报 |
当前版本: 3.1.0-SNAPSHOT
<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>digitalhainan-log-starter</artifactId>
</dependency>
</dependencies>digitalhainan:
log:
report:
enable: false # 是否启用日志上报
kafka:
log-topic: log-topic # Kafka Topic@OperationLog 注解的方法自动输出操作日志| 配置键 | 类型 | 默认值 | 说明 |
|---|---|---|---|
digitalhainan.log.report.enable | Boolean | false | 是否启用日志上报 |
digitalhainan.log.report.kafka.log-topic | String | log-topic | Kafka 日志 Topic |
| 需求场景 | 参考章节 |
|---|---|
| 操作日志记录 | 4.1 @OperationLog |
| 手动设置日志上下文变量 | 4.2 OperationLogContext |
| SkyWalking 链路追踪日志 | 4.3 TraceUtils |
| 自定义日志上报 | 4.4 日志上报 |
| 自定义日志编码枚举 | 4.5 日志编码 |
package com.example.service;
import cn.com.digitalhainan.log.conf.annotation.OperationLog;
import cn.com.digitalhainan.log.constants.ILogCodeConfiguration;
import org.springframework.stereotype.Service;
/**
* 操作日志使用示例
* @OperationLog 注解标注在方法上,AOP 自动记录操作日志
*/
@Service
public class OperationLogDemoService {
/**
* 基础用法:记录操作日志
*/
@OperationLog(
logCode = "@demoLogCode", // SpEL 表达式,引用 Bean 的日志编码
successTemp = "操作成功", // 成功模板
failTemp = "操作失败: #_errMsg", // 失败模板,#_errMsg 为异常消息
exceptionTemp = "系统异常: #_errMsg"
)
public String doOperation(String param) {
return "result";
}
/**
* 记录入参和出参
*/
@OperationLog(
logCode = "@demoLogCode",
inParam = true, // 记录入参
outParam = true, // 记录出参
record = true // 是否记录日志
)
public String doOperationWithParams(String name, Integer age) {
return name + ":" + age;
}
/**
* 提取业务流水号和用户信息
*/
@OperationLog(
logCode = "@demoLogCode",
businessOrderNum = "#orderNo", // SpEL 提取业务流水号
userId = "#userId", // SpEL 提取用户ID
nickname = "#nickName", // SpEL 提取昵称
account = "#account", // SpEL 提取账号
logType = "BUSINESS" // 日志类型
)
public String processOrder(String orderNo, String userId, String nickName, String account) {
return "processed";
}
/**
* 业务成功条件判断
*/
@OperationLog(
logCode = "@demoLogCode",
bizSuccessCondition = "#_result == true", // SpEL 判断业务是否成功
successTemp = "处理成功",
failTemp = "处理失败"
)
public boolean processData() {
return true;
}
}@OperationLog 注解参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
logCode | String | "" | 日志编码(SpEL 表达式) |
subLogCode | String | "" | 子日志编码(SpEL) |
nickname | String | "" | 用户昵称(SpEL) |
userId | String | "" | 用户ID(SpEL) |
account | String | "" | 用户账号(SpEL) |
businessOrderNum | String | "" | 业务流水号(SpEL) |
successTemp | String | #_result | 成功日志模板 |
failTemp | String | #_errMsg | 失败日志模板 |
exceptionTemp | String | #_errMsg | 异常日志模板 |
record | boolean | true | 是否记录 |
inParam | boolean | true | 是否记录入参 |
outParam | boolean | true | 是否记录出参 |
bizSuccessCondition | String | "true" | 业务成功条件(SpEL) |
logType | String | BUSINESS | 日志类型 |
businessVersion | String | "" | 业务版本 |
SpEL 内置变量:
| 变量 | 说明 |
|---|---|
#_result | 方法返回值 |
#_errMsg | 异常消息 |
#_extra | 额外信息(Map) |
#参数名 | 方法参数(按参数名引用) |
package com.example.service;
import cn.com.digitalhainan.log.interceptor.OperationLogContext;
/**
* OperationLogContext 使用示例
* 在业务代码中手动设置日志上下文变量,@OperationLog 的 SpEL 可引用这些变量
*/
public class LogContextDemo {
public void doBusiness() {
// 设置日志上下文变量
OperationLogContext.put("_logCode", "CUSTOM_LOG_CODE");
OperationLogContext.put("_sub_log_code", "SUB_CODE");
OperationLogContext.put("_business_order_num", "BIZ-2024-001");
OperationLogContext.put("_business_version", "v2.0");
OperationLogContext.put("_extra", java.util.Map.of("key", "value"));
// 业务逻辑...
// 清理上下文(@OperationLog AOP 会自动清理,手动使用时需自行清理)
OperationLogContext.clearContext();
}
}package com.example.service;
import cn.com.digitalhainan.log.componet.slf4j.LoggerInfo;
import cn.com.digitalhainan.log.constants.ILogCodeConfiguration;
import cn.com.digitalhainan.log.trace.TraceUtils;
import org.apache.skywalking.apm.toolkit.trace.SpanRef;
/**
* TraceUtils 使用示例
* 创建 SkyWalking 本地 Span,关联操作日志
*/
public class TraceDemo {
/**
* 使用 TraceUtils 创建追踪 Span
*/
public void traceDemo() {
ILogCodeConfiguration logCode = new ILogCodeConfiguration() {
@Override public String code() { return "TRACE_DEMO"; }
@Override public String defaultMsg() { return "追踪示例"; }
@Override public String appCode() { return "my-app"; }
};
LoggerInfo loggerInfo = LoggerInfo.newInstance()
.setLogContent("业务处理")
.setBusinessOrderNum("BIZ-001")
.setSuccess(true);
String result = TraceUtils.trace(logCode, loggerInfo, (SpanRef spanRef) -> {
// 业务逻辑
spanRef.tag("customTag", "customValue");
return "done";
});
}
}实现 ILogReporter 接口:
package com.example.log;
import cn.com.digitalhainan.log.report.ILogReporter;
import cn.com.digitalhainan.log.report.config.props.LogReportProperties;
import cn.com.digitalhainan.log.report.dto.LogReportInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 自定义日志上报实现
*/
@Component
public class CustomLogReporter implements ILogReporter {
@Autowired
private LogReportProperties logReportProperties;
@Override
public void report(LogReportInfo logReportInfo) {
// 自定义上报逻辑(如 HTTP、文件、数据库等)
}
@Override
public LogReportProperties getLogReportProperties() {
return logReportProperties;
}
@Override
public String appName() {
return "my-service";
}
@Override
public String reportNode() {
return "node-1";
}
}package com.example.log;
import cn.com.digitalhainan.log.constants.ILogCodeConfiguration;
/**
* 日志编码枚举示例
* 实现 ILogCodeConfiguration 接口定义日志编码
*/
public enum DemoLogCodeEnum implements ILogCodeConfiguration {
USER_LOGIN("USER_LOGIN_001", "用户登录", "user-service"),
USER_LOGOUT("USER_LOGOUT_001", "用户登出", "user-service"),
DATA_EXPORT("DATA_EXPORT_001", "数据导出", "user-service");
private final String code;
private final String defaultMsg;
private final String appCode;
DemoLogCodeEnum(String code, String defaultMsg, String appCode) {
this.code = code;
this.defaultMsg = defaultMsg;
this.appCode = appCode;
}
@Override
public String code() {
return this.code;
}
@Override
public String defaultMsg() {
return this.defaultMsg;
}
@Override
public String appCode() {
return this.appCode;
}
}使用时通过 SpEL 引用:
@OperationLog(logCode = "@demoLogCodeEnum.USER_LOGIN")
public void login() { ... }原因: 未引入 spring-boot-starter-aop 依赖,或方法在同类内部调用(AOP 未代理)。 解决: 确保引入 AOP 依赖,且方法通过 Spring 代理调用(非 this.method())。
原因: SpEL 表达式格式不正确。 解决: 方法参数使用 #参数名 引用,返回值使用 #_result,异常消息使用 #_errMsg。
原因: 未引入 spring-kafka 依赖或 Kafka 未配置。 解决: 添加 spring-kafka 依赖并配置 Kafka 连接,设置 digitalhainan.log.report.enable: true。
| digitalhainan-log-starter | Spring Boot | JDK | 说明 |
|---|---|---|---|
| 3.1.0-SNAPSHOT | 3.x | 21 | 当前版本 |
| 3.0.0 ~ 3.0.1 | 3.x | 21 | Spring Boot 3.x |
| 2.1.0 | 2.x | 8/11 | javax 命名空间 |
| 2.0.0 | 2.x | 8/11 | 初始版本 |