Programming/Kotlin

Kotlin + Spring Boot 프로젝트 기본 구조(Layered Architecture)와 예제 코드

2025. 10. 8. 13:08
반응형

Kotlin과 Spring Boot를 이용한 웹 애플리케이션 개발을 시작하시나요?
이 글에서는 가장 기본적이고 실무에서도 널리 사용되는 Layered Architecture(계층형 구조) 기반으로
Controller, Service, Repository, Domain 계층을 나누고, 실제 예제 코드까지 작성해 보겠습니다.


반응형

들어가며

앞선 글에서 살펴본 것처럼, Spring Boot 프로젝트 구조에는 여러 방식이 있지만 개인 학습용 및 소규모 프로젝트에는 Layered Architecture가 가장 적합합니다.

 

Spring Boot 프로젝트 구조 설계 가이드 (MVC, Layered, Domain 기반, Hexagonal)

Spring Boot로 웹 애플리케이션을 개발할 때 어떤 프로젝트 구조를 선택해야 할지 고민되시나요?MVC, Layered, Domain 기반, Hexagonal 구조 등 대표적인 설계 방식들의 특징과 장단점을 비교하고, 개인 학

ggobugi.tistory.com

이번 글에서는 이 구조를 기반으로 실제로

  • 패키지 구조 설계
  • 각 계층별 역할
  • 기본 CRUD 예제 코드

를 통해 Kotlin + Spring Boot 애플리케이션의 기초를 다져보겠습니다.

1. 기본 패키지 구조

프로젝트 구조는 Layered Architecture를 사용하기로 했으므로 Spring Boot 프로젝트를 생성하고 패키지 구조를 다음과 같이 생성합니다.

com.example.demo
 ├── DemoApplication.kt
 ├── controller
 │    └── UserController.kt
 ├── service
 │    └── UserService.kt
 ├── repository
 │    └── UserRepository.kt
 └── domain
      └── User.kt

각 폴더의 역할은 다음과 같습니다:

패키지 역할
controller HTTP 요청을 받고 응답을 반환
service 비즈니스 로직을 수행
repository 데이터베이스 접근 (JPA, MyBatis 등)
domain 엔티티(데이터 모델) 정의

2. Domain (엔티티) 작성

먼저 사용자 정보를 저장할 User 엔티티를 작성해보겠습니다.

User.kt

package com.example.demo.domain

import jakarta.persistence.*

@Entity
data class User(
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0,

    @Column(nullable = false)
    val name: String,

    @Column(nullable = false, unique = true)
    val email: String
)

@Entity를 통해 데이터베이스 테이블과 매핑됩니다.
Kotlin 에서는 data class를 사용해 불변 객체로 관리하는 것이 일반적입니다.

3. Repository 작성

데이터베이스 CRUD를 담당하는 UserRepository를 만듭니다.

UserRepository.kt

package com.example.demo.repository

import com.example.demo.domain.User
import org.springframework.data.jpa.repository.JpaRepository

interface UserRepository : JpaRepository<User, Long> {
    fun findByEmail(email: String): User?
}

JpaRepository interface를 상속하면 기본적인 CRUD 메서드(findAll, save, deleteById 등)를 바로 사용할 수 있습니다.

4. Service 작성

비즈니스 로직을 처리하는 UserService는 Repository를 호출하여 데이터를 조작합니다.

UserService.kt

package com.example.demo.service

import com.example.demo.domain.User
import com.example.demo.repository.UserRepository
import org.springframework.stereotype.Service

@Service
class UserService(
    private val userRepository: UserRepository
) {
    fun getAllUsers(): List<User> = userRepository.findAll()

    fun getUserByEmail(email: String): User? = userRepository.findByEmail(email)

    fun createUser(name: String, email: String): User {
        val newUser = User(name = name, email = email)
        return userRepository.save(newUser)
    }
}

@Service 어노테이션을 통해 스프링이 이 클래스를 서비스 빈으로 관리하게 됩니다.

5. Controller 작성

이제 HTTP 요청을 받아 JSON 형태로 응답하는 Controller를 작성합니다.

UserController.kt

package com.example.demo.controller

import com.example.demo.domain.User
import com.example.demo.service.UserService
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/api/users")
class UserController(
    private val userService: UserService
) {
    @GetMapping
    fun getUsers(): List<User> = userService.getAllUsers()

    @GetMapping("/{email}")
    fun getUserByEmail(@PathVariable email: String): User? =
        userService.getUserByEmail(email)

    @PostMapping
    fun createUser(@RequestBody request: CreateUserRequest): User =
        userService.createUser(request.name, request.email)
}

data class CreateUserRequest(
    val name: String,
    val email: String
)

@RestController를 사용하면 API 응답을 자동으로 JSON 형태로 반환합니다.
POST 요청에서는 @RequestBody를 통해 JSON 데이터를 객체로 변환합니다.

6. 실행 및 테스트

  1. 상단 메뉴에서 Run → Run DemoApplication 실행
  2. 콘솔에 "Started DemoApplication" 로그가 출력되면 성공
  3. 테스트
    • 전체 사용자 조회: GET http://localhost:8080/api/users
    • 사용자 생성:
    • POST http://localhost:8080/api/users { "name": "ggobugi", "email": "ggobugi@example.com" }
    • 특정 사용자 조회: GET http://localhost:8080/api/users/ggobugi@example.com

7. Layered 구조의 장점 요약

  • 코드 책임이 명확하게 분리되어 유지보수 용이
  • 테스트 작성이 쉬움 (각 계층 단위로 가능)
  • 규모가 커져도 확장성이 좋음

초보자에게는 조금 복잡해 보일 수도 있지만, 익숙해지면 실제 실무 프로젝트와 거의 동일한 형태로 확장할 수 있습니다.

마무리

이번 글에서는 Layered Architecture 기반의 Spring Boot 프로젝트 구조와 예제 코드를 살펴봤습니다.
이제 이 구조를 기반으로 기능을 점진적으로 확장하면,
실무 수준의 애플리케이션을 자연스럽게 설계할 수 있게 됩니다.

다음 글에서는 "Kotlin + Spring Boot 프로젝트에 데이터베이스(H2, MySQL) 연결 및 환경 설정하는 방법"을 다루겠습니다.

반응형

'Programming > Kotlin' 카테고리의 다른 글

[Kotlin] Data Class  (0) 2025.05.06