Study Note

SpringBoot JPA의 QueryDSL 본문

Spring/Spring Boot

SpringBoot JPA의 QueryDSL

moreLearn 2020. 2. 11. 11:28

MyBatis에서 동적 쿼리를 만들어서 사용하듯이 JPA에서 동적 쿼리를 사용하기 위해서는 QueryDSL를 사용해야 한다. @Query는 project가 로딩되는 시점에서 파싱 되기 때문에 고정된 SQL만 사용할 수 있다.
QueryDSL는 오픈소스로서 자바 코드로 작성된 일종의 JPQL( Java Persistence Query Language) 빌더이다. JPA, JDBC Lucene, Hibernate Search, MongoDB, 자바 컬렌션등을 지원한다.

QueryDSL 설정하기

QueryDSL를 사용하기 위해 pom.xml에 다음과 같이 작성하여 라이브러리를 사용한다. 특정 버전을 사용하려면 <version>을 추가하면 되지만 <parent> POM에서 이미 라이브러리의 버전을 명시되어 있기 때문에 없어도 된다.

라이브러리가 저장되었으면 플러그인을 추가해야 한다. 프로젝트 우 클릭해서 Maven -> Add Plugin을 하여 플러그인을 추가한다.

그 후 pom.xml에 추가된 플러그인을 다음과 같이 수정한다.

apt-maven-plugin이 추가되었고 쿼리 타입 클래스인 Q클래스의 위치를 src/main/querydsl에 지정했다.

pom.xml 파일을 수정한 후 Maven -> Update Project..를 하면 메이븐 project를 업데이트하고 플러그인이 다운된다. 이후 src/main/querydsl에 Q클래스가 생성되어 있다.

동적 쿼리 사용하기

동적 쿼리를 사용하기 위해 Board와 DynamicBoardRepository를 생성한다.

package com.example.demo.domain;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
@Entity
public class Board {
	@Id @GeneratedValue
	private Long seq;
	private String title;
	private String writer;
	private String content;
	@Temporal(value = TemporalType.TIMESTAMP)
	private Date createDate;

}

 

package com.example.demo.persistence;

import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.CrudRepository;

import com.example.demo.domain.Board;

public interface DynamicBoardRepository extends CrudRepository<Board, Long>, QuerydslPredicateExecutor<Board> {

}

DynamicBoardRepository에서 QuerydslPredicateExecutor를 추가했기 때문에 사용할 수 있는 메소드가 다음과 같이 증가했다. 해당 표를 보면 공통적으로 Predicate를 인자로 사용하며 이 Predicate 인터페이스를 구현한 게 BooleanBuilder 클래스이다.

다음과 같이 DynamicQueryTest를 테스트 파일에 생성하여 실행해 본다.

package com.example.demo;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.test.context.junit4.SpringRunner;

import com.example.demo.domain.Board;
import com.example.demo.domain.QBoard;
import com.example.demo.persistence.DynamicBoardRepository;
import com.querydsl.core.BooleanBuilder;

@RunWith(SpringRunner.class)
@SpringBootTest
public class DynamicQueryTest {
	@Autowired
	private DynamicBoardRepository boardRepo;

	@Test
	public void testDynamicQuery() {
		String searchCondition = "CONTENT";
		String searchKeyword = "Test Content 10";

		
		BooleanBuilder builder = new BooleanBuilder();
		
		QBoard qboard = QBoard.board;
		
		if(searchCondition.equals("TITLE")) {
			builder.and(qboard.title.like("%" + searchKeyword + "%"));
		} else if(searchCondition.equals("CONTENT")) {
			builder.and(qboard.content.like("%" + searchKeyword + "%"));
		}		
		
		Pageable paging = PageRequest.of(0, 5);
		
		Page<Board> boardList = boardRepo.findAll(builder, paging);
				
		System.out.println("검색 결과");
		for (Board board : boardList) {
			System.out.println("---> " + board.toString());
		}
	}
}

Mybatis의 동적 쿼리처럼 searchCondition의 값에 따라 서로 다른 builder를 저장하고 Pageable에서 paging 설정을 하여 다음과 같이 쿼리를 실행한다.

Page<Board> boardList = boardRepo.findAll(builder, paging);

searchCondition을 왼쪽은 “CONTENT”로, 오른쪽은 “TITLE”로 지정했고 searchKeyword는 왼쪽은 “Test Content 10”, 오른쪽은 “Test Title 10”로 설정해서 실행한 결과이며 두 쿼리가 다르다는 것을 볼 수 있다.

'Spring > Spring Boot' 카테고리의 다른 글

Spring Boot JPA 사용하기  (0) 2020.02.11