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);
}