From 936ce722e84c7bfaf72a1cd0db5f7248f5fcf718 Mon Sep 17 00:00:00 2001 From: dongxiayu Date: Sun, 8 Jun 2025 23:16:32 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E5=BA=95=E5=BA=A7=E3=80=91=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E9=85=8D=E7=BD=AE=E5=A2=9E=E5=8A=A0=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E5=90=8D=E7=A7=B0=EF=BC=8C=E5=BA=95=E5=BA=A7=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?traceId=E6=9C=BA=E5=88=B6=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/aspect/CustomTraceIdConverter.java | 52 ++++++++++++++++ .../interceptor/CommonTraceInterceptor.java | 42 +++++++++++++ .../vip/xiaonuo/common/pojo/CommonResult.java | 23 +++++++ .../common/util/CommonTraceIdUtil.java | 60 +++++++++++++++++++ .../xiaonuo/core/config/GlobalConfigure.java | 12 ++++ .../src/main/resources/application.properties | 5 +- .../src/main/resources/logback-spring.xml | 4 ++ 7 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 snowy-common/src/main/java/vip/xiaonuo/common/aspect/CustomTraceIdConverter.java create mode 100644 snowy-common/src/main/java/vip/xiaonuo/common/interceptor/CommonTraceInterceptor.java create mode 100644 snowy-common/src/main/java/vip/xiaonuo/common/util/CommonTraceIdUtil.java diff --git a/snowy-common/src/main/java/vip/xiaonuo/common/aspect/CustomTraceIdConverter.java b/snowy-common/src/main/java/vip/xiaonuo/common/aspect/CustomTraceIdConverter.java new file mode 100644 index 00000000..57a6f28d --- /dev/null +++ b/snowy-common/src/main/java/vip/xiaonuo/common/aspect/CustomTraceIdConverter.java @@ -0,0 +1,52 @@ +/* + * Copyright [2022] [https://www.xiaonuo.vip] + * + * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + * + * 1.请不要删除和修改根目录下的LICENSE文件。 + * 2.请不要删除和修改Snowy源码头部的版权声明。 + * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。 + * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip + * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。 + * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip + */ +package vip.xiaonuo.common.aspect; + +import ch.qos.logback.classic.pattern.ClassicConverter; +import ch.qos.logback.classic.spi.ILoggingEvent; +import org.springframework.stereotype.Component; +import vip.xiaonuo.common.util.CommonTraceIdUtil; + +/** + * 自定义traceId转换器 + * + * @author dongxiayu + * @date 2025/1/9 15:36 + */ +@Component +public class CustomTraceIdConverter extends ClassicConverter { + + // 使用常量避免重复创建字符串 + private static final String LEFT_BRACKET = "["; + private static final String RIGHT_BRACKET = "]"; + + // 缓存StringBuilder以减少对象创建 + private static final ThreadLocal bufferHolder = + ThreadLocal.withInitial(() -> new StringBuilder(64)); + + @Override + public String convert(ILoggingEvent event) { + StringBuilder buffer = bufferHolder.get(); + buffer.setLength(0); + String traceId = CommonTraceIdUtil.getTraceId(); + + buffer.append(LEFT_BRACKET); + if (traceId != null && !traceId.isEmpty()) { + buffer.append(traceId); + } else { + buffer.append(event.getThreadName()); + } + buffer.append(RIGHT_BRACKET); + return buffer.toString(); + } +} \ No newline at end of file diff --git a/snowy-common/src/main/java/vip/xiaonuo/common/interceptor/CommonTraceInterceptor.java b/snowy-common/src/main/java/vip/xiaonuo/common/interceptor/CommonTraceInterceptor.java new file mode 100644 index 00000000..a2c8a86a --- /dev/null +++ b/snowy-common/src/main/java/vip/xiaonuo/common/interceptor/CommonTraceInterceptor.java @@ -0,0 +1,42 @@ +/* + * Copyright [2022] [https://www.xiaonuo.vip] + * + * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + * + * 1.请不要删除和修改根目录下的LICENSE文件。 + * 2.请不要删除和修改Snowy源码头部的版权声明。 + * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。 + * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip + * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。 + * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip + */ +package vip.xiaonuo.common.interceptor; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.servlet.HandlerInterceptor; +import vip.xiaonuo.common.util.CommonTraceIdUtil; + +/** + * 公共链路追踪拦截器 + * + * @author dongxiayu + * @date 2025/1/10 11:42 + */ +public class CommonTraceInterceptor implements HandlerInterceptor { + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + try { + CommonTraceIdUtil.getTraceId(request); + } catch (Exception e) { + return false; + } + return true; + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + CommonTraceIdUtil.clear(); + HandlerInterceptor.super.afterCompletion(request, response, handler, ex); + } +} diff --git a/snowy-common/src/main/java/vip/xiaonuo/common/pojo/CommonResult.java b/snowy-common/src/main/java/vip/xiaonuo/common/pojo/CommonResult.java index 1061a6c3..acfcbc2e 100644 --- a/snowy-common/src/main/java/vip/xiaonuo/common/pojo/CommonResult.java +++ b/snowy-common/src/main/java/vip/xiaonuo/common/pojo/CommonResult.java @@ -14,6 +14,7 @@ package vip.xiaonuo.common.pojo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; +import vip.xiaonuo.common.util.CommonTraceIdUtil; import java.io.Serial; import java.io.Serializable; @@ -47,6 +48,9 @@ public class CommonResult implements Serializable{ @Schema(description = "返回数据") private T data; + @Schema(description = "跟踪ID") + private String traceId; + public CommonResult() { } @@ -54,6 +58,7 @@ public class CommonResult implements Serializable{ this.setCode(code); this.setMsg(msg); this.setData(data); + this.setTraceId(CommonTraceIdUtil.getTraceId()); } /** @@ -64,6 +69,14 @@ public class CommonResult implements Serializable{ return this.code; } + /** + * 获取traceId + * @return traceId + */ + public String getTraceId() { + return this.traceId; + } + /** * 给code赋值,连缀风格 * @param code code @@ -94,6 +107,16 @@ public class CommonResult implements Serializable{ return this; } + /** + * 给traceId赋值,连缀风格 + * @param traceId traceId + * @return 对象自身 + */ + public CommonResult setTraceId(String traceId) { + this.traceId = traceId; + return this; + } + // ============================ 构建 ================================== diff --git a/snowy-common/src/main/java/vip/xiaonuo/common/util/CommonTraceIdUtil.java b/snowy-common/src/main/java/vip/xiaonuo/common/util/CommonTraceIdUtil.java new file mode 100644 index 00000000..e20f490a --- /dev/null +++ b/snowy-common/src/main/java/vip/xiaonuo/common/util/CommonTraceIdUtil.java @@ -0,0 +1,60 @@ +/* + * Copyright [2022] [https://www.xiaonuo.vip] + * + * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + * + * 1.请不要删除和修改根目录下的LICENSE文件。 + * 2.请不要删除和修改Snowy源码头部的版权声明。 + * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。 + * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip + * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。 + * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip + */ +package vip.xiaonuo.common.util; + +import cn.hutool.core.util.StrUtil; +import jakarta.servlet.http.HttpServletRequest; + +import java.util.UUID; + +/** + * TraceId工具类 + * + * @author dongxiayu + * @date 2025/1/9 17:07 + */ +public class CommonTraceIdUtil { + + public static final String TRACE_ID_STRING = "traceId"; + + private static final InheritableThreadLocal TRACE_ID = new InheritableThreadLocal<>(); + + public static String generateTraceId(HttpServletRequest request) { + String header = request.getHeader(TRACE_ID_STRING); + if (header != null) { + return header; + } + return UUID.randomUUID().toString().replace(StrUtil.DASHED, StrUtil.EMPTY); + } + + public static String getTraceId() { + return TRACE_ID.get(); + } + + public static String getTraceId(HttpServletRequest request) { + String traceId = getTraceId(); + if (traceId == null) { + traceId = generateTraceId(request); + setTraceId(traceId); + } + return traceId; + } + + public static void setTraceId(String traceId) { + TRACE_ID.set(traceId); + } + + public static void clear() { + TRACE_ID.remove(); + } +} diff --git a/snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalConfigure.java b/snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalConfigure.java index c7b8fada..a2ccecd0 100644 --- a/snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalConfigure.java +++ b/snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalConfigure.java @@ -66,6 +66,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.jdbc.support.JdbcUtils; import org.springframework.stereotype.Component; import org.springframework.util.ResourceUtils; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import vip.xiaonuo.auth.core.util.StpClientUtil; @@ -74,6 +75,7 @@ import vip.xiaonuo.common.annotation.CommonWrapper; import vip.xiaonuo.common.cache.CommonCacheOperator; import vip.xiaonuo.common.enums.CommonDeleteFlagEnum; import vip.xiaonuo.common.exception.CommonException; +import vip.xiaonuo.common.interceptor.CommonTraceInterceptor; import vip.xiaonuo.common.listener.CommonDataChangeEventCenter; import vip.xiaonuo.common.listener.CommonDataChangeListener; import vip.xiaonuo.common.pojo.CommonResult; @@ -702,4 +704,14 @@ public class GlobalConfigure implements WebMvcConfigurer { public void registerListenerList(List dataChangeListenerList) { CommonDataChangeEventCenter.registerListenerList(dataChangeListenerList); } + + /** + * 添加应用拦截器 + * @param registry + */ + @Override + public void addInterceptors(InterceptorRegistry registry) { + // 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关,只是说明哪些接口不需要被拦截器拦截,此处都拦截) + registry.addInterceptor(new CommonTraceInterceptor()).addPathPatterns("/**"); + } } diff --git a/snowy-web-app/src/main/resources/application.properties b/snowy-web-app/src/main/resources/application.properties index 35fa6054..b70f8c3a 100644 --- a/snowy-web-app/src/main/resources/application.properties +++ b/snowy-web-app/src/main/resources/application.properties @@ -2,6 +2,7 @@ # server configuration ######################################### server.port=82 +spring.application.name=snowy ######################################### # spring allow-circular-references @@ -27,9 +28,9 @@ spring.servlet.multipart.max-file-size=100MB # mysql spring.datasource.dynamic.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver -spring.datasource.dynamic.datasource.master.url=jdbc:mysql://localhost:3306/snowy?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&useInformationSchema=true&rewriteBatchedStatements=true +spring.datasource.dynamic.datasource.master.url=jdbc:mysql://localhost:3306/snowy3-gitee?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&useInformationSchema=true&rewriteBatchedStatements=true spring.datasource.dynamic.datasource.master.username=root -spring.datasource.dynamic.datasource.master.password=12345678 +spring.datasource.dynamic.datasource.master.password=123456 spring.datasource.dynamic.strict=true # postgres diff --git a/snowy-web-app/src/main/resources/logback-spring.xml b/snowy-web-app/src/main/resources/logback-spring.xml index 5d28c043..48ad0c31 100644 --- a/snowy-web-app/src/main/resources/logback-spring.xml +++ b/snowy-web-app/src/main/resources/logback-spring.xml @@ -4,6 +4,10 @@ + + + +