Spring/Maven Project

Spring에 Pagination(페이지네이션) 처리 및 적용 1

carrotweb 2022. 12. 18. 01:00
728x90
반응형

이전 Paging(페이징) 처리로 Page(페이지) 단위로 게시판에서 게시물 리스트를 가져올 수 있게 되었습니다.

 

이번에는 나누어진 Page(페이지)를 번호로 표시하여 노출시키고 페이지 번호를 클릭하면 해당 페이지에 해당하는 게시물 리스트를 가져오게 처리하겠습니다.

 

 

Maven Spring Project의 main.jsp에 Pagination UI 추가하기

 

1. /src/main/webapp/WEB-INF/views/main/main.jsp 파일을 오픈합니다.

 

2. form에 현재 페이지 번호를 전달하기 위해 현재 페이지 번호(pageNo)를 hidden 태그로 추가합니다.

  1. <form:form> 태그 안에 <form:hidden> 태그를 생성하고 path 속성에 boardSearch 객체에서 paging 객체의 pageNo 변수를 지정합니다.
<form:hidden path="paging.pageNo" />

 

3. <table> 태그 뒤에 pagination UI를 추가합니다.

  1. 전달된 Model인 boardList에 데이터가 있을 때만 페이지네이션 UI가 노출되게 JSTL의 조건문인 <c:if> 태그로 처리합니다.
  2. 페이지네이션 영역을 <div> 태그로 생성하고 페이지네이션 UI는 <ul> 태그로 생성합니다.
  3. 페이지 번호를 표시하기 위해 boardSearch 객체에서 paging 객체의 페이지 마지막 번호(pageLastNo) 변수를 가져와서 JSTL의 반복문인 <c:forEach> 태그를 사용하여 <li> 태그로 페이지 번호(page)를 생성합니다. 그리고 페이지 번호(page)가 현재 페이지 번호(pageNo)와 같으면 <li> 태그의 class 속성 값에  "active"를 추가합니다.
  4. 페이지 번호를 클릭하면 이동하기 위해 <a> 태그로 생성하고 페이지 번호를 데이터 속성(data-pageno) 값에 추가합니다. <a> 태그의 클릭 이벤트를 공통 처리하기 위해 href 속성은 void로 처리합니다.
<c:if test="${not empty boardList}">
	<div>
		<ul id="boardPagination" class="pagination">
			<c:forEach var="page" begin="1" end="${boardSearch.page.pageLastNo}" step="1">
				<li class="page-item<c:if test="${boardSearch.page.pageNo == page}"> active</c:if>">
					<a class="page-link" data-pageno="${page}" href="javascript:void(0)">${page}</a>
				</li>
			</c:forEach>
		</ul>
	</div>
</c:if>

 

4. <style> 태그에 페이지네이션 영역에 대한 CSS를 추가합니다.

.board ul.pagination { display: flex; list-style: none; padding: 0; justify-content: center!important; flex-wrap: wrap; }
.board ul.pagination li.page-item a { display: block; padding: 0.5em 0.75em; border: 1px solid #dee2e6; margin-left: -1px; text-decoration: none; color: #333; }
.board ul.pagination li.page-item.active a  { color: #fff; background-color: #0d6efd; }

 

5. script를 추가합니다.

  1. 페이지네이션 영역에서 페이지 번호가 클릭되면 form의 현재 페이지 번호(pageNo)를 변경하고 form를 submit 하게 합니다.
$('#boardPagination .page-link').click(function(event) {
	event.preventDefault();
	event.stopPropagation();
	boardSearch.find('input:hidden[name="paging.pageNo"]').val($(this).attr("data-pageno"));
	boardSearch.submit();
});

 

 

Maven Spring Project를 실행하여 웹 브라우저로 확인하기

 

1. "Servers"탭에서 "Tomcat9"를 선택하고 "start"버튼(start the server)을 클릭하면 Tomcat이 실행됩니다.

 

2. 웹 브라우저에서 "http://localhost:9000/index.do"를 입력합니다. 게시판의 전체 게시물이 10개이고 페이지 크기가 10 이기 때문에 페이지네이션에 페이지 번호가 1개 나타납니다.

 

3. 페이지 크기를 10에서 5로 변경합니다. 그러면 페이지 크기가 5로 계산되어서 페이지네이션에 페이지 번호가 2개 나타납니다.

 

4. 페이지네이션에서 페이지 번호 2를 클릭하면 2번째 페이지에 해당되는 게시물 리스트를 가져옵니다.

 

정상적으로 페이지네이션이 처리되는 것을 확인할 수 있습니다. 그러나 게시물의 번호가 1번 페이지의 게시물 번호가 동일하게 나오는 문제점가 있습니다. 그래서 게시물의 번호와 검색 결과 없을 경우 메시지 표시되도록 수정하겠습니다.

 

 

 

 

Maven Spring Project의 main.jsp에 Pagination UI 수정하기

 

1. /src/main/webapp/WEB-INF/views/main/main.jsp 파일을 오픈하고 해당 페이지에 맞게 게시물의 번호가 부여되게 변경합니다.

  1. 현재는 전달된 Model인 boardList의 전체 데이터 수에서 JSTL의 반복문인 <c:forEach> 태그의 현재 순서(status.count)를 빼서 게시물의 번호를 부여하였습니다. (현재 순서(status.count)가 1부터 시작하기 때문에 1을 더해 줘야 합니다.)
  2. 그러다 보니 페이지가 이동되어도 게시물의 번호가 동일하게 나오는 문제점가 있습니다.
  3. 그래서 해당 페이지에 맞게 게시물의 번호가 계산되게 전체 레코드 수(recordTotalCount)에서 현재 페이지 번호(pageNo)와 페이지 레코드 수(recordCountPerPage)를 곱한 값을 빼고 현재 순서(status.count)를 빼서 게시물의 번호를 부여하게 계산합니다. (내림차순)
변경 전
<td>${fn:length(boardList) - status.count + 1}</td>

변경 후
<td>${boardSearch.paging.recordTotalCount - ((boardSearch.paging.pageNo - 1) * boardSearch.paging.recordCountPerPage) - status.count + 1}</td>

만약, 게시물의 번호를 오름차순으로 부여한다면 현재 페이지 번호(pageNo)와 페이지 레코드 수(recordCountPerPage)를 곱한 값에 현재 순서(status.count)를 더해주면 됩니다.

<td>${((boardSearch.paging.pageNo - 1) * boardSearch.paging.recordCountPerPage) + status.count}</td>

 

2. Model인 boardList의 데이터가 없을 때 태그에 메시지를 표시하기 위해서 태그로 처리합니다.

<c:choose>
	<c:when test="${empty boardList}">
		<tr><td colspan="4">검색된 게시물이 없습니다.</td></tr>
	</c:when>
	<c:otherwise>
		<c:forEach var="boardItem" items="${boardList}" varStatus="status">
			<tr>
				<td>${boardSearch.paging.recordTotalCount - ((boardSearch.paging.pageNo - 1) * boardSearch.paging.recordCountPerPage) - status.count + 1}</td>
				<td>${boardItem.subject}</td>
				<td>${boardItem.registrationId}</td>
				<td>${boardItem.registrationDateTime}</td>
			</tr>
		</c:forEach>
	</c:otherwise>
</c:choose>

 

전체 소스입니다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>게시판</title>
		<style>
			.board { width:800px; margin: 20px auto; }
			.board table { width:100%; border-top:2px solid #1d4281; border-spacing:0; }
			.board table thead th { padding:8px 10px 10px 10px; vertical-align:middle; color:#1d4281; font-size:14px; border-bottom:1px solid #ccc; background:#f8f8f8; }
			.board table tbody td { padding:7px 10px 9px 10px; text-align:center; vertical-align:middle; border-bottom:1px solid #ccc; font-size:14px; line-heighT:150%; }
			.board table tbody td:nth-child(2) { text-align:left;}
			.board form { margin-bottom: 10px; }
			.board form select { padding: 4px 4px; }
			.board form input[type="text"] { padding: 4px 4px; width: 200px; }
			.board form button { display: inline-flex; height: 27px; font-size: 14px; }
			.board form .search-result { display: flex; justify-content: space-between; margin-top: 10px; }
			.board ul.pagination { display: flex; list-style: none; padding: 0; justify-content: center!important; flex-wrap: wrap; }
			.board ul.pagination li.page-item a { display: block; padding: 0.5em 0.75em; border: 1px solid #dee2e6; margin-left: -1px; text-decoration: none; color: #333; }
			.board ul.pagination li.page-item.active a { color: #fff; background-color: #0d6efd; }
		</style>
	</head>
	<body>
		<div class="board">
			<form:form modelAttribute="boardSearch" autocomplete="off">
				<form:hidden path="paging.pageNo" />
				<div>
					<form:select path="searchType">
						<form:option value="subject" label="제목" />
						<form:option value="subjectandcontent" label="제목+내용" />
					</form:select>
					<form:select path="searchCondition">
						<form:option value="equal" label="일치" />
						<form:option value="like" label="포함" />
					</form:select>
					<form:input path="searchKeyword" placeholder="검색할 키워드를 입력하세요." />
					<button id="searchBtn" type="button">검색</button>
				</div>
				<div class="search-result">
					<div>
						검색 결과 : ${boardSearch.paging.recordTotalCount}건
					</div>
					<div>
						<form:select path="paging.recordCountPerPage">
							<form:option value="5" label="5" />
							<form:option value="10" label="10" />
							<form:option value="25" label="25" />
							<form:option value="50" label="50" />
							<form:option value="100" label="100" />
						</form:select>
					</div>
				</div>
			</form:form>
			<table>
				<colgroup>
					<col style="width:10%">
					<col style="width:*">
					<col style="width:15%">
					<col style="width:25%">
				</colgroup>
				<thead>
					<tr>
						<th scope="col">번호</th>
						<th scope="col">제목</th>
						<th scope="col">작성자</th>
						<th scope="col">작성일</th>
					</tr>
				</thead>
				<tbody>
					<c:choose>
						<c:when test="${empty boardList}">
							<tr><td colspan="4">검색된 게시물이 없습니다.</td></tr>
						</c:when>
						<c:otherwise>
							<c:forEach var="boardItem" items="${boardList}" varStatus="status">
							<tr class="board-item" data-sequence="${boardItem.sequence}">
								<td>${boardSearch.paging.recordTotalCount - ((boardSearch.paging.pageNo - 1) * boardSearch.paging.recordCountPerPage) - status.count + 1}</td>
								<td>${boardItem.subject}</td>
								<td>${boardItem.registrationId}</td>
								<td>${boardItem.registrationDateTime}</td>
							</tr>
							</c:forEach>
						</c:otherwise>
					</c:choose>
				</tbody>
			</table>
			<c:if test="${not empty boardList}">
				<div>
					<ul id="boardPagination" class="pagination">
						<c:forEach var="page" begin="1" end="${boardSearch.paging.pageLastNo}" step="1">
							<li class="page-item<c:if test="${boardSearch.paging.pageNo == page}"> active</c:if>">
								<a class="page-link" data-pageno="${page}" href="javascript:void(0)">${page}</a>
							</li>
						</c:forEach>
					</ul>
				</div>
			</c:if>
		</div>
		<script type="text/javascript">
			$(function() {
				var boardSearch = $('#boardSearch');
				$('#searchBtn').click(function() {
					$(this).attr("disabled", "disabled");
					boardSearch.submit();
				});
				$('#searchKeyword').keypress(function(event){
					if (13 == event.which) {
						$('#searchBtn').click();
						return false;
					}
				});
				$('select[name="paging.recordCountPerPage"]').change(function(event) {
					boardSearch.submit();
				});
				$('#boardPagination .page-link').click(function(event) {
					event.preventDefault();
					event.stopPropagation();
					boardSearch.find('input:hidden[name="paging.pageNo"]').val($(this).attr("data-pageno"));
					boardSearch.submit();
				});
			});
		</script>
	</body>
</html>

 

 

Maven Spring Project를 실행하여 웹 브라우저로 확인하기

 

1. "Servers"탭에서 "Tomcat9"를 선택하고 "start"버튼(start the server)을 클릭하면 Tomcat이 실행됩니다.

 

2. 웹 브라우저에서 "http://localhost:9000/index.do"를 입력하고 페이지 크기를 10에서 5로 변경합니다.

그러면 게시물의 번호가 페이지에 맞게 처리된 것을 확인할 수 있습니다.

 

3. 검색어에 게시물에 없는 제목인 "게시물"을 입력하여 검색하면 테이블에 메시지가 표시되는 것을 확인할 수 있습니다.

 

이어서 페이지네이션에서 노출되는 페이지 번호가 많으면 발생하는 문제점을 확인해 보고 페이지네이션 클래스를 생성하여 처리해 보도록 하겠습니다. 

728x90
반응형