mirror of
				https://github.moeyy.xyz/https://github.com/GeWuYou/forgeboot
				synced 2025-10-31 06:36:39 +08:00 
			
		
		
		
	Compare commits
	
		
			No commits in common. "1537973803b8e5fa56be87fcb51668a556ad9373" and "47691cd605c97fe711a3cc47fd27441a1952becf" have entirely different histories.
		
	
	
		
			1537973803
			...
			47691cd605
		
	
		
| @ -35,6 +35,8 @@ allprojects { | ||||
|     // 设置全局属性 | ||||
|     ext { | ||||
|         set(ProjectFlags.IS_ROOT_MODULE, false) | ||||
|         set(ProjectFlags.USE_SPRING_BOOT_BOM, false) | ||||
|         set(ProjectFlags.USE_CONFIGURATION_PROCESSOR, false) | ||||
|     } | ||||
|     afterEvaluate { | ||||
|         if (project.getPropertyByBoolean(ProjectFlags.IS_ROOT_MODULE)) { | ||||
| @ -51,21 +53,13 @@ allprojects { | ||||
| subprojects { | ||||
|     version = rootProject.version | ||||
|     afterEvaluate { | ||||
|         val isRootModule = project.getPropertyByBoolean(ProjectFlags.IS_ROOT_MODULE) | ||||
|         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) { | ||||
|         if (project.getPropertyByBoolean(ProjectFlags.USE_SPRING_BOOT_BOM)) { | ||||
|             dependencies { | ||||
|                 implementation(platform(libs.springBootDependencies.bom)) | ||||
|                 implementation(platform(libs.springCloudDependencies.bom)) | ||||
|             } | ||||
|         } | ||||
|         if(project.getPropertyByBoolean(ProjectFlags.USE_CONFIGURATION_PROCESSOR)){ | ||||
|             dependencies { | ||||
|                 annotationProcessor(libs.springBoot.configuration.processor) | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -1,3 +1,3 @@ | ||||
| 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 { | ||||
|     implementation(project(Modules.Core.EXTENSION)) | ||||
| 
 | ||||
|  | ||||
| @ -8,7 +8,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; | ||||
|  * @author gewuyou | ||||
|  * @since 2025-02-18 23:59:57 | ||||
|  */ | ||||
| @ConfigurationProperties(prefix = "forgeboot.i18n") | ||||
| @ConfigurationProperties(prefix = "base-forge.i18n") | ||||
| 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 { | ||||
| 
 | ||||
|     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 { | ||||
|     implementation(project(Modules.Core.EXTENSION)) | ||||
|     implementation(libs.springBootStarter.aop) | ||||
|  | ||||
| @ -1,3 +1,7 @@ | ||||
| extra { | ||||
|     // 需要SpringBootBom | ||||
|     setProperty(ProjectFlags.USE_SPRING_BOOT_BOM, true) | ||||
| } | ||||
| dependencies { | ||||
|     implementation(project(Modules.Core.EXTENSION)) | ||||
| 
 | ||||
|  | ||||
| @ -8,7 +8,6 @@ kotlinxDatetime-version = "0.6.1" | ||||
| kotlinxSerializationJSON-version = "1.7.3" | ||||
| #kotlinxCoroutines-version = "1.9.0" | ||||
| axion-release-version = "1.18.7" | ||||
| spring-cloud-version = "2024.0.1" | ||||
| spring-boot-version = "3.4.4" | ||||
| 
 | ||||
| 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" } | ||||
| 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-web = { group = "org.springframework.boot", name = "spring-boot-starter-web" } | ||||
| 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" } | ||||
| 
 | ||||
| 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 | ||||
| [bundles] | ||||
| kotlinxEcosystem = ["kotlinxDatetime", "kotlinxSerialization", "kotlinxCoroutines-core"] | ||||
| @ -49,4 +43,4 @@ maven-publish = { id = "maven-publish" } | ||||
| # 引入 Kotlin 支持 | ||||
| kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin-version" } | ||||
| # 支持 Spring 的 Kotlin 插件 | ||||
| kotlin-plugin-spring = { id = "org.jetbrains.kotlin.plugin.spring", version.ref = "kotlin-version" } | ||||
| kotlin-plugin-spring = { id = "org.jetbrains.kotlin.plugin.spring", version.ref = "kotlin-version" } | ||||
| @ -43,23 +43,9 @@ project(":forgeboot-core").name = "forgeboot-core" | ||||
| project(":forgeboot-core:forgeboot-core-extension").name = "forgeboot-core-extension" | ||||
| //endregion | ||||
| 
 | ||||
| //region module i18n | ||||
| //region i18n | ||||
| include( | ||||
|     "forgeboot-i18n" | ||||
| ) | ||||
| project(":forgeboot-i18n").name = "forgeboot-i18n-spring-boot-starter" | ||||
| //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 | ||||
| //endregion | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user