페이징과 정렬
실전! 스프링 데이터 JPA - 인프런 | 강의
스프링 데이터 JPA는 기존의 한계를 넘어 마치 마법처럼 리포지토리에 구현 클래스 없이 인터페이스만으로 개발을 완료할 수 있습니다. 그리고 반복 개발해온 기본 CRUD 기능도 모두 제공합니다.
www.inflearn.com
Spring Data JPA - Reference Documentation
Example 119. Using @Transactional at query methods @Transactional(readOnly = true) interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") void del
docs.spring.io
목표
- 페이징 및 정렬에 사용되는 인터페이스와 클래스를 확인해보고 구현해본다.
페이징과 정렬
스프링 데이터는 페이징과 정렬기능을 간편하게 사용할 수 있는 기능을 제공해준다.
- 쿼리메서드의 '메서드이름으로 쿼리 생성' 기능을 사용하여 페이징 하는 방법
- org.springframework.data.domain 패키지의 인터페이스와 클래스를 직접 사용하여 페이징 하는 방법
쿼리메서드의 '메서드이름으로 쿼리 생성' 기능을 사용하여 페이징 하는 방법
First와 Top 키워드를 사용하여 페이징, Desc, Asc 키워드를 사용하여 정렬 할 수 있다.
Member findFirstByOrderByNameAsc();
Member findTopByOrderByAgeDesc();
Page<Member> queryFirst10ByName(String name, Pageable pageable);
Slice<Member> findTop3ByName(String name, Pageable pageable);
List<Member> findFirst10ByName(String name, Sort sort);
List<Member> findTop10ByUName(String name, Pageable pageable);
인터페이스와 클래스를 직접 사용하여 페이징 하는 방법
org.springframework.data.domain 패키지에 페이징 및 정렬을 위한 인터페이스 및 클래스가 정의되어 있다.
파라미터로사용되는 인터페이스 및 클래스
Sort : 정렬 기능을 기능을 정의해놓은 클래스
Pageable : 페이징 기능을 정의해놓은 인터페이스 (내부에 sort 클래스가 포함되어있다.)
PageRequest : Pageable 인터페이스를 구현한 추상클래스 AbstractPageRequest를 상속받아 구현된 클래스
반환타입으로 사용되는 인터페이스
Page : 추가 count 쿼리 결과를 포함하는 페이징 인터페이스 (Slice 인터페이스를 상속받는다)
Slice : 추가 count 쿼리 없이 다음 페이지 여부만 확인 가능한 페이징 인터페이스 (limit + 1 조회)
해당 인터페이스들의 구현체는 Spring Data Jpa에서 타입에맞게 반환해주며, PageImpl, SliceImpl 등이 있다.
Page와 Slice 인터페이스는 map 메서드를 지원하여 엔티티를 DTO로 편하게 변환할 수 있다.
Page 및 Slice 인터페이스
public interface Page<T> extends Slice<T> {
int getTotalPages(); //전체 페이지 수
long getTotalElements(); //전체 데이터 수
<U> Page<U> map(Function<? super T, ? extends U> converter); //변환기
}
public interface Slice<T> extends Streamable<T> {
int getNumber();
int getSize();
int getNumberOfElements();
List<T> getContent();
boolean hasContent();
Sort getSort();
boolean isFirst();
boolean isLast();
boolean hasNext();
boolean hasPrevious();
Pageable getPageable(); // 현재 페이지 객체
Pageable nextPageable(); // 다음 페이지 객체
Pageable previousPageable(); // 이전 페이지 객체
<U> Slice<U> map(Function<? super T, ? extends U> converter); // 변환기
}
페이징 및 정렬 구현코드
@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
Page<Member> findPagebyAge (int age, Pageable pageable);
Slice<Member> findSlicebyAge (int age, Pageable pageable);
List<Member> findListWithPageablebyAge (int age, Pageable pageable);
List<Member> findListWithSortbyAge (int age, Sort sort);
// @Query를 사용하면 countQuery를 분리하여 사용할 수 있다.(속도개선)
@Query(value = "select m from Member m",
countQuery = "select count(m.username) from Member m")
Page<Member> findPageByAge(Pageable pageable);
}
@Service
public class MemberService {
public Page<Member> findByAge{
Sort sort = Sort.by(Sort.Direction.DESC, "username");
// PageRequest.of(Page, Size, Sort);
PageRequest pageRequest = PageRequest.of(0, 10, sort);
Page<Member> page = memberRepository.findByAge(10, pageRequest);
return page;
}
// 페이지를 유지하면서 엔티티를 Dto로 변환하기
public Page<MemberDto> findDtoByAge{
Sort sort = Sort.by(Sort.Direction.DESC, "username");
// PageRequest.of(Page, Size, Sort);
PageRequest pageRequest = PageRequest.of(0, 10, sort);
Page<Member> page = memberRepository.findByAge(10, pageRequest);
// page객체의 map 메서드를 통해 편하게 변환가능
Page<MemberDto> dtoPage = page.map(m -> new MemberDto());
return dtoPage;
}
}