minlog
article thumbnail

Querydsl

 

JPA 기본 쿼리 메서드의 기능과 @Query 어노테이션만으로 어려운 복잡한 검색 조건을 동적으로 쿼리를 생성해서 처리할 수 있는 기술이다.  

 

Querydsl 사용해보기

 

1. 빌드 추가

라이브러리를 사용하기 위해서 build.gradle 파일에 내용을 추가해주어야 한다.

 

📑 build.gradle

// 1. querydsl 추가
buildscript {
    ext {
        queryDslVersion = "5.0.0"
    }
}

plugins {
    id 'org.springframework.boot' version '2.7.10'
    id 'io.spring.dependency-management' version '1.0.15.RELEASE'
    //2. querydsl 추가
    id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
    id 'java'
}

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'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    // https://mvnrepository.com/artifact/mysql/mysql-connector-java
    implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.28'

    //3. querydsl 추가
    implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
    implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
}

//4. querydsl 추가
def querydslDir = "$buildDir/generated/querydsl"

querydsl {
    jpa = true
    querydslSourcesDir = querydslDir
}
sourceSets {
    main.java.srcDir querydslDir
}
compileQuerydsl{
    options.annotationProcessorPath = configurations.querydsl
}
configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
    querydsl.extendsFrom compileClasspath
}



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

 

저장 후 파일을 갱신하면 Gradle에 추가된 파일들을 확인할 수 있는데 compileQuerydsl를 눌러주면 

폴더 : build > generated > querydsl > entity  폴더에 생성했던 entity 클레스가 Q가 붙어 생성이된다. 

 

 

2. Repository 인터페이스 설정 추가

레파지토리 인터페이스에서 Querydsl 을 이용하려면 QuerydslPredicateExecutor 라는 인터페이스를 상속 받아야한다. 

public interface GuestbookRepository
        extends JpaRepository<Guestbook,Long>,
        QuerydslPredicateExecutor<Guestbook> {
    Guestbook getGuestbookByTitle(String title);
}

 

 

 

3. 테스트로 querydsl 사용 해보기

  • Q도메인 클래스를 얻어온다. 
  • 조건을 넣어주는 컨테이너를 생성한다. 
  • 조건은 필드와 결합해서 생성한다.
  • 생성한 조건은 and 또는 or을 사용하여 컨테이너에 넣어준다.
  • 레파지토리 인터페이스에서 사용하는 메서드와 함께 사용이 가능하다.

 

@Test
@DisplayName("querydsl 사용하기")
public void querydslTest(){
    Pageable pageable = PageRequest.of(0,10, Sort.by("gno").descending());
    QGuestbook qGuestbook = QGuestbook.guestbook; // Q도메인 클래스 얻어오기
    String keyword = "1";
    BooleanBuilder builder = new BooleanBuilder(); // 조건들을 넣어주는 컨테이너 생성
    BooleanExpression expression = qGuestbook.title.contains(keyword); // 조건은 필드와 결합해서 생성
    builder.and(expression); // 생성한 조건을 and 또는 or로 컨테이너에 넣어준다.
    Page<Guestbook> result = guestbookRepository.findAll(builder,pageable); // BooleanBuilder는 레파지토리에서 추가된 인터페이스의 findAll() 을 사용할 수 있다.

    result.stream().forEach(guestbook -> {
        System.out.println(guestbook);
    });

}

 

 

🍫 더 많은 조건 추가 해보기

private BooleanBuilder getSearch(PageRequestDto requestDto){
    String type = requestDto.getType();
    String keyword = requestDto.getKeyword();
    QGuestbook qGuestbook = QGuestbook.guestbook;
    BooleanBuilder booleanBuilder= new BooleanBuilder();

    //조건 생성
    BooleanExpression expression = qGuestbook.gno.gt(0L);

    booleanBuilder.and(expression);
    //검색조건이 없을 경우
    if (type == null || type.trim().length() == 0){
        return booleanBuilder;
    }
    //검색조건
    BooleanBuilder conditionGuilder = new BooleanBuilder();
    if(type.contains("t")){
        conditionGuilder.or(qGuestbook.title.contains(keyword));
    }
    if(type.contains("c")){
        conditionGuilder.or(qGuestbook.content.contains(keyword));
    }
    if(type.contains("w")){
        conditionGuilder.or(qGuestbook.writer.contains(keyword));
    }
    booleanBuilder.and(conditionGuilder);
    return booleanBuilder;
}
@Test
@DisplayName(" querydsl 여러 조건 결합하여 검색하기")
public void querydslTest2(){
    PageRequestDto pageRequestDto = PageRequestDto.builder()
            .page(1)
            .size(10)
            .type("tc")
            .keyword("title5")
            .build();
    PageResultDto<GuestbookDto,Guestbook> resultDto = service.getList(pageRequestDto);
    System.out.println("--------------------------");
    for (GuestbookDto guestbookDto : resultDto.getDtoList()){
        System.out.println(guestbookDto);
    }
    System.out.println("--------------------------");
    resultDto.getPageList().forEach(i ->{
        System.out.println(i);
    });
}

 

 

- 쿼리문 실행결과

Hibernate: 
    select
        guestbook0_.gno as gno1_0_,
        guestbook0_.moddate as moddate2_0_,
        guestbook0_.regdate as regdate3_0_,
        guestbook0_.content as content4_0_,
        guestbook0_.title as title5_0_,
        guestbook0_.writer as writer6_0_ 
    from
        guestbook guestbook0_ 
    where
        guestbook0_.gno>? 
        and (
            guestbook0_.title like ? escape '!' 
            or guestbook0_.content like ? escape '!'
        ) 
    order by
        guestbook0_.gno desc limit ?
Hibernate: 
    select
        count(guestbook0_.gno) as col_0_0_ 
    from
        guestbook guestbook0_ 
    where
        guestbook0_.gno>? 
        and (
            guestbook0_.title like ? escape '!' 
            or guestbook0_.content like ? escape '!'
        )

 

profile

minlog

@jimin-log

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!