Post

Paging

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.