데이터가 많아지면 모든 데이터가 한 페이지에 보여지는 문제가 있다.
이러한 이유로 페이징은 반드시 필요하다.
테스트를 위해 대량의 테스트 데이터를 만든다.
@SpringBootTest
public class SbbApplicationTest {
@Autowired
private QuestionService questionService;
@Test
void testJpa() {
for (int i = 1; i < = 300; i++) {
String subject = String.format("테스트 데이터입니다:[%03d]", i);
String content = "내용무";
this.questionService.create(subject, content);
}
}
}
Jpa 관련 라이브러리에 페이징을 위한 패키지들이 들어있다.
public interface QuestionRepository extends
(... 생략 ...)
Page<Question> findAll(Pageable pageable);
}
✅ Pageable 객체를 입력받아 Page<Question> 타입 객체를 리턴하는 findAll 메서드를 생성했다.
public Page<Question> getList(int page) {
Pageable pageable = PageRequest.of(page, 10);
return questionRepository.findAll(pageable);
}
✅ getList 메서드를 페이지 번호를 입력받아서 해당 페이지의 질문 목록을 리턴하는 메서드로 변경했다.
Pageable
PageRequest.of(page, 10)
page
: 조회할 페이지 번호10
: 한 페이지에 보여줄 게시물의 갯수 @GetMapping("/list")
public String list(Model model, @RequestParam(value="page", defaultValue = "0") int page) {
Page<Question> paging = questionService.getList(page);
model.addAttribute("paging", paging);
return "question_list";
}
✅ http://localhost:8080/question/list?page=0
처럼 GET 방식으로 요청된 URL에서 page 값을 가져오기 위해 @RequestParam
을 매개변수에 추가했다.
✅ page가 전달되지 않으면 defaultValue 값인 0으로 설정된다.
✅ 모델에 paging
이라는 Page<Question>
객체를 담아서 view로 전달한다.
항목 | 설명 |
---|---|
isEmpty | 페이지 존재 여부 (게시물이 있으면 false, 없으면 true) |
totalElements | 전체 게시물 개수 |
totalPages | 전체 페이지 개수 |
size | 페이지당 보여줄 게시물 개수 |
number | 현재 페이지 번호 |
hasPrevious | 이전 페이지 존재 여부 |
hasNext | 다음 페이지 존재 여부 |
http://localhost:8080/question/list?page=0
실행 결과이제 다음과 같이 한 페이지에 10개의 게시물을 볼 수 있다.
지금은 queryString으로 직접 페이지 번호를 전송해야 페이지를 이동할 수 있다.
이전, 다음 과 같은 버튼을 눌러서 페이지를 이동할 수 있도록 만들어보자.
<!-- 페이징처리 시작 -->
<div th:if="${!paging.isEmpty()}">
<ul class="pagination justify-content-center">
<li class="page-item" th:classappend="${!paging.hasPrevious} ? 'disabled'">
<a class="page-link"
th:href="@{|?page=${paging.number-1}|}">
<span>이전</span>
</a>
</li>
<li th:each="page: ${#numbers.sequence(0, paging.totalPages-1)}"
th:classappend="${page == paging.number} ? 'active'"
class="page-item">
<a th:text="${page}" class="page-link" th:href="@{|?page=${page}|}"></a>
</li>
<li class="page-item" th:classappend="${!paging.hasNext} ? 'disabled'">
<a class="page-link" th:href="@{|?page=${paging.number+1}|}">
<span>다음</span>
</a>
</li>
</ul>
</div>
<!-- 페이징처리 끝 -->
th:classappend="${!paging.hasPrevious} ? 'disabled'"
th:classappend="${!paging.hasNext} ? 'disabled'"
th:href="@{|?page=${paging.number-1}|}"
th:href="@{|?page=${paging.number+1}|}"
th:each="page: ${#numbers.sequence(0,paging.totalPages-1)}"
#numbers.sequence(start, end)
th:classappend="${page == paging.number} ? 'active'"
th:if="${page >= paging.number-5 and page <= paging.number+5}"
http://localhost:8080/question/list?page=0
실행 결과페이징 처리가 잘 되었고 현재 페이지인 8번 페이지가 활성화되어 보인다.
현재 질문 리스트는 등록한 순서로 데이터가 표시된다.
최근에 작성한 게시물이 먼저 보이도록 수정하자.
public Page<Question> getList(int page) {
List<Sort.Order> sorts = new ArrayList<>();
sorts.add(Sort.Order.desc("createDate"));
Pageable pageable = PageRequest.of(page, 10, Sort.by(sorts));
return questionRepository.findAll(pageable);
}
List<Sort.Order> sorts = new ArrayList<>();
Sort.Order.desc("createData")
Sort.Order
객체를 이용하여 createDate 필드를 기준으로 내림차순 정렬을 수행하도록 설정Sort.by(sorts)
PageRequest.of()
메서드의 세번째 파라미터로 정렬 정보를 나타낸다.