Skip to content
返回

后端脚手架

脚手架

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

概述
后端脚手架

digitalhainan-log-starter ​

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

执行顺序:

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

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


8.1.1 模块简介 ​

digitalhainan-log-starter 是数字海南框架的 日志组件,提供:

  • 操作日志 — @OperationLog 注解,AOP 拦截自动记录操作日志(入参/出参/耗时/异常)
  • SpEL 表达式 — 支持 SpEL 动态提取日志编码、用户信息、业务流水号等
  • OperationLogContext — ThreadLocal 上下文,手动设置日志变量
  • SkyWalking 链路追踪 — TraceUtils 工具类,创建本地 Span 并关联日志
  • Logger 装饰器 — LoggerDecorator 模式,增强 SLF4J Logger,支持日志上报
  • 日志上报 — ILogReporter 接口,支持 Kafka 上报(可扩展其他渠道)
  • i18n 异常消息 — 业务异常消息自动国际化转义

Maven 坐标:

xml
<dependency>
    <groupId>cn.com.digitalhainan</groupId>
    <artifactId>digitalhainan-log-starter</artifactId>
</dependency>

前置依赖:

依赖说明
digitalhainan-pom父 POM
digitalhainan-tools工具集
spring-boot-starter-aopAOP 支持
spring-kafka(可选)Kafka 日志上报

当前版本: 3.1.0-SNAPSHOT


8.1.2 快速集成 ​

8.1.2.1 确认父 POM ​

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

8.1.2.2 添加依赖 ​

xml
<dependencies>
    <dependency>
        <groupId>cn.com.digitalhainan</groupId>
        <artifactId>digitalhainan-log-starter</artifactId>
    </dependency>
</dependencies>

8.1.2.3 配置(application.yml) ​

yaml
digitalhainan:
  log:
    report:
      enable: false          # 是否启用日志上报
      kafka:
        log-topic: log-topic  # Kafka Topic

8.1.2.4 验证清单 ​

  • [ ] Spring Boot 启动成功
  • [ ] 使用 @OperationLog 注解的方法自动输出操作日志
  • [ ] 日志包含入参、出参、耗时信息

8.1.3 配置属性参考 ​

配置键类型默认值说明
digitalhainan.log.report.enableBooleanfalse是否启用日志上报
digitalhainan.log.report.kafka.log-topicStringlog-topicKafka 日志 Topic

8.1.4 核心功能使用 ​

功能集成决策索引 ​

需求场景参考章节
操作日志记录4.1 @OperationLog
手动设置日志上下文变量4.2 OperationLogContext
SkyWalking 链路追踪日志4.3 TraceUtils
自定义日志上报4.4 日志上报
自定义日志编码枚举4.5 日志编码

8.1.4.1 @OperationLog 操作日志 ​

java
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 注解参数:

参数类型默认值说明
logCodeString""日志编码(SpEL 表达式)
subLogCodeString""子日志编码(SpEL)
nicknameString""用户昵称(SpEL)
userIdString""用户ID(SpEL)
accountString""用户账号(SpEL)
businessOrderNumString""业务流水号(SpEL)
successTempString#_result成功日志模板
failTempString#_errMsg失败日志模板
exceptionTempString#_errMsg异常日志模板
recordbooleantrue是否记录
inParambooleantrue是否记录入参
outParambooleantrue是否记录出参
bizSuccessConditionString"true"业务成功条件(SpEL)
logTypeStringBUSINESS日志类型
businessVersionString""业务版本

SpEL 内置变量:

变量说明
#_result方法返回值
#_errMsg异常消息
#_extra额外信息(Map)
#参数名方法参数(按参数名引用)

8.1.4.2 OperationLogContext ​

java
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();
    }
}

8.1.4.3 TraceUtils 链路追踪 ​

java
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";
        });
    }
}

8.1.4.4 自定义日志上报 ​

实现 ILogReporter 接口:

java
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";
    }
}

8.1.4.5 自定义日志编码 ​

java
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 引用:

java
@OperationLog(logCode = "@demoLogCodeEnum.USER_LOGIN")
public void login() { ... }

8.1.5 版本变更记录 ​

v3.1.0(当前版本) ​

  • Spring Boot 3.x / JDK 21 适配
  • TraceUtils 链路追踪增强
  • Logger 装饰器模式重构

v3.0.1 ​

  • 初始化 3.0.1

v3.0.0 ​

  • Spring Boot 3.x 适配

v2.1.0 ​

  • 操作日志 SpEL 增强
  • 日志上报 Kafka 支持

v2.0.0 ​

  • 初始版本

8.1.6 常见问题 ​

Q1:@OperationLog 不生效? ​

原因: 未引入 spring-boot-starter-aop 依赖,或方法在同类内部调用(AOP 未代理)。 解决: 确保引入 AOP 依赖,且方法通过 Spring 代理调用(非 this.method())。

Q2:日志中 SpEL 变量未解析? ​

原因: SpEL 表达式格式不正确。 解决: 方法参数使用 #参数名 引用,返回值使用 #_result,异常消息使用 #_errMsg。

Q3:Kafka 日志上报不生效? ​

原因: 未引入 spring-kafka 依赖或 Kafka 未配置。 解决: 添加 spring-kafka 依赖并配置 Kafka 连接,设置 digitalhainan.log.report.enable: true。


8.1.7 版本兼容性矩阵 ​

digitalhainan-log-starterSpring BootJDK说明
3.1.0-SNAPSHOT3.x21当前版本
3.0.0 ~ 3.0.13.x21Spring Boot 3.x
2.1.02.x8/11javax 命名空间
2.0.02.x8/11初始版本

Power By 数字海南