QueryDSL JPA Test (Spring Boot 3.0) - QueryDSL 사용하기(3)

Tech/Java 2023. 8. 3. 07:52
728x90
728x90

셋팅

def queryDslVersion = '5.0.0'

dependencies {
	//QueryDsl
    // 필수
	implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta"
	implementation "com.querydsl:querydsl-core:${queryDslVersion}"
    
    // QueryDsl 쿼리 타입 생성 (QClass 생성 시 @Entity 탐색)
	annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta"
    
    // java.lang.NoClassDefFoundError:javax/persistence/Entity 에러 방지
	annotationProcessor "jakarta.persistence:jakarta.persistence-api"
	annotationProcessor "jakarta.annotation:jakarta.annotation-api"
}

// QueryDsl 빌드 옵션 (선택)
// QueryDsl 디렉토리 경로
def querydslDir = "$buildDir/generated/querydsl"

// 경로 추가 >> QueryDsl 소스 코드 컴파일 시 빌드
sourceSets {
	main.java.srcDirs += [ querydslDir ]
}

// 컴파일 설정(AnnotationProcessor가 생성하는 소스코드를 해당 경로로 설정)
tasks.withType(JavaCompile) {
	options.annotationProcessorGeneratedSourcesDirectory = file(querydslDir)
}

// clean실행 시 마지막 작업으로 디렉토리(QClass) 삭제 >> 충돌 방지
clean.doLast {
	file(querydslDir).deleteDir()
}

 

 

 

위와 같은 셋팅을 사용했고, 주의할 점은 아래에 있다.

implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta"

//implementation 'com.querydsl:querydsl-jpa'

아래처럼, 버전과 jakarta를 명시해주지 않으면 Config파일 설정 시 에러가 발생한다.

 

 

또한 Q 파일을 찾지 못해 java.lang.NoClassDefFoundException 관련 에러가 발생한다면 아래 코드를 추가하자.

annotationProcessor 'jakarta.persistence:jakarta.persistence-api'
annotationProcessor 'jakarta.annotation:jakarta.annotation-api'

 

또한 아래의 Config 클래스를 생성하여 JPAQueryFactory를 Bean으로 등록해주었다.

필요 시 Repository에서 JPAQueryFactory를 DI하여 사용할 수 있다.

@Configuration
@RequiredArgsConstructor
public class QuerydslConfig {
 
    private final EntityManager em;
    @Bean
    public JPAQueryFactory jpaQueryFactory(EntityManager em){
        return new JPAQueryFactory(em);
    }
}

 

 

모든 설정을 마쳤다면 Gradle - Build - Clean 후 compileJava를 수행하거나. (Gradle 빌드 도구 활용)

 

직접 터미널에 아래 명령어를 입력해도 된다.

./gradlew clean

./gradlew compileJava

 

 

 

테스트 해보기

package com.example.lolchampionsinvestment;

import com.example.lolchampionsinvestment.config.QuerydslConfig;
import com.example.lolchampionsinvestment.domain.champion.Champion;
import com.example.lolchampionsinvestment.domain.champion.ChampionRepository;
import com.example.lolchampionsinvestment.domain.champion.QChampion;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
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.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;

import java.time.LocalDateTime;

import static org.assertj.core.api.Assertions.assertThat;

@DataJpaTest
@ActiveProfiles("test")
@Import(QuerydslConfig.class)
@Transactional
public class QuerydslTest {

    @PersistenceContext
    EntityManager em;

    JPAQueryFactory jpaQueryFactory;

    @BeforeEach
    void init() {
        jpaQueryFactory = new JPAQueryFactory(em);

        Champion aatrox = createChampion("Aatrox", 1000, "아트록스", LocalDateTime.now());
        Champion teemo = createChampion("Teemo", 2000, "티모", LocalDateTime.now());
        Champion ahri = createChampion("Ahri", 3000, "아리", LocalDateTime.now());
        em.persist(aatrox);
        em.persist(teemo);
        em.persist(ahri);
    }

    @DisplayName("Querydsl test >> 올바르게 insert되었는지 확인")
    @Test
    void selectBeforeInsertDataWithQuerydsl(){
        //given
        QChampion champion = new QChampion("champion");

        //when
        Champion result1 = jpaQueryFactory.select(champion)
                .from(champion)
                .where(champion.name.eq("Aatrox"))
                .fetchOne();
        Champion result2 = jpaQueryFactory.select(champion)
                .from(champion)
                .where(champion.name.eq("Teemo"))
                .fetchOne();
        Champion result3 = jpaQueryFactory.select(champion)
                .from(champion)
                .where(champion.name.eq("Ahri"))
                .fetchOne();

        //then
        assertThat(result1.getName()).isEqualTo("Aatrox");
        assertThat(result2.getPrice()).isEqualTo(2000);
        assertThat(result3.getDescription()).isEqualTo("아리");
    }

    private static Champion createChampion(String name, int price, String description, LocalDateTime createDateTime) {
        return Champion.builder()
                .name(name)
                .price(price)
                .description(description)
                .createDateTime(createDateTime)
                .build();
    }


}

 

테스트는 정상 수행되었다.

 

Insert 세 건에 대한 조회를 진행하여 모두 일치하는 것을 확인할 수 있다.

 

 

 

 

 

 

 

 

다양한 쿼리 키워드나, 연산에 대한 사용법은 정리가 잘 된 포스팅을 발견했다. 결국 API를 호출해서 API의 포맷대로 잘 사용하면 되는 것 같다.

 

 

Spring-Data-JPA [8] Querydsl 사용

저번 포스팅에선 Querydsl 설정을 했습니다. 이제는 직접 사용해보겠습니다. 1. JPAQueryFactory 등록 JpaRepository를 custom 했다는 컨벤션으로 ~~ RepositoryCustom을 만들어 해당 Repository를 상속하고, ~~ Impl로

dingdingmin-back-end-developer.tistory.com

 

 

 

 

마무리

다음 포스팅에선, 드디어 실제 토이 프로젝트에 적용될 예시 쿼리를 QueryDSL로 직접 사용해서 View까지 해보도록 하겠다.

 

 

 

 

 

 

 

참조

https://velog.io/@youngerjesus/%EC%9A%B0%EC%95%84%ED%95%9C-%ED%98%95%EC%A0%9C%EB%93%A4%EC%9D%98-Querydsl-%ED%99%9C%EC%9A%A9%EB%B2%95

https://tecoble.techcourse.co.kr/post/2021-08-08-basic-querydsl/

https://binco.tistory.com/entry/QueryDSL-%EC%A0%81%EC%9A%A9-%EC%98%88%EC%A0%9C%EC%8B%9C%EB%A6%AC%EC%A6%88

https://velog.io/@soyeon207/QueryDSL-Spring-Boot-%EC%97%90%EC%84%9C-QueryDSL-JPA-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

 

 

 

 

 

 

관련 포스팅

QueryDSL이란? - QueryDSL 사용하기(1)

JPQL이란? - QueryDSL 사용하기(2)

 

 

 

 

 

 

728x90
300x250
mag1c

mag1c

2년차 주니어 개발자.

방명록