Pagination (페이징)
MySQL + MVC2
간혹 프로젝트가 서버에서 꼬이는수가 있다
서버에서 다른 프로젝트 를 제거하고,
현재 작동하는 프로젝트만 add 한뒤. clean 해보고 시작하길 추천
구현시 고려할 요소들
한 ‘페이지’당 몇개의 글목록을 나타낼 것인가
한 [페이징]당 몇개의 페이지를 표현할 것인가?
고려 해야 하는 것들
[페이징]을 구현하기 위해서는 아래 두가지가 구현되어야 한다
1. 한 ‘페이지’에 몇개의 ‘목록’을 표시 할 것인가? → 세팅값
2. 한 [페이징]에는 몇개의 ‘페이지’를 표시 할 것인가? → 세팅값
3. ‘페이지’ 리스트에 표시되어야 할 ‘목록’이 총 몇개인가?
→ SQL 함수 count(*) 사용
4. ‘몇번째(fromRow)’ 부터 ‘몇개(pageRows)’를 SELECT 할 것인가?
→ ROWNUM 사용 (*ORACLE 의 경우)
→ LIMIT 사용 (*MySQL 의 경우)
다량의 데이터 필요. 일단, 목록의 개수가 많아야함
아래 쿼리 실행할때마다 기존의 레코드들을 그대로 복사 생성(x2 씩 늘어남)
약 400개 이상 준비
list.do 돌려보면
n 번째 페이지 목록, 쿼리문은?
MySQL 은 limit 키워드 사용
-- 첫번째 페이지는? ★limit 는 0 부터 시작한다★ 처음부터 5개
SELECT * FROM t2_write ORDER BY uid desc limit 5;
-- 두번째 페이지는? 5부터 5개
SELECT * FROM t2_write ORDER BY uid desc limit 5, 5;
-- 세번째 페이지는? 10부터 5개
SELECT * FROM t2_write ORDER BY uid desc limit 10, 5;
* n 번째 페이지 목록, 쿼리문은?
pageRows : 한 페이지에 보여지는 글의 개수
page 번째 페이지의 글록록을 보여주는 쿼리문은?
SELECT * FROM t2_write ORDER BY uid desc
limit (page - 1) * pageRows, pageRows;
* 쿼리문 준비
D.java
// 글 전체 개수 가져오기
public static final String SQL_WRITE_COUNT_ALL =
"SELECT count(*) FROM t2_write";
// fromRow 로부터 row 만큼 SELECT 하기 : LIMIT 은 0 부터 시작함 주의!
public static final String SQL_WRITE_SELECT_PAGE =
SQL_WRITE_USER
+ "ORDER BY w.uid DESC\r\n"
+ "LIMIT ?, ?"
;
* DAO 에 추가
list.do 에 page parameter 추가 운영
페이징을 하려면 list.do 에 몇페이지를 보여줄지 에 대한 parameter 가 필요하다
list.do ← page parameter 없으면 기본 1 page
list.do?page=2
list.do?page=10
…
..
// 페이징 관련
// 몇번째(from) 부터 몇개(rows) 를 SELECT
public List<WriteDTO> selectFromRow(int from, int rows) throws SQLException {
List<WriteDTO> list = null;
try{
pstmt = conn.prepareStatement(D.SQL_WRITE_SELECT_PAGE);
pstmt.setInt(1, from);
pstmt.setInt(2, rows);
rs = pstmt.executeQuery();
list = buildList(rs);
}finally{
close();
} // end try
return list;
}
// 전체 글의 개수
public int countAll() throws SQLException {
int cnt = 0;
try{
pstmt = conn.prepareStatement(D.SQL_WRITE_COUNT_ALL);
rs = pstmt.executeQuery();
rs.next();
cnt = rs.getInt(1);
}finally{
close();
} // end try
return cnt;
} // end countAll()
* ListCommand 작성
package command.write;
import java.sql.SQLException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import command.Command;
import domain.WriteDAO;
import domain.WriteDTO;
public class ListCommand implements Command {
@Override
public void execute(HttpServletRequest request, HttpServletResponse response) {
int page = 1; // 현재 페이지 (디폴트는 1 page)
String pageParam = request.getParameter("page");
if(pageParam != null && !pageParam.trim().equals("")) {
try {
page = Integer.parseInt(pageParam);
} catch (NumberFormatException e) {
// 별도의 처리 안함
}
} // end if
// 페이징
// writePages: 한 [페이징] 당 몇개의 페이지가 표시되나
// pageRows: 한 '페이지'에 몇개의 글을 리스트 할것인가?
HttpSession session = request.getSession();
Integer writePages = (Integer)session.getAttribute("writePages");
if(writePages == null) writePages = 10; // session 에 없으면 기본값으로
Integer pageRows = (Integer)session.getAttribute("pageRows");
if(pageRows == null) pageRows = 10; // session 에 없으면 기본값으로
int cnt = 0; // 글 전체의 개수
int totalPage = 0; // 총 몇 '페이지' 분량인가?
List<WriteDTO> list = null;
try {
cnt = new WriteDAO().countAll(); // 글 전체의 개수
totalPage = (int)Math.ceil(cnt / (double)pageRows); // 총 페이지 수
// 현재 페이지 보정 (범위를 벗어난 경우)
if(page < 1) page = 1;
if(page > totalPage) page = totalPage;
// 쿼리 실행
int fromRow = (page - 1) * pageRows; // (MySQL)
list = new WriteDAO().selectFromRow(fromRow, pageRows);
// [페이징] 에 표시할 '시작페이지' 와 '마지막페이지' 계산
int startPage = ((int)((page - 1) / writePages) * writePages) + 1;
int endPage = startPage + writePages - 1;
if (endPage >= totalPage) endPage = totalPage;
request.setAttribute("cnt", cnt); // 전체 글 개수
request.setAttribute("writePages", writePages); // [페이징] 에 표시할 숫자 개수
request.setAttribute("pageRows", pageRows); // 한 '페이지' 에 표시할 글 개수
session.setAttribute("page", page); // 현재 페이지 (세션에 저장해두자)
request.setAttribute("startPage", startPage); // [페이징] 에 표시할 시작 페이지
request.setAttribute("endPage", endPage); // [페이징] 에 표시할 마지막 페이지
request.setAttribute("totalPage", totalPage); // 총 페이지 개수
request.setAttribute("url", request.getRequestURI()); // 목록 url
// "list" 란 name 으로 request 에 list 를 담아 컨트롤러에 전달
request.setAttribute("list", list);
} catch(SQLException e) {
e.printStackTrace();
// ※ 예외 처리 필요
// ex) 예외 페이지 설정, 혹은 예외 페이지로 redirect
}
}
}
pageRows 값 변화에 따른 페이징
list.jsp 상단에 select 수정
<form> 감싸기
select 값이 변화될때 submit 되기 → jQuery 동작
현재 page 값이
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%-- JSTL 버젼으로 바뀌니, import 의 번잡함도 사라진다! JAVA 변수 선언도 사라진다! --%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://kit.fontawesome.com/51772bd9bd.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="${pageContext.request.contextPath }/js/list.js"></script>
<title>목록</title>
</head>
<body>
<%-- 인증 헤더 --%>
<jsp:include page="/WEB-INF/views/common/header.jsp"/>
<div class="container mt-3">
<h2>목록</h2>
<hr>
<div class="mb-3 mt-3 clearfix">
<span class="float-start me-2">총 ${cnt }개</span>
<span class="float-start">page ${page }/${totalPage }</span>
<span class="float-end">
<form name="frmPageRows">
<input type="hidden" name="page" value="${page }">
<select class="form-select" name="pageRows">
<option value="10" ${pageRows == 10 ? 'selected' : '' }>10</option>
<option value="15" ${pageRows == 15 ? 'selected' : '' }>15</option>
<option value="20" ${pageRows == 20 ? 'selected' : '' }>20</option>
<option value="50" ${pageRows == 50 ? 'selected' : '' }>50</option>
</select>
</form>
</span>
</div>
<table class="table table-hover">
<thead class="table-success">
<tr>
<th>UID</th>
<th>제목</th>
<th>작성자</th>
<th>조회수</th>
<th>작성일</th>
</tr>
</thead>
<tbody>
<c:forEach var="dto" items="${list }">
<tr>
<td>${dto.uid }</td>
<td><a href="view.do?uid=${dto.uid }">${dto.subject }</a></td>
<td>${dto.user.username }</td>
<td>${dto.viewCnt }</td>
<td>${dto.regDateTime }</td>
</tr>
</c:forEach>
</tbody>
</table>
<div class="row">
<c:if test="${not empty sessionScope.PRINCIPAL }">
<div class="col-12">
<a class="btn btn-outline-dark" href="write.do">작성</a>
</div>
</c:if>
</div>
</div>
<!-- pagination -->
<div class="container mt-1">
<ul class="pagination justify-content-center">
<%-- << 표시여부 --%>
<c:if test="${page > 1 }">
<li class="page-item"><a class="page-link" href="${url }" title="처음"><i class="fa fa-angle-double-left"></i></a></li>
</c:if>
<%-- < 표시 여부 --%>
<c:if test="${startPage > 1 }">
<li class="page-item"><a class="page-link" href="${url }?page=${startPage - 1}"><i class="fas fa-angle-left"></i></a></li>
</c:if>
<%-- 페이징 안의 '숫자' 표시 --%>
<c:if test="${totalPage > 1 }">
<c:forEach var="k" begin="${startPage }" end="${endPage }">
<c:choose>
<c:when test="${k != page }">
<li class="page-item"><a class="page-link" href="${url }?page=${k }">${k }</a></li>
</c:when>
<c:otherwise>
<li class="page-item active"><a class="page-link" href="javascript:void(0);">${k }</a></li>
</c:otherwise>
</c:choose>
</c:forEach>
</c:if>
<%-- > 표시 여부 --%>
<c:if test="${totalPage > endPage }">
<li class="page-item"><a class="page-link" href="${url }?page=${endPage + 1 }"><i class='fas fa-angle-right'></i></a></li>
</c:if>
<%-- >> 표시 여부 --%>
<c:if test="${page < totalPage }">
<li class="page-item"><a class="page-link" href="${url }?page=${totalPage }"><i class='fas fa-angle-double-right'></i></a></li>
</c:if>
</ul>
</div>
<!-- pagination -->
</body>
</html>
js 코드 추가
js/list.js 추가 및
list.jsp 에는 jQuery 및 js 파일 포함시키기
list.js 작성
pageRows.do 가 작동하는지 확인하자.
pageRows.do 작성하기
DoController.java 에 추가
ViewCommand.java view.jsp 수정
SelectCommand.java update.jsp 수정
조회, 혹은 수정 중에 '목록' 으로 돌아오려면
기존의 page 로 돌아오게 해주어야 한다.
'JSP' 카테고리의 다른 글
[JSP] File Update, Delete (0) | 2022.04.12 |
---|---|
[JSP] FileUpload / Download (0) | 2022.04.11 |
[JSP] Authentification - 회원제 게시판 (0) | 2022.04.10 |
[JSP] Authentication - 로그인/로그아웃 (0) | 2022.04.10 |
[JSP] Authentication - 회원가입 (0) | 2022.04.07 |