Develop/spring-data

[JPA] Querydsl에 pageable을 적용하며... 2가지 방법을 소개하겠습니다.

에디개발자 2020. 12. 10. 07:00
반응형

Querydsl을 적용하고 paging 처리를 위해 pageable을 적용한 내용을 정리하겠습니다.

Querydsl을 적용방법은 지난 글에 정리해놓았습니다.

나를 닮았다고 한다...

 

지난글에서 정리한 Querydsl 3가지 방법 중 제가 테스트를 해본 2가지 방법 모두 적용방법을 알아보겠습니다.

QuerydslRepositorySupport 상속받아서 사용

@Repository
public class StoreRepositorySupport extends QuerydslRepositorySupport {
    private final JPAQueryFactory jpaQueryFactory;
    private final EntityManager entityManager;

    /**
     * Creates a new {@link QuerydslRepositorySupport} instance for the given domain type.
     *
     * @param domainClass must not be {@literal null}.
     * @param entityManager
     */
    public StoreRepositorySupport(JPAQueryFactory jpaQueryFactory, EntityManager entityManager) {
        super(Store.class);
        this.jpaQueryFactory = jpaQueryFactory;
        this.entityManager = entityManager;
    }
    
    public PageImpl<StoreVo> findStoresByNamePaging(String name, Pageable pageable) {
        JPQLQuery<StoreVo> query = jpaQueryFactory        // 1)
                .select(Projections.fields(StoreVo.class,
                        store.id
                        , store.name
                        , store.address
                ))
                .from(store)
                .where(store.name.eq(name));

        long totalCount = query.fetchCount();             // 2)
        List<StoreVo> results = getQuerydsl().applyPagination(pageable, query).fetch();  // 3)
        return new PageImpl<>(results, pageable, totalCount);  // 4)
    }
}
  1. JPQLQuery를 생성합니다.
  2. JPQLQuery로 TotalCount를 조회합니다.
  3. JPQLQuery로 데이터를 조회합니다.
    1. QuerydslRepositorySupport의 getQuerydsl() 메소드를 이용합니다.
    2. Pageable 객체의 page, limit, sort값을 적용합니다.
    3. 적용된 쿼리를 이용하여 데이터를 조회합니다.
  4. PageImpl 객체로 리턴합니다.
여기서 주의할 점은 Pageable의 page 값은 0부터 입니다.
전 1로 세팅해서 데이터가 왜 안나오는지 삽질을 1시간 넘게한 흑역사가 있습니다. 꼭 0부터 세팅해주세요.

 

 

Test 코드를 작성하여 실행하면 Success가 나오는 것을 확인할 수 있습니다.

@ActiveProfiles("local")
@ExtendWith(SpringExtension.class)
@SpringBootTest
public class StoreRepositorySupportTest {
    @Test
    void querydsl_페이징처리() {
        //given
        final String name = "용태스토어";

        Sort.Order order = Sort.Order.desc("id");
        Sort sort = Sort.by(order);

        Pageable pageable = PageRequest.of(0, 10, sort);

        //when
        PageImpl<StoreVo> result = storeRepositorySupport.findStoresByNamePaging(name, pageable);

        //then
        assertThat(result.getNumber()).isEqualTo(0);
        assertThat(result.getTotalPages()).isEqualTo(1);
        assertThat(result.getContent().size()).isEqualTo(1);
    }
}    

 

JpaRepository에서 상속받아 사용

구현 방법은 이 글에서 작성하지 않겠습니다. 궁금하신 분께서는 글 도입부의 지난글 링크를 참조해주세요.

Querydsl paging 처리 로직은 impl 클래스에 작성하였습니다. 간단하게 소스를 살펴보겠습니다.

import static com.example.querydsl.staff.entity.QStaff.staff;

@RequiredArgsConstructor    // 의존성 주입
public class CustomizedStaffRepositoryImpl implements CustomizedStaffRepository {
    private final JPAQueryFactory jpaQueryFactory;

    public PageImpl<StaffVo> findStaffsByNamePaging(String name, Pageable pageable) {
        JPQLQuery<StaffVo> query = jpaQueryFactory       // 1)
                .select(Projections.fields(StaffVo.class,
                        staff.id
                        , staff.age
                        , staff.name
                ))
                .from(staff)
                .where(staff.name.eq(name));

        return pagingUtil.getPageImpl(pageable, query, Staff.class);    // 2)
    }
}
  1. JPQLQuery를 생성합니다.
  2. 이 방법은 QuerydslRespositorySupport 를 상속받지 않아 getQuerydsl 메서드를 사용할 수 없습니다. 그래서 동일한 기능을 하는 메서드를 유틸리티로 생성하였습니다. 

공통메서드 PagingUtil을 살펴보겠습니다.

@Component
@RequiredArgsConstructor
public class PagingUtil {

    private final EntityManager entityManager;

    private Querydsl getQuerydsl(Class clazz) {    // 1)
        PathBuilder<Staff> builder = new PathBuilderFactory().create(clazz);
        return new Querydsl(entityManager, builder);
    }

    public <T> PageImpl<T> getPageImpl(Pageable pageable, JPQLQuery<T> query, Class clazz) {    // 2)
        long totalCount = query.fetchCount();
        List<T> results = getQuerydsl(clazz).applyPagination(pageable, query).fetch();
        return new PageImpl<>(results, pageable, totalCount);
    }

}
  1. QuerydslRepositorySupport 내부의 getQuerydsl과 동일하게 메서드를 생성하였습니다.
  2. getQuerydsl 메서드를 이용해서 PageImpl 객체를 생성하여 가져오는 코드입니다.
    1. Class 파라미터는 Entity 클래스를 넣어주세요.

Test 코드를 작성하여 실행하면 Success를 확인할 수 있습니다. 

 @ActiveProfiles("local")
@ExtendWith(SpringExtension.class)
@SpringBootTest
public class StaffRepositoryTest {
    @Test
    void querydsl_페이징처리() {
        //given
        final String name = "임임용태";

        Sort.Order order = Sort.Order.desc("id");
        Sort sort = Sort.by(order);

        Pageable pageable = PageRequest.of(0, 10, sort);

        //when
        PageImpl<StaffVo> staffsByNamePaging = staffRepository.findStaffsByNamePaging(name, pageable);

        //then
        assertThat(staffsByNamePaging.getNumber()).isEqualTo(0);
        assertThat(staffsByNamePaging.getTotalPages()).isEqualTo(1);
        assertThat(staffsByNamePaging.getContent().size()).isEqualTo(1);
    }
}

 

반응형