데이터베이스 액세스를 위해 Spring Data CrudRepository 사용하기
이 섹션은 Spring Boot와 Kotlin 시작하기 튜토리얼의 마지막 부분입니다. 계속 진행하기 전에 이전 단계들을 완료했는지 확인하세요:
Kotlin으로 Spring Boot 프로젝트 생성하기
Spring Boot 프로젝트에 데이터 클래스 추가하기
Spring Boot 프로젝트에 데이터베이스 지원 추가하기
데이터베이스 액세스를 위해 Spring Data CrudRepository 사용하기
이번 파트에서는 데이터베이스 액세스를 위해 JdbcTemplate 대신 Spring Data CrudRepository를 사용하도록 서비스 레이어를 마이그레이션합니다. _CrudRepository_는 특정 타입의 저장소(repository)에 대한 일반적인 CRUD 작업을 위한 Spring Data 인터페이스입니다. 이 인터페이스는 데이터베이스와 상호작용하기 위한 여러 메서드를 기본으로 제공합니다.
애플리케이션 업데이트하기
먼저, CrudRepository API와 함께 작동하도록 Message 클래스를 조정해야 합니다:
Message클래스에@Table어노테이션을 추가하여 데이터베이스 테이블 매핑을 선언합니다.id필드 앞에@Id어노테이션을 추가합니다.이 어노테이션들을 사용하려면 추가적인 임포트(import)가 필요합니다.
kotlin// Message.kt package com.example.demo import org.springframework.data.annotation.Id import org.springframework.data.relational.core.mapping.Table @Table("MESSAGES") data class Message(@Id val id: String?, val text: String)또한,
Message클래스 사용을 더욱 코틀린답게(idiomatic) 만들기 위해,id속성의 기본값을 null로 설정하고 데이터 클래스 속성의 순서를 바꿀 수 있습니다:kotlin@Table("MESSAGES") data class Message(val text: String, @Id val id: String? = null)이제
Message클래스의 새 인스턴스를 생성할 때text속성만 파라미터로 지정할 수 있습니다:kotlinval message = Message("Hello") // id는 null이 됩니다.Message데이터 클래스와 함께 작동할CrudRepository인터페이스를 선언합니다.MessageRepository.kt파일을 생성하고 다음 코드를 추가하세요:kotlin// MessageRepository.kt package com.example.demo import org.springframework.data.repository.CrudRepository interface MessageRepository : CrudRepository<Message, String>MessageService클래스를 업데이트합니다. 이제 SQL 쿼리를 직접 실행하는 대신MessageRepository를 사용하게 됩니다:kotlin// MessageService.kt package com.example.demo import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service @Service class MessageService(private val db: MessageRepository) { fun findMessages(): List<Message> = db.findAll().toList() fun findMessageById(id: String): Message? = db.findByIdOrNull(id) fun save(message: Message): Message = db.save(message) }확장 함수 (Extension functions)
findByIdOrNull()함수는 Spring Data JDBC에서CrudRepository인터페이스를 위해 제공되는 확장 함수입니다.CrudRepository save() 함수
이 함수는 새로운 객체가 데이터베이스에 ID를 가지고 있지 않다는 가정하에 작동합니다. 따라서 삽입(insertion)을 위해서는 ID가 null이어야 합니다.
만약 ID가 null이 아니라면,
CrudRepository는 해당 객체가 이미 데이터베이스에 존재한다고 가정하고 삽입 작업이 아닌 업데이트(update) 작업으로 간주합니다. 삽입 작업이 완료되면, 데이터 저장소에 의해 생성된id가Message인스턴스에 다시 할당됩니다.삽입된 객체에 대해 ID를 자동으로 생성하도록 messages 테이블 정의를 업데이트합니다.
id가 문자열이므로,RANDOM_UUID()함수를 사용하여 기본적으로 ID 값을 생성하도록 설정할 수 있습니다:sql-- schema.sql CREATE TABLE IF NOT EXISTS messages ( id VARCHAR(60) DEFAULT RANDOM_UUID() PRIMARY KEY, text VARCHAR NOT NULL );src/main/resources폴더에 있는application.properties파일에서 데이터베이스 이름을 업데이트합니다:nonespring.application.name=demo spring.datasource.driver-class-name=org.h2.Driver spring.datasource.url=jdbc:h2:file:./data/testdb2 spring.datasource.username=name spring.datasource.password=password spring.sql.init.schema-locations=classpath:schema.sql spring.sql.init.mode=always
애플리케이션의 전체 코드는 다음과 같습니다:
// DemoApplication.kt
package com.example.demo
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class DemoApplication
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}// Message.kt
package com.example.demo
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table
@Table("MESSAGES")
data class Message(val text: String, @Id val id: String? = null)// MessageRepository.kt
package com.example.demo
import org.springframework.data.repository.CrudRepository
interface MessageRepository : CrudRepository<Message, String>// MessageService.kt
package com.example.demo
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
@Service
class MessageService(private val db: MessageRepository) {
fun findMessages(): List<Message> = db.findAll().toList()
fun findMessageById(id: String): Message? = db.findByIdOrNull(id)
fun save(message: Message): Message = db.save(message)
}// MessageController.kt
package com.example.demo
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import java.net.URI
@RestController
@RequestMapping("/")
class MessageController(private val service: MessageService) {
@GetMapping
fun listMessages() = ResponseEntity.ok(service.findMessages())
@PostMapping
fun post(@RequestBody message: Message): ResponseEntity<Message> {
val savedMessage = service.save(message)
return ResponseEntity.created(URI("/${savedMessage.id}")).body(savedMessage)
}
@GetMapping("/{id}")
fun getMessage(@PathVariable id: String): ResponseEntity<Message> =
service.findMessageById(id).toResponseEntity()
private fun Message?.toResponseEntity(): ResponseEntity<Message> =
// 메시지가 null인 경우 (찾지 못한 경우), 응답 코드를 404로 설정합니다.
this?.let { ResponseEntity.ok(it) } ?: ResponseEntity.notFound().build()
}애플리케이션 실행하기
축하합니다! 애플리케이션을 다시 실행할 준비가 되었습니다. JdbcTemplate을 CrudRepository로 교체한 후에도 기능은 동일하게 유지되므로 애플리케이션은 이전과 같이 작동합니다.
이제 requests.http 파일에서 POST 및 GET HTTP 요청을 실행하여 동일한 결과를 확인할 수 있습니다.
다음 단계
Kotlin 기능을 탐색하고 언어 학습 진행 상황을 추적하는 데 도움이 되는 개인 언어 지도를 받아보세요:

- Spring Framework 문서를 확인해 보세요.
- 웹 애플리케이션 보안 설정 튜토리얼에서 보호된 리소스가 있는 간단한 웹 애플리케이션을 만들어 보세요.
- Spring Boot와 Kotlin으로 웹 애플리케이션 빌드하기 튜토리얼을 완료해 보세요.
