mirror of
https://github.moeyy.xyz/https://github.com/GeWuYou/forgeboot
synced 2025-10-27 19:36:36 +08:00
feat(webmvc): Add version control support
- Added ApiVersion annotations for version control of controllers and methods - Implement VersionAutoConfiguration automatic configuration class - Add ApiVersionRequestMappingHandlerMapping to handle version mapping - Update build configuration, support Spring Boot and version control - Added Git-related configuration files
This commit is contained in:
parent
2e60505c20
commit
c22389d584
160
build.gradle.kts
160
build.gradle.kts
@ -8,38 +8,38 @@ plugins {
|
||||
// Kotlin Spring 支持
|
||||
alias(libs.plugins.kotlin.plugin.spring)
|
||||
}
|
||||
//scmVersion {
|
||||
// tag {
|
||||
// prefix.set("") // 不加 v,生成 1.0.1 而不是 v1.0.1
|
||||
// }
|
||||
// versionIncrementer("incrementMinorIfNotOnRelease")
|
||||
// hooks {
|
||||
// pre("fileUpdate", mapOf(
|
||||
// "file" to "README.md",
|
||||
// "pattern" to "version: (.*)",
|
||||
// "replacement" to "version: \$version"
|
||||
// ))
|
||||
// pre("commit")
|
||||
// post("push")
|
||||
// }
|
||||
//
|
||||
//}
|
||||
//version = scmVersion.version
|
||||
scmVersion {
|
||||
tag {
|
||||
prefix.set("") // 不加 v,生成 1.0.1 而不是 v1.0.1
|
||||
}
|
||||
versionIncrementer("incrementMinorIfNotOnRelease")
|
||||
hooks {
|
||||
pre(
|
||||
"fileUpdate", mapOf(
|
||||
"file" to "README.md",
|
||||
"pattern" to "version: (.*)",
|
||||
"replacement" to "version: \$version"
|
||||
)
|
||||
)
|
||||
pre("commit")
|
||||
post("push")
|
||||
}
|
||||
|
||||
}
|
||||
version = scmVersion.version
|
||||
|
||||
val configDir = "$rootDir/config/"
|
||||
val tasksDir = "$configDir/tasks/"
|
||||
//apply {
|
||||
// from(file("$tasksDir/gradleTask.gradle"))
|
||||
//
|
||||
|
||||
allprojects {
|
||||
// 设置全局属性
|
||||
ext {
|
||||
set(ProjectFlags.IS_ROOT_MODULE, false)
|
||||
set(ProjectFlags.USE_SPRING_BOOT_BOM, false)
|
||||
set(ProjectFlags.USE_SPRING_BOOT_WEB, false)
|
||||
}
|
||||
afterEvaluate {
|
||||
if(project.getPropertyByBoolean(ProjectFlags.IS_ROOT_MODULE)){
|
||||
if (project.getPropertyByBoolean(ProjectFlags.IS_ROOT_MODULE)) {
|
||||
/**
|
||||
* 由于 Kotlin 插件引入时会自动添加依赖,但根项目不需要 Kotlin 依赖,因此需要排除 Kotlin 依赖
|
||||
*/
|
||||
@ -48,58 +48,106 @@ allprojects {
|
||||
}
|
||||
}
|
||||
}
|
||||
project.group = "com.gewuyou.forgeboot"
|
||||
}
|
||||
subprojects {
|
||||
// afterEvaluate {
|
||||
// if (project.getPropertyByBoolean(ProjectFlags.USE_GRPC)) {
|
||||
// dependencies{
|
||||
// implementation(platform(libs.grpc.bom))
|
||||
// // gRPC Stub
|
||||
// implementation(libs.grpc.stub)
|
||||
// }
|
||||
// }
|
||||
// if (project.getPropertyByBoolean(ProjectFlags.USE_SPRING_BOOT)){
|
||||
// dependencies{
|
||||
// implementation(platform(libs.springBootDependencies.bom))
|
||||
// compileOnly(libs.springBootStarter.web)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
version = rootProject.version
|
||||
afterEvaluate {
|
||||
if(project.getPropertyByBoolean(ProjectFlags.USE_SPRING_BOOT_BOM)){
|
||||
dependencies{
|
||||
implementation(platform(libs.springBootDependencies.bom))
|
||||
}
|
||||
}
|
||||
if (project.getPropertyByBoolean(ProjectFlags.USE_SPRING_BOOT_WEB)){
|
||||
dependencies{
|
||||
compileOnly(libs.springBootStarter.web)
|
||||
}
|
||||
}
|
||||
}
|
||||
val libs = rootProject.libs
|
||||
apply {
|
||||
plugin(libs.plugins.java.get().pluginId)
|
||||
plugin(libs.plugins.maven.publish.get().pluginId)
|
||||
plugin(libs.plugins.kotlin.jvm.get().pluginId)
|
||||
plugin(libs.plugins.axionRelease.get().pluginId)
|
||||
// plugin(libs.plugins.spring.dependency.management.get().pluginId)
|
||||
// 导入仓库配置
|
||||
from(file("$configDir/repositories.gradle.kts"))
|
||||
// 导入源代码任务
|
||||
from(file("$tasksDir/sourceTask.gradle"))
|
||||
from(file("$tasksDir/sourceTask.gradle.kts"))
|
||||
// // 导入发布配置
|
||||
// from(file("$configDir/publishing.gradle"))
|
||||
// from(file("$configDir/publishing.gradle.kts"))
|
||||
}
|
||||
dependencies {
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
name = "localRepo"
|
||||
url = uri("file://D:/Maven/mvn_repository")
|
||||
}
|
||||
maven {
|
||||
name = "GitHubPackages"
|
||||
url = uri("https://maven.pkg.github.com/GeWuYou/forgeboot")
|
||||
credentials {
|
||||
username = System.getenv("GITHUB_USERNAME")
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
}
|
||||
publications {
|
||||
create<MavenPublication>("mavenJava") {
|
||||
val projectName = project.name
|
||||
from(components["java"])
|
||||
groupId = project.group.toString()
|
||||
artifactId = projectName
|
||||
version = project.version.toString()
|
||||
|
||||
}
|
||||
configure<JavaPluginExtension> {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(21))
|
||||
pom {
|
||||
name.set(projectName)
|
||||
description.set("Part of Forgeboot Starters")
|
||||
url.set("https://github.com/GeWuYou/forgeboot")
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name.set("Apache-2.0")
|
||||
url.set("https://www.apache.org/licenses/LICENSE-2.0")
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id.set("gewuyou")
|
||||
name.set("gewuyou")
|
||||
email.set("gewuyou1024@gmail.com")
|
||||
}
|
||||
}
|
||||
scm {
|
||||
connection.set("scm:git:git://github.com/GeWuYou/forgeboot.git")
|
||||
developerConnection.set("scm:git:ssh://github.com/GeWuYou/forgeboot.git")
|
||||
url.set("https://github.com/GeWuYou/forgeboot")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
|
||||
}
|
||||
configure<JavaPluginExtension> {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(21))
|
||||
}
|
||||
}
|
||||
tasks.withType<Jar> {
|
||||
isEnabled = true
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
tasks.named<Test>("test") {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
}
|
||||
// kotlin {
|
||||
// compilerOptions {
|
||||
// freeCompilerArgs.addAll("-Xjsr305=strict")
|
||||
// }
|
||||
// }
|
||||
tasks.withType<Jar> {
|
||||
isEnabled = true
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
tasks.named<Test>("test") {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
fun Project.getPropertyByBoolean(key: String): Boolean {
|
||||
return properties[key]?.toString()?.toBoolean() ?: false
|
||||
}
|
||||
@ -8,6 +8,7 @@
|
||||
object Modules {
|
||||
|
||||
object Webmvc {
|
||||
const val STARTER = ":forgeboot-webmvc"
|
||||
const val VERSION_STARTER = ":forgeboot-webmvc:forgeboot-webmvc-version-starter"
|
||||
const val LOGGER_STARTER = ":forgeboot-webmvc:forgeboot-webmvc-logger-starter"
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
object ProjectFlags {
|
||||
const val IS_ROOT_MODULE = "isRootModule"
|
||||
const val USE_SPRING_BOOT_BOM = "useSpringBootBom"
|
||||
const val USE_SPRING_BOOT_WEB = "useSpringBootWeb"
|
||||
}
|
||||
0
config/publishing.gradle.kts
Normal file
0
config/publishing.gradle.kts
Normal file
@ -1,17 +1,19 @@
|
||||
// This task creates a jar file with the source code of the project
|
||||
tasks.register("sourceTask", Jar, { Jar jar ->
|
||||
|
||||
tasks.register<Jar>("sourceTask") {
|
||||
logger.info("正在配置${project.name}源代码 jar 文件...")
|
||||
|
||||
// 单独添加 Kotlin 源代码目录
|
||||
from(sourceSets.main.kotlin.srcDirs) {
|
||||
into("kotlin") // 将 Kotlin 源代码放入子目录 kotlin
|
||||
// 收集所有源代码(包括 Kotlin 和 Java)
|
||||
val sourceSet = project.extensions.getByType<SourceSetContainer>()["main"]
|
||||
from(sourceSet.allSource) {
|
||||
into("sources") // 将所有源代码放入子目录 sources
|
||||
}
|
||||
|
||||
archiveClassifier.set("sources") // 设置生成文件的分类标识
|
||||
|
||||
logger.info("正在创建${project.name}源代码 jar 文件...")
|
||||
logger.info("创建${project.name}源代码 jar 文件完成!")
|
||||
}).configure {
|
||||
group = "build"
|
||||
}.configure {
|
||||
group = "source"
|
||||
description = "使用项目的源代码创建源代码 jar 文件"
|
||||
}
|
||||
3
forgeboot-webmvc/.gitattributes
vendored
Normal file
3
forgeboot-webmvc/.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/gradlew text eol=lf
|
||||
*.bat text eol=crlf
|
||||
*.jar binary
|
||||
40
forgeboot-webmvc/.gitignore
vendored
Normal file
40
forgeboot-webmvc/.gitignore
vendored
Normal 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
|
||||
8
forgeboot-webmvc/build.gradle.kts
Normal file
8
forgeboot-webmvc/build.gradle.kts
Normal file
@ -0,0 +1,8 @@
|
||||
extra {
|
||||
// 标记为根项目
|
||||
setProperty(ProjectFlags.IS_ROOT_MODULE, true)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
}
|
||||
3
forgeboot-webmvc/forgeboot-webmvc-version-starter/.gitattributes
vendored
Normal file
3
forgeboot-webmvc/forgeboot-webmvc-version-starter/.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/gradlew text eol=lf
|
||||
*.bat text eol=crlf
|
||||
*.jar binary
|
||||
40
forgeboot-webmvc/forgeboot-webmvc-version-starter/.gitignore
vendored
Normal file
40
forgeboot-webmvc/forgeboot-webmvc-version-starter/.gitignore
vendored
Normal 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
|
||||
@ -0,0 +1,8 @@
|
||||
extra {
|
||||
// 标记为根项目
|
||||
setProperty(ProjectFlags.USE_SPRING_BOOT_BOM, true)
|
||||
setProperty(ProjectFlags.USE_SPRING_BOOT_WEB, true)
|
||||
}
|
||||
dependencies {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.gewuyou.forgeboot.webmvc.version.annotation
|
||||
|
||||
/**
|
||||
*API 版本注解
|
||||
* 可用于类或方法上,用于标识 API 的版本号。方法上的注解优先级高于类上的注解。
|
||||
* @since 2025-02-04 20:23:34
|
||||
* @author gewuyou
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class ApiVersion (
|
||||
/**
|
||||
* API 版本号值 (如 v1, v2, v3 等)默认值为 v1
|
||||
*/
|
||||
vararg val value: String = ["v1"]
|
||||
)
|
||||
@ -0,0 +1,28 @@
|
||||
package com.gewuyou.forgeboot.webmvc.version.config
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.version.mapping.ApiVersionRequestMappingHandlerMapping
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
/**
|
||||
*版本自动配置
|
||||
*
|
||||
* @since 2025-04-26 13:09:58
|
||||
* @author gewuyou
|
||||
*/
|
||||
@Configuration
|
||||
open class VersionAutoConfiguration {
|
||||
/**
|
||||
* 创建并配置一个 ApiVersionRequestMappingHandlerMapping 实例
|
||||
*
|
||||
* 该方法通过注解 @Bean 标记,表明此方法会返回一个由 Spring 管理的 Bean 实例
|
||||
* ApiVersionRequestMappingHandlerMapping 是一个自定义的 HandlerMapping,
|
||||
* 它支持基于 API 版本的请求映射处理,这对于需要版本控制的 RESTful API 设计非常有用
|
||||
*
|
||||
* @return ApiVersionRequestMappingHandlerMapping 实例,用于处理基于 API 版本的请求映射
|
||||
*/
|
||||
@Bean
|
||||
open fun apiVersionRequestMappingHandlerMapping(): ApiVersionRequestMappingHandlerMapping {
|
||||
return ApiVersionRequestMappingHandlerMapping()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
package com.gewuyou.forgeboot.webmvc.version.mapping
|
||||
|
||||
|
||||
import com.gewuyou.forgeboot.webmvc.version.annotation.ApiVersion
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
|
||||
import java.lang.reflect.Method
|
||||
|
||||
/**
|
||||
*API 版本请求映射处理程序映射
|
||||
*
|
||||
* @since 2025-02-04 20:30:44
|
||||
* @author gewuyou
|
||||
*/
|
||||
class ApiVersionRequestMappingHandlerMapping : RequestMappingHandlerMapping() {
|
||||
/**
|
||||
* 判断是否处理特定类型的Bean
|
||||
* 仅处理标注了 @RestController 注解的类
|
||||
* @param beanType 要判断的Bean类型
|
||||
* @return 如果类型标注了 @RestController,则返回true,否则返回false
|
||||
*/
|
||||
override fun isHandler(beanType: Class<*>): Boolean {
|
||||
// 仅处理标注了 @RestController 注解的类
|
||||
return AnnotatedElementUtils.hasAnnotation(beanType, RestController::class.java)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取方法的映射信息
|
||||
* 首先尝试从方法上获取 @ApiVersion 注解,如果不存在,则尝试从类上获取
|
||||
* 如果存在 @ApiVersion 注解,则会根据注解中的版本信息来组合新地映射路径
|
||||
* @param method 方法对象
|
||||
* @param handlerType 处理器类型
|
||||
* @return 可能包含版本信息的 RequestMappingInfo,如果不存在 @ApiVersion 注解,则返回原始的映射信息
|
||||
*/
|
||||
override fun getMappingForMethod(method: Method, handlerType: Class<*>): RequestMappingInfo? {
|
||||
// 获取原始的 @RequestMapping 信息
|
||||
val requestMappingInfo = super.getMappingForMethod(method, handlerType) ?: return null
|
||||
// 优先获取方法上的注解
|
||||
val methodApiVersion = AnnotatedElementUtils.findMergedAnnotation(method, ApiVersion::class.java)
|
||||
// 当方法注解存在时构建并返回 RequestMappingInfo
|
||||
methodApiVersion?.let {
|
||||
return combineVersionMappings(requestMappingInfo, it.value)
|
||||
}
|
||||
// 获取类上的 @ApiVersion 注解
|
||||
val classApiVersion = AnnotatedElementUtils.findMergedAnnotation(handlerType, ApiVersion::class.java)
|
||||
classApiVersion?.let {
|
||||
return combineVersionMappings(requestMappingInfo, it.value)
|
||||
}
|
||||
// 当类注解不存在时返回原始的 RequestMappingInfo
|
||||
return requestMappingInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* 组合版本路径,支持多个版本
|
||||
* @param originalMapping 原始的 RequestMappingInfo
|
||||
* @param versions 版本数组
|
||||
* @return 组合后的 RequestMappingInfo
|
||||
*/
|
||||
private fun combineVersionMappings(
|
||||
originalMapping: RequestMappingInfo,
|
||||
versions: Array<out String>
|
||||
): RequestMappingInfo {
|
||||
return versions
|
||||
.map {
|
||||
// 加上版本前缀
|
||||
RequestMappingInfo
|
||||
.paths("/api/$it")
|
||||
.build()
|
||||
}.reduce {
|
||||
// 组合
|
||||
acc, mapping ->
|
||||
acc.combine(mapping)
|
||||
}
|
||||
// 组合原始 RequestMapping
|
||||
.combine(originalMapping)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
com.gewuyou.forgeboot.webmvc.version.config.VersionAutoConfiguration
|
||||
@ -15,6 +15,8 @@ kotlinxDatetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.r
|
||||
kotlinxSerialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJSON-version" }
|
||||
kotlinxCoroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutines-version" }
|
||||
|
||||
springBootStarter-web = { group = "org.springframework.boot", name = "spring-boot-starter-web" }
|
||||
springBootDependencies-bom = { module = "org.springframework.boot:spring-boot-dependencies", version.ref = "spring-boot-version" }
|
||||
|
||||
# Libraries can be bundled together for easier import
|
||||
[bundles]
|
||||
|
||||
@ -27,5 +27,6 @@ include(
|
||||
":forgeboot-webmvc:forgeboot-webmvc-version-starter",
|
||||
":forgeboot-webmvc:forgeboot-webmvc-logger-starter"
|
||||
)
|
||||
project(":forgeboot-webmvc:forgeboot-webmvc-version-starter").name = "forgeboot-webmvc-version-starter"
|
||||
project(":forgeboot-webmvc:forgeboot-webmvc-logger-starter").name = "forgeboot-webmvc-logger-starter"
|
||||
project(":forgeboot-webmvc").name = "forgeboot-webmvc-spring-boot-starter"
|
||||
project(":forgeboot-webmvc:forgeboot-webmvc-version-starter").name = "forgeboot-webmvc-version-spring-boot-starter"
|
||||
project(":forgeboot-webmvc:forgeboot-webmvc-logger-starter").name = "forgeboot-webmvc-logger-spring-boot-starter"
|
||||
Loading…
x
Reference in New Issue
Block a user