페이징처리하기
이번 글은 정말 많은 시간을 투자한 페이징처리이다. 구현하는 방법을 모르겠어서 구글링을 통해 참고하여 작성하였다.
먼저 페이징처리를 위한 DTO가 필요하다.
public class PageDTO {
private Long page; //현재페이지
private Long postPerPage; //한페이지에 글이 몇개인지
private Long totalPage; //페이지 전체수
private Long startRow; //페이지 첫글
private Long lastRow; //페이지 마지막글
private Long nowPageNumber; //현재 페이지블럭
private Long pageNumber; //전체 페이지블럭
private Long startPageNumber; //시작 페이지블럭
private Long lastPageNumber; //마지막 페이지블럭
private boolean previous; //이전버튼
private boolean next; //다음버튼
//현재페이지, 한 페이지에 몇 개의 게시물, 하나의 블럭에 몇 개의 페이지
public PageDTO(){
this.page = 1L;
this.postPerPage = 8L;
this.pageNumber = 5L;
}
public Long getPage(){
if(this.page == null){
this.page = 1L;
}else if(this.page < 1){
this.page = 1L;
}
return page;
}
public Long getPostPerPage(){
if(this.postPerPage == null){
this.postPerPage = 8L;
}
return postPerPage;
}
//각 페이지별 첫번째 글과 마지막 글
public void setRow(){
this.startRow = (this.getPage()-1)*this.getPostPerPage()+1;
this.lastRow = this.getPage()*this.getPostPerPage();
}
//전체 페이지 수와 전체 블럭 수
public void setNum(Long totalCount){
this.totalPage = (totalCount + this.getPostPerPage() - 1) /this.getPostPerPage();
Long curBlock = (this.getPage() - 1) / this.getPageNumber() + 1;
//블럭의 시작과 끝
this.startPageNumber = (curBlock-1)*this.getPageNumber() + 1;
this.lastPageNumber = Math.min(curBlock * this.getPageNumber(), totalPage);
//현재 페이지가 2이상이면 이전 버튼 활성화
this.previous = page > 1;
this.next = page < totalPage ;
}
}
DTO를 통하여 한 페이지에 얼마나 많은 글이 들어갈지, 하나의 블럭에 몇 개의 페이지를 넣을지를 설정해야한다.
가장 먼저 초기값을 설정해줘야 한다. 첫 페이지는 1, 한페이지에 8개의 글이 들어가고, 한블럭에는 5개의 페이지가 들어가도록 한다.
이 초기값은 자신이 원하는 값을 설정해주면 된다.
public PageDTO(){
this.page = 1L;
this.postPerPage = 8L;
this.pageNumber = 5L;
}
그 후에는 각 페이지의 첫번째글과 마지막 글이 무엇인지 설정해줘야한다.
예를 들어, 아래와 같이 표현하여면 내가 구상한 페이지별 글의 개수에 따른 수학적인 계산이 필요하다.
//page startRow lastRow
//1 1 8
//2 9 16
//3 17 24
public void setRow(){
this.startRow = (this.getPage()-1)*this.getPostPerPage()+1;
this.lastRow = this.getPage()*this.getPostPerPage();
}
이후에 전체 글을 불러오고, 이에 따라서 페이지는 몇개가 나오는지, 블럭을 몇개가 나오는지 설정한다.
마찬가지로 수학적인 계산이 필요하다.
마지막으로 이전버튼과 다음버튼을 어떨 때 활성화시킬지 설정한다.
public void setNum(Long totalCount){
this.totalPage = (totalCount + this.getPostPerPage() - 1) /this.getPostPerPage();
Long curBlock = (this.getPage() - 1) / this.getPageNumber() + 1;
//블럭의 시작과 끝
//block startPageNumber lastPageNumber
//1 1 5
//2 6 10
//3 11 15
this.startPageNumber = (curBlock-1)*this.getPageNumber() + 1;
this.lastPageNumber = Math.min(curBlock * this.getPageNumber(), totalPage);
//현재 페이지가 2이상이면 이전 버튼 활성화
this.previous = page > 1;
this.next = page < totalPage ;
}
이렇게 DTO설정을 마무리하면, Controller를 설정해준다.
아래의 코드에는 사용자의 정보를 불러오는 코드도 있기 때문에 살짝 복잡해 보인다.
@GetMapping("/post/allPost")
public String allPost(Model model, @RequestParam(value = "page", defaultValue = "1") int page) {
PageDTO pageDTO = new PageDTO();
pageDTO.setPage((long) page);
List<PostEntity> postList = postService.getList(pageDTO);
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
//authentication을 통해 정보 가져오기
Object principal = authentication.getPrincipal();
if (principal instanceof CustomUserDetails) {
CustomUserDetails userDetails = (CustomUserDetails) principal;
model.addAttribute("username", userDetails.getName());
model.addAttribute("postList", postList);
model.addAttribute("pageDTO", pageDTO);
}
return "/post/allPost";
}
패이징 처리와 관련된 부분만 추출해보면, 아래와 같다. 코드를 살짝 분석해보자면, 가장 핵심은 pageDTO와 postList를 불러와서 모델에 담는 것이다.
또한, @RequestParam을 이용하여 page파라미터 값을 받아와 pageDTO의 page로 설정한다.
받아오는 값이 없다면 1(첫페이지)로 설정한다.
@GetMapping("/post/allPost")
public String allPost(Model model, @RequestParam(value = "page", defaultValue = "1") int page) {
PageDTO pageDTO = new PageDTO();
pageDTO.setPage((long) page);
List<PostEntity> postList = postService.getList(pageDTO);
model.addAttribute("postList", postList);
model.addAttribute("pageDTO", pageDTO);
}
return "/post/allPost";
}
Controller작성이 끝났으면 이제 Service를 작성해준다. 여기서는 getList()메서드를 작성하면 된다.
가장 먼저, Repository를 통하여 글의 전체 개수를 받아온다.
이후 setRow와 setNum(totalCount)를 이용하여 전체 페이지 수 등을 설정한다.
또한, PageRequest.of를 통하여 현재 페이지와 페이지에 보여질 글의 개수를 설정한다.
public List<PostEntity> getList(PageDTO pageDTO) {
Long totalCount = postRepository.count();
pageDTO.setRow();
pageDTO.setNum(totalCount);
Pageable pageable = PageRequest.of(pageDTO.getPage().intValue() - 1, pageDTO.getPostPerPage().intValue());
return postRepository.findAll(pageable).getContent();
}
이후에는 Repository를 살짝 수정한다. findAllByOrderByPostCreatedTimeDesc메서드를 통하여 글을 내림차순으로 정렬한다.
List<PostEntity> findAllByOrderByPostCreatedTimeDesc(Pageable pageable);
이제 마지막으로 html을 수정하면 끝이다.
<div>
<nav aria-label="Page navigation example">
<ul class="pagination">
<li class="page-item" value="${postDTO.previous}" id="previous">
<a class="page-link" th:href="@{/post/allPost(page=${pageDTO.page - 1})}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<li th:each="i:${#numbers.sequence(pageDTO.startPageNumber, pageDTO.lastPageNumber)}"
class="page-item"
th:classappend="${pageDTO.page==i}? 'active':''">
<a class="page-link" th:href="@{/post/allPost(page=${i})}" th:text="${i}">1</a>
</li>
<li class="page-item ${pager.next?'':'disabled'}" id="next">
<a class="page-link" th:href="@{/post/allPost(page=${pageDTO.page+1})}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>