Spring

Spring Jpa - Query DSL + Gradle 6 설정

일태우 2020. 9. 21. 15:03

최근 Spring boot + jpa 로 프로젝트 진행하다 jpa 인터페이스 네이밍 방식의 단점을 느끼고 Query DSL을 도입하면서 정리한 글

 

기본 제공 @Query와 인터페이스 메서드 네이밍 방식은 한계가 있고 가독성도 안좋음

// 쿼리가 길어질수록 더러워짐
@Query(value="UPDATE Work W SET W.workGroup = :workGroup WHERE W.workSeq = :workSeq", nativeQuery = false)

// 네이밍이 길어질수록 더러워짐
Page<Work> findByWorkGroup_WorkGroupNmContainingAndWorkNmContaining(String workGroupNm, String workNm, Pageable pageable);

1. Gradle 설정

많은 기술블로그에 나와있는 방식은 Gradle의 annotationProcessor 지원 전의 내용이다 본 글은 5 이후의 annotationProcessor를 사용하여 진행한다. 장점으로는 플러그인에 의존하지 않는다, 좀더 깔끔해진다.

buildscript {
	ext {
		queryDslVersion = "4.4.0"
	}
}

plugins {
	id "org.springframework.boot" version "2.4.0-SNAPSHOT"
	id "io.spring.dependency-management" version "1.0.9.RELEASE"
	id "java"
}

group = "kr.taeu.workorder"
version = "0.0.1-SNAPSHOT"
sourceCompatibility = "1.8"

repositories {
	mavenCentral()
	maven { url "https://repo.spring.io/milestone" }
	maven { url "https://repo.spring.io/snapshot" }
}

dependencies {
	implementation "org.springframework.boot:spring-boot-starter-data-jpa"
	implementation "org.springframework.boot:spring-boot-starter-web"
	implementation "org.springframework.boot:spring-boot-devtools"

	// QueryDSL
	implementation ("com.querydsl:querydsl-jpa:${queryDslVersion}")
	annotationProcessor ("com.querydsl:querydsl-apt:${queryDslVersion}:jpa")
	testImplementation ("com.querydsl:querydsl-jpa:${queryDslVersion}")
	testAnnotationProcessor ("com.querydsl:querydsl-apt:${queryDslVersion}:jpa")

	// Lombok
	implementation "org.projectlombok:lombok"
	annotationProcessor ("org.projectlombok:lombok")
	testImplementation ("org.projectlombok:lombok")
	testAnnotationProcessor ("org.projectlombok:lombok")

	runtimeOnly "com.h2database:h2"

	testImplementation "org.springframework.boot:spring-boot-starter-test"
}

test {
	useJUnitPlatform()
}

플러그인을 사용할때와는 다르게 코드가 매우 깔끔해졌다.  중요한 부분은 QueryDSL 주석부분과 맨위의 버전변수 부분이다. 이외엔 기타 라이브러리 설정이니 무시하자.

2. Java Config

@EnableJpaAuditing
@Configuration
public class DatabaseConfig {

  ...

  @Bean
  public JPAQueryFactory jpaQueryFactory(EntityManager em) {
    return new JPAQueryFactory(em);
  }
  
  ...
}

JPAQueryFactory를 bean으로 등록하는것으로 끝

3. 사용법

domain에 대한 repository를 생성해주자 아래는 테스트를 위한 JpaRepository

public interface WorkGroupRepository extends JpaRepository<WorkGroup, Long> {}

아래는 Querydsl Repository이다.

package kr.taeu.workorder.domain.workgroup.repository;

import static kr.taeu.workorder.domain.workgroup.domain.QWorkGroup.workGroup;

...

@Repository
@RequiredArgsConstructor
public class WorkGroupRepositorySupport {
    private final JPAQueryFactory queryFactory;

    public List<WorkGroup> findByWorkGroupNm(String name) {
        return queryFactory.selectFrom(workGroup)
                .where(workGroup.workGroupNm.containsIgnoreCase(name))
                .fetch();
    }
}

JPAQueryFactory는 Bean으로 위에서 등록한걸 주입받는다. 중요한건 맨위의 정적 import를 빼먹지말자.

4. 테스트

@ExtendWith(SpringExtension.class)
@SpringBootTest
public class QuerydslTest {
    @Autowired
    private WorkGroupRepository workGroupRepository;

    @Autowired
    private WorkGroupRepositorySupport workGroupRepositorySupport;

    @AfterEach
    public void clean() throws Exception {
        workGroupRepository.deleteAllInBatch();
    }

    @Test
    public void querydsl_기본_테스트() {
        // given
        String workGroupNm = "테스트그룹1";
        workGroupRepository.save(new WorkGroup(workGroupNm));
        workGroupNm = "테스트그룹1-1";
        workGroupRepository.save(new WorkGroup(workGroupNm));
        workGroupNm = "테스트그룹2";
        workGroupRepository.save(new WorkGroup(workGroupNm));

        // when
        List<WorkGroup> workGroups = workGroupRepositorySupport.findByWorkGroupNm("그룹1");

        // then
        Assertions.assertTrue(workGroups.size() == 2);
        Assertions.assertEquals(workGroups.get(0).getWorkGroupNm(), "테스트그룹1");
    }
}

테스트 데이터 3개를 생성하고, Querydsl로 작성한 findByWorkGroupNm 메서드로 조회하여 결과를 확인

성공~

아주 쉽게 설정부터 테스트까지 완료했다.

'Spring' 카테고리의 다른 글

Spring Cloud Gateway - API Gateway 맛보기  (5) 2020.10.19
Spring Security OAuth2 - Authorization endpoint  (0) 2020.10.07
Spring Jpa - Paging api 처리하기  (0) 2020.09.18
Spring Data Jpa Auditing  (0) 2020.07.29
ApplicationContext와 Singleton  (0) 2020.07.29