Compare commits

...

3 Commits

Author SHA1 Message Date
gewuyou
1537973803 feat(trace): Add request tracking function - Added TraceProperties class to configure tracking properties
- Implement RequestIdUtil tool class generation and storage request ID
- Add TraceAutoConfiguration Automatic Configuration Class
- Implementing RequestIdFilter and ReactiveRequestIdFilterRequestIdInterceptor interceptor support Feign clients
-Filter
- Add Feign to implement WebClientRequestIdFilter to support WebClient
- Add RequestIdTaskDecorator Decorator to support asynchronous thread pooling
- Added Request extension function to determine whether requests are skipped
2025-05-02 22:35:42 +08:00
gewuyou
6bfda9227f chore(forgeboot-webflux): Initialize project configuration
- Add .gitattributes files, set file line breaks and binary files to handle - Create .gitignore files, ignore unnecessary project files and directories
- Create a new build.gradle.kts file, configure root project properties and dependencies
2025-05-02 14:14:01 +08:00
gewuyou
15709c6516 refactor(projectStructure):Adjust dependencies and module configuration - Remove duplicate Spring Boot BOM configurations from each module
- Delete API dependencies in modules such as forgeboot-core, forgeboot-i18n
- Add submodule dependencies in the root project
- Optimize settings.gradle.kts, add forgeboot-webflux module
2025-05-02 14:13:27 +08:00
25 changed files with 623 additions and 26 deletions

View File

@ -35,8 +35,6 @@ 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)) {
@ -53,13 +51,21 @@ allprojects {
subprojects {
version = rootProject.version
afterEvaluate {
if (project.getPropertyByBoolean(ProjectFlags.USE_SPRING_BOOT_BOM)) {
val isRootModule = project.getPropertyByBoolean(ProjectFlags.IS_ROOT_MODULE)
val isStarterModule = project.name.contains("starter")
if (isRootModule) {
dependencies {
implementation(platform(libs.springBootDependencies.bom))
project.subprojects.forEach {
if (!it.getPropertyByBoolean(ProjectFlags.IS_ROOT_MODULE)) {
project.dependencies.add("api", project(it.path))
}
}
}
}
if(project.getPropertyByBoolean(ProjectFlags.USE_CONFIGURATION_PROCESSOR)){
if (isStarterModule&&!isRootModule) {
dependencies {
implementation(platform(libs.springBootDependencies.bom))
implementation(platform(libs.springCloudDependencies.bom))
annotationProcessor(libs.springBoot.configuration.processor)
}
}

View File

@ -1,3 +1,3 @@
dependencies {
api(project(Modules.Core.EXTENSION))
}

View File

@ -1,8 +1,3 @@
extra {
// 需要SpringBootBom
setProperty(ProjectFlags.USE_SPRING_BOOT_BOM, true)
setProperty(ProjectFlags.USE_CONFIGURATION_PROCESSOR, true)
}
dependencies {
implementation(project(Modules.Core.EXTENSION))

View File

@ -8,7 +8,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @author gewuyou
* @since 2025-02-18 23:59:57
*/
@ConfigurationProperties(prefix = "base-forge.i18n")
@ConfigurationProperties(prefix = "forgeboot.i18n")
public class I18nProperties {
/**
* 默认语言

3
forgeboot-trace/.gitattributes vendored Normal file
View File

@ -0,0 +1,3 @@
/gradlew text eol=lf
*.bat text eol=crlf
*.jar binary

40
forgeboot-trace/.gitignore vendored Normal file
View File

@ -0,0 +1,40 @@
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

View File

@ -0,0 +1,12 @@
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)
}

View File

@ -0,0 +1,54 @@
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";
/**
* MDCMapped 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;
}
}

View File

@ -0,0 +1,30 @@
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();
}
}

View File

@ -0,0 +1,91 @@
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 MVCSpring WebFluxFeign和异步线程池的请求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))
}
}

View File

@ -0,0 +1,29 @@
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)
}
}
}
}

View File

@ -0,0 +1,60 @@
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
}
}

View File

@ -0,0 +1,64 @@
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()
}
}
}

View File

@ -0,0 +1,63 @@
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()
}
}
}

View File

@ -0,0 +1,57 @@
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()
}
}
}

View File

@ -0,0 +1,30 @@
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。")
}
}
}

View File

@ -0,0 +1 @@
com.gewuyou.forgeboot.trace.config.TraceAutoConfiguration

3
forgeboot-webflux/.gitattributes vendored Normal file
View File

@ -0,0 +1,3 @@
/gradlew text eol=lf
*.bat text eol=crlf
*.jar binary

40
forgeboot-webflux/.gitignore vendored Normal file
View File

@ -0,0 +1,40 @@
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

View File

@ -0,0 +1,8 @@
extra {
// 标记为根项目
setProperty(ProjectFlags.IS_ROOT_MODULE, true)
}
dependencies {
}

View File

@ -4,6 +4,5 @@ extra {
}
dependencies {
api(project(Modules.Webmvc.VERSION_STARTER))
api(project(Modules.Webmvc.LOGGER_STARTER))
}

View File

@ -1,7 +1,3 @@
extra {
// 需要SpringBootBom
setProperty(ProjectFlags.USE_SPRING_BOOT_BOM, true)
}
dependencies {
implementation(project(Modules.Core.EXTENSION))
implementation(libs.springBootStarter.aop)

View File

@ -1,7 +1,3 @@
extra {
// 需要SpringBootBom
setProperty(ProjectFlags.USE_SPRING_BOOT_BOM, true)
}
dependencies {
implementation(project(Modules.Core.EXTENSION))

View File

@ -8,6 +8,7 @@ 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"
@ -22,11 +23,16 @@ 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"]
@ -43,4 +49,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" }

View File

@ -43,9 +43,23 @@ project(":forgeboot-core").name = "forgeboot-core"
project(":forgeboot-core:forgeboot-core-extension").name = "forgeboot-core-extension"
//endregion
//region i18n
//region module i18n
include(
"forgeboot-i18n"
)
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