๐ก๏ธ Spring Boot 4.0.4 & Java 25 ์์ ์ผ์ง
Last Updated: 2026๋ 04์ 13์ผ
๊ทผ 1๋ ๋์ ์์ ์๋๊ณ ์๋์ค์ ์ ๋ฐ์ดํธ ๋์๋ค๊ณ ํด์ ๋ฌด์กฐ๊ฑด ์ต์ ์ผ๋ก ํ๋๋ง ์ฌ๋ฌ๊ฐ์ง ๋ฌธ์ ์ ์ด ๋ฐ์์ ํ๋ค. ์ผ๋จ ์ ๋ฆฌ๋ฅผ ์ข ํด์ผ๊ฒ ๋ค๋ ์๊ฐ์ ์์ ํ๋ฉด์ ๋ฐ์ํ ๋ฌธ์ ์ ๋๋ ๋ฐ๋์ ์ ํ๋ํ๋ ์ถ๊ฐ๋ฅผ ํ๋ค.
[2026.03.29] ๋ฌธ์ ์ต์ด ์์ฑ ๋ฐ build.gradle ์ถ๊ฐ
[2026.04.12] gradle ํ๊ธ ๊นจ์ง ํ์ ์์
- Java 25 + Spring Boot 4.0.4 + Redis + Leaflet + ApexCharts + ์บ๋ฌ์ (Carousel)
- Redis ์ฌ์ฉ – https://upstash.com/
- 50% ์ถ์๋ ์์ ํ๋ฉด ์ด๋ฏธ์ง.
- ์์ ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ
D:.
โโjava
โ โโkr
โ โโnarrator
โ โโcommon (๊ณตํต ์ธํ๋ผ ๋ก์ง)
โ โ โโdomain (BaseTimeEntity ๋ฑ๋ฑ)
โ โ โโdto (ApiResponse ๊ฐ์ ์ ์ญ ์๋ต ๊ท๊ฒฉ์ ๊ด๋ฆฌ)
โ โ โโexception
โ โ โโutils (IP ์ถ์ถ ๋ก์ง ๋ฑ์ ๋ถ๋ฆฌ)
โ โโconfig (์ ํ๋ฆฌ์ผ์ด์
์ ๋ผ๋ ์ค์ , RedisConfig์ JpaAuditConfig ๋ฑ๋ฑ)
โ โโdomains (๋น์ฆ๋์ค ๋ก์ง์ ์ฌ์ฅ๋ถ)
โ โ โโdashboard (๋ฉ์ธ ํ๋ฉด)
โ โ โ โโcontroller
โ โ โ โโdto
โ โ โ โโservice
โ โ โโvisitor (๋ฐฉ๋ฌธ์ ๊ด๋ จ ๊ธฐ๋ฅ)
โ โ โโcontroller
โ โ โโdto
โ โ โโentity
โ โ โโrepository
โ โ โโservice
โ โโtest
โโresources
โโstatic
โ โโcss
โ โ โโlibs
โ โ โโbootstrap
โ โ โโsweetalert2
โ โโfonts
โ โโimages
โ โ โโbrands
โ โ โโflags
โ โ โโsvg
โ โ โโusers
โ โโjs
โ โ โโlibs
โ โ โ โโbootstrap
โ โ โ โโchoices
โ โ โ โโfeather-icons
โ โ โ โโflatpickr
โ โ โ โโnode-waves
โ โ โ โโsimplebar
โ โ โ โโsweetalert2
โ โ โ โโtoastify
โ โ โโmodules
โ โ โโpages
โ โ โโadmin
โ โ โโdashboard
โ โโlang
โโtemplates
โโerror
โโhtml
โ โโadmin
โ โโdashboard
โ โโfragments (ํ๋ฉด์ ์กฐ๊ฐ์ผ๋ก ๋๋์ด ๊ด๋ฆฌ)
โโlayouts (๋ชจ๋ ํ์ด์ง์ ๊ณตํต ํค๋/ํธํฐ/์ฌ์ด๋๋ฐ๋ฅผ ํ๊ณณ์์ ๊ด๋ฆฌ)
โโadmin
โโbasic
- build.gradle ์ค์
plugins {
id 'java'
id 'org.springframework.boot' version '4.0.4'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'kr.narrator'
def timestamp = java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd_HHmm"))
version = "0.0.1-${timestamp}"
description = '์ฌ๋ฌ๊ฐ์ง ์์
์ ํ
์คํธํ๋ ์๋น์ค, ์นํ๋ก์ ํธ ๋ฐฑ์๋ ์๋ฒ'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(25)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
// --- Spring Boot Core ---
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-webflux' // WebClient ์ฌ์ฉ์ ์ํด WebFlux ์ถ๊ฐ
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:4.0.0' // ์์ ํ ๋ถ๋ถ
// --- Monitoring & Utils ---
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
// --- Infrastructure & DB ---
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
// --- Lombok & MapStruct (์์ ์ค์) ---
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
// --- DevTools & Test & Spring REST Docs ---
developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.withType(JavaCompile) {
options.compilerArgs.add("-parameters")
}
tasks.named('test') {
useJUnitPlatform()
}
[2026.04.12] gradle ํ๊ธ ๊นจ์ง ํ์ ์์
- https://gradle.org/releases/ ์์ ย binary-only ๋ค์ด๋ก๋ (gradle-9.4.1-bin.zip)
- ํ๊ฒฝ๋ณ์ ์ถ๊ฐ – ๋ณ์ ์ด๋ฆ: GRADLE_USER_HOME, ๋ณ์ ๊ฐ: d:\Java\gradle_home.gradle
- Preferences > Gradle ์์ – Local install…: D:\Java\gradle_home, Java home: D:\Java\jdk-25.0.2
// ... (์๋จ ์๋ต)
// --- Java ์ปดํ์ผ ์ต์
์ต์ ํ ---
tasks.withType(JavaCompile) {
options.compilerArgs += ["-parameters"]
options.encoding = 'UTF-8'
}
jacoco {
toolVersion = "0.8.14"
}
// 1. ๊ณตํต ์ ์ธ ๋์ ์ ์ (์ค๋ณต ์ ๊ฑฐ ๋ฐ ์ ์ง๋ณด์์ฑ ํฅ์)
def jacocoExcludes = [
"**/dto/**",
"**/entity/**",
"**/*Application*",
"**/*MapperImpl*", // MapStruct
"**/common/config/**"
]
jacocoTestReport {
dependsOn test
reports {
xml.required = false
html.required = true
}
// 2. ๋ฆฌํฌํธ ์์ฑ ์ ํด๋์ค ํํฐ๋ง ๋ก์ง ์ต์ ํ
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: jacocoExcludes)
}))
}
}
jacocoTestCoverageVerification {
dependsOn test
violationRules {
rule {
element = 'BUNDLE'
limit {
counter = 'INSTRUCTION'
value = 'COVEREDRATIO'
minimum = 0.00 // ํ์ฌ 0.19์ด๋ฏ๋ก ๋น๋ ํต๊ณผ ๊ฐ๋ฅ
}
}
rule {
element = 'CLASS'
// 3. ๋ณ์ํํ ์ ์ธ ๋์์ ๊ทธ๋๋ก ์ฌ์ฌ์ฉ (์ค์ ๋ฐฉ์ง)
excludes = jacocoExcludes
limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.00 // 0.00๋ณด๋ค๋ ์์ฃผ ๋ฎ์ ์์น๋ผ๋ ์ค์ ํด๋๋ ๊ฒ์ด ์ข์ต๋๋ค.
}
}
}
}
tasks.named('test') {
useJUnitPlatform()
finalizedBy jacocoTestReport
}
tasks.named('check') {
dependsOn jacocoTestCoverageVerification // check ์คํ ์ ๊ฒ์ฆ ์ํ
}