Table of Contents
Add Paging
게시판에 페이징 기능을 추가합니다.
개발환경
- Spring Boot 2.1.x
- Gradle 4.10.2
프로젝트는 이전 글에서 작성된 프로젝트에 파일을 추가 또는 수정하는 방식으로 진행됩니다. 이전 글을 따라 하지 않은 경우, 먼저 이전 글대로 프로젝트를 구성하시기 바랍니다.
파일추가
JpaRepository
는 PagingAndSortingRepository
를 확장하고 있습니다.
클래스명에 있듯이 페이징과 정렬도 처리하는데 정렬기능은 사용하지 않겠습니다.
src/main/java/kr/co/episode/example/domain/posts/PostsPagingRepository.java
package kr.co.episode.example.domain.posts;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.JpaRepository;
public interface PostsPagingRepository extends JpaRepository<Posts, Long> {
@Query(value = "SELECT p FROM Posts p ORDER BY p.id DESC")
Page<Posts> findAllDesc(Pageable pageable);
}
src/main/java/kr/co/episode/example/service/posts/PostsPagingService.java
package kr.co.episode.example.service.posts;
import kr.co.episode.example.domain.posts.Posts;
import kr.co.episode.example.domain.posts.PostsPagingRepository;
import kr.co.episode.example.web.dto.PostsListResponseDto;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.stream.Collectors;
@RequiredArgsConstructor
@Service
public class PostsPagingService {
private final PostsPagingRepository postsPagingRepository;
@Transactional(readOnly = true)
public Page<PostsListResponseDto> findAllDesc(Pageable pageable) {
Page<Posts> posts = postsPagingRepository.findAllDesc(pageable);
List<PostsListResponseDto> results = posts.getContent().stream()
.map(PostsListResponseDto::new)
.collect(Collectors.toList());
long totalCount = posts.getTotalElements();
return new PageImpl<>(results, pageable, totalCount);
}
}
파일수정
src/main/java/kr/co/episode/example/web/IndexController.java
// ......
private final PostsPagingService postsPagingService;
@GetMapping("/")
public String index(Model model, @PageableDefault Pageable pageable) {
//model.addAttribute("posts", postsService.findAllDesc());
// 페이지당 표시 게시글 수를 3개로 제한
pageable = PageRequest.of(pageable.getPageNumber(), 3);
model.addAttribute("posts", postsPagingService.findAllDesc(pageable));
return "index";
}
// ......
src/main/resources/templates/index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>게시판</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<style>
.container p { display: inline }
</style>
</head>
<body class="container">
<h1>스프링 부트 게시판</h1>
<div class="col-md-12">
<div class="row">
<div class="col-md-6">
<a href="/posts/save" role="button" class="btn" btn-primary>글 등록</a>
</div>
</div>
</div>
<div style="height: 80px;">
</div>
<table class="table">
<tr>
<th>글 번호</th>
<th>글쓴이</th>
<th>글 제목</th>
<th>최종수정</th>
</tr>
<tr th:each="posts: ${posts}">
<td th:text="${posts.id}"></td>
<td>
<a th:href="${posts.link}" th:text="${posts.author}" />
</td>
<td>
<a th:href="${posts.link}" th:text="${posts.title}" />
</td>
<td th:text="${posts.modifiedDate}"></td>
</tr>
</table>
<nav style="text-align: center;">
<ul class="pagination"
th:with="start=${T(Math).floor(posts.number/10)*10},
last=(${start + 9 < posts.totalPages-1 ? start + 9 : posts.totalPages-1})">
<li>
<a th:href="@{/(page=0)}" aria-label="First">
<span aria-hidden="true">First</span>
</a>
</li>
<li th:class="${posts.first} ? 'disabled'">
<a th:href="${posts.first} ? '#' :@{/(page=${posts.number-1})}" aria-label="Previous">
<span aria-hidden="true"><</span>
</a>
</li>
<li th:each="page: ${#numbers.sequence(start, last)}" th:class="${page == posts.number} ? 'active'">
<a th:text="${page+1}" th:href="@{/(page=${page})}"></a>
</li>
<li th:class="${posts.last} ? 'disabled'">
<a th:href="${posts.last} ? '#' : @{/(page=${posts.number+1})}" aria-label="Next">
<span aria-hidden="true">></span>
</a>
</li>
<li>
<a th:href="@{/(page=${posts.totalPages-1})}" aria-label="Last">
<span aria-hidden="true">Last</span>
</a>
</li>
</ul>
</nav>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="/js/app/index.js"></script>
</body>
</html>