feat(banner): Add Forge Banner Module

- Added Banner module, including API, implementation and automatic configuration components
- Add banner configuration properties and policy enumeration
- Implement configurable banner provider class
- Create necessary project structures and configuration files
This commit is contained in:
gewuyou 2025-06-03 15:09:03 +08:00
parent 58593f7b21
commit bd03558440
19 changed files with 361 additions and 0 deletions

View File

@ -30,4 +30,10 @@ object Modules {
const val IMPL = ":forgeboot-trace-spring-boot-starter:forgeboot-trace-impl"
const val AUTOCONFIGURE = ":forgeboot-trace-spring-boot-starter:forgeboot-trace-autoconfigure"
}
object Banner {
const val STARTER = ":forgeboot-banner"
const val API = ":forgeboot-banner:forgeboot-banner-api"
const val IMPL = ":forgeboot-banner:forgeboot-banner-impl"
const val AUTOCONFIGURE = ":forgeboot-banner:forgeboot-banner-autoconfigure"
}
}

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

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

40
forgeboot-banner/.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,6 @@
extra{
setProperty(ProjectFlags.IS_ROOT_MODULE,true)
}
dependencies {
}

View File

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

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,6 @@
dependencies {
compileOnly(platform(libs.springBootDependencies.bom))
compileOnly(libs.springBootStarter.web)
kapt(libs.springBoot.configuration.processor)
}

View File

@ -0,0 +1,16 @@
package com.gewuyou.forgeboot.banner.api.config.entities
import com.gewuyou.forgeboot.banner.api.enums.BannerStrategy
import org.springframework.boot.context.properties.ConfigurationProperties
/**
*横幅配置
*
* @since 2025-06-03 12:55:18
* @author gewuyou
*/
@ConfigurationProperties("forgeboot.banner")
class BannerProperties {
var path: String = "banners/"
var strategy: BannerStrategy = BannerStrategy.Random
}

View File

@ -0,0 +1,13 @@
package com.gewuyou.forgeboot.banner.api.enums
/**
*横幅策略
*
* @since 2025-06-03 13:04:30
* @author gewuyou
*/
enum class BannerStrategy {
First,
Random,
All
}

View File

@ -0,0 +1,18 @@
package com.gewuyou.forgeboot.banner.api.provider
import java.io.PrintStream
/**
* 横幅提供商接口用于定义横幅输出行为
*
* @since 2025-06-03 12:17:19
* @author gewuyou
*/
fun interface BannerProvider {
/**
* 输出横幅内容到指定的输出流
*
* @param out 输出流对象
*/
fun printBanner(out: PrintStream)
}

View File

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

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,6 @@
dependencies {
compileOnly(platform(libs.springBootDependencies.bom))
compileOnly(libs.springBootStarter.web)
compileOnly(project(Modules.Banner.API))
}

View File

@ -0,0 +1,75 @@
package com.gewuyou.forgeboot.banner.impl
import com.gewuyou.forgeboot.banner.api.enums.BannerStrategy
import com.gewuyou.forgeboot.banner.api.provider.BannerProvider
import com.gewuyou.forgeboot.banner.api.config.entities.BannerProperties
import org.springframework.core.io.Resource
import org.springframework.core.io.support.PathMatchingResourcePatternResolver
import java.io.PrintStream
import java.util.Random
import java.util.Scanner
/**
* 可配置横幅提供者类根据配置属性输出横幅
*
* @param properties 横幅属性配置对象
*/
class ConfigurableBannerProvider(
private val properties: BannerProperties,
): BannerProvider {
/**
* 输出横幅内容到指定的输出流
*
* @param out 输出流对象可为空
*/
override fun printBanner(out: PrintStream) {
try {
// 根据属性配置获取横幅资源路径模式
val pattern = "classpath*:" + properties.path + "*.txt"
// 使用路径匹配获取所有符合条件的资源
val resources: Array<Resource?> = PathMatchingResourcePatternResolver().getResources(pattern)
// 如果没有找到任何资源,则输出提示信息并返回
if (resources.isEmpty()) {
out.println("No banner found in: " + properties.path)
return
}
// 根据配置的策略选择横幅输出方式
when (properties.strategy) {
BannerStrategy.First-> resources[0]?.let { printResource(it, out) }
BannerStrategy.Random -> resources[Random().nextInt(resources.size)]?.let { printResource(it, out) }
BannerStrategy.All -> {
for (resource in resources) {
resource?.let { printResource(it, out) }
out.println()
}
}
}
} catch (e: Exception) {
// 异常处理:输出错误信息
out.println("Error loading banners: " + e.message)
}
}
/**
* 打印资源内容到指定的输出流
*
* @param resource 要打印的资源对象
* @param out 输出流对象
*/
private fun printResource(resource: Resource, out: PrintStream) {
try {
// 使用输入流读取资源内容并输出
resource.inputStream.use { `is` ->
Scanner(`is`).useDelimiter("\\A").use { scanner ->
while (scanner.hasNext()) {
out.println(scanner.next())
}
}
}
} catch (e: java.lang.Exception) {
// 异常处理:输出错误信息
out.println("Failed to print banner: " + e.message)
}
}
}

View File

@ -0,0 +1 @@
spring.application.name=forgeboot-banner-impl

View File

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

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 @@
dependencies {
compileOnly(platform(libs.springBootDependencies.bom))
compileOnly(libs.springBootStarter.web)
compileOnly(project(Modules.Banner.IMPL))
compileOnly(project(Modules.Banner.API))
implementation(project(Modules.Core.EXTENSION))
}

View File

@ -0,0 +1,34 @@
package com.gewuyou.forgeboot.banner.launcher
import com.gewuyou.forgeboot.banner.api.config.entities.BannerProperties
import com.gewuyou.forgeboot.banner.impl.ConfigurableBannerProvider
import org.springframework.boot.Banner
import org.springframework.boot.builder.SpringApplicationBuilder
import org.springframework.boot.context.properties.bind.Binder
import org.springframework.core.env.StandardEnvironment
/**
* 使用Forge横幅运行Spring应用的函数
* 该函数主要用于简化Spring应用的启动过程特别是当需要自定义横幅时
* 它通过反射启动一个Spring应用并允许开发者在启动时自定义横幅
*
* @param T Spring应用的主类类型必须是Any的子类
* @param args 命令行参数传递给Spring应用
*/
inline fun <reified T : Any> runApplicationWithForgeBanner(vararg args: String) {
// 创建并配置Spring应用的环境
val env = StandardEnvironment()
// 获取配置属性绑定器
val binder = Binder.get(env)
// 从配置中绑定BannerProperties属性如果没有找到则使用默认值
val props = binder.bind("banner", BannerProperties::class.java).orElse(BannerProperties())
// 创建一个自定义的Banner实例
val banner = Banner { _, _, out -> ConfigurableBannerProvider(props).printBanner(out) }
// 构建并运行Spring应用
SpringApplicationBuilder()
.sources(T::class.java)
.banner(banner)
.environment(env)
.run(*args)
}