spring boot에 querydsl 적용하기

송준희·2021년 7월 26일
0
post-thumbnail

프로젝트 검색 기능을 만들면서 title 혹은 content로 검색을 하고 싶었다.
MyBatis는 동적 쿼리문을 사용할 수 있기 때문에 if문을 추가해서 쉽게 구현할 수 있다.
하지만 JPA에서는 동적 쿼리문을 지원하지 않기 때문에 Querydsl을 사용해보기로 했다.

먼저 dependency에 아래 코드를 추가한다.

implementation('com.querydsl:querydsl-jpa')

gradle의 맨위에 있는 pulgins에도 querydsl plugin을 추가한다.

plugins {
    id 'org.springframework.boot' version '2.5.1'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
    id 'com.ewerk.gradle.plugins.querydsl' version '1.0.10'
}

dependencies 뒷부분에 아래의 코드를 추가한다.

def querydslDir = "$buildDir/generated/querydsl"
querydsl {
    jpa = true
    querydslSourcesDir = querydslDir
}
sourceSets {
    main.java.srcDir querydslDir
}
configurations {
    querydsl.extendsFrom compileClasspath
}
compileQuerydsl {
    options.annotationProcessorPath = configurations.querydsl
}

추가가 잘 됐다면 오른쪽 Gradle을 눌렀을 때 qeurydsl 관련 tab이 나올 것이다.

other tab의 compileQuerydsl을 실행하면 build.generated 폴더에 Q + entity명으로 구성된 클래스들이 생성될 것이다. entity가 변경되면 Gradle의 querydsl에 있는 cleanQeurydslSourcesDir을 실행하고 다시 compileQuerydsl을 실행하면 entity 정보가 갱신된다.

이제 Repository에서 QuerydslRepositorySupport를 상속받아 querydsl을 사용하면 된다.
샘플 코드는 아래와 같다.

import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.vitasoft.annotation.domain.model.dto.project.ProjectDto;
import com.vitasoft.annotation.domain.model.entity.Project;
import com.vitasoft.annotation.domain.model.entity.User;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.stream.Collectors;
import static com.vitasoft.annotation.domain.model.entity.QProject.project;
import static com.vitasoft.annotation.domain.model.entity.QTask.task;
import static com.vitasoft.annotation.domain.model.entity.QUser.user;
@Repository
public class ProjectRepositorySupport extends QuerydslRepositorySupport {
    private final JPAQueryFactory queryFactory;
    public ProjectRepositorySupport(JPAQueryFactory queryFactory) {
        super(Project.class);
        this.queryFactory = queryFactory;
    }
    public List<ProjectDto> findByUserAndTitleContainingOrContentContaining(User pUser, String title, String content) {
        return queryFactory.selectFrom(task)
                .leftJoin(task.project, project).fetchJoin()
                .leftJoin(project.user, user).fetchJoin()
                .where(
                        getFindByUserAndTitleContainingOrContentContainingCondition(title, content)
                )
                .fetch()
                .stream().map(
                        task -> new ProjectDto(task.getProject())
                )
                .collect(Collectors.toList());
    }

    private BooleanExpression getFindByUserAndTitleContainingOrContentContainingCondition(String title, String content) {
        BooleanExpression expression = null;
        boolean isNull = true;
        if (StringUtils.hasText(title)) {
            expression = project.title.containsIgnoreCase(title);
            isNull = false;
        }
        if (StringUtils.hasText(content))
            expression = isNull ? project.content.containsIgnoreCase(content) : expression.or(project.content.contains(content));
        return expression;
    }
}

참고자료 https://jojoldu.tistory.com/372, https://sup2is.github.io/2020/10/20/what-is-jpa-query-dsl.html

profile
오늘 달리면 내일 걸을 수 있다!

0개의 댓글