게시판 기능을 사용하다보면, 리스트 하단에 아래 사진처럼 페이지 번호들이 나열되어있습니다. 뿐만 아니라 많은 양의 데이터를 조회할 때도 아래처럼 페이징 기능이 사용되죠. 페이징은 이처럼 한 번에 뱉는 데이터 양을 조절하며, 서버 부하를 막고 가독성을 높이기 위해 사용됩니다
페이징 처리를 위한 정보들을 담기 위해 사용하는 인터페이스입니다
페이지 번호, 크기, offset 등의 정보들을 취할 수 있습니다
pageable 인스턴스에 정보를 담기 위해 사용되는 클래스입니다
of
메소드를 사용해 해당 인스턴스를 생성할 수 있습니다
페이지 번호와 페이지 크기, 정렬 기준 등을 인자로 사용합니다
프로젝트를 진행하며 포트폴리오 전체 조회, 포트폴리오 검색, 아티스트 조회 등의 기능을 위해 페이징 처리를 구현했으며, 아래의 예제는 페이징 처리에 초점을 맞추기 위해 포트폴리오 전체 조회 API 에 대한 코드를 사용했습니다
artistId를 받아 해당 아티스트의 포트폴리오를 조회하는 API입니다
@RequestParam
을 통해 page 번호를 받아 service에 넘겨줍니다
@Operation(summary = "포트폴리오 전체 조회", description = "포트폴리오 전체를 조회하는 API입니다.")
@GetMapping("/{artistId}")
public ApiResponse getPortfolio(@PathVariable Long artistId,
@RequestParam(value = "page", defaultValue = "0", required = false) int page
){
return ApiResponse.SuccessResponse(SuccessStatus.PORTFOLIO_GET, portfolioService.getPortfolio(artistId, page));
}
PageableDefault
를 사용해 정렬과 페이징 관련 인자들을 받는 방식도 존재하지만, 사용자에게 페이지 번호만 요청받기 위해 인자를 제한했습니다
⬇️ 아래 코드는 pageableDefault를 사용해 페이징 정보를 받는 예제입니다
page
: 페이지 번호, 기본값 0size
: 페이지 크기, 기본값 20sort
: 정렬 기준 @PageableDefault(size = 30, sort = "id", direction = Sort.Direction.ASC) Pageable page
편의를 위해 PortfolioRepository가 아닌 Artist의 PortfolioList를 사용해 조회 기능을 구현했습니다
isblock
field가 true면 반환 리스트에서 제거Page<>
로 변환Page
형태로 리턴 // 포트폴리오 전체 조회
public PortfolioPageDto getPortfolio(Long artistId, int page) {
//아티스트 조회
Artist artist = artistRepository.findById(artistId)
.orElseThrow(() -> new GlobalException(ErrorStatus.NOT_EXIST_ARTIST));
//아티스트의 포트폴리오 리스트 가져오기
List<Portfolio> portfolioList = artist.getPortfolioList();
//isblock이면 리스트에서 제거
portfolioList.removeIf(Portfolio::isBlock);
//list를 page로 변환
Page<Portfolio> portfolioPage = getPage(page, portfolioList);
//pagedto로 반환
return PortfolioPageDto.from(portfolioPage);
}
위의 코드에서 사용한 getPage
함수입니다
PageRequest.of
함수를 사용해 Pageable 인스턴스 생성Page<>
인스턴스 생성 private Page<Portfolio> getPage(int page, List<Portfolio> list){
//Pageable interface
Pageable pageable = PageRequest.of(page, 30);
int start = (int) pageable.getOffset();
int end = Math.min((start + pageable.getPageSize()), list.size());
//list를 page로 변환
return new PageImpl<>(list.subList(start, end),
pageable, list.size());
}
현재 사용하는 예제는 repository를 거치지 않고, list를 page 인스턴스로 가공해 반환하고 있습니다! 추가로, repository를 통해 page인스턴스를 바로 가져오는 기능은 ⬇️ 아래 포스팅을 참조해주세요 😁
https://velog.io/@dooo_it_ly/SprintBoot-JPA-검색-기능-Paging-기능-구현하기
내보낼 PageDto입니다
메인데이터, 현재 페이지 번호, 페이지 크기(30으로 지정) 등의 필드를 지정해 dto로 만들어줍니다
Builder
를 사용해 반환하였으며, 메인 데이터 리스트도 stream()
을 사용해 dto로 변환해서 사용해줍니다
아래 Page
클래스에 내장된 메소드들을 사용했습니다
getSize()
: 페이지 크기getNumber()
: 현재 페이지 번호getNumberOfElements()
: 전체 아이템 개수getTotalPages()
: 전체 페이지 개수@AllArgsConstructor
@NoArgsConstructor
@Builder
public class PortfolioPageDto {
private List<PortfolioDto> content;
private int currentPage; //현재 페이지 번호
private int pageSize; //페이지 크기
private int totalNumber; //전체 메이크업 개수
private int totalPage; //전체 페이지 개수
public static PortfolioPageDto from(Page<Portfolio> page){
//검색 결과가 없을 시
if(page.getContent().isEmpty())
throw new GlobalException(ErrorStatus.SEARCH_NOT_FOUNT);
List<PortfolioDto> content = page.stream()
.map(PortfolioDto::from)
.toList();
return PortfolioPageDto.builder()
.content(content)
.pageSize(page.getSize())
.currentPage(page.getNumber())
.totalNumber(page.getNumberOfElements())
.totalPage(page.getTotalPages())
.build();
}
}
고수신데용