프로젝트를 진행하다가 3개의 카테고리에 대해 null을 허용해주며 null이 아닌 데이터에 대해서만 where조건을 걸어주는 API를 작성해야 했다. 3개의 카테고리라 총 7가지의 경우로 메서드를 각각 제작하여 모든 경우의 쿼리를 만드는 건 일단 몸이 아니라고 말하고 있었다.
그렇다면 null인 경우에 대해 문자열로 쿼리를 동적으로 만들어야 하나? 했을 때 그것도 매우 복잡한 상황일 것 같아 구글에 뒤적뒤적 하였다.
Querydsl 공식 홈페이지
조건에 따라서 실행되는 쿼리인 동적 쿼리를 편하게 작성할 수 있는 라이브러리이다.
Querydsl은 JPQL을 JAVA 코드로 만드는 빌더라고 생각하면 된다.
특히 실무에서 복잡한 동적 쿼리를 많이 사용하게 되는데 Querydsl을 사용하면 높은 개발 생산성을 얻으면서 쿼리 오류를 컴파일 시점에 빠르게 잡을 수 있다. 꼭 동적쿼리가 아니라 정적 쿼리인 경우에도 Querydsl을 사용하는 것이 좋다.
직관적인 문법
컴파일 시점에 문법 오류 발견
코드 재사용성 증가
JPQL에서 new를 사용하는 것과 비교가 안될정도로 깔끔한 DTO조회를 지원한다.
//querydsl 추가
buildscript {
dependencies {
classpath("gradle.plugin.com.ewerk.gradle.plugins:querydsl-plugin:1.0.10")
}
}
//apply plugin: 'io.spring.dependency-management'
apply plugin: "com.ewerk.gradle.plugins.querydsl"
dependencies {
implementation 'com.google.code.findbugs:jsr305:3.0.2'
implementation 'com.querydsl:querydsl-jpa'
implementation 'com.querydsl:querydsl-apt'
}
//querydsl 추가
def querydslDir = "src/main/generated"
querydsl {
library = "com.querydsl:querydsl-apt"
jpa = true
querydslSourcesDir = querydslDir
}
sourceSets {
main {
java {
srcDirs = ['src/main/java', querydslDir]
}
}
}
compileQuerydsl{
options.annotationProcessorPath = configurations.querydsl
}
configurations {
querydsl.extendsFrom compileClasspath
}
Querydsl을 사용하기 위해 build.gradle에 위와같이 추가를 해주면된다.
추가를 해주고 gradle에 compil.java를 실행시켜주면 아래와같이 generated폴더 지정한 경로에 생긴다.


기존에 사용하던 Entity에 Q가 접두어로 붙어서 QClass가 생성된다.
QueryDsl을 사용하기 위해 queryFacotry를 Config해주는 클래스를 작성하면 된다.
@Configuration
public class QueryDslConfiguration {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory(){
return new JPAQueryFactory(entityManager);
}
}

처음에 작성하고자 했던 코드를 위와 같이 간단하게 작성할 수 있다.
where문 안에 메서드들은 직접 정의를 해주었다.

특정 분류가 빈문자열이거나 null일 경우 null을 return해주고 아니라면 해당 문자열이 같은지 비교해주는 Querydsl의 메서드를 호출해준다.
매개변수에 Pageable 그리고 return문에 offset과 limit은 페이징처리를 위한 것 이다.
처음에 Querydsl을 사용할 때 Q클래스가 포함되는 generated폴더를 git에 같이 올려주었지만 다른 컴퓨터에서 이 프로젝트를 클론하여 컴파일을 할 때 어차피 새로 컴파일 해야했다. 그렇기 때문에 그냥 gitignore에 generated를 추가해서 올리자