예전에 혼자 만들던 프로젝트에 페이징기능과 검색기능을 추가해보기로 했다.
(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에서 전달받은 데이터를 알맞게 출력한다.
'웹개발 > SpringBoot' 카테고리의 다른 글
네이버 검색 API를 이용하기 (0) | 2023.07.26 |
---|---|
검색 기능 적용하기 (0) | 2023.07.26 |
swagger 작성해보기, Springboot swagger 연동하기 (0) | 2023.07.05 |
MySQL 설치 및 Spring 연동 방법 (0) | 2023.06.09 |
로그인 여부에 따라 바뀌는 로그인/로그아웃 버튼 만들기 (0) | 2023.05.27 |
댓글