스프링부트 + 코틀린 사용을 익히기위한 예제 실습
확장자 만들기
이제 앞으로 자주 사용할 날짜포멧터 확장자을 만들어보자, 근데 슬러그 변환 함수를 곁들인
src/main/kotlin/com/example/demo/Extensions.kt
package com.example.demo.blog
import java.time.LocalDateTime
import java.time.format.DateTimeFormatterBuilder
import java.time.temporal.ChronoField
import java.util.*
fun LocalDateTime.format() = this.format(koreanDateFormat)
private val daysLookup = (1..31).associate{ it.toLong() to getOrdinary(it)}
private val koreanDateFormat = DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd")
.appendLiteral(" ")
.appendText(ChronoField.DAY_OF_MONTH, daysLookup)
.appendLiteral(" ")
.appendPattern("yyyy")
.toFormatter(Locale.KOREAN)
private fun getOrdinary(n:Int) = when {
n in 11..13 -> "${n}th"
n % 10 == 1 -> "${n}st"
n % 10 == 2 -> "${n}nd"
n % 10 == 3 -> "${n}rd"
else -> "${n}th"
}
fun String.toSlug() = toLowerCase()
.replace("\n", " ")
.replace("[^a-z\\d\\s]".toRegex(), "")
.split(" ")
.joinToString("-")
.replace("-+".toRegex(), "-")
LocalDataTime 타입에 한국의 날짜 형식을 생성해주는 format이란 함수를 추가한다.
덤으로 슬러그로 변환해주는 함수도 String 타입에 추가해준다
앞으로 LocalDataTime 타입은 foramt() 함수를 사용가능하고 String 타입은 toSlug() 함수를 사용가능하다
Persistence와 JPA 사용하기
먼저 조인을 효율적으로 호출해주는 lazy fetching을 사용하기 위해서는 코틀린allOpen
플러그인을 선언해준다
build.gradle.kts
plugins {
id("org.springframework.boot") version "2.6.0"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
war
kotlin("jvm") version "1.6.0"
kotlin("plugin.spring") version "1.6.0"
kotlin("plugin.jpa") version "1.6.0"
}
allOpen {
annotation("javax.persistence.Entity")
annotation("javax.persistence.Embeddable")
annotation("javax.persistence.MappedSuperclass")
}
그러면 이제 아래와 같이 엔티티를 선언해 사용할 수 있다
src/main/kotlin/com/example/demo/Entities.kt
package com.example.demo.blog
import java.time.LocalDateTime
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.Id
import javax.persistence.ManyToOne
@Entity
class Article (
var title:String,
var headline: String,
var content: String,
@ManyToOne var author: User,
var slug: String = title.toSlug(),
var addedAt: LocalDateTime = LocalDateTime.now(),
@Id @GeneratedValue var id: Long? = null)
@Entity
class User(
var login: String,
var firstName: String,
var lastName: String,
var description: String? = null,
@Id @GeneratedValue var id: Long? = null)
엔티티를 생성했으니 Spring Data Jpa repositories를 생성해보자
src/main/kotlin/com/example/demo/Repositories.kt
package com.example.demo.blog
import org.springframework.data.repository.CrudRepository
interface ArticleRepositoriy: CrudRepository<Article, Long> {
fun findBySlug(slug: String) : Article?
fun findAllByOrderByAddedAtDesc() : Iterable<Article>
}
interface UserRepository: CrudRepository<User, Long>{
fun findByLogin(login: String) : User?
}
마지막으로 만든 레포지토리들을 테스트를 해보자
src/test/kotlin/com/example/demo/RepositoriesTests.kt
package com.example.demo
import com.example.demo.blog.Article
import com.example.demo.blog.ArticleRepositoriy
import com.example.demo.blog.User
import com.example.demo.blog.UserRepository
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 userRepository: UserRepository,
val articleRepositoriy: ArticleRepositoriy
) {
@Test
fun `When findByIdOrNull then return Article`(){
val user = User("login", "firstname", "lastname")
entityManager.persist(user)
val article = Article("title", "headline", "content", user)
entityManager.persist(article)
entityManager.flush()
val found = articleRepositoriy.findByIdOrNull(article.id!!)
assertThat(found).isEqualTo(article)
}
@Test
fun `When findByLogin then return User`() {
val user = User("login", "firstname", "lastname")
entityManager.persist(user)
entityManager.flush()
val found = userRepository.findByLogin(user.login)
assertThat(found).isEqualTo(user)
}
}
확장자를 만들었고, 그것을 사용하는 엔티티와 레포지토리를 생성하고 테스트까지 진행해보았다