반응형
05-15 16:06
Today
Total
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
관리 메뉴

개발하는 고라니

[Spring Boot] Kotlin Querydsl 적용 (with. Mono repo, Multi module) 본문

Framework/Spring Boot

[Spring Boot] Kotlin Querydsl 적용 (with. Mono repo, Multi module)

조용한고라니 2022. 2. 27. 14:43
반응형

 

 

[Spring Boot] Mono Repo, Multi Module (with. Gradle Kotlin DSL)

Intro 개인 프로젝트 정도의 규모라면 하나의 프로젝트 안에 api, web, admin 등이 모두 들어가있어도 커버가 되지만, 규모가 커지면 각각 개별 프로젝트로 나누어야 관리가 될 정도가 된다. 그럼 나

dev-gorany.tistory.com

이전 글에서 프로젝트를 다중 모듈로 구성해보았다. Gradle을 사용하면 어렵지 않게 구현가능하다. 하지만 Gradle Kotlin DSL의 문법은 생소하기도 하고, 사용법이 미세하지만 달라서 낯설기 때문에 여러 삽질이 필요했다. 

 

이번 글에서는 Querydsl을 적용해 api에서 QDomain class를 사용하는 것을 목표로 해보자.

 

목표

  • api, domain 모듈에 Querydsl 의존성과 플러그인을 추가한다.
  • domain 컴파일시, QClass가 생성되는 것을 확인한다.

build.gradle.kts

먼저, root module의 build.gradle.kts는 다음과 같다. 내용이 길어서 일부 중략하긴 했다. Querydsl 부분만 추가해주면 된다.

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.springframework.boot.gradle.tasks.bundling.BootJar

plugins {
	...
    kotlin("kapt") version "1.3.61" //Querydsl
}

...

subprojects {

    val querydslVersion = "5.0.0" //querydsl

    apply(plugin = "java")
	...
    apply(plugin = "kotlin-kapt") //querydsl

    dependencies {
		...

        //querydsl
        implementation("com.querydsl:querydsl-jpa:$querydslVersion")
        kapt("com.querydsl:querydsl-apt:$querydslVersion:jpa")
        kapt("org.springframework.boot:spring-boot-configuration-processor")

		...
    }

	...
}

...

 

api 모듈의 gradle은 추가해줄 것이 없다.

 

domain 모듈에는 QClass가 생길 곳을 지정하는 코드를 작성해야한다.

plugins {
}

...

dependencies {

}

//querydsl
sourceSets["main"].withConvention(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::class) {
    kotlin.srcDir("$buildDir/generated/source/kapt/main")
}

Check QClass 

$ ./gradlew :domain:build

 

이제 domain 모듈을 빌드해보자. 아니면 gradle task 중에 compileKotlin 해도 된다.

 

그러면 domain 모듈에 @Entity 어노테이션이 붙은 엔티티 클래스를 Querydsl에서 사용할 수 있도록 QClass로 만들어 다음 경로에 저장한다.

domain/build/generated/source/kapt/main/...

Querydsl 사용

준비물은 챙겼으니 이제 사용할 차례이다. 바로 사용해도 되지만, 나중에 확장성을 고려해서 간단한 추상 클래스와 config를 만들어주자.

 

import com.querydsl.jpa.impl.JPAQueryFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import javax.persistence.EntityManager
import javax.persistence.PersistenceContext

@Configuration
class QuerydslConfig(
    @PersistenceContext val em: EntityManager
) {
    @Bean
    fun jpaQueryFactory() = JPAQueryFactory(em)
}

 

import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport
import org.springframework.stereotype.Repository
import javax.persistence.EntityManager
import javax.persistence.PersistenceContext

@Repository
abstract class CustomQuerydslRepositorySupport
/**
 * Creates a new [QuerydslRepositorySupport] instance for the given domain type.}}"}}}
 * @param domainClass must not be null.
 */
    (domainClass: Class<*>?) : QuerydslRepositorySupport(domainClass!!) {
    @PersistenceContext
    override fun setEntityManager(entityManager: EntityManager) {
        super.setEntityManager(entityManager)
    }
}

 

별거는 아니고, Querydsl Support를 사용하려고 하는 작업이기 때문에 굳이 필요하진 않다. 다만 나중에 DB를 여러개 사용할 때 각 DB마다 EntityManager를 할당해주어야 하는데, 이를 용이하게 할 수 있다.

 

간단히 MemberRepository를 가지고 Querydsl을 사용해보자.

 

먼저 Support Interface를 만들어주고..

interface MemberSupport {
    fun getMembers(): List<Member>
}

 

Spring Data JPA를 이용하는 Repository에 상속받는다.

interface MemberRepository: JpaRepository<Member, Long>, MemberSupport

 

SupportImpl을 만들어보자.

import com.gorany.entity.Member
import com.gorany.entity.QMember.member
import com.gorany.repository.querydsl.CustomQuerydslRepositorySupport
import com.gorany.repository.querydsl.MemberSupport
import com.querydsl.jpa.impl.JPAQueryFactory

class MemberSupportImpl(
    private val query: JPAQueryFactory,
) : CustomQuerydslRepositorySupport(Member::class.java), MemberSupport {

    override fun getMembers(): List<Member> {
        return query.selectFrom(member)
            .fetch()
    }
}

아까 만든 추상클래스를 상속하고, Support 인터페이스를 구현한다. 이렇게 하면 매번 생성자에서 EntityManger를 JPAFactory에 세팅할 필요가 없다.

 

# Github: https://github.com/rhacnddl/monorepo

반응형
Comments