Home Paging
Post
Cancel

Paging

Paging

기존 페이징을 작성할 때는 게시글 페이지만 적용했기 때문에 바로 Service 코드에 작성했다.

이후에는 Video, MyPage에도 페이징이 필요해서 이를 Dto에서 추상화 시켜 적용했다.



기존 코드

DTO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class PagingDto {
   private List<RegistryResponseDto> boardList;
   private int curPage;
   private boolean prev;
   private boolean next;
   private int startPage;
   private int endPage;
   private int totalPage;


   public static PagingDto of(List<RegistryResponseDto> registry, int totalPage, int curPage, int startPage, int endPage, boolean prev, boolean next){
      return PagingDto.builder()
            .boardList(registry)
            .totalPage(totalPage)
            .curPage(curPage)
            .startPage(startPage)
            .endPage(endPage)
            .prev(prev)
            .next(next)
            .build();
   }
}


Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public PagingDto getBoards(int curPage) {
    Pageable pageable = PageRequest.of(curPage - 1, PAGE_POST_COUNT);
    Page<Registry> boards = registryRepository.findAllByOrderByCreatedAtDesc(pageable);
    List<RegistryResponseDto> boardList = boards.stream()
            .map(board -> new RegistryResponseDto(board.getIdx(), board.getTitle()))
            .collect(Collectors.toList());
    int startPage = ((int)Math.floor((curPage-1) / (double)displayPageNum)) * displayPageNum + 1; // 시작 페이지 번호
    int endPage = Math.min(startPage + displayPageNum - 1, boards.getTotalPages()); // 끝 페이지 번호
    boolean prev = startPage != 1; // 이전 페이지 여부
    boolean next = endPage < boards.getTotalPages(); // 다음 페이지 여부
    return PagingDto.builder()
            .boardList(boardList)
            .curPage(curPage)
            .startPage(startPage)
            .endPage(endPage)
            .prev(prev)
            .next(next)
            .build();
}




구현

Dto

PagingDto 클래스는 제네릭 타입 T를 사용하여 일반화된 페이징 정보를 저장하는 클래스다.

1
2
3
@Getter
public class PagingDto<T> {
}

한 페이지 별로 보여지는 게시물 개수는 페이지 마다 다르므로 Service에서 적용하고

dto에서는 각 페이지를 몇 개씩 띄우는 공통적인 부분만 작성했다.

나는 모든 페이지가 총 5페이지씩 띄우는 것으로 구현했기 때문에

private static final int DISPLAY_PAGE_NUM = 5;로 작성했다.



페이징 하는 계산은 그대로 dto에 옮겨준다.

단, PagingDto 클래스에서 생성자를 private으로 설정하여 외부에서 직접 인스턴스를 생성하지 못하도록했다.

대신 of 메소드를 사용하여 생성자를 간접적으로 호출할 수 있게 작성했다.

→ 생성자의 접근을 제한하고, of 메소드를 통해 인스턴스를 생성하는 방식

1
2
3
4
5
6
7
8
9
private PagingDto(Pageable page, List<T> content, long total){
    this.content = content;
    this.curPage = page.getPageNumber()+1;
    this.totalPage = total;
    this.startPage = (int) ((curPage-1) / (double) DISPLAY_PAGE_NUM) * DISPLAY_PAGE_NUM + 1;
    this.endPage = (int) Math.min(startPage + DISPLAY_PAGE_NUM - 1, totalPage);
    this.prev = startPage != 1;
    this.next = endPage < totalPage;
}



of 메소드는 Registry, Video를 모두 받아야 하기 때문에

모든 클래스의 최상위 클래스인 Object를 사용했다.

1
2
3
4
5
6
public static <T> PagingDto<Object> of(Page<T> page, List<Registry> registryContent, List<VideoFile> videoContent, long total) {
    List<Object> content = new ArrayList<>();
    content.addAll(registryContent);
    content.addAll(videoContent);
    return new PagingDto<>(page.getPageable(), content, total);
}

public static 에서 는 제네릭 타입 매개변수를 나타낸다.

파라미터에 제네릭이 붙기 때문에 붙여준다.

메소드에서 제네릭을 쓸때는 타입 앞에다가 적어줘야 한다.



가장 어려웠던 건 어떻게 myPage에 registry와 video를 함께 페이징을 하는 것이었다.

같은 개수를 페이징하는 것이아니라 각각 4개, 8개씩 페이징 하는 것이라서

각각 다르게 게시물 개수를 보여주되 페이징을 할 때 같이 동작 해야한다.

페이지 수도 게시물 개수가 많은 게시물 대로 보여주는 것이 아니라

페이징 된 페이징 수를 기준으로 전체 페이지 수 중 더 큰 값을 갖고 가야했다.

Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override // mypage
public PagingDto<Object> myPage(int curPage, User user) {
    Pageable registryPageable = PageRequest.of(curPage - 1, MY_PAGE);
    Pageable videoPageable = PageRequest.of(curPage - 1, MY_PAGE*2);
    Page<Registry> registryPage = registryRepository.findByNickname(user.getNickname(), registryPageable);
    Page<VideoFile> videoPage = videoRepository.findByNickname(user.getNickname(), videoPageable);

    List<Registry> registryList = registryPage.getContent();
    List<VideoFile> videoList = videoPage.getContent();

    long total = Math.max(registryPage.getTotalPages(), videoPage.getTotalPages());

    if(registryPage.getTotalPages()>=videoPage.getTotalPages()){
        return PagingDto.of(registryPage, registryList, videoList, total);
    }else{
        return PagingDto.of(videoPage, registryList, videoList, total);
    }
}



최종 코드

Dto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Getter
public class PagingDto<T> {
    private static final int DISPLAY_PAGE_NUM = 5;
    private int curPage;
    private boolean prev;
    private boolean next;
    private int startPage;
    private int endPage;
    private long totalPage;
    private List<T> content;

    public PagingDto(Pageable page, List<T> content, long total){
        this.content = content;
        this.curPage = page.getPageNumber()+1;
        this.totalPage = total;
        this.startPage = (int) ((curPage-1) / (double) DISPLAY_PAGE_NUM) * DISPLAY_PAGE_NUM + 1;
        this.endPage = (int) Math.min(startPage + DISPLAY_PAGE_NUM - 1, totalPage);
        this.prev = startPage != 1;
        this.next = endPage < totalPage;
    }

    public static <T> PagingDto<T> of(Page<T> page) {
        return new PagingDto<>(page.getPageable(), page.getContent(), page.getTotalElements());
    }

    public static <T> PagingDto<T> of(Pageable page, List<T> content, long total) {
        return new PagingDto<>(page, content, total);
    }
}
  • Pageable 대신 Page 사용

  • Dto는 추상화만 하고 service에서 계산을 다 처리 하게 구현하는 것으로 수정했다.

  • Object를 쓰면 제네릭을 쓰는 이유가 없어진다. → t로 수정(PagingDto<T>)


Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Override // 작성 글 페이징
public PagingDto<Registry> getBoards(int curPage) {
    Pageable pageable = PageRequest.of(curPage - 1, PAGE_POST_COUNT);
    Page<Registry> boards = registryRepository.findAllByOrderByCreatedAtDesc(pageable);
    return PagingDto.of(boards);
}


@Override
public PagingDto<Object> myPage(int curPage, User user) {
    Pageable registryPageable = PageRequest.of(curPage - 1, MY_PAGE);
    Pageable videoPageable = PageRequest.of(curPage - 1, MY_PAGE*2);

    Page<Registry> registryPage = registryRepository.findByNickname(user.getNickname(), registryPageable);
    Page<VideoFile> videoPage = videoRepository.findByNickname(user.getNickname(), videoPageable);

    List<Registry> registryList = registryPage.getContent();
    List<VideoFile> videoList = videoPage.getContent();

    List<Object> mergeList = new ArrayList<>();
    mergeList.addAll(registryList);
    mergeList.addAll(videoList);

    long total = Math.max(registryPage.getTotalPages(), videoPage.getTotalPages());

    if(registryPage.getTotalPages()>=videoPage.getTotalPages()){
        return PagingDto.of(registryPageable, mergeList, total);
    }
    return PagingDto.of(videoPageable, mergeList, total);
}
This post is licensed under CC BY 4.0 by the author.