[JPA] Spring Date JPA에서 Querydsl 사용하기
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
가 정상적으로 생성된 것을 볼 수 있다.
Querydsl 사용하기
이제 Querydsl 지원을 이용해 API 검색 옵션에 추가해보자.
QuerydslPredicateExecutor
와 QuerydslBinderCustomizer
을 적용한다.
Repository 클래스 적용
Repository 클래스에 QuerydslPredicateExecutor
와 QuerydslBinderCustomizer
을 상속한다.
주의할 점은 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로 부분 검색을 해보면 결과가 잘 나오는 걸 확인할 수 있다.
정리
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