Querydsl

띠로리·2024년 8월 8일

JPA의 쿼리 메서드 기능과 @Query를 통해서 많은 기능을 구현할 수 있지만, 선언할 때 고정된 형태의 값을 가진다는 단점이 있다. 이 때문에 단순한 몇 가지의 검색 조건을 만들어야 하는 상황에서는 기본 기능만으로 충분하지만, 복잡한 조합을 이용하는 경우의 수가 많은 상황에서는 동적으로 쿼리를 생성해서 처리할 수 있는 기능이 필요하다.

Querydsl

코드 내부에서 상황에 맞는 쿼리를 생성할 수 있게 된다. 하지만 이를 위해서는 작성된 엔티티 클래스를 그대로 이용하는 것이 아닌 'Q도메인'이라는 것을 이용해야한다.

build.gradle

  • buildscript 항목 추가
  • plugins 항목 변경
  • dependencies 항목에 필요한 라이브러리 추가
  • 기타 추가
plugins {
    id 'java'
    id 'org.springframework.boot' version '3.3.2'
    id 'io.spring.dependency-management' version '1.1.6'
}

group = 'org.zerock'
version = '0.0.1-SNAPSHOT'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'com.mysql:mysql-connector-j'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    implementation 'com.querydsl:querydsl-jpa:5.1.0:jakarta'
    annotationProcessor(
            "jakarta.persistence:jakarta.persistence-api",
            "jakarta.annotation:jakarta.annotation-api",
            'com.querydsl:querydsl-apt:5.1.0:jakarta'
    )
}

tasks.named('test') {
    useJUnitPlatform()
}

build.gradle 파일을 수정하고 프로그램을 시작하면 build 폴더 내에 generated 폴더가 생성된 것을 확인할 수 있고, 내부에는 Q로 시작하는 파일들이 생성된 것을 확인할 수 있다.

Querydsl 테스트

Querydsl의 사용법

  • BooleanBuilder를 생성한다.
  • 조건에 맞는 구문은 Querydsl에서 사용하는 Predicate 타입의 함수를 생성한다.
  • BooleanBuilder에 작성된 Predicate를 추가하고 실행한다.

1. 단일 항목 검색 테스트

@Test
public void testQuery1() {
    Pageable pageable = PageRequest.of(0, 10, Sort.by("gno").descending());
    QGuestbook qGuestbook = QGuestbook.guestbook; // 1
    String keyword = "1";
    BooleanBuilder builder = new BooleanBuilder(); // 2
    BooleanExpression expression = qGuestbook.title.contains(keyword); // 3
    builder.and(expression); // 4
    Page<Guestbook> result = guestbookRepository.findAll(builder, pageable); // 5
    result.stream().forEach(guestbook -> System.out.println(guestbook));
}
  1. 동적으로 처리하기 위해 Q도메인 클래스를 얻어온다.
  2. BooleanBuilder는 where문에 들어가는 조건들을 넣어주는 컨테이너 역할
  3. 원하는 조건은 필드 값과 같이 결함해서 생성해야한다.
    • BooleanBuilder 안에 들어가는 값은 com.querydsl.core.types.Predicate 타이이어야 한다.
  4. 만들어진 조건은 and나 or 키워드와 결합시킨다.
  5. BooleanBuilder는 GuestbookRepository에 추가된 QuerydslPredicateExcutor 인터페이스와 findAll()을 사용할 수 있다.

결과값

2. 다중 항목 검색 테스트

@Test
public void testQuery2() {
    Pageable pageable = PageRequest.of(0, 10, Sort.by("gno").descending());
    QGuestbook qGuestbook = QGuestbook.guestbook;
    String keyword = "1";
    BooleanBuilder builder = new BooleanBuilder();
    BooleanExpression exTitle = qGuestbook.title.contains(keyword);
    BooleanExpression exContent = qGuestbook.content.contains(keyword);
    BooleanExpression exAll = exTitle.or(exContent);
    builder.and(exAll);
    builder.and(qGuestbook.gno.gt(0L));
    Page<Guestbook> result = guestbookRepository.findAll(builder, pageable);
    result.stream().forEach(guestbook -> System.out.println(guestbook));
}
profile
차곡 차곡 기록 쌓기

0개의 댓글