본문 바로가기
Spring

페이지네이션 (Pagination) - Servlet 프로그래밍

by SuldenLion 2023. 7. 8.
반응형

● 페이지네이션(Pagination)

- 페이지네이션(Pagination) 또는 페이징(Paging)은 데이터나 콘텐츠를 페이지로 나누는 기술이나 기법을 의미함

- 주로 대량의 데이터나 긴 목록을 여러 페이지로 나누어 표시할 때 사용

- 사용자는 페이지 단위로 데이터를 탐색하고 필요한 정보에 빠르게 접근할 수 있음

- 각 페이지는 일정한 개수의 아이템을 포함하며, 페이지간에 이전 페이지와 다음 페이지로 이동할 수 있는 링크 또는 버튼이 제공됨

- 페이지네이션은 웹 애플리케이션, 블로그, 포럼, 검색 결과 페이지 등 다양한 온라인 플랫폼에서 사용되는 기능

 

 

 

위와 같은 경우가 페이지네이션의 예시이다.

 

 

 

 

 

이전 게시글의 프로그램을 바탕으로 도서목록을 띄워주는 화면에 페이지네이션 기능을 구현해보겠다.

https://suldenlion.tistory.com/113(도서 CRUD프로그램 링크)

 

 

 

위과 같은 목록을 3개씩 네 페이지로 나눠서 화면을 구성해보겠다.

 

 

 

 

 

 

 

먼저 Front UI 부터 만들어 보겠다.

<%@page import="bitedu.bipa.member.vo.BookCopy"%>
<%@page import="java.util.ArrayList"%>
<%@ 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/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Book List</title>
<style>
        table, td, th {
            border : 1px solid black;
            border-collapse: collapse;
            margin: 20px auto;
        }
        td {
            width: 150px;
            height: 50px;
            padding: 5px;
            font-size: 20px;
            /* text-align: center; */
        }

        input , select {
            font-size: 20px;
        }
        .data_ui {
            /* width: 250px; */
            height: 50px;
        }

        button {
            font-size: 15px;
            margin: 5px;
        }
        
        
        #sending {
        	text-align: center;
        }
        
        input.poster :disabled {
        	background: gray;
        }
        
        #form {
        	font-size: 30px;
        }
        
        #title {
        	height: 80px;
        	font-size: 50px;
        }
    </style>
</head>
<body>
${param.flag=='true'?"<script>alert('삭제성공');</script>":""}
<%
	ArrayList<BookCopy> list = (ArrayList<BookCopy>)request.getAttribute("list");
%>

<table>
	<tr><th colspan="5" id="title">도서리스트</th></tr>
	<tr><td>순번</td><td>타이틀</td><td>저자</td><td>출판일</td><td></td></tr>

<!-- expression language 사용 -->
<c:forEach var="copy" items="${list}"> 
	<tr>
	<td>${copy.bookSeq}</td>
	<td><a href='./BlmController?cmd=detail&bookSeq=${copy.bookSeq}'>${copy.title}</a></td>
	<td>${copy.author}</td>
	<td><fmt:formatDate value="${copy.publishDate}" pattern="yyyy-MM-dd"/> </td>
	<td><a href="./BlmController?cmd=remove&bookSeq=${copy.bookSeq}">삭제</a></td>
	</tr>
</c:forEach>

	<tr><td colspan="5"><a href="/MemberSample0629/BlmController?cmd=view_regist"><button>도서등록</button></a>
	
	<!-- 페이징. 도서등록 버튼 옆으로 옮길지 말지 -->
	<c:if test="${currentPage > 1}">
		<a href="/MemberSample0629/BlmController?cmd=list&page=${currentPage-1}" style="text-decoration: none">&lt;</a>
	</c:if>
	
	<c:forEach var="pageNumber" begin="1" end="${totalPages}">
		<c:choose>
			<c:when test="${pageNumber == currentPage}">
				<strong>${pageNumber}</strong>
			</c:when>
			<c:otherwise>
				<a href="/MemberSample0629/BlmController?cmd=list&page=${pageNumber}" style="text-decoration: none">${pageNumber}</a>
			</c:otherwise>
		</c:choose>	
	</c:forEach>
	
	<c:if test="${currentPage < totalPages}">
		<a href="/MemberSample0629/BlmController?cmd=list&page=${currentPage+1}" style="text-decoration: none">&gt;</a>
	</c:if>
	
	<!-- <input type="submit" value="Paging으로 보기" id="paging"> -->
	<a href="/MemberSample0629/BlmController?cmd=list&page=1"><button id="paging">Paging으로 보기</button></a> 
	</td></tr>
</table>
</body>
</html>

book_list.jsp이다.

 

페이징 관련된 아래 이 부분만 보면 된다.

 

 

 

이 코드는 페이지가 1보다 클 때, 이전 페이지를 갈 수 있게하는 버튼을 만들어낸다. 페이지가 1일때는 만들지 않는다.

&lt는 less than을 의미하며 "<" 꺽쇠 괄호와 같다.

 

 

위 코드는 숫자 1부터 전체 페이지까지를 표시해주기 위한 것이다. 서블릿에서 넘어온 totalPages값을 가지고 동적으로 필요한 숫자만큼 띄워줄 것이다. 

 

<c:choose>, <c:when>, <c:otherwise>는 jstl로, 각각 switch, case, default에 해당한다고 보면 된다.

<c:when에는 test="..."> 가 붙는데 조건식을 쓰기 위한 필수 속성이다.

선택된 페이지의 숫자가 현재 페이지이면 숫자에 Bold를 주기 위해 사용한다.

선택되지 않은 그 외의 숫자들은 해당 하는 페이지를 향하게 하고(클릭시), style을 text_decoration: none을 줌으로써 숫자의 밑줄을 없애준다. (이 조건을 안적어주면 숫자 밑에 밑줄이 남음)

 

 

현재 페이지가 마지막 페이지보다 작은경우 ">" 표시를 띄워준다. &gt는 greater than을 의미한다.

 

 

그럼 처음에 목록이 전부 나열되어있는 list 페이지에서 Paging으로 보기 버튼을 눌러 페이지를 나눠보도록 하겠다.

 

 

 

다음은 Controller를 보겠다.

기존의 list에다 page라는 Parameter를 받아와서 존재한다면 페이지네이션 작업을 한다. 

 

처음 page에 값이 세팅될 때는 Paging으로 보기 버튼을 눌렀을 때가 될 것이다.

 

우선 데이터의 총 개수인 totalDataCount를 구한다.

서비스의 getTotalDataCount()를 시행한다.

 

dao에서 select문을 통해 처리하고자 한다.

 

count(*)을 하여 모든 데이터량을 구해온다.

 

(근데 totalDataCount는 이렇게 할 필요없이, searchBookAll()을 통해 ArrayList를 만든것이 있으니 해당 list의 size() 함수를 써도 됐다.)

 

다음은 넘겨받은 pageNumber로 현재 페이지를 구한다.

페이지가 null이 아닌 경우에, String type인 page를 숫자로 파싱하여준다.

기본적으로 1을 리턴한다.

 

이것도 굳이 메서드로 따로 빼줄필요없이

int currentPage = (pageNumber != null) ? Integer.parseInt(pageNumber) : 1; 과 같은 삼항연산식으로 표현해도 된다. 

 

페이지당 띄울 데이터 수를 dataPerPage라는 변수로 정의해주고, 전체 페이지 수를 구해준다.

 

전체 데이터 수에서 페이지당 띄울 데이터 수를 나눠주면 된다. 그리고 Math.ceil로 올려야지 누락되는 데이터 없이 전체 페이지 수를 잘 구할수 있다.

 

현재 화면에 띄워줄 도서 목록을 ArrayList로 만들어 getDataForPage(currentPage, dataPerPage)를 시행 후 값을 가져온다. 

 

넘어온 현재 페이지와 페이지당 개수를 통해 보여주고 싶은 도서 목록을 찾아낼 것이다.

start에는 (현재 페이지 - 1) * 페이지당 데이터 수를 할 건데, 이를 통해 해당 페이지의 데이터 시작점을 구한다.

 

예를 들어, 3번 페이지를 띄울것이면 start는 6이고,

원하는 첫번째 데이터의 index는 7,8,9 총 3개이다.

end는 띄워줄 데이터 수와 같은데 마지막 페이지의 데이터가 dataPerPage보다 작은 경우가 있을 수 있으므로 Math.min으로 비교하여 더 작은 값을 넘겨준다.

 

public ArrayList<BookCopy> selectCurrentPageData(int start, int end) {
    ArrayList<BookCopy> list = null;
    list = new ArrayList<BookCopy>();
    BookCopy copy = null;
    StringBuilder sb = new StringBuilder("select i.*, c.* from book_info i ");
    sb.append("inner join book_copy c on i.book_isbn=c.book_isbn limit ?, ?");
    String sql = sb.toString();
    Connection con = manager.getConnection();
    PreparedStatement pstmt;
    try {
        pstmt = con.prepareStatement(sql);
        pstmt.setInt(1, start);
        pstmt.setInt(2, end);

        ResultSet rs = pstmt.executeQuery();

        while(rs.next()) {
            copy = new BookCopy();
            copy.setIsbn(rs.getString(1));
            copy.setTitle(rs.getString(2));
            copy.setAuthor(rs.getString(3));
            copy.setPublishDate(rs.getTimestamp(4));
            copy.setBookSeq(rs.getInt(5));
            copy.setBookPosition(rs.getString(6));
            copy.setBookStatus(rs.getString(7));
            list.add(copy);
        }
        manager.closeConnection(rs, pstmt, con);
    } catch (SQLException e) {
        e.printStackTrace();
    }

    return list;
}

값을 select 해올것인데, limit 문에 start와 end를 주어 원하는 값만 select 해올 수 있게한다.

 

 

위의 예시인 3번 페이지는 

 

이 쿼리문과 같고, 아래 결과를 가져올 것이다.

 

도서 데이터 값들을 리스트에 담아서 리턴해준다.

 

 

구해온 list2, currentPage, totalPages 값들을 request를 통해 Front로 세팅해주면 끝이다.

 

반응형

댓글