본문 바로가기
Dev/JPA

Kotlin으로 Spring Boot JPA 프로젝트에 Querydsl 적용하기

by 돈코츠라멘 2019. 10. 1.

코드 작성 과정과 방법은 모두 https://jojoldu.tistory.com/372에서 참조하였다.

build.gradle.kts

build.gradle.kts에서 Querydsl을 사용하기 위한 gradle 설정을 추가한다.

apply(plugin = "kotlin-kapt")
apply(plugin = "kotlin-jpa")

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

dependencies {
    kapt("org.springframework.boot:spring-boot-configuration-processor")
    compile("com.querydsl:querydsl-jpa:4.2.1")
    kapt("com.querydsl:querydsl-apt:4.2.1:jpa")
}
  • kapt plugin 사용 - Java Compiler가 Annotation Processing을 실행하는 과정에서 Kotlin 코드를 인지할 수 없어서 JPA Entity class의 쿼리 타입을 생성할 수 없다. 따라서 Kotlin 코드의 Annotation Process을 지원하는 kapt 플로그인을 적용한다.
  • sourceSets"$buildDir/generated/source/kapt/main" 경로 추가 - 프로젝트를 빌드하면 모든 Entity class의 QClass가 생성된다. 이 경로는 QClass가 위치한 경로이며, 이를 sourceSets에 포함시켜야 Querydsl 코드에서 import해서 사용할 수 있다.

Querydsl Config

Repository에서 JPAQueryFactory를 주입받아 Querydsl을 사용할 수 있게 한다.

@Configuration
class QuerydslConfig(

        @PersistenceContext
        val entityManager: EntityManager

) {
    @Bean
    fun jpaQueryFactory(): JPAQueryFactory {
        return JPAQueryFactory(entityManager)
    }
}

Entity, Repository

Entity

간단하게 유저 정보를 담고 있는 Entity class를 작성한다.

@Entity
data class User(

        @Id
        val id: String,
        val password: String = "password",
        val name: String,
        val mobile: String? = null,
        val email: String? = null

)

Repository

예시 제공을 위해 UserRepository라는 JPA interface와 UserRepositorySupport라는 Querydsl을 적용한 class에서 findByEmail method를 작성하였다.

여기서 만약 QUser를 찾을 수 없다면 프로젝트를 빌드한 후 다시 import 한다. 프로젝트를 빌드해야 Entity class의 QClass가 생성된다.

interface UserRepository : JpaRepository<User, String> {
    fun findByEmail(email: String): User?
}

@Repository
class UserRepositorySupport(

        @Resource(name = "jpaQueryFactory")
        val query: JPAQueryFactory

) : QuerydslRepositorySupport(User::class.java) {

    fun findByEmail(email: String): User? {
        return query.selectFrom(QUser.user)
                .where(QUser.user.email.eq(email))
                .fetchOne()
    }

}
  • JPA는 개발자가 interface만 작성하면 바로 Data Access가 가능하다. boilerplate code가 줄어들어서 코드도 깔끔하고 지루한 단순 반복작업이 줄어든다는 장점이 있다. JPA는 method 이름만으로 JPQL 쿼리를 생성한다. 선언된 method에 대해서 application 로딩 시점에 이미 쿼리를 다 만든다. 명시적으로 쓰고 싶은 쿼리가 있다면 @Query annnotaion을 사용해서 작성하면 된다.
  • Querydsl은 SQL, JPQL을 코드로 작성할 수 있도록 도와주는 빌더 API이다. Mybatis를 사용했을 때와는 달리 컴파일 시점에서 문법 오류를 발견할 수 있다. 그리고 SQL 쿼리에 비해 (개발자 기준으로!) 훨씬 단순하고 쉽게 Data Access를 할 수 있다. 위에서 작성한 User라는 Entity class로 QUser.java라는 Querydsl 전용 객체를 만들어서 이를 사용한다.

Test

@RunWith(SpringRunner::class)
@SpringBootTest
class UserRepositoryTest {

    @Autowired
    lateinit var userRepository: UserRepository

    @Autowired
    lateinit var userRepositorySupport: UserRepositorySupport

    @Before
    fun setup() {
        userRepository.save(User(id = "test", name = "Park", email = "eyey@example.com"))

    @After
    fun tearDown() {
        userRepository.deleteAll()
    }

    @Test
    fun findByEmailTest() {
        val user = userRepository.findByEmail("eyey@example.com")
        println(user)
        assertEquals("test", user?.id)
    }

    @Test
    fun findByEmailWithQuerydslTest() {
        val user = userRepositorySupport.findByEmail("eyey@example.com")
        println(user)
        assertEquals("test", user?.id)
    }

}

댓글