본문 바로가기
프로그래밍/Springboot-토이프로젝트

【게시판-07】페이징 처리

by 코이킹 2022. 9. 16.
반응형

안녕하세요 코이킹입니다.
이번 포스트는 페이징 처리 기능 구현에 대한 내용이 되겠습니다. 

 


1. 목표 

  - 스프링 부트를 사용해서 DB의 데이터를 웹에 표시할 때 페이징 처리를 할 수 있다.

 

2. 페이징 처리란?

하나의 페이지에 표시해야 할 데이터가 너무 많을 경우, 데이터를 나누어 표시하는 것이 페이징 처리입니다. 

페이징 처리를 구현하기 위해선 다음과 같은 값들을 가지고 다양한 처리를 해주어야 할 필요가 있습니다.  

 - 전체 데이터의 수  

 - 하나의 페이지에 표시할 데이터의 수

 - 전체 페이지의 수 

 - 현재의 페이지 번호 

 - 하나의 페이지에 표시할 데이터는 몇 번부터 몇 번까지 인지 계산하기

 

따라서 페이징 처리를 직접 구현하려하면 상당히 어렵습니다만, 스프링 부트가 제공하는 기능을 활용하면 페이징 처리를 쉽게 구현할 수 있습니다. 

 

3. 페이징 처리 구현 소스코드와 해석 

1) 글목록 템플릿 : /template-springboot/src/main/resources/templates/board/list.html 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, inital-scale=1.0"/>
</head>
<body>

	<div>
		<div class="nav justify-content-end px-5 pt-2">
	        <button class="btn btn-info text-white" id="write-board" type="button" onclick="location.href='/board/write'">
	        Contents Write
	        </button>
	    </div>
	    <hr/>
	    <div>
		    <table class="table" border="1">
		    <thead class="table-dark">
		    <tr>
		        <th>No</th>
		        <th>Contents Type</th>
		        <th>Title</th>
		        <th>CreatedTime</th>
		        <th>UpdatedTime</th>
		        <th>Likes</th>
		    </tr>
		    </thead>
		    <tbody>
		    <tr th:each="board: ${pageInfo.getContent()}">
		        <td th:text="${board.boardNo}"></td>
		        <td th:text="${board.type}==1 ? 'Normal' : 'MemberShip'"></td>
		        <td><a th:href="@{/board/read/{boardNo}(boardNo=${board.boardNo})}">[[${board.title}]]</a></td>
		        <td th:text="${board.createdTime}"></td>
		        <td th:text="${board.updatedTime}"></td>
		        <td th:text="${board.likes}"></td>
		    </tr>
		    </tbody>
		    </table>
	    </div>

	    <hr/>

	    <!-- paging -->
	    <div id="paging-container" class="pagination nav justify-content-center px-4">
	            <div th:class="${pageInfo.first} ? 'page-item disabled' : 'page-item'">
	                <span class="page-link" th:if="${pageInfo.first}">Prev</span>
	                <a class="page-link" th:if="${not pageInfo.first}" th:href="@{/board/list(page=1)}">Prev</a>
	            </div>
	            <div th:class="${p} != ${pageInfo.number+1} ? 'page-item' : 'page-item disabled'" th:each="p : ${#numbers.sequence(1, (pageInfo.totalPages))}">
	                <span class="page-link" th:if="${p} == ${pageInfo.number+1}" th:text="'['+${p}+']&nbsp;'"></span>
	                <a class="page-link" th:if="${p} != ${pageInfo.number+1}" th:href="@{/board/list(page=${p})}">
	                    <span th:text="'['+${p}+']'"></span>
	                </a>
	            </div>
	            <div th:class="${pageInfo.last} ? 'page-item disabled' : 'page-item' ">
	                <span class="page-link"  th:if="${pageInfo.last}">Next</span>
	                <a class="page-link" th:if="${not pageInfo.last}" th:href="@{/board/list(page=(${pageInfo.totalPages}))}">Next</a>
	            </div>
	    </div>
	</div>

</body>
</html>

- 45~48행 : 다음 페이지 버튼을 조건부로 활성화한다. 

- 49~54행 : 페이지 번호를 표시한다. 현재 페이지의 번호의 경우 링크를 비활성화한다. 

- 55~58행 : 다음 페이지 버튼을 조건부로 활성화 한다. 

 

2) 컨트롤러 : 

package com.sb.template.controller;

import java.util.List;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.sb.template.entity.Board;
import com.sb.template.enums.BoardType;
import com.sb.template.exception.InvalidParamException;
import com.sb.template.exception.ProcFailureException;
import com.sb.template.forms.BoardForm;
import com.sb.template.service.BoardService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping(path = "/board")
public class BoardController {

	@Autowired
	private BoardService boardService;

	@RequestMapping(method = RequestMethod.GET, value = {"list", "/", ""})
	public String viewBoardList(Pageable pageable, Model model) {

		Page<Board> pageInfo = boardService.getAllBoard(pageable);
		model.addAttribute("pageInfo", pageInfo);

		return "board/list";
	}
    ...
    ...
    ...

}

- 41행 : Pageable을 변수로 매개변수로 추가한다. 요청 파라미터로 page(페이지 번호), size(한 페이지에 보여줄 데이터 수)를 보내면 알아서 Pageable에 매핑된다. 

- 43~44행 : 게시글 데이터의 리스트가 아닌 Page객체를 리턴 받도록 수정.

 

3) 서비스 :  /template-springboot/src/main/java/com/sb/template/service/BoardService.java

package com.sb.template.service;

import java.util.NoSuchElementException;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;

import com.sb.template.annotation.Timer;
import com.sb.template.entity.Board;
import com.sb.template.enums.BoardType;
import com.sb.template.repo.BoardRepository;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class BoardService {

	@Autowired
	private BoardRepository boardRepository;

	@Timer
	public Page<Board> getAllBoard(Pageable pageable) {
		int page = (pageable.getPageNumber() == 0) ? 0 : (pageable.getPageNumber() - 1);
		pageable = PageRequest.of(page, pageable.getPageSize());

		Page<Board> res = boardRepository.findAll(pageable);
		if (res == null) return null;

		log.debug("Data from DB : {}", res);

		return res;
	}

    ...
    ...
    ...
}

- 29~30 행 : Pageable을 매개변수로 리포지토리의 findAll메서드를 호출하면, 페이징 된 데이터를 DB로부터 받아올 수 있다. 

4. 동작확인 

5. 전체 소스코드 

https://github.com/leeyoungseung/template-springboot/tree/feature/07_paging

 

GitHub - leeyoungseung/template-springboot

Contribute to leeyoungseung/template-springboot development by creating an account on GitHub.

github.com

 


이것으로 페이징 처리 구현에 대한 포스트는 마치겠습니다. 

다음 포스트는 레이아웃 합치기와 부트스트랩(CSS) 적용에 대한 내용이 되겠습니다. 

 

반응형

댓글