최근 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 |