Appearance
๐ฆ ๋ฉํฐ ๋ชจ๋ ๊ฐ์ด๋ โ
๊ตฌ์กฐ ๊ฐ์ โ
mo-it/
โโโ gradle/libs.versions.toml # ์์กด์ฑ ๋ฒ์ ๊ด๋ฆฌ
โโโ build.gradle.kts # ๊ณตํต Gradle ์ค์ (subprojects ๋ธ๋ก)
โโโ settings.gradle.kts # ๋ชจ๋ ์ ์
โโโ common/ # ๊ณตํต ์ ํธ, Exception, Response DTO
โโโ core/ # ๋๋ฉ์ธ Entity, Service, Port Interface
โโโ api/ # REST Controller
โโโ persistence/ # JPA Entity, Repository ๊ตฌํ
โโโ app/ # Spring Boot ์คํ๊ณตํต Gradle ์ค์ โ
๋ชจ๋ ๋ชจ๋์ ๊ณตํต ์ค์ ์ ๋ฃจํธ build.gradle.kts ์ subprojects ๋ธ๋ก์์ ๊ด๋ฆฌํฉ๋๋ค.
kotlin
// build.gradle.kts (๋ฃจํธ)
subprojects {
apply(plugin = "org.jetbrains.kotlin.jvm")
apply(plugin = "org.jetbrains.kotlin.plugin.spring")
apply(plugin = "io.spring.dependency-management")
// ๊ณตํต ์์กด์ฑ
dependencies {
"implementation"("com.fasterxml.jackson.module:jackson-module-kotlin")
"implementation"("org.jetbrains.kotlin:kotlin-reflect")
"testImplementation"("org.jetbrains.kotlin:kotlin-test-junit5")
}
// ๊ณตํต ์ค์ (Java 21, JUnit ๋ฑ)
configure<JavaPluginExtension> {
toolchain { languageVersion.set(JavaLanguageVersion.of(21)) }
}
tasks.withType<Test> { useJUnitPlatform() }
}์ฅ์ : ๊ฐ ๋ชจ๋์ build.gradle.kts๊ฐ ๋งค์ฐ ๊ฐ๊ฒฐํด์ง๋๋ค.
์์กด์ฑ ๋ฒ์ ๊ด๋ฆฌ (Version Catalog) โ
gradle/libs.versions.toml ์์ ์์กด์ฑ ๋ฒ์ ์ ์ค์ ๊ด๋ฆฌํฉ๋๋ค.
toml
[versions]
kotlin = "1.9.25"
spring-boot = "3.2.3"
[libraries]
spring-boot-starter-web = { module = "org.springframework.boot:spring-boot-starter-web" }
[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }์ฌ์ฉ๋ฒ:
kotlin
// ๋ชจ๋ build.gradle.kts
dependencies {
implementation(libs.spring.boot.starter.web)
}๋ชจ๋๋ณ ์ญํ โ
| ๋ชจ๋ | ์ญํ | ํจํค์ง |
|---|---|---|
common | ๊ณตํต Exception, Response DTO | com.moit.common.* |
core | ๋๋ฉ์ธ, ์๋น์ค, ํฌํธ ์ธํฐํ์ด์ค | com.moit.core.* |
api | REST Controller, ์์ฒญ/์๋ต DTO | com.moit.api.* |
persistence | JPA Entity, Repository ๊ตฌํ์ฒด | com.moit.persistence.* |
app | Spring Boot Main, ์ค์ ํ์ผ | com.moit |
์์กด์ฑ ํ๋ฆ โ
app
โโโ api โโโ core โโโ common
โโโ persistence โโโ core โโโ common
โโโ core โโโ common๊ท์น:
- ํ์ดํ ๋ฐฉํฅ์ผ๋ก๋ง ์์กด ๊ฐ๋ฅ
common์ ๋ค๋ฅธ ๋ชจ๋์ ์์กดํ์ง ์์core๋persistence๋ฅผ ๋ชจ๋ฆ (์ธํฐํ์ด์ค๋ง ์ ์)
์ ๊ธฐ๋ฅ ์ถ๊ฐ ๊ฐ์ด๋ โ
1. ์ ๋๋ฉ์ธ ์ถ๊ฐ (์: User) โ
kotlin
// 1๏ธโฃ core/domain/User.kt - ๋๋ฉ์ธ ๋ชจ๋ธ
data class User(
val id: Long?,
val email: String,
val name: String
)
// 2๏ธโฃ core/port/UserRepository.kt - ํฌํธ ์ธํฐํ์ด์ค
interface UserRepository {
fun findById(id: Long): User?
fun save(user: User): User
}
// 3๏ธโฃ core/service/UserService.kt - ๋น์ฆ๋์ค ๋ก์ง
@Service
class UserService(private val userRepository: UserRepository) {
fun getById(id: Long) = userRepository.findById(id)
}2. Repository ๊ตฌํ (persistence ๋ชจ๋) โ
kotlin
// persistence/entity/UserEntity.kt
@Entity
class UserEntity(
@Id @GeneratedValue
val id: Long? = null,
val email: String,
val name: String
)
// persistence/repository/UserJpaRepository.kt
interface UserJpaRepository : JpaRepository<UserEntity, Long>
// persistence/repository/UserRepositoryImpl.kt
@Repository
class UserRepositoryImpl(
private val jpaRepository: UserJpaRepository
) : UserRepository {
override fun findById(id: Long) = jpaRepository.findByIdOrNull(id)?.toDomain()
override fun save(user: User) = jpaRepository.save(user.toEntity()).toDomain()
}3. Controller ์ถ๊ฐ (api ๋ชจ๋) โ
kotlin
// api/controller/UserController.kt
@RestController
@RequestMapping("/api/users")
class UserController(private val userService: UserService) {
@GetMapping("/{id}")
fun getById(@PathVariable id: Long) = ApiResponse.success(userService.getById(id))
}์์กด์ฑ ์ถ๊ฐ โ
1. libs.versions.toml์ ์ถ๊ฐ โ
toml
[libraries]
spring-boot-starter-security = { module = "org.springframework.boot:spring-boot-starter-security" }2. ๋ชจ๋์์ ์ฌ์ฉ โ
kotlin
// build.gradle.kts
dependencies {
implementation(libs.spring.boot.starter.security)
}ํ์ฅ ๊ฐ์ด๋ โ
infra ๋ชจ๋ ์ถ๊ฐ (Redis, Kafka ๋ฑ) โ
settings.gradle.kts์ ์ถ๊ฐ:
kotlin
include("infra")infra/build.gradle.kts์์ฑ:
kotlin
dependencies {
implementation(project(":core"))
implementation("org.springframework.boot:spring-boot-starter-data-redis")
}- core ๋ชจ๋์ ์บ์ ํฌํธ ์ ์, infra์์ ๊ตฌํ
๋น๋ & ์คํ โ
bash
# ์ ์ฒด ๋น๋
./gradlew clean build
# ์ฑ ์คํ
./gradlew :app:bootRun
# ํน์ ๋ชจ๋ ๋น๋
./gradlew :core:build
# ํ
์คํธ ์คํ
./gradlew testFAQ โ
Q. ๊ณตํต ์ค์ ์ ์ด๋์ ๊ด๋ฆฌํ๋์?
A. ๋ฃจํธ
build.gradle.kts์subprojects๋ธ๋ก์์ ๊ด๋ฆฌํฉ๋๋ค.
Q. ์์กด์ฑ ๋ฒ์ ์ ์ด๋์ ๊ด๋ฆฌํ๋์?
A.
gradle/libs.versions.tomlํ์ผ์์ ์ค์ ๊ด๋ฆฌํฉ๋๋ค.
Q. ์ํ ์์กด์ด ๋ฐ์ํ์ด์
A. ๋ชจ๋ ์์๋ฅผ ํ์ธํ์ธ์: common โ core โ api/persistence โ app
Q. ์ ๋ชจ๋์ ์ถ๊ฐํ๋ ค๋ฉด?
A. settings.gradle.kts์ include ์ถ๊ฐ ํ, build.gradle.kts ์์ฑ
Q. ์ core์ persistence๊ฐ ๋ถ๋ฆฌ๋ผ ์๋์?
A. core๋ ์์ ๋น์ฆ๋์ค ๋ก์ง, persistence๋ DB ๊ธฐ์ ์ ์ข ์. ๋์ค์ DB ๋ณ๊ฒฝ ์ core๋ ์์ ์์