3 분 소요

이번 글은 정말 많은 시간을 투자한 페이징처리이다. 구현하는 방법을 모르겠어서 구글링을 통해 참고하여 작성하였다.

먼저 페이징처리를 위한 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";
}

패이징 처리와 관련된 부분만 추출해보면, 아래와 같다. 코드를 살짝 분석해보자면, 가장 핵심은 pageDTOpostList를 불러와서 모델에 담는 것이다.

또한, @RequestParam을 이용하여 page파라미터 값을 받아와 pageDTOpage로 설정한다.

받아오는 값이 없다면 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를 통하여 글의 전체 개수를 받아온다.

이후 setRowsetNum(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">&laquo;</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">&raquo;</span>
        </a>
      </li>
    </ul>
  </nav>
</div>

카테고리:

업데이트: