본문 바로가기
웹개발/SpringBoot

페이징 기능 적용하기

by 철없는민물장어 2023. 7. 26.
728x90

예전에 혼자 만들던 프로젝트에 페이징기능과 검색기능을 추가해보기로 했다.

(1로 표시해놓은 페이지 전환버튼까지 적용함. 2번은 게시물 검색기능인데 이건 다음 글에서...) 


페이징

1. Repository

public interface ArticleRepository extends JpaRepository<Article,Long> {
	...
    Page<Article> findAll(Pageable pageable);

}

JpaRepository를 상속받는 레파지토리 인터페이스에서, 메소드 파라미터로 Pageable을 넣으면 Page<T>로 엔티티를 반환받을 수 있다.

 

Pageable은 SpringDataJPA에서 제공하는 인터페이스로, 페이지 번호, 페이지 크기, 정렬 기준 등의 정보를 가지고 있다.

 

Page는 SpringDataJPA에서 제공하는 인터페이스로, 조회 결과를 페이지 단위로 관리하는데 사용된다.

더보기

예를 들어 Page<Article>은...

Page<Article>
{
	List<Article> content; //현재 페이지에 속하는 Article엔티티 객체들 리스트
    int number; //현재 페이지 번호
    int numberOfElements; //현재 페이지에 속하는 Article객체의 수
    int size; //한 페이지당 데이터 수
    int totalPages; //전체 페이지 수
    long totalElements; //전체 Article엔티티 객체의 개수
    Pageable pageable; //페이징 정보를 담고있는 Pageable객체
    Sort sort; //데이터 정렬 기준
}

이러한 정보를 담고있다고 생각하면 된다.(위 코드는... 그냥 보기좋게 정리한것 뿐임)

getContent(), getNumber()..등의 메소드부터, hasNext(), hasPrevois(), ...등의 메소드들이 많이 있다.

 

나는 모든 게시물을 조회해서 Page객체로 받을것이기 때문에, findAll메소드를 사용했다.

 

2. Controller

    @GetMapping("/forum")
    public String forum(Model model,@PageableDefault(sort = "id", size=2,direction = Sort.Direction.DESC)
    Pageable pageable){

        Page<ArticleDto> articlePage = articleService.getAllArticlesWithPaging(pageable);

        model.addAttribute("articlePage",articlePage);
        model.addAttribute("hasPrev",articlePage.hasPrevious());
        model.addAttribute("hasNext",articlePage.hasNext());
        model.addAttribute("previous",articlePage.previousOrFirstPageable().getPageNumber());
        model.addAttribute("next",articlePage.nextOrLastPageable().getPageNumber());

        return "articles/list";
    }

컨트롤러에서 페이징을 사용할 메소드에 파라미터로 Pageable을 추가한다.

클라이언트가 페이지 번호, 페이지 크기, 정렬 기준을 쿼리 파라미터로 전달하면 Spring Framework가 이를 Pageable 객체로 변환해준다.

 

이렇게 파라미터로 받은 Pageable을 서비스단으로 넘겨서 Page<ArticleDto>를 반환받는다.

그리고, 뷰로 데이터를 전달하기 위해 model.addAttribute로 page정보, 다음/이전 페이지 존재여부, 다음/이전 페이지 숫자를 전달했다.

 

3. Service

    public Page<ArticleDto> getAllArticlesWithPaging(Pageable pageable){
        return articleRepository.findAll(pageable).map(ArticleDto::createArticleDto);
    }

서비스에서는 파라미터로 받은 Pageable을 이용해 레파지토리의 findAll을 호출한다.

(맨 처음 레파지토리에 작성했던 findAll메소드)

그리고, 받은 Page<Article>을 map 메소드를 이용하여 ArticleDto로 변환하여 리턴한다.

 

4. View

<h2>게시물 목록</h2>
{{#articlePage.content}}
    <div class="card mt-3">
        <div class="card-body">
            <h5 class="card-title"><a href="/forum/{{id}}">{{title}}</a></h5>
            <h6 class="card-subtitle mb-2 text-muted">{{nickname}}/{{createdAt}}</h6>
        </div>
    </div>
{{/articlePage.content}}
<a href="/forum/new" class="btn btn-outline-primary mt-3">create article</a>
<!-- 현재 페이지 번호 출력 -->
<p>Current Page: {{articlePage.number}}</p>

<!-- 총 페이지 수 출력 -->
<p>Total Pages: {{articlePage.totalPages}}</p>

<!-- 총 엔티티 수 출력 -->
<p>Total Elements: {{articlePage.totalElements}}</p>


<div class="pagination justify-content-center">
    {{#hasPrev}}
        <a href="?page={{previous}}" role="button" class="btn btn-lg btn-danger bi bi-caret-left-square-fill"><</a>
    {{/hasPrev}}
    {{^hasPrev}}
        <a href="?page={{previous}}" role="button" class="btn btn-lg btn-danger bi bi-caret-left-square-fill disabled"><</a>
    {{/hasPrev}}

    {{#hasNext}}
        <a href="?page={{next}}" role="button" class="btn btn-lg btn-primary bi bi-caret-right-square-fill">></a>
    {{/hasNext}}
    {{^hasNext}}
        <a href="?page={{next}}" role="button" class="btn btn-primary btn-lg bi bi-caret-right-square-fill disabled">></a>
    {{/hasNext}}
</div>

mustache 템플릿엔진을 사용.

Controller에서 전달받은 데이터를 알맞게 출력한다.

 

728x90

댓글