[8] 스프링 데이터 JPA를 사용해 게시글 페이징 처리
들어가며
이전 포스팅까지 삭제하기 기능을 구현해 봤습니다. 이번 포스팅에서는 스피링 데이터 JPA를 사용해 페이징 처리를 해보겠습니다.(JPA를 활용했기 때문에 동적 쿼리를 사용하지 않습니다.)
사전 준비
[SpringBoot] 무작정 (REST API)CRUD 게시판을 만들어 보자 게시글 삭제하기 구현 [7]
[7] 작성한 게시글 삭제하기 들어가며 이전 포스팅에서는 작성한 게시글을 수정하는 기능을 구현해봤습니다. 이번 포스팅에서는 작성한 게시글을 삭제하는 기능을 구현해볼것입니다. 사전 준비
back-stead.tistory.com
게시글 페이징 처리
페이징이란?
페이징은 대량의 데이터를 일정한 크기의 작은 덩어리로 나눠서 표시하는 기술이다.
게시판을 보면 대량의 게시글이 작성된다. 만약 게시글이 1000건이 있다고 해보자 그러면 1000건을 한 페이지에 보여주는 생각해 봐도 끔찍한 것이다. 그래서 페이징 처리를 통해 원하는 게시글의 건수 한 페이지에 보여주도록 할 것입니다.
Repository
BoardRepository
Page<Board> findByTitleContaining(String title,Pageable pageable);
findByTitleContaining는 Jpa에서 지원하는 메서드이다.
<SELECT b FROM Board b WHERE b.title LIKE %:title%?>
Board에 title이 포함된 쿼리를 대신 만들어서 실행해 준다.
만약 내용에 있는 것 까지검색하고 싶다면
findByTitleContainingaAndContentContaining 이렇게 작성해 주면 된다.
Service
BoardServiceImpl
@Override
public Page<Board> search(String title, Pageable pageable) {
return boardRepository.findByTitleContaining(title,pageable);
}
검색 로직 추가
Controller
BoardController
@GetMapping("/board")
public String board(
Model model,
@PageableDefault(size = 4) Pageable pageable,
@RequestParam(required = false, defaultValue = "") String title,
HttpSession session
) {
// 게시글 검색 및 페이징 처리
Page<Board> boards = boardService.search(title, pageable);
List<Board> boardAll = boards.getContent();
getSession(model, session);
int currentPage = boards.getPageable().getPageNumber() + 1;
int totalPages = boards.getTotalPages();
int visiblePages = 3;
int startPage = Math.max(1, currentPage - visiblePages / 2);
int endPage = Math.min(totalPages, startPage + visiblePages - 1);
if (boardAll != null) {
model.addAttribute("boardAll", boardAll);
}
model.addAttribute("startPage", startPage);
model.addAttribute("endPage", endPage);
model.addAttribute("page", boards);
return "board/board";
}
- @PageableDefault(size = 4) Pageable pageable: 페이징 처리를 위한 Pageable 객체를 매개변수로 받습니다. 기본적으로 한 페이지당 4개의 항목을 보여주도록 설정
- @RequestParam(required = false, defaultValue = "") String title: 검색할 게시글의 제목을 매개변수로 받습니다. 기본값은 빈 문자열로 설정
- Page :
- int totalPages = boards.getTotalPages() : 전체 페이지 수를 계산
- int visiblePages = 3 : 페이징 처리 시 보일 페이지 수를 설정.
- int startPage = Math.max(1, currentPage - visiblePages / 2) : 현재 페이지를 중심으로 앞으로 visiblePages/2 만큼의 범위를 표시하는데, 최솟값은 1입니다.
- int endPage = Math.min(totalPages, startPage + visiblePages - 1) : 시작 페이지부터 visiblePages 개수만큼의 범위를 표시하되, 전체 페이지 수를 초과하지 않도록 설정합니다.
이렇게 spring Data JPA를 활용해서 페이징 처리를 서버에서 설정했습니다. 이제는 뷰단을 설정해 보겠습니다.
HTML
Board.html
<div> 총 상품수 :
<span th:text="${page.totalElements}">19</span>
</div>
- totalElements : 페이지의 데이터의 전체 값
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-center">
<li class="page-item " th:classappend="${1 == page.pageable.pageNumber +1}?'disabled'">
<a class="page-link" href="#" th:href="@{/board(page=${page.pageable.pageNumber - 1})}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
<li class="page-item" th:classappend="${i == page.pageable.pageNumber+1}? 'disabled'" th:each="i : ${#numbers.sequence(startPage,endPage)}">
<a class="page-link" href="#" th:href="@{/board(page=${i} -1)}" th:text="${i}" >pageNumber</a>
</li>
<li class="page-item" th:classappend="${page.totalPages == page.pageable.pageNumber +1 } ? 'disabled'">
<a class="page-link" href="#" th:href="@{/board(page=${page.pageable.pageNumber+1})}">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
- th:classappend : Thymeleaf 템플릿 엔진에서 사용되는 속성으로, HTML 요소의 클래스(class) 속성에 동적으로 클래스를 추가할 때 사용. 이 속성은 기존 클래스에 새로운 클래스를 추가하는 데 사용된다
- JPA는 0부터 시작하기 때문에 +1 로 해줘야 시작 페이지를 1부터보여준다.
구현 테스트
(제목으로 "123", "aaa", "bbb", "ccc", "ddd" 존재)
사진 1에서 보는 것처럼 쿼리파리미터가 0이지만 시작 페이지가 1부터 시작되는 것을 볼 수 있다. 총 상품수도 실제 DB에 저장된 수를 표시해 준다.
aaa를 검색하면 제목에 aaa가 들어간 글만 출력한다.
다음으로
이번 포스팅에서는 간단한 페이징을 구현한 해봤습니다. 다음 포스팅에서는 게시판의 마지막 단계로 댓글 기능을 추가해보겠습니다. 먼저, 댓글 엔티티를 정의하고 게시글과의 연관관계를 설정합니다. 그리고 댓글 입력 폼을 만들어 기본적인 댓글 기능을 활성화시킬 것입니다. 감사합니다!