
한번 더 QueryDSL
JPA를 다루다 보면 DB에서 하나 검색할 때 마다 메서드를 한개씩 만들게 된다.
이러한 행위를 방지하고자 DB 쿼리의 조건을 간단하게 쓸 수 있게 도와주는 것이 QueryDSL 이다.
JPA에서 제공하는 Specification가 있는데, QueryDSL과 비교하면 실무에서 JpaSpecificationExcutor를 사용하는것은 지양한다고 한다.
이유는 JpaSpecification은 Criteria로 이루어지는데, 복잡해질수록 사용하기가 어렵기 때문이다.
gradle 설정
우선 build.gradle에 의존성을 추가해주어야 한다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
// QueryDsl
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
}
'''
다른 방법도 있겠지만 위 4줄만 추가했을 때 실행이 되었다.
그리고 나서 global 패키지에 JpaConfig 클래스를 생성하여 Bean 등록과 EntityManager를 등록해 주면 된다.
```java
@Configuration
@EnableJpaAuditing
public class JpaConfig {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(JPQLTemplates.DEFAULT, entityManager);
}
}
사용방법
Spring에서 QueryDSL을 사용하는 방법은 3가지가 있다.
1. Spring Data Jpa Custom Repository
2. QueryRepositorySupport
3. JPAQueryFactory
여기서는 익숙한 1번을 사용한다.

그림으로 이해하자면 다음과 같다.
JpaRepository(interface) : JpaRepository
MyRepository(interface) : JpaRepository와 Customrepository를 다중 상속받는다.
CustomRepository(interface) : 선언부.
MyRepositoryImpl(class) : 구현부, Customrepository를 상속받음
결론은 CustomRepository에서 선언하고 MyRepositoryImpl에서 구현하면 된다!
public interface MyRepositoryCustom {
}
---------------------------------------
@RequiredArgsConstructor // queryFactory를 생성자에 포함
public class MyRepositoryImpl implements MyRepositoryCustom{
private final JPAQueryFactory queryFactory;
}
---------------------------------------
public interface MyRepository extends JpaRepository<Store, Long>, MyRepositoryCustom {
}
위와 같은 모습이 기본 뼈대이고,
@RequiredArgsConstructor
public class StoreRepositoryImpl implements StoreRepositoryCustom {
private final JPAQueryFactory queryFactory;
@Override
public List<Store> findAll(String keyword){
List<Store> stores = queryFactory
.selectFrom(store)
.where(nameCon(keyword)
.or(categoryCon(keyword)
.or(statusCon(keyword))))
.fetch();
return stores;
}
private BooleanExpression nameCon(String keyword) {
if (keyword == null || keyword.isEmpty()) {
return null;
}
return store.name.contains(keyword);
}
private BooleanExpression categoryCon(String keyword) {
if (keyword == null || keyword.isEmpty()) {
return null;
}
return store.category.contains(keyword);
}
private BooleanExpression statusCon(String keyword) {
if (keyword == null || keyword.isEmpty()) {
return null;
}
for(Status status : Status.values()) {
if (status.name().equals(keyword)) {
return store.status.eq(status);
}
}
return null;
}
}
추가로 더 공부해서 쿼리문에 익숙해진다면, 편리한 방법이 될 것이다.