mirror of
				https://github.moeyy.xyz/https://github.com/GeWuYou/forgeboot
				synced 2025-10-31 15:24:21 +08:00 
			
		
		
		
	Compare commits
	
		
			No commits in common. "1537973803b8e5fa56be87fcb51668a556ad9373" and "47691cd605c97fe711a3cc47fd27441a1952becf" have entirely different histories.
		
	
	
		
			1537973803
			...
			47691cd605
		
	
		
| @ -35,6 +35,8 @@ allprojects { | |||||||
|     // 设置全局属性 |     // 设置全局属性 | ||||||
|     ext { |     ext { | ||||||
|         set(ProjectFlags.IS_ROOT_MODULE, false) |         set(ProjectFlags.IS_ROOT_MODULE, false) | ||||||
|  |         set(ProjectFlags.USE_SPRING_BOOT_BOM, false) | ||||||
|  |         set(ProjectFlags.USE_CONFIGURATION_PROCESSOR, false) | ||||||
|     } |     } | ||||||
|     afterEvaluate { |     afterEvaluate { | ||||||
|         if (project.getPropertyByBoolean(ProjectFlags.IS_ROOT_MODULE)) { |         if (project.getPropertyByBoolean(ProjectFlags.IS_ROOT_MODULE)) { | ||||||
| @ -51,21 +53,13 @@ allprojects { | |||||||
| subprojects { | subprojects { | ||||||
|     version = rootProject.version |     version = rootProject.version | ||||||
|     afterEvaluate { |     afterEvaluate { | ||||||
|         val isRootModule = project.getPropertyByBoolean(ProjectFlags.IS_ROOT_MODULE) |         if (project.getPropertyByBoolean(ProjectFlags.USE_SPRING_BOOT_BOM)) { | ||||||
|         val isStarterModule = project.name.contains("starter") |  | ||||||
|         if (isRootModule) { |  | ||||||
|             dependencies { |  | ||||||
|                 project.subprojects.forEach { |  | ||||||
|                     if (!it.getPropertyByBoolean(ProjectFlags.IS_ROOT_MODULE)) { |  | ||||||
|                         project.dependencies.add("api", project(it.path)) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         if (isStarterModule&&!isRootModule) { |  | ||||||
|             dependencies { |             dependencies { | ||||||
|                 implementation(platform(libs.springBootDependencies.bom)) |                 implementation(platform(libs.springBootDependencies.bom)) | ||||||
|                 implementation(platform(libs.springCloudDependencies.bom)) |             } | ||||||
|  |         } | ||||||
|  |         if(project.getPropertyByBoolean(ProjectFlags.USE_CONFIGURATION_PROCESSOR)){ | ||||||
|  |             dependencies { | ||||||
|                 annotationProcessor(libs.springBoot.configuration.processor) |                 annotationProcessor(libs.springBoot.configuration.processor) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,3 +1,3 @@ | |||||||
| dependencies { | dependencies { | ||||||
| 
 |     api(project(Modules.Core.EXTENSION)) | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,3 +1,8 @@ | |||||||
|  | extra { | ||||||
|  |     // 需要SpringBootBom | ||||||
|  |     setProperty(ProjectFlags.USE_SPRING_BOOT_BOM, true) | ||||||
|  |     setProperty(ProjectFlags.USE_CONFIGURATION_PROCESSOR, true) | ||||||
|  | } | ||||||
| dependencies { | dependencies { | ||||||
|     implementation(project(Modules.Core.EXTENSION)) |     implementation(project(Modules.Core.EXTENSION)) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; | |||||||
|  * @author gewuyou |  * @author gewuyou | ||||||
|  * @since 2025-02-18 23:59:57 |  * @since 2025-02-18 23:59:57 | ||||||
|  */ |  */ | ||||||
| @ConfigurationProperties(prefix = "forgeboot.i18n") | @ConfigurationProperties(prefix = "base-forge.i18n") | ||||||
| public class I18nProperties { | public class I18nProperties { | ||||||
|     /** |     /** | ||||||
|      * 默认语言 |      * 默认语言 | ||||||
|  | |||||||
							
								
								
									
										3
									
								
								forgeboot-trace/.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								forgeboot-trace/.gitattributes
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +0,0 @@ | |||||||
| /gradlew text eol=lf |  | ||||||
| *.bat text eol=crlf |  | ||||||
| *.jar binary |  | ||||||
							
								
								
									
										40
									
								
								forgeboot-trace/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										40
									
								
								forgeboot-trace/.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,40 +0,0 @@ | |||||||
| HELP.md |  | ||||||
| .gradle |  | ||||||
| build/ |  | ||||||
| !gradle/wrapper/gradle-wrapper.jar |  | ||||||
| !**/src/main/**/build/ |  | ||||||
| !**/src/test/**/build/ |  | ||||||
| 
 |  | ||||||
| ### STS ### |  | ||||||
| .apt_generated |  | ||||||
| .classpath |  | ||||||
| .factorypath |  | ||||||
| .project |  | ||||||
| .settings |  | ||||||
| .springBeans |  | ||||||
| .sts4-cache |  | ||||||
| bin/ |  | ||||||
| !**/src/main/**/bin/ |  | ||||||
| !**/src/test/**/bin/ |  | ||||||
| 
 |  | ||||||
| ### IntelliJ IDEA ### |  | ||||||
| .idea |  | ||||||
| *.iws |  | ||||||
| *.iml |  | ||||||
| *.ipr |  | ||||||
| out/ |  | ||||||
| !**/src/main/**/out/ |  | ||||||
| !**/src/test/**/out/ |  | ||||||
| 
 |  | ||||||
| ### NetBeans ### |  | ||||||
| /nbproject/private/ |  | ||||||
| /nbbuild/ |  | ||||||
| /dist/ |  | ||||||
| /nbdist/ |  | ||||||
| /.nb-gradle/ |  | ||||||
| 
 |  | ||||||
| ### VS Code ### |  | ||||||
| .vscode/ |  | ||||||
| 
 |  | ||||||
| ### Kotlin ### |  | ||||||
| .kotlin |  | ||||||
| @ -1,12 +0,0 @@ | |||||||
| dependencies { |  | ||||||
|     implementation(project(Modules.Core.EXTENSION)) |  | ||||||
|     // Spring Cloud OpenFeign (Compile Only) |  | ||||||
|     // https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign |  | ||||||
|     compileOnly(libs.springCloudStarter.openfeign) |  | ||||||
|     // Reactor Core (Compile Only) |  | ||||||
|     // https://mvnrepository.com/artifact/io.projectreactor/reactor-core |  | ||||||
|     compileOnly(libs.reactor.core) |  | ||||||
| 
 |  | ||||||
|     compileOnly(libs.springBootStarter.web) |  | ||||||
|     compileOnly(libs.springBootStarter.webflux) |  | ||||||
| } |  | ||||||
| @ -1,54 +0,0 @@ | |||||||
| package com.gewuyou.forgeboot.trace.config.entities; |  | ||||||
| 
 |  | ||||||
| import org.springframework.boot.context.properties.ConfigurationProperties; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * 跟踪属性 |  | ||||||
|  * 该类用于配置和管理请求跟踪相关的属性,通过这些属性可以对请求进行唯一的标识和跟踪 |  | ||||||
|  * 主要功能包括定义请求ID的HTTP头名称、请求ID在MDC中的键名称,以及忽略跟踪的URL模式 |  | ||||||
|  * |  | ||||||
|  * @author gewuyou |  | ||||||
|  * @since 2025-05-02 20:58:45 |  | ||||||
|  */ |  | ||||||
| @ConfigurationProperties(prefix = "forgeboot.trace") |  | ||||||
| public class TraceProperties { |  | ||||||
|     /** |  | ||||||
|      * HTTP请求头中用于传递请求ID的字段名称,默认为"X-Request-Id"。 |  | ||||||
|      */ |  | ||||||
|     private String requestIdHeaderName = "X-Request-Id"; |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * MDC(Mapped Diagnostic Context)中用于存储请求ID的键名,默认为"requestId"。 |  | ||||||
|      */ |  | ||||||
|     private String requestIdMdcKey = "requestId"; |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * 配置忽略日志记录的路径模式,通常用于静态资源文件, |  | ||||||
|      * 默认忽略以.css、.js、.png等结尾的静态资源请求。 |  | ||||||
|      */ |  | ||||||
|     private String[] ignorePatten = new String[]{".*\\.(css|js|png|jpg|jpeg|gif|svg)"}; |  | ||||||
| 
 |  | ||||||
|     public String getRequestIdHeaderName() { |  | ||||||
|         return requestIdHeaderName; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public String[] getIgnorePatten() { |  | ||||||
|         return ignorePatten; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setIgnorePatten(String[] ignorePatten) { |  | ||||||
|         this.ignorePatten = ignorePatten; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setRequestIdHeaderName(String requestIdHeaderName) { |  | ||||||
|         this.requestIdHeaderName = requestIdHeaderName; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public String getRequestIdMdcKey() { |  | ||||||
|         return requestIdMdcKey; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setRequestIdMdcKey(String requestIdMdcKey) { |  | ||||||
|         this.requestIdMdcKey = requestIdMdcKey; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,30 +0,0 @@ | |||||||
| package com.gewuyou.forgeboot.trace.util; |  | ||||||
| 
 |  | ||||||
| import java.util.UUID; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * 请求 ID Util |  | ||||||
|  * 这个类需配合 RequestIdFilter 使用,用于生成请求 ID,并将其绑定到线程变量中,供后续可能需要的地方使用。 |  | ||||||
|  * @author gewuyou |  | ||||||
|  * @since 2025-01-02 14:27:45 |  | ||||||
|  */ |  | ||||||
| public class RequestIdUtil { |  | ||||||
|     private static final ThreadLocal<String> REQUEST_ID_HOLDER = new ThreadLocal<>(); |  | ||||||
|     private RequestIdUtil() { |  | ||||||
|     } |  | ||||||
|     public static void generateRequestId() { |  | ||||||
|         REQUEST_ID_HOLDER.set(UUID.randomUUID().toString()); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static String getRequestId() { |  | ||||||
|         return REQUEST_ID_HOLDER.get(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static void setRequestId(String uuid) { |  | ||||||
|         REQUEST_ID_HOLDER.set(uuid); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static void removeRequestId() { |  | ||||||
|         REQUEST_ID_HOLDER.remove(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,91 +0,0 @@ | |||||||
| package com.gewuyou.forgeboot.trace.config |  | ||||||
| 
 |  | ||||||
| import com.gewuyou.forgeboot.trace.config.entities.TraceProperties |  | ||||||
| import com.gewuyou.forgeboot.trace.decorator.RequestIdTaskDecorator |  | ||||||
| import com.gewuyou.forgeboot.trace.filter.ReactiveRequestIdFilter |  | ||||||
| import com.gewuyou.forgeboot.trace.filter.RequestIdFilter |  | ||||||
| import com.gewuyou.forgeboot.trace.filter.WebClientRequestIdFilter |  | ||||||
| import com.gewuyou.forgeboot.trace.interceptor.FeignRequestIdInterceptor |  | ||||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnBean |  | ||||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnClass |  | ||||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean |  | ||||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty |  | ||||||
| import org.springframework.boot.context.properties.EnableConfigurationProperties |  | ||||||
| import org.springframework.cloud.openfeign.FeignAutoConfiguration |  | ||||||
| import org.springframework.context.annotation.Bean |  | ||||||
| import org.springframework.context.annotation.Configuration |  | ||||||
| import org.springframework.web.reactive.function.client.WebClient |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * 跟踪自动配置 |  | ||||||
|  * |  | ||||||
|  * 该配置类用于自动配置请求跟踪功能,包括Spring MVC、Spring WebFlux、Feign和异步线程池的请求ID生成和传递 |  | ||||||
|  * @since 2025-03-17 16:33:40 |  | ||||||
|  * @author gewuyou |  | ||||||
|  */ |  | ||||||
| @Configuration |  | ||||||
| @EnableConfigurationProperties(TraceProperties::class) |  | ||||||
| open class TraceAutoConfiguration { |  | ||||||
|     /** |  | ||||||
|      * Spring MVC 过滤器(仅当 Spring MVC 存在时生效) |  | ||||||
|      * |  | ||||||
|      * 该过滤器用于在Spring MVC应用中生成和传递请求ID |  | ||||||
|      * @param traceProperties 跟踪配置属性 |  | ||||||
|      * @return RequestIdFilter实例 |  | ||||||
|      */ |  | ||||||
|     @Bean |  | ||||||
|     @ConditionalOnProperty(name = ["spring.main.web-application-type"], havingValue = "servlet", matchIfMissing = true) |  | ||||||
|     @ConditionalOnMissingBean |  | ||||||
|     open fun requestIdFilter(traceProperties: TraceProperties): RequestIdFilter = RequestIdFilter(traceProperties) |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Spring WebFlux 过滤器(仅当 Spring WebFlux 存在时生效) |  | ||||||
|      * |  | ||||||
|      * 该过滤器用于在Spring WebFlux应用中生成和传递请求ID |  | ||||||
|      * @param traceProperties 跟踪配置属性 |  | ||||||
|      * @return ReactiveRequestIdFilter实例 |  | ||||||
|      */ |  | ||||||
|     @Bean |  | ||||||
|     @ConditionalOnProperty(name = ["spring.main.web-application-type"], havingValue = "reactive") |  | ||||||
|     @ConditionalOnMissingBean |  | ||||||
|     open fun reactiveRequestIdFilter(traceProperties: TraceProperties): ReactiveRequestIdFilter = |  | ||||||
|         ReactiveRequestIdFilter(traceProperties) |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Feign 拦截器(仅当 Feign 存在时生效) |  | ||||||
|      * |  | ||||||
|      * 该拦截器用于在Feign客户端中传递请求ID |  | ||||||
|      * @param traceProperties 跟踪配置属性 |  | ||||||
|      * @return FeignRequestIdInterceptor实例 |  | ||||||
|      */ |  | ||||||
|     @Bean |  | ||||||
|     @ConditionalOnClass(FeignAutoConfiguration::class) |  | ||||||
|     @ConditionalOnMissingBean |  | ||||||
|     open fun feignRequestIdInterceptor(traceProperties: TraceProperties): FeignRequestIdInterceptor = |  | ||||||
|         FeignRequestIdInterceptor(traceProperties) |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * 线程池装饰器(用于 @Async) |  | ||||||
|      * |  | ||||||
|      * 该装饰器用于在异步线程池中传递请求ID,确保异步执行的任务能够携带正确地请求信息 |  | ||||||
|      * @param traceProperties 跟踪配置属性 |  | ||||||
|      * @return RequestIdTaskDecorator实例 |  | ||||||
|      */ |  | ||||||
|     @Bean |  | ||||||
|     @ConditionalOnMissingBean |  | ||||||
|     open fun requestIdTaskDecorator(traceProperties: TraceProperties): RequestIdTaskDecorator = |  | ||||||
|         RequestIdTaskDecorator(traceProperties) |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * 配置 WebClient 并自动添加请求 ID 过滤器(仅在 WebClient 已存在时引入) |  | ||||||
|      */ |  | ||||||
|     @Bean |  | ||||||
|     @ConditionalOnBean(WebClient.Builder::class) // 如果 WebClient.Builder 已存在,则添加过滤器 |  | ||||||
|     open fun webClientRequestIdFilter( |  | ||||||
|         webClientBuilder: WebClient.Builder, |  | ||||||
|         traceProperties: TraceProperties |  | ||||||
|     ): WebClient.Builder { |  | ||||||
|         // 在现有 WebClient 配置中添加请求 ID 过滤器 |  | ||||||
|         return webClientBuilder.filter(WebClientRequestIdFilter(traceProperties)) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,29 +0,0 @@ | |||||||
| package com.gewuyou.forgeboot.trace.decorator |  | ||||||
| 
 |  | ||||||
| import com.gewuyou.forgeboot.trace.config.entities.TraceProperties |  | ||||||
| import org.slf4j.MDC |  | ||||||
| import org.springframework.core.task.TaskDecorator |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  *请求ID任务装饰器 |  | ||||||
|  * |  | ||||||
|  * @since 2025-03-17 16:57:54 |  | ||||||
|  * @author gewuyou |  | ||||||
|  */ |  | ||||||
| class RequestIdTaskDecorator( |  | ||||||
|     private val traceProperties: TraceProperties |  | ||||||
| ) : TaskDecorator { |  | ||||||
|     override fun decorate(task: Runnable): Runnable { |  | ||||||
|         val requestIdMdcKey = traceProperties.requestIdMdcKey |  | ||||||
|         // 获取主线程 requestId |  | ||||||
|         val requestId = MDC.get(requestIdMdcKey) |  | ||||||
|         return Runnable { |  | ||||||
|             try { |  | ||||||
|                 MDC.put(requestIdMdcKey, requestId) |  | ||||||
|                 task.run() |  | ||||||
|             } finally { |  | ||||||
|                 MDC.remove(requestIdMdcKey) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,60 +0,0 @@ | |||||||
| package com.gewuyou.forgeboot.trace.extension |  | ||||||
| 
 |  | ||||||
| import jakarta.servlet.http.HttpServletRequest |  | ||||||
| import org.springframework.http.HttpMethod |  | ||||||
| import org.springframework.http.server.reactive.ServerHttpRequest |  | ||||||
| import org.springframework.web.reactive.function.client.ClientRequest |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * 请求扩展 |  | ||||||
|  * |  | ||||||
|  * @since 2025-05-02 21:59:26 |  | ||||||
|  * @author gewuyou |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * 判断是否跳过请求 |  | ||||||
|  * @apiNote 这个方法是给反应式请求id过滤器使用的 |  | ||||||
|  * @return true: 跳过请求; false: 不跳过请求 |  | ||||||
|  */ |  | ||||||
| fun ServerHttpRequest.isSkipRequest(ignorePaths: Array<String>): Boolean { |  | ||||||
|     return isSkipRequest(this.method.name(), this.uri.path, ignorePaths) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * 判断是否跳过请求 |  | ||||||
|  * @apiNote 这个方法是给请求id过滤器使用的 |  | ||||||
|  * @return true: 跳过请求; false: 不跳过请求 |  | ||||||
|  */ |  | ||||||
| fun HttpServletRequest.isSkipRequest(ignorePaths: Array<String>): Boolean { |  | ||||||
|     return isSkipRequest(this.method, this.requestURI, ignorePaths) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * 判断是否跳过请求 |  | ||||||
|  * @apiNote 这个方法是给请求id过滤器使用的 |  | ||||||
|  * @return true: 跳过请求; false: 不跳过请求 |  | ||||||
|  */ |  | ||||||
| fun ClientRequest.isSkipRequest(ignorePaths: Array<String>): Boolean { |  | ||||||
|     return isSkipRequest(this.method().name(), this.url().path, ignorePaths) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * 判断是否跳过请求 |  | ||||||
|  * @param method 请求方法 |  | ||||||
|  * @param uri 请求路径 |  | ||||||
|  * @return true: 跳过请求; false: 不跳过请求 |  | ||||||
|  */ |  | ||||||
| fun isSkipRequest(method: String, uri: String, ignorePaths: Array<String>): Boolean { |  | ||||||
|     return when { |  | ||||||
|         // 跳过 OPTIONS 请求 |  | ||||||
|         HttpMethod.OPTIONS.name() == method -> true |  | ||||||
|         // 跳过 HEAD 请求 |  | ||||||
|         HttpMethod.HEAD.name() == method -> true |  | ||||||
|         // 跳过 TRACE 请求 |  | ||||||
|         HttpMethod.TRACE.name() == method -> true |  | ||||||
|         // 跳过模式匹配 |  | ||||||
|         ignorePaths.any { uri.matches(Regex(it)) } -> true |  | ||||||
|         else -> false |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,64 +0,0 @@ | |||||||
| package com.gewuyou.forgeboot.trace.filter |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| import com.gewuyou.forgeboot.core.extension.log |  | ||||||
| import com.gewuyou.forgeboot.trace.config.entities.TraceProperties |  | ||||||
| import com.gewuyou.forgeboot.trace.extension.isSkipRequest |  | ||||||
| import com.gewuyou.forgeboot.trace.util.RequestIdUtil |  | ||||||
| import org.slf4j.MDC |  | ||||||
| import org.springframework.web.server.ServerWebExchange |  | ||||||
| import org.springframework.web.server.WebFilter |  | ||||||
| import org.springframework.web.server.WebFilterChain |  | ||||||
| import reactor.core.publisher.Mono |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * 反应式请求 ID 过滤器 |  | ||||||
|  * |  | ||||||
|  * 该类的主要作用是在每个请求开始时生成或获取一个唯一的请求 ID,并将其设置到日志上下文中, |  | ||||||
|  * 以便在后续的日志记录中能够追踪到该请求。它还支持基于特定模式跳过某些请求的处理。 |  | ||||||
|  * |  | ||||||
|  * @param traceProperties 配置属性,包含请求 ID 的头名称和 MDK 关键等信息 |  | ||||||
|  * @since 2025-02-09 02:14:49 |  | ||||||
|  * @author gewuyou |  | ||||||
|  */ |  | ||||||
| class ReactiveRequestIdFilter( |  | ||||||
|     private val traceProperties: TraceProperties |  | ||||||
| )  : WebFilter { |  | ||||||
|     override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> { |  | ||||||
|         val request = exchange.request |  | ||||||
|         // 检测请求是否需要跳过 |  | ||||||
|         if (request.isSkipRequest(traceProperties.ignorePatten)) { |  | ||||||
|             return chain.filter(exchange) |  | ||||||
|         } |  | ||||||
|         // 获取请求头中请求 ID 的名称和 MDK 中的键 |  | ||||||
|         val requestIdHeader = traceProperties.requestIdHeaderName |  | ||||||
|         val requestIdMdcKey = traceProperties.requestIdMdcKey |  | ||||||
|         // 尝试从请求头中获取 requestId,如果存在则设置到 RequestIdUtil 中,否则生成一个新的 requestId |  | ||||||
|         request.headers[requestIdHeader]?.let { |  | ||||||
|             it.firstOrNull()?.let(RequestIdUtil::setRequestId) ?: RequestIdUtil.generateRequestId() |  | ||||||
|         } ?: RequestIdUtil.generateRequestId() |  | ||||||
|         // 获取当前的 requestId |  | ||||||
|         val currentRequestId = RequestIdUtil.getRequestId() |  | ||||||
|         // 将 requestId 设置到日志中 |  | ||||||
|         MDC.put(requestIdMdcKey, currentRequestId) |  | ||||||
|         log.info("设置 Request id: $currentRequestId") |  | ||||||
|         // ✅ **创建新的 request 并更新 exchange** |  | ||||||
|         // 更新请求头,确保后续的请求处理中包含 requestId |  | ||||||
|         val mutatedRequest = request.mutate() |  | ||||||
|             .header(requestIdHeader, currentRequestId) |  | ||||||
|             .build() |  | ||||||
|         val mutatedExchange = exchange.mutate().request(mutatedRequest).build() |  | ||||||
|         // 放行请求 |  | ||||||
|         return chain.filter(mutatedExchange) |  | ||||||
|             // ✅ 让 Reactor 线程也能获取 requestId |  | ||||||
|             // 将 requestId 写入 Reactor 的上下文中,以便在异步处理中也能访问 |  | ||||||
|             .contextWrite { ctx -> ctx.put(requestIdMdcKey, currentRequestId) } |  | ||||||
|             .doFinally { |  | ||||||
|                 // 清理 MDC 中的 requestId,避免内存泄漏 |  | ||||||
|                 MDC.remove(requestIdMdcKey) |  | ||||||
|                 // 将 requestId 清除 |  | ||||||
|                 RequestIdUtil.removeRequestId() |  | ||||||
|             } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,63 +0,0 @@ | |||||||
| package com.gewuyou.forgeboot.trace.filter |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| import com.gewuyou.forgeboot.core.extension.log |  | ||||||
| import com.gewuyou.forgeboot.trace.config.entities.TraceProperties |  | ||||||
| import com.gewuyou.forgeboot.trace.extension.isSkipRequest |  | ||||||
| import com.gewuyou.forgeboot.trace.util.RequestIdUtil |  | ||||||
| import jakarta.servlet.FilterChain |  | ||||||
| import jakarta.servlet.http.HttpServletRequest |  | ||||||
| import jakarta.servlet.http.HttpServletResponse |  | ||||||
| import org.slf4j.MDC |  | ||||||
| import org.springframework.web.filter.OncePerRequestFilter |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * 请求过滤器 |  | ||||||
|  * |  | ||||||
|  * 该过滤器用于在请求处理过程中添加和管理请求ID(RequestId),以便于日志追踪和调试 |  | ||||||
|  * 它基于Spring的OncePerRequestFilter,确保每个请求只被过滤一次 |  | ||||||
|  * |  | ||||||
|  * @param traceProperties Trace属性配置,包含请求ID的相关配置信息 |  | ||||||
|  * @since 2025-01-02 14:31:07 |  | ||||||
|  * @author gewuyou |  | ||||||
|  */ |  | ||||||
| class RequestIdFilter( |  | ||||||
|     private val traceProperties: TraceProperties |  | ||||||
| ) : OncePerRequestFilter() { |  | ||||||
|     override fun doFilterInternal( |  | ||||||
|         request: HttpServletRequest, |  | ||||||
|         response: HttpServletResponse, |  | ||||||
|         chain: FilterChain |  | ||||||
|     ) { |  | ||||||
|         // 检查请求是否需要跳过 |  | ||||||
|         if (request.isSkipRequest(traceProperties.ignorePatten)) { |  | ||||||
|             return chain.doFilter(request, response) |  | ||||||
|         } |  | ||||||
|         // 获取请求头中 requestId 的名称和 MDC 中的键 |  | ||||||
|         val requestIdHeader = traceProperties.requestIdHeaderName |  | ||||||
|         val requestIdMdcKey = traceProperties.requestIdMdcKey |  | ||||||
|         try { |  | ||||||
|             // 尝试从请求头中获取 requestId |  | ||||||
|             request.getHeader(requestIdHeader)?.also( |  | ||||||
|                 RequestIdUtil::setRequestId |  | ||||||
|             ) ?: run { |  | ||||||
|                 // 如果没有,则生成新的 requestId |  | ||||||
|                 RequestIdUtil.generateRequestId() |  | ||||||
|             } |  | ||||||
|             // 获取 requestId |  | ||||||
|             val requestId = RequestIdUtil.getRequestId() |  | ||||||
|             // 将requestId 设置到日志中 |  | ||||||
|             MDC.put(requestIdMdcKey, requestId) |  | ||||||
|             log.info("设置 Request id: $requestId") |  | ||||||
|             // 将 requestId 设置到响应头中 |  | ||||||
|             response.setHeader(requestIdHeader, requestId) |  | ||||||
|             // 继续处理请求 |  | ||||||
|             chain.doFilter(request, response) |  | ||||||
|         } finally { |  | ||||||
|             // 移除 MDC 中的 requestId |  | ||||||
|             MDC.remove(requestIdMdcKey) |  | ||||||
|             // 清理当前线程的 RequestId,防止内存泄漏 |  | ||||||
|             RequestIdUtil.removeRequestId() |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,57 +0,0 @@ | |||||||
| package com.gewuyou.forgeboot.trace.filter |  | ||||||
| 
 |  | ||||||
| import com.gewuyou.forgeboot.core.extension.log |  | ||||||
| import com.gewuyou.forgeboot.trace.config.entities.TraceProperties |  | ||||||
| import com.gewuyou.forgeboot.trace.extension.isSkipRequest |  | ||||||
| import com.gewuyou.forgeboot.trace.util.RequestIdUtil |  | ||||||
| import org.slf4j.MDC |  | ||||||
| import org.springframework.web.reactive.function.client.ClientRequest |  | ||||||
| import org.springframework.web.reactive.function.client.ClientResponse |  | ||||||
| import org.springframework.web.reactive.function.client.ExchangeFilterFunction |  | ||||||
| import org.springframework.web.reactive.function.client.ExchangeFunction |  | ||||||
| import reactor.core.publisher.Mono |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Web客户端请求ID过滤器 |  | ||||||
|  * |  | ||||||
|  * 该类的主要作用是在发出HTTP请求时,确保请求ID的正确传递和记录 |  | ||||||
|  * 如果请求被忽略,则直接传递不做处理;否则,会尝试从请求头中获取请求ID, |  | ||||||
|  * 如果获取不到则生成新的请求ID,并将其设置到请求头中以及日志中,以便于追踪请求 |  | ||||||
|  * |  | ||||||
|  * @param traceProperties 追踪属性配置,包括忽略模式、请求ID头名称和MDK中的键 |  | ||||||
|  * @since 2025-05-02 22:18:06 |  | ||||||
|  * @author gewuyou |  | ||||||
|  */ |  | ||||||
| class WebClientRequestIdFilter( |  | ||||||
|     private val traceProperties: TraceProperties |  | ||||||
| ) : ExchangeFilterFunction { |  | ||||||
|     override fun filter(request: ClientRequest, next: ExchangeFunction): Mono<ClientResponse> { |  | ||||||
|         // 检查请求是否被忽略,如果被忽略,则直接执行请求 |  | ||||||
|         if (request.isSkipRequest(traceProperties.ignorePatten)) { |  | ||||||
|             return next.exchange(request) |  | ||||||
|         } |  | ||||||
|         // 获取请求头中请求 ID 的名称和 MDK 中的键 |  | ||||||
|         val requestIdHeader = traceProperties.requestIdHeaderName |  | ||||||
|         val requestIdMdcKey = traceProperties.requestIdMdcKey |  | ||||||
|         // 尝试从请求头中获取 requestId,如果存在则设置到 RequestIdUtil 中,否则生成一个新的 requestId |  | ||||||
|         request.headers()[requestIdHeader]?.let { |  | ||||||
|             it.firstOrNull()?.let(RequestIdUtil::setRequestId) ?: RequestIdUtil.generateRequestId() |  | ||||||
|         } ?: RequestIdUtil.generateRequestId() |  | ||||||
|         // 获取当前的 requestId |  | ||||||
|         val currentRequestId = RequestIdUtil.getRequestId() |  | ||||||
|         // 将 requestId 设置到日志中 |  | ||||||
|         MDC.put(requestIdMdcKey, currentRequestId) |  | ||||||
|         log.info("设置 Request id: $currentRequestId") |  | ||||||
|         // 创建一个新的请求,包含 requestId 头 |  | ||||||
|         val mutatedRequest = ClientRequest.from(request) |  | ||||||
|             .header(requestIdHeader, currentRequestId) |  | ||||||
|             .build() |  | ||||||
|         // 执行请求,并在请求完成后清除 MDC 和 RequestIdUtil 中的 requestId |  | ||||||
|         return next.exchange(mutatedRequest) |  | ||||||
|             .doFinally { |  | ||||||
|                 MDC.remove(requestIdMdcKey) |  | ||||||
|                 RequestIdUtil.removeRequestId() |  | ||||||
|             } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -1,30 +0,0 @@ | |||||||
| package com.gewuyou.forgeboot.trace.interceptor |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| import com.gewuyou.forgeboot.core.extension.log |  | ||||||
| import com.gewuyou.forgeboot.trace.config.entities.TraceProperties |  | ||||||
| import com.gewuyou.forgeboot.trace.util.RequestIdUtil |  | ||||||
| import feign.RequestInterceptor |  | ||||||
| import feign.RequestTemplate |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Feign请求ID 拦截器 |  | ||||||
|  * |  | ||||||
|  * @since 2025-03-17 16:42:50 |  | ||||||
|  * @author gewuyou |  | ||||||
|  */ |  | ||||||
| class FeignRequestIdInterceptor( |  | ||||||
|     private val traceProperties: TraceProperties |  | ||||||
| ) : RequestInterceptor { |  | ||||||
|     override fun apply(template: RequestTemplate) { |  | ||||||
|         // 尝试获取当前请求的请求id |  | ||||||
|         val requestId = RequestIdUtil.getRequestId() |  | ||||||
|         requestId?.let { |  | ||||||
|             // 如果请求id存在,则添加到请求头中 |  | ||||||
|             template.header(traceProperties.requestIdHeaderName, requestId) |  | ||||||
|         } ?: run { |  | ||||||
|             log.warn("请求ID为null,请检查您是否已在过滤链中添加了请求filter。") |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1 +0,0 @@ | |||||||
| com.gewuyou.forgeboot.trace.config.TraceAutoConfiguration |  | ||||||
							
								
								
									
										3
									
								
								forgeboot-webflux/.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								forgeboot-webflux/.gitattributes
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +0,0 @@ | |||||||
| /gradlew text eol=lf |  | ||||||
| *.bat text eol=crlf |  | ||||||
| *.jar binary |  | ||||||
							
								
								
									
										40
									
								
								forgeboot-webflux/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										40
									
								
								forgeboot-webflux/.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,40 +0,0 @@ | |||||||
| HELP.md |  | ||||||
| .gradle |  | ||||||
| build/ |  | ||||||
| !gradle/wrapper/gradle-wrapper.jar |  | ||||||
| !**/src/main/**/build/ |  | ||||||
| !**/src/test/**/build/ |  | ||||||
| 
 |  | ||||||
| ### STS ### |  | ||||||
| .apt_generated |  | ||||||
| .classpath |  | ||||||
| .factorypath |  | ||||||
| .project |  | ||||||
| .settings |  | ||||||
| .springBeans |  | ||||||
| .sts4-cache |  | ||||||
| bin/ |  | ||||||
| !**/src/main/**/bin/ |  | ||||||
| !**/src/test/**/bin/ |  | ||||||
| 
 |  | ||||||
| ### IntelliJ IDEA ### |  | ||||||
| .idea |  | ||||||
| *.iws |  | ||||||
| *.iml |  | ||||||
| *.ipr |  | ||||||
| out/ |  | ||||||
| !**/src/main/**/out/ |  | ||||||
| !**/src/test/**/out/ |  | ||||||
| 
 |  | ||||||
| ### NetBeans ### |  | ||||||
| /nbproject/private/ |  | ||||||
| /nbbuild/ |  | ||||||
| /dist/ |  | ||||||
| /nbdist/ |  | ||||||
| /.nb-gradle/ |  | ||||||
| 
 |  | ||||||
| ### VS Code ### |  | ||||||
| .vscode/ |  | ||||||
| 
 |  | ||||||
| ### Kotlin ### |  | ||||||
| .kotlin |  | ||||||
| @ -1,8 +0,0 @@ | |||||||
| extra { |  | ||||||
|     // 标记为根项目 |  | ||||||
|     setProperty(ProjectFlags.IS_ROOT_MODULE, true) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| dependencies { |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -4,5 +4,6 @@ extra { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| dependencies { | dependencies { | ||||||
| 
 |     api(project(Modules.Webmvc.VERSION_STARTER)) | ||||||
|  |     api(project(Modules.Webmvc.LOGGER_STARTER)) | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,3 +1,7 @@ | |||||||
|  | extra { | ||||||
|  |     // 需要SpringBootBom | ||||||
|  |     setProperty(ProjectFlags.USE_SPRING_BOOT_BOM, true) | ||||||
|  | } | ||||||
| dependencies { | dependencies { | ||||||
|     implementation(project(Modules.Core.EXTENSION)) |     implementation(project(Modules.Core.EXTENSION)) | ||||||
|     implementation(libs.springBootStarter.aop) |     implementation(libs.springBootStarter.aop) | ||||||
|  | |||||||
| @ -1,3 +1,7 @@ | |||||||
|  | extra { | ||||||
|  |     // 需要SpringBootBom | ||||||
|  |     setProperty(ProjectFlags.USE_SPRING_BOOT_BOM, true) | ||||||
|  | } | ||||||
| dependencies { | dependencies { | ||||||
|     implementation(project(Modules.Core.EXTENSION)) |     implementation(project(Modules.Core.EXTENSION)) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -8,7 +8,6 @@ kotlinxDatetime-version = "0.6.1" | |||||||
| kotlinxSerializationJSON-version = "1.7.3" | kotlinxSerializationJSON-version = "1.7.3" | ||||||
| #kotlinxCoroutines-version = "1.9.0" | #kotlinxCoroutines-version = "1.9.0" | ||||||
| axion-release-version = "1.18.7" | axion-release-version = "1.18.7" | ||||||
| spring-cloud-version = "2024.0.1" |  | ||||||
| spring-boot-version = "3.4.4" | spring-boot-version = "3.4.4" | ||||||
| 
 | 
 | ||||||
| slf4j-version = "2.0.17" | slf4j-version = "2.0.17" | ||||||
| @ -23,16 +22,11 @@ kotlinxCoroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-co | |||||||
| kotlinxCoroutines-reactor = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-reactor" } | kotlinxCoroutines-reactor = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-reactor" } | ||||||
| slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j-version" } | slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j-version" } | ||||||
| 
 | 
 | ||||||
| springBootDependencies-bom = { module = "org.springframework.boot:spring-boot-dependencies", version.ref = "spring-boot-version" } |  | ||||||
| springBootStarter-aop = { group = "org.springframework.boot", name = "spring-boot-starter-aop" } | springBootStarter-aop = { group = "org.springframework.boot", name = "spring-boot-starter-aop" } | ||||||
| springBootStarter-web = { group = "org.springframework.boot", name = "spring-boot-starter-web" } | springBootStarter-web = { group = "org.springframework.boot", name = "spring-boot-starter-web" } | ||||||
| springBootStarter-webflux = { group = "org.springframework.boot", name = "spring-boot-starter-webflux" } | springBootStarter-webflux = { group = "org.springframework.boot", name = "spring-boot-starter-webflux" } | ||||||
|  | springBootDependencies-bom = { module = "org.springframework.boot:spring-boot-dependencies", version.ref = "spring-boot-version" } | ||||||
| springBoot-configuration-processor = { group = "org.springframework.boot", name = "spring-boot-configuration-processor", version.ref = "spring-boot-version" } | springBoot-configuration-processor = { group = "org.springframework.boot", name = "spring-boot-configuration-processor", version.ref = "spring-boot-version" } | ||||||
| 
 |  | ||||||
| springCloudDependencies-bom = { module = "org.springframework.cloud:spring-cloud-dependencies", version.ref = "spring-cloud-version" } |  | ||||||
| springCloudStarter-openfeign = { group = "org.springframework.cloud", name = "spring-cloud-starter-openfeign" } |  | ||||||
| 
 |  | ||||||
| reactor-core={group="io.projectreactor", name="reactor-core"} |  | ||||||
| # Libraries can be bundled together for easier import | # Libraries can be bundled together for easier import | ||||||
| [bundles] | [bundles] | ||||||
| kotlinxEcosystem = ["kotlinxDatetime", "kotlinxSerialization", "kotlinxCoroutines-core"] | kotlinxEcosystem = ["kotlinxDatetime", "kotlinxSerialization", "kotlinxCoroutines-core"] | ||||||
|  | |||||||
| @ -43,23 +43,9 @@ project(":forgeboot-core").name = "forgeboot-core" | |||||||
| project(":forgeboot-core:forgeboot-core-extension").name = "forgeboot-core-extension" | project(":forgeboot-core:forgeboot-core-extension").name = "forgeboot-core-extension" | ||||||
| //endregion | //endregion | ||||||
| 
 | 
 | ||||||
| //region module i18n | //region i18n | ||||||
| include( | include( | ||||||
|     "forgeboot-i18n" |     "forgeboot-i18n" | ||||||
| ) | ) | ||||||
| project(":forgeboot-i18n").name = "forgeboot-i18n-spring-boot-starter" | project(":forgeboot-i18n").name = "forgeboot-i18n-spring-boot-starter" | ||||||
| //endregion | //endregion | ||||||
| 
 |  | ||||||
| //region module webflux |  | ||||||
| include( |  | ||||||
|     "forgeboot-webflux", |  | ||||||
| ) |  | ||||||
| project(":forgeboot-webflux").name = "forgeboot-webflux-spring-boot-starter" |  | ||||||
| //endregion |  | ||||||
| 
 |  | ||||||
| //region module trace |  | ||||||
| include( |  | ||||||
|     "forgeboot-trace" |  | ||||||
| ) |  | ||||||
| project(":forgeboot-trace").name = "forgeboot-trace-spring-boot-starter" |  | ||||||
| //endregion |  | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user