2 minute read

Updated:

👩🏻‍💻 스프링 3.x.x에서 Querydsl을 사용해보고자 합니다.

Querydsl 소개

Querydsl이란?

Springboot와 JPA를 조합하여 사용할 때 해결하지 못하는 한계점이 있는데 바로 복잡한 쿼리와 동적 쿼리 문제이다. 실무에서는 검색 조건에 따라 복잡한 동적 쿼리를 생성해야 할 일이 많은데, 이 문제를 해결하는 기술이 Querydsl이다.

Querydsl의 장점

1) Querydsl은 쿼리를 자바 코드로 작성할 수 있게 도와준다. 따라서 문법 오류를 컴파일 시점에 잡아준다.
2) 동적 쿼리 문제를 해결해준다.
3) SQL 스타일의 쉬운 문법으로 학습도 쉽고 복잡한 쿼리도 쉽게 작성할 수 있다.

Querydsl 설정 방법

Querydsl 사용할 수 있는 환경을 구성해보자. 유의할 점은 스프링 부트 버전에 따라 Querydsl 설정 방법이 조금씩 다르다. 이 글에 사용된 프레임워크/라이브러리 버전은 다음과 같다.

  • Spring boot : 3.1.1
  • Gradle : 8.1.1
  • Querydsl : 5.0.0
  • Lombok : 1.18.28

gradle 설정

먼저 다음과 같이 build.gradle 파일에 추가한다. 모든 설정이 다 필요한 것은 아니다.
collections 정도는 없어도 동작에는 무리가 없지만 일단은 Querydsl에서 제공하는 기능은 다 포함시키고자 한다.

    //Querydsl 설정
    implementation "com.querydsl:querydsl-jpa:5.0.0:jakarta"
    implementation "com.querydsl:querydsl-core"
    implementation "com.querydsl:querydsl-collections"
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" //groovy 문법을 이용해 버전을 자동으로 삽입함
    annotationProcessor "jakarta.annotation:jakarta.annotation-api" //java.lang.NoClassDefFoundError (javax.annotation.Generated) 대응 코드
    annotationProcessor "jakarta.persistence:jakarta.persistence-api" //java.lang.NoClassDefFoundError(javax.annotation.Entity) 대응 코드

Querydsl 전용 설정도 마찬가지로 build.gradle에 추가한다.
IntelliJ IDE에서 사용할 때 생길 수 있는 Grdle과의 중복 빌드 문제를 해결하고자 일부러 QClass의 생성 위치를 꺼내놓는 추가 설정을 하였다.

// Querydsl 설정부
def generated  = 'src/main/generated' //

//querydal QClass 파일 생성 위치를 지정
tasks.withType(JavaCompile) {
    options.getGeneratedSourceOutputDirectory().set(file(generated))
}

// java soruce set에 querydsl QClass 위치 추가
sourceSets {
    main.java.srcDirs += [ generated ]
}

// gradle clean 시에 QClass 디렉토리 삭제
clean {
    delete file(generated)
}

이제 Gradle의 build를 실행해보자.
설정한 파일 위치 (src/main/generated) 에 Qclass가 정상적으로 생성된 것을 볼 수 있다.

image image

Querydsl 사용하기

이제 Querydsl 지원을 이용해 API 검색 옵션에 추가해보자.
QuerydslPredicateExecutorQuerydslBinderCustomizer을 적용한다.

Repository 클래스 적용

Repository 클래스에 QuerydslPredicateExecutorQuerydslBinderCustomizer을 상속한다.
주의할 점은 QuerydslBinderCustomizer의 제네릭 타입은 Qclass를 넣어야 한다.
QuerydslPredicateExecutor의 역할은 entity 클래스에 선언된 모든 필드에 대한 기본 검색 기능을 추가해준다. 부분 검색은 불가하고 exact match로만 동작한다. QuerydslBinderCustomizer를 추가하면 부분 검색 기능을 구현할 수 있다.
QuerydslBinderCustomizer의 customize 메서드를 오버라이드하여 구현하면, 구현한 내용을 토대로 검색의 세부 규칙이 정해진다.

@RepositoryRestResource
public interface ArticleRepository extends
        JpaRepository<Article, Long>,
        QuerydslPredicateExecutor<Article>,
        QuerydslBinderCustomizer<QArticle> {
    
    @Override
    default void customize(QuerydslBindings bindings, QArticle root) {
        bindings.excludeUnlistedProperties(true); //listing을 하지 않은 property는 검색에서 제외시킴
        bindings.including(root.title, root.content, root.hashtag, root.createdAt, root.createdBy); //검색 원하는 필드 추가
        bindings.bind(root.title).first(StringExpression::containsIgnoreCase); // like '%s{v}%' 대소문자 구분없이 검색
        bindings.bind(root.content).first(StringExpression::containsIgnoreCase);
        bindings.bind(root.hashtag).first(StringExpression::containsIgnoreCase);
        bindings.bind(root.createdAt).first(DateTimeExpression::eq);
        bindings.bind(root.createdBy).first(StringExpression::containsIgnoreCase);
    }
}

HAL Explorer에서 검색 옵션 확인하기

이제까지 적용한 내용을 build하고 서버를 실행해준다.
미리 셋팅해둔 HAL Explorer에서 title로 부분 검색을 해보면 결과가 잘 나오는 걸 확인할 수 있다. image image

정리

Spring Data JPA에 Querydsl을 더하면 단순 반복 개발 코드들이 확연히 줄고 개발자는 핵심 비즈니스 로직에만 집중할 수 있다. 초기 설정이 조금 까다로운 것이 단점이지만 실무에서 중요하게 쓰이는 기술인만큼 반복적으로 활용하며 체득하는 과정이 필요하겠다.


Reference

https://www.inflearn.com/course/lecture?tab=curriculum&volume=1.00&courseSlug=Querydsl-%EC%8B%A4%EC%A0%84&unitId=30114
https://madplay.github.io/post/introduction-to-querydsl
10개 프로젝트로 완성하는 백엔드 웹개발(Java/Spring) 초격차 패키지 Online