mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-18 09:35:29 +08:00
Pre Merge pull request !823 from miracle-bean/dev
This commit is contained in:
commit
c237c3514a
@ -2,8 +2,8 @@
|
||||
<configuration>
|
||||
<property name="log.path" value="./logs"/>
|
||||
<property name="console.log.pattern"
|
||||
value="%cyan(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
|
||||
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
|
||||
value="%cyan(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) %magenta([traceId:%X{traceId:-}]) - %msg%n"/>
|
||||
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%X{traceId:-}] - %msg%n"/>
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
|
||||
@ -3,6 +3,7 @@ package org.dromara.common.web.config;
|
||||
import jakarta.servlet.DispatcherType;
|
||||
import org.dromara.common.web.config.properties.XssProperties;
|
||||
import org.dromara.common.web.filter.RepeatableFilter;
|
||||
import org.dromara.common.web.filter.TraceIdFilter;
|
||||
import org.dromara.common.web.filter.XssFilter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@ -10,6 +11,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.boot.web.servlet.FilterRegistration;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* Filter配置
|
||||
@ -38,4 +40,15 @@ public class FilterConfig {
|
||||
return new RepeatableFilter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<TraceIdFilter> traceIdFilterRegistration() {
|
||||
FilterRegistrationBean<TraceIdFilter> registration = new FilterRegistrationBean<>();
|
||||
registration.setDispatcherTypes(DispatcherType.REQUEST);
|
||||
registration.setFilter(new TraceIdFilter());
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setName("traceIdFilter");
|
||||
registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 10);
|
||||
return registration;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,89 @@
|
||||
package org.dromara.common.web.context;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* TraceId 上下文工具类(基于 MDC + ThreadLocal 双保险)
|
||||
*/
|
||||
public final class TraceContext {
|
||||
|
||||
private static final String TRACE_ID_KEY = "traceId";
|
||||
|
||||
private TraceContext() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前 traceId(不存在返回 null)
|
||||
*/
|
||||
public static String getTraceId() {
|
||||
return MDC.get(TRACE_ID_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取或创建 traceId(不存在时自动生成)
|
||||
*/
|
||||
public static String getOrCreateTraceId() {
|
||||
String traceId = getTraceId();
|
||||
if (traceId == null) {
|
||||
traceId = generateTraceId();
|
||||
setTraceId(traceId);
|
||||
}
|
||||
return traceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 traceId 到 MDC
|
||||
*/
|
||||
public static void setTraceId(String traceId) {
|
||||
if (traceId != null) {
|
||||
MDC.put(TRACE_ID_KEY, traceId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理当前线程的 traceId(非常重要!)
|
||||
*/
|
||||
public static void clear() {
|
||||
MDC.remove(TRACE_ID_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 traceId 的规则
|
||||
*/
|
||||
public static String generateTraceId() {
|
||||
return IdUtil.getSnowflake().nextIdStr();
|
||||
}
|
||||
|
||||
/**
|
||||
* 捕获当前线程的完整 MDC 上下文快照
|
||||
* <p>适用于手动创建 Thread、CompletableFuture、自定义线程池等场景</p>
|
||||
*/
|
||||
public static Map<String, String> captureMdc() {
|
||||
return MDC.getCopyOfContextMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在新线程/任务中恢复完整的 MDC 上下文
|
||||
* <p>建议在新线程的开头调用,在 finally 块中调用 clear()</p>
|
||||
*/
|
||||
public static void restoreMdc() {
|
||||
Map<String, String> contextMap = TraceContext.captureMdc();
|
||||
if (contextMap != null) {
|
||||
MDC.setContextMap(contextMap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在新线程/任务中只恢复 traceId
|
||||
*/
|
||||
public static void restoreTraceId(String traceId) {
|
||||
MDC.remove(TRACE_ID_KEY);
|
||||
if (traceId != null) {
|
||||
MDC.put(TRACE_ID_KEY, traceId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package org.dromara.common.web.filter;
|
||||
|
||||
import jakarta.servlet.*;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.dromara.common.web.context.TraceContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Author: miracle
|
||||
* Date: 2026/1/14 下午1:41
|
||||
*/
|
||||
public class TraceIdFilter implements Filter {
|
||||
|
||||
private static final String TRACE_ID_HEADER = "X-Trace-Id";
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
HttpServletRequest req = (HttpServletRequest) request;
|
||||
HttpServletResponse resp = (HttpServletResponse) response;
|
||||
|
||||
String traceId = req.getHeader(TRACE_ID_HEADER);
|
||||
|
||||
// 前端传了就用前端的,没传就自己生成
|
||||
if (!StringUtils.hasText(traceId)) {
|
||||
traceId = TraceContext.generateTraceId();
|
||||
}
|
||||
|
||||
try {
|
||||
TraceContext.setTraceId(traceId);
|
||||
// 可选:把 traceId 写回响应头,方便前端/测试工具看到
|
||||
resp.setHeader(TRACE_ID_HEADER, traceId);
|
||||
chain.doFilter(request, response);
|
||||
} finally {
|
||||
// 必须清理!防止线程池复用导致上下文泄漏
|
||||
TraceContext.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user