본문 바로가기

Kotlin

2) kotlin jpa 설정 간단한 샘플예제

반응형

앞에서 만든 kotlin 프로젝트에 h2 DB 연결을 하고 JPA설정을 추가해 보자.

  1. h2 DB 설치 및 설정
  2. category  , item entity 추가
  3. repository 추가 및 querydsl lib 추가
  4. 간단한 CRUD 기능 테스트

이렇게 위의 순서대로 설정을 진행해 보자. 

먼저 h2 db에 대해 알아보자. 

h2 DB는 embaded mode , inMemory mode , Serve mode 로 이렇게 세가지 모드로 사용하다. 

  • server mode는 말그대로 h2 db자체를 설치해서 h2 db 자체 단독으로 서버로 사용하는것을 애기한다.
  • embaded mode는 application이 뜰때 사용하고 application이 종료되면 h2 db 서버도 종료되는 모드를 애기한다. 이때 데이터는 그대로 남아 있어 다시 application이 실행되면 저장된 데이터를 사용가능하다.
  • inMemory mode 는  embaded mode와 똑같은데 메모리에 데이터를 쓰고 읽고 하는 방식이라 application이 종료되면 저장된 데이터도 다 사라지게 된다.

여기서는 간단하게 embaed mode를 사용할 예정이고 아래 build.gradle 파일에 설정을 추가 하면된다.

 

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version "2.7.8"
    id("io.spring.dependency-management") version "1.0.15.RELEASE"
    kotlin("jvm") version "1.5.20"
    kotlin("plugin.spring") version "1.5.20"
    kotlin("plugin.jpa") version "1.5.20"
}

group = "com.ksj"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_16

configurations {
    compileOnly {
        extendsFrom(configurations.annotationProcessor.get())
    }
}

repositories {
    google()
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-data-jdbc")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    compileOnly("org.projectlombok:lombok")
    runtimeOnly("com.h2database:h2")
//    runtimeOnly("com.mysql:mysql-connector-j")
//    runtimeOnly("org.mariadb.jdbc:mariadb-java-client")
    annotationProcessor("org.projectlombok:lombok")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf("-Xjsr305=strict")
        jvmTarget = "16"
    }
}

tasks.withType<Test> {
    useJUnitPlatform()
}

 

# h2 database web으로 확인
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

# spring - h2 연결
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:~/sample-db
#spring.datasource.url=jdbc:h2:mem:test # In-Memory mode
spring.datasource.username=sa
spring.datasource.password=

build.gradle 파일에 h2 db와  jdbc , jpa 관련 lib를 추가하고 application.properties에  위와 같이 db datasource설정을 추가하고 나서 application을 실행해 보자.

 

DB 연결이 잘되는지 확을 위해 브라우저 창에 아래와 같이 연결했을때 h2 console 화면이 뜨면 성공!

위와 같은 화면이 보여지면 설정이 잘되었고 Connect를 누루면 sample-db로 연결이 된다.

이렇게 간단하게 embaded mode로도 사용가능하지만 

h2 db를 직접설치해 보고 embade mode와 말고 server mode는 어떤식으로 사용하는지 알아 보자.

http://h2database.com/html/main.html 요기로 접속해서 

위 그림에서 All Platform을 다운받는다.

zip 파일이 다운받아 질것이고 이것을 압축을 해제한다.

 

압축 해제된 폴더안에 bin 폴더로 가면 h2.sh  파일이 있고 ( mac os 라서 sh 파일을 실행 , window는 h2.bat를 실행)  해당 파일을 실행하면 된다.

h2.sh 파일을 실행하면 permission denied 에러 발생 할텐데 그러면 위에 chmod를 이용해서 파일의 권한을 변경해주면된다.

그리고 브라우저에서 

localhost:8082/login.jsp 를 입력하면 위와 초기 console 화면이 나오게 된다. 

그리고 와같이 DB 정보를 입력하면 

 

연결을 누루면 아래와 같이 db 파일이 생성이 되거나 

위와 같이 파일을 찾지 못했다는 에러가 발생한다 .이 에러의 발생원인은 db 파일이 만들어지지 않아 생긴 문제이고 , 빈 파일을 하나만들어주고 다시 연결을 하면 해결된다.

 

이제 DB도 연결되었고 , 이 DB에 우리가 원하는 테이블을 생성해 보자.

간단하게  1: N 구조의 테이블 두개를 생성했다. 이제 해당 테이블과 연결되는 entity설정을 추가해 보자.

 


@Entity
@Table(name="category")
class Category(
    @Column(name="category_name")
    var categoryName:String,
    @Column(name="created_date")
    var cratedDate : LocalDateTime = LocalDateTime.now(),
    @Column(name="updated_date")
    var updatedDate : LocalDateTime = LocalDateTime.now(),
    @OneToMany(fetch = FetchType.LAZY)
    @JoinColumn(name = "category_seq")
    var items : List<Item> = ArrayList()
){
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="seq")
    var seq : Long?= null
}
@Entity
@Table(name = "item")
class Item(
    @Column(name = "item_name")
    var itemName: String = "",
    @Column(name = "category_seq")
    var category: Long? = null,
    @Column(name = "created_date")
    var cratedDate: LocalDateTime = LocalDateTime.now(),
    @Column(name = "updated_date")
    var updatedDate: LocalDateTime = LocalDateTime.now(),
) {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "seq")
    var seq: Long?=null
}

 

category , item entity를 만들어 보았다. 

java와 는 다르게 빌더 패턴을 사용하기 위해서 기존 java의 lombok를 사용해도 되지만 

kotlin에서는 생성자를 위와 같은 모습으로 만들어서 builder패턴을 바로 사용할수있게 되었다.

builder 패턴의 사용법은 아래 service 코드에서 참조.

 

  • 코드중 
var category: Long? = null,

요런 부분이 보인다. 이것은 해당 변수가 null 일수도 있다고 명시적으로 null를 허용하게 할수 있다. 

jpa에서 entity의 아이디값은 null 이어야 신규 생성 엔티티로 인식하고 insert 쿼리를 실행하게 되는데 

이럴때 아이디 변수는 null를 허용해야지만 신규 entity를 builder 패턴으로 생성해서 save 할수 있다.

( 요런것을 보면 kotlin과 jpa 는 좀 안맞는건가 ? 싶은 생각이 든다)

 

이제 카테고리를 저장하는 service와 repository를 만들어 보자.

package com.ksj.kotlin.repository

import com.ksj.kotlin.entity.Category
import org.springframework.data.jpa.repository.JpaRepository

interface CategoryRespository : JpaRepository<Category, Long > {
}

 

 

@Service
class CategoryService @Autowired constructor(
    val categoryRespository : CategoryRespository,
    var itemRepository: ItemRespository
    ){

    fun findCategory() : List<Category> {
        return categoryRespository.findAll()
    }

    fun saveCategory(saveRequest:CategorySaveRequest) : CategoryResponse {
        var category:Category = Category(categoryName = saveRequest.categoryName)
        categoryRespository.save(category)
        return CategoryResponse(seq = category.seq,
            categoryName = category.categoryName,
            createDate = category.cratedDate,
            updatedDate = category.updatedDate
            )
    }

 

요기서도 java와 다른 특이한 부분이 보인다. 

java 에서는 spring bean 을 주입할떄 각 변수벼루 @Autowired를 달아 주었는데 . 

kotlin은 생성자를 설정하고 해당 생성자 에 @Autowired를 달면 끝. 

( 개인적으로 lombok을 사용할때가 더 편한것 같다 ..) 

 

요렇게 해서 controller까지 완성해 보면 아래 모양이 될것이다.


@RestController
class CategoryController @Autowired constructor(val categoryService: CategoryService) {
    @GetMapping("/category")
    fun findCategories() : List<Category>{
        return categoryService.findCategory()
    }

    @PostMapping("/saveCategory")
    fun saveCategory(@RequestBody saveRequest: CategorySaveRequest) : CategoryResponse{
        return categoryService.saveCategory(saveRequest)
    }

 

정상적으로 데이터가 저장되고 . 조회는것을 확인! 

간단하게 만들어 보았고,  다음에는 QueryDsl를 적용해 보도록하자.

 

코드는 아래 github를 참조.

https://github.com/devraccon/kotlin-sample

'Kotlin' 카테고리의 다른 글

1) springboot 2.7 kotlin 1.5 시작하기 - GetMapping  (0) 2023.01.28