코틀린 스프링 부트 서버 구성을 이어서 진행해보자.
build.gradle.kts에 플러그인을 추가해서 lazy fetching이 가능하도록 한다. 이로 인해서 @Entity 어노테이션이 추가된 오브젝트는 lazy fetching을 할 수 있다.
plugins {
id("org.springframework.boot") version "2.5.4"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
kotlin("jvm") version "1.5.21"
kotlin("plugin.spring") version "1.5.21"
kotlin("plugin.jpa") version "1.5.21"
// 여기 새로 추가
kotlin("plugin.allopen") version "1.4.32"
}
// allOpen 정의
allOpen {
annotation("javax.persistence.Entity")
annotation("javax.persistence.Embeddable")
annotation("javax.persistence.MappedSuperclass")
}
lazy-fetching(지연 로딩)이란?
필요한 정보만 가져오고 필요하지 않은 정보는 프록시를 이용하여 가져오는 방식. 예를 들면 밑의 Article Entity 코드에서 Article을 조회할 경우 필요하지 않으면 User는 프록시를 이용해서 가져온다.이와 반대되는 개념으로는 eager-fetching(지연 로딩)이 있다.
그리고 Article과 User Entity를 생성한다. 아래 예시는 Article Entity이다.
package com.example.kotlinserver.entities
import java.time.LocalDateTime
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.Id
import javax.persistence.ManyToOne
import com.example.kotlinserver.extensions.toSlug
@Entity
class Article(
var title: String,
var headline: String,
var content: String,
@ManyToOne var autor: User,
var addedAt: LocalDateTime = LocalDateTime.now(),
@Id @GeneratedValue var id: Long? = null,
var slug: String = title.toSlug()
)
1편에서 만들었던 Extension 중 하나인 toSlug를 사용했다.
여기서도 문제를 겪었다.. 처음에 계속 unresolved method라고 해서 수동 import를 해줬는데도 못 알아듣길래 코틀린 사이트의 원본 소스코드를 확인해봤다. 난 자바처럼 파일 이름과 동일한 클래스를 생성하고 그 안에 Extension들을 선언해줬는데 그게 아니라 그냥 바로 Extension 클래스를 파일 안에 선언해서 구현하는 거였다..!
자바랑 비슷하지만 많이 다른 코틀린..
Entity를 구할 수 있는 Jpa Repository를 생성한다. 아래 예시는 ArticleRepository이다.
package com.example.kotlinserver.repositories
import com.example.kotlinserver.entities.Article
import org.springframework.data.repository.CrudRepository
interface ArticleRepository : CrudRepository<Article, Long> {
fun findByTitle(title: String): Article?
fun findAllByOrderByAddedAtDesc() : Iterable<Article>
}
다음과 같이 Repository 테스트를 진행하면 값을 제대로 찾아서 반환하는 것을 확인할 수 있다.
package com.example.kotlinserver
import com.example.kotlinserver.entities.Article
import com.example.kotlinserver.entities.User
import com.example.kotlinserver.repositories.ArticleRepository
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
import org.springframework.data.repository.findByIdOrNull
@DataJpaTest
class RepositoriesTests @Autowired constructor(
val entityManager: TestEntityManager,
val articleRepository: ArticleRepository
){
@Test
fun `When findByIdOrNull then return Article`() {
// given
val newUser = User("s2moon98", "jieun", "moon")
entityManager.persist(newUser)
var newArticle = Article("new article title", "new headline", "new content", newUser)
entityManager.persist(newArticle)
entityManager.flush()
// when
// !!의 의미 : null이 들어올 수 없는 경우
val found = articleRepository.findByIdOrNull(newArticle.id!!)
// then
assertThat(found).isEqualTo(newArticle)
}
}
테스트 성공!
Article Entity를 선언할 때 id를 nullable로 선언했기 때문에 인자로 받을 때
!!
연산자를 사용한다.
!!
연산자는 모든 객체를 non-Null 타입으로 변경하며 null값이 들어올 경우 예외를 발생시킨다. (Null Pointer Exception과 비슷하게 생각 가능)
깃허브에서 코드 확인하기 : https://github.com/s2moon98/first-kotlin-server