Spring Boot + Kotlin + MongoDB로 CRUD 해보기
개요
Spring Boot + Kotlin + MongoDB를 활용하여 CRUD를 수행해보고자 합니다.
만약 MongoDB에 대해 잘 모르겠다면 "MongoDB란?"이라는 글을 참고하시고 오셔도 좋을 것 같습니다.
실제 코드는 github을 참고해 주세요.
환경
- Spring Boot 3.1
- JDK 17
- MongoDB with Docker
Gradle 의존성 추가
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-mongodb")
web와 mongodb에 대한 의존성을 추가해 줍니다.
docker-compose.yml
version: '3'
services:
mongodb:
image: mongo
container_name: mongodb-container
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: password
mongoDB에 대한 docker compose 파일을 작성하였습니다.
docker-compose up -d 명령어로 백그라운드에서 mongoDB를 실행할 수 있습니다.
application.yml
spring:
data:
mongodb:
uri: mongodb://root:password@localhost:27017/mongodb-container?authSource=admin
docker compose 파일에 적힌 대로 uri를 명시해 주며 인증을 위해 authSource=admin을 쿼리파라미터로 붙여주었습니다.
Member Entity 만들기
@Document
data class Member(
@Id
var id: String? = null,
@Field("histories")
val histories: MutableMap<String, String>
) {
fun addHistories(additionalHistories: List<String>) {
additionalHistories.forEach {
histories[it] = it
}
}
}
@Document, @Field 어노테이션을 활용하여 mongoDB에 영속될 수 있는 객체로 만들어냅니다.
MemberRepository
interface MemberRepository: MongoRepository<Member, String> {
}
MongoRepository를 상속받습니다.
MemberService
@Service
@Transactional(readOnly = true)
class MemberService(
private val memberRepository: MemberRepository,
){
fun findUserBy(id: String): Member {
return memberRepository.findByIdOrNull(id) ?: throw IllegalArgumentException("${id}로 회원을 조회할 수 없습니다")
}
@Transactional
fun signUp(memberHistories: List<String>): String{
val histories = memberHistories.map { it to it }.toMap().toMutableMap()
val member = Member(histories = histories)
return memberRepository.save(member).id!!
}
@Transactional
fun addMemberHistories(id: String, additionalHistories: List<String>): Member{
val member = memberRepository.findByIdOrNull(id) ?: throw IllegalArgumentException("${id}로 회원을 조회할 수 없습니다")
member.addHistories(additionalHistories)
return memberRepository.save(member)
}
@Transactional
fun withdraw(id: String){
memberRepository.deleteById(id)
}
}
memberRepository를 활용하여 CRUD를 수행하였습니다.
MemberController
@RestController
@RequestMapping("/members")
class MemberController(
private val memberService: MemberService,
) {
@GetMapping("/{id}")
fun getMemberById(@PathVariable id: String): ResponseEntity<Member> {
val member = memberService.findUserBy(id)
return ResponseEntity.ok(member)
}
@PostMapping
fun signUp(@RequestBody signUpRequest: SignUpRequest): ResponseEntity<String> {
val id = memberService.signUp(signUpRequest.histories)
return ResponseEntity.ok(id)
}
@PutMapping("/{id}/history")
fun addMemberHistories(
@PathVariable id: String,
@RequestBody addHistoryRequest: AddHistoryRequest,
): ResponseEntity<Member> {
val member = memberService.addMemberHistories(id = id, additionalHistories = addHistoryRequest.histories)
return ResponseEntity.ok(member)
}
@DeleteMapping("/{id}")
fun withdraw(@PathVariable id: String): ResponseEntity<Unit> {
memberService.withdraw(id = id)
return ResponseEntity.noContent().build()
}
}
REST API를 활용하여 CRUD를 구현하였습니다.
기타 DTO들
data class AddHistoryRequest(
val histories: List<String>,
)
data class SignUpRequest(
val histories: List<String>,
)
실제 API 호출을 통한 테스트 - curl
회원 가입
curl --location 'http://localhost:8080/members' \
--header 'Content-Type: application/json' \
--data '{
"histories": [
"wakeup", "eat", "study"
]
}'
회원 조회
curl --location 'http://localhost:8080/members/6589c650554cf81aee139c3c'
회원 이력 수정
curl --location --request PUT 'http://localhost:8080/members/6589c650554cf81aee139c3c/history' \
--header 'Content-Type: application/json' \
--data '{
"histories": [
"drink","sleep"
]
}'
회원 탈퇴
curl --location --request DELETE 'http://localhost:8080/members/1'
마무리
이 글을 작성하기 전에 JPA로 JSON Column CRUD 해보기라는 글을 작성해 보았습니다.
데이터베이스가 MySQL에서 MongoDB로 변환되었지만 Spring에서 지원하는 추상화 덕분에 이전에 작성했던 코드를 재사용하여 최소한의 수정으로 MongoDB CRUD 튜토리얼을 수행해 볼 수 있었습니다.
Spring의 추상화의 강력함을 다시 한번 느끼게 되는 것 같습니다.
참고자료
https://docs.spring.io/spring-data/mongodb/docs/current-SNAPSHOT/reference/html/#mongodb-connectors
https://medium.com/@sumanzadeakhil/spring-boot-mongodb-rest-api-crud-with-kotlin-227d296bbbef
https://www.mongodb.com/compatibility/spring-boot
https://www.baeldung.com/spring-data-mongodb-connection