스프링

[Spring Boot] 동적 쿼리 처리를 위해 Querydsl 알아보기

zumsim 2023. 2. 13. 21:00
728x90
반응형
Querydsl ?

 

- JPA의 쿼리 메서드의 기능과 @Query를 통해 많은 기능을 구현 할 수는 있지만, 선언할 때 고정된 형태의 값을
  가지는 단점이 있다. 이러한 경우엔 동적으로 쿼리를 생성하여 처리할 수 있는 Querydsl을 사용한다.
- Querydsl은 작성된 엔티티 클래스는 그대로 이용하는 것이 아닌 'Q도메인'이란 것을 이용해야 하고, 이 과정에서 추가적인 설정이 필요하다.

 

querydsl을 위한 설정 추가 (본인은 스프링부트 2.7.7 기준으로 작성)
- build.gradle 파일에 다음과 같은 내용을 처리하자.
 1. plugins 항목에 querydsl 관련 부분을 추가
 2. dependencies 항목에 필요한 라이브러리 추가
 3. Gradle에서 사용할 추가적인 항목 추가

 

buildscript {
    ext {
        queryDslVersion = "5.0.0"
    }
}

plugins {
    id 'java'
    id 'base'
    id 'war'
    id 'org.springframework.boot' version '2.7.7'
    id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

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'
    annotationProcessor 'org.projectlombok:lombok'
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.7.5'
    implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"

    annotationProcessor(

            "javax.persistence:javax.persistence-api",

            "javax.annotation:javax.annotation-api",

            "com.querydsl:querydsl-apt:${queryDslVersion}:jpa")


    implementation 'org.modelmapper:modelmapper:3.1.0'

    implementation 'net.coobird:thumbnailator:0.4.16'
}

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


sourceSets {
    main {
        java {
            srcDirs = ["$projectDir/src/main/java", "$projectDir/build/generated"]
        }
    }
}

compileJava.dependsOn('clean')

 

- 위의 내용을 추가 후 build.gradle 파일을 갱신하고 프로젝트를 재 실행하면 build 폴더 안에 'Q'로 시작되는 파일들이 엔티티 클래스의 이름과 동일하게 만들어진다.

- 자동으로 생성된다는 말은 곧 Q로 시작되는 클래스들은 개발자가 직접 건드리지 않는다는 것이다.

- 사용할 Repository 인터페이스에서 QuerydslPredicateExecutor라는 인터페이스를 추가로 상속하여 사용한다.

 

 

엔티티 테스트 해보기

 

test를 위해 만들어둔 폴더 내에 repository 패키지 생성 후 클래스를 생성하자.

본인은 학습과정에서 만들어둔 예제 GuestbookRepositoryTests란 이름을 사용하였다.

 

1. 단일 항목 검색 테스트

- 제목(title)에 '1'이라는 글자가 있는 엔티티들 검색

public class GuestbookRepositoryTests {
 
    @Autowired
    private GuestbookRepository guestbookRepository;
 
    @Test
    public void testQuery1() {
        Pageable pageable = PageRequest.of(0,10, Sort.by("ano").descending());
 
        QGuestbook qGuestbook = QGuestbook.guestbook;
 
        String keyword = "1";

//BooleanBuilder는 where문에 들어가는 조건을 넣어주는 컨테이너 역할
        BooleanBuilder builder = new BooleanBuilder();
 
        BooleanExpression expression = qGuestbook.title.contains(keyword);
 
        builder.and(expression);
 
        Page<Guestbook> result = guestbookRepository.findAll(builder, pageable);
 
        result.stream().forEach(guestbook -> {
            System.out.println(guestbook);
        });
    }
}
cs

 

2. 다중 항목 검색 테스트

- 제목(title) 혹은 내용(content)에 특정 키워드가 있고 gno가 0보다 큰 조건을 검색

public class GuestbookRepositoryTests {
 
    @Autowired
    private GuestbookRepository guestbookRepository;
 
    @Test
    public void testQuery2() {
        Pageable pageable = PageRequest.of(0,10, Sort.by("ano").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.ano.gt(0L));
 
        Page<Guestbook> result = guestbookRepository.findAll(builder, pageable);
 
        result.stream().forEach(guestbook -> {
            System.out.println(guestbook);
        });
    }
}
cs

 

728x90
반응형