
글목록과 페이지네이션(Pagination)
게시물을 DB에서 불러와 화면에 표시하려면 게시글 목록을 가져오는 작업과 페이징 처리 두 가지를 고려해야 한다.
게시글 데이터를 한 번에 불러오기 위해 ArrayList를 사용하여 DB에서 작성자, 제목 등 게시글의 주요 정보를 포함한 데이터를 가져온다. 이 때 중요한 점은 페이징 처리이다. 페이징 처리는 한 페이지에 몇 개의 게시글을 보여줄지 결정하는 과정이며, 예를 들어 한 페이지에 총 10개의 게시글을 가져오도록 설정할 수 있다.
그래서 오늘은 `BbsDAO`에 특정 페이지 번호(pageNumber)에 해당하는 게시글 목록을 반환하는 메서드 ⚡ `getList(int pageNumber)`를 만들어 볼 것이다.
그리고 페이징 처리에서 페이지 번호를 기준으로 다음 페이지가 존재하는지 여부를 반환하는 메서드 ⚡`boolean nextPage(int pageNumber)`도 만들어줄 것이다.
`getList()` 메서드로 데이터베이스에서 특정 범위의 게시글을 불러오고, 사용자가 "다음 페이지" 버튼을 클릭했을 때, 그 페이지가 실제로 존재하는지 `boolean nextPage(int pageNumber)` 로 판단해 주는 것이다.
페이지네이션(Pagination)
1. 페이지네이션이란?
Pagination이란, 많은 데이터를 부분적으로 불러오는 기술을 의미한다. 우리가 일반적으로 데이터를 불러올 때, 만약에 모든 데이터를 불러오게 되면 매우 비효율적일 것이다.
아래와 같이 보통 웹사이트 게시판 아래에는 페이지 번호가 있다. 페이지 번호를 하나 누르면 10개에서 15개 정도의 게시물이 나누어서 화면에 보여지게 된다. 이렇게 특정 페이지를 클릭하면 그 페이지에 해당하는 데이터만 불러와서 보여주는 것이 페이지네이션(페이지 처리, 페이징 기법이라고도 함)이다.
만약 이 작업을 하지 않으면 한 화면에 수천개 수만개의 게시물이 불러와질 것이다.

2. 페이지네이션 기본 원리
아래는 페이지네이션에 필요한 기본적인 요소이다.
- 페이지 크기 (page size): 한 페이지에 표시할 게시글 수를 결정합니다. 나는 10개로 지정할 것이다.
- 현재 페이지 (current page): 사용자가 보고 있는 페이지 번호를 기준으로, 해당 페이지에 맞는 게시글을 불러온다.
- DB 쿼리에서 `LIMIT` 사용: DB에서 데이터를 가져올 때, `LIMIT`과 `OFFSET`을 사용하여 현재 페이지에 해당하는 데이터를 가져온다.
예를 들면 게시글이 100개 있는 게시판에 현재 페이지가 3일 경우, 3페이지는 `80 ~ 71`번째 게시글을 불러온다.
`SELECT * FROM 게시글 LIMIT 10 OFFSET 80`을 해서 데이터를 가져오기 때문이다 `OFFSET`이 무엇인지 왜 80인지는 아래에 자세히 기술하도록 하겠다. 그리고 보통 게시판에서는 최근글 순으로 불러오기 때문에 내림차순 정렬을 해 준다.
+ 페이징 처리를 할 때, 사용자에게 페이지 네비게이션을 보여주는 것도 중요하다. 화면 하단에 페이지 번호를 기반으로 '이전', '다음' 버튼을 만들거나, 페이지 번호를 직접 입력할 수 있게 하는 작업이다.
일반적인 게시판은 하단에 1부터 10까지, 11부터 20까지, 21부터 30까지 10개씩 부분적으로 페이지 수를 화면에 보여주는데 나는 그냥 간단하게 `이전`, `다음` 버튼으로 페이지를 이동할 수 있도록 처리하려고 한다.
페이징처리 예시코드
// 페이징 처리 기본값
int pageSize = 10; // 한 페이지에 10개의 게시글을 표시
int currentPage = 1; // 기본적으로 1페이지부터 시작
// DB에서 데이터 불러오기 (예: currentPage가 1일 경우)
int offset = (currentPage - 1) * pageSize; // OFFSET 계산
String sql = "SELECT * FROM 게시글 LIMIT ? OFFSET ?";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setInt(1, pageSize); // LIMIT: 한 페이지에 표시할 게시글 수
ps.setInt(2, offset); // OFFSET: 현재 페이지에 맞는 시작 인덱스
ResultSet rs = ps.executeQuery();
// 결과를 ArrayList에 저장
ArrayList<Post> posts = new ArrayList<>();
while (rs.next()) {
String author = rs.getString("author");
String title = rs.getString("title");
// 필요한 필드 추가
posts.add(new Post(author, title)); // Post 클래스는 게시글 정보를 담는 객체
}
// posts 리스트에는 해당 페이지의 게시글들이 들어감⚡ 페이지 번호에 해당하는 글목록을 반환하는 getList 메서드
// 특정한 페이지에 맞는 게시글 리스트가 list에 담겨 반환
public ArrayList<Bbs> getList(int pageNumber) {
String SQL = "SELECT * FROM BBS WHERE bbsID < ? AND bbsAvailable = 1 ORDER BY bbsID DESC LIMIT 10";
ArrayList<Bbs> list = new ArrayList<>();
try {
PreparedStatement psmt = conn.prepareStatement(SQL);
psmt.setInt(1, getNext() - (pageNumber-1) * 10);
rs = psmt.executeQuery();
while (rs.next()) {
Bbs bbs = new Bbs();
bbs.setBbsID(rs.getInt(1));
bbs.setBbsTitle(rs.getString(2));
bbs.setUserID(rs.getString(3));
bbs.setBbsDate(rs.getString(4));
bbs.setBbsContent(rs.getString(5));
bbs.setBbsAvailable(rs.getInt(1));
list.add(bbs);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
📌 `SELECT * FROM BBS` BBS 테이블에서 모든 열을 가져옴
`WHERE bbsID < ?: bbsID` 가 매개변수로 전달된 값보다 작은 게시글들을 선택(페이지네이션)
`bbsAvailable = 1` 현재 게시글이 사용 가능한 상태(삭제 안된것)인 것만 선택
`ORDER BY bbsID DESC` bbsID를 내림차순으로 정렬, 즉 최신 게시글부터 가져오게 설정한 것
`LIMIT 10` 한 번에 10개의 게시글만 가져오기. 즉, 페이지당 10개의 게시글을 반환하도록 설정
📌 `psmt.setInt(1, getNext() - (pageNumber-1) * 10)`
페이지 번호에 맞는 게시글을 가져오기 위해 오프셋을 설정하는 부분
`getNext()`와 `(pageNumber - 1) * 10`을 결합해서 `시작 위치(오프셋)` 결정
📌오프셋(offset)
오프셋 은 데이터베이스에서 쿼리로 데이터를 가져올 때, 가져올 데이터의 `시작 위치`를 의미한다. 주로 사용자가 요청한 페이지에 맞는 데이터를 가져오기 위해 `어디서부터` 데이터를 시작할지를 결정한다.
getNext()는 보통 게시글 목록에서 가장 최신의 게시글 ID를 반환하는 값이다. 정확히 말하면 getNext() 메서드는 `다음 게시글 번호`를 반환하는 메서드인데 이걸로 해당 페이지에 맞는 게시글 시작 번호(OFFSET)를 계산하는데 쓰인다. getNext() 값이 100이라고 가정해 보자.
사용자가 페이지 1을 요청했다고 가정하면, pageNumber = 1이 된다.
`(pageNumber - 1) * 10 = (1 - 1) * 10 = 0`
따라서, psmt.setInt(1, getNext() - 0)이 되어, psmt.setInt(1, 100)으로 설정된다.
즉, 100번째 게시글부터 10개를 가져온다.
사용자가 페이지 2를 요청했다고 가정하면, pageNumber = 2이다.
`(pageNumber - 1) * 10 = (2 - 1) * 10 = 10`
따라서, psmt.setInt(1, getNext() - 10)이 되어, psmt.setInt(1, 100 - 10) → psmt.setInt(1, 90)으로 설정된다.
90번째 게시글부터 10개를 가져온다.
이런 식으로 사용자가 페이지 3을 요청했다고 가정하면, pageNumber = 3이고,
`(pageNumber - 1) * 10 = (3 - 1) * 10 = 20`
따라서, psmt.setInt(1, getNext() - 20)이 되어, psmt.setInt(1, 100 - 20) → psmt.setInt(1, 80)으로 설정된다.
80번째 게시글부터 10개를 가져온다.
페이지 1: psmt.setInt(1, 100) → 100번 게시글부터 10개
페이지 2: psmt.setInt(1, 90) → 90번 게시글부터 10개
페이지 3: psmt.setInt(1, 80) → 80번 게시글부터 10개
이 방식으로 페이지마다 시작하는 게시글의 위치(오프셋)를 계산해서 LIMIT 10을 사용해서 한 페이지에 10개의 게시글을 가져올 수 있다. 이 과정에서 게시글을 가져오는 방식은 내림차순으로 정렬되기 때문에, 가장 큰 값인 100번 게시글부터 시작하는 것이다.
게시글이 내림차순으로 정렬된 경우, 가장 큰 게시글 ID가 100번이라고 가정했을 때
페이지 1은 psmt.setInt(1, 100) → 100번 게시글부터 10개 가져오기 때문에 결과적으로 100번, 99번, 98번, ... 이렇게 내림차순으로 10개의 게시글이 반환된다.
그 이유는 가장 최신에 작성된 글부터 보여 주기 위해서이다. 그래서 `ORDER BY bbsID DESC (내림차순 정렬)`으로 쿼리를 작성했기 때문에, 100번이 가장 먼저 나온다. 페이지 1에서 100번부터 시작하고, 페이지가 바뀔 때마다 내림차순으로 다음 게시글들을 가져온다.
// 특정한 페이지에 맞는 게시글 리스트가 list에 담겨 반환
public ArrayList<Bbs> getList(int pageNumber) {
String SQL = "SELECT * FROM BBS WHERE bbsID < ? AND bbsAvailable = 1 ORDER BY bbsID DESC LIMIT 10";
ArrayList<Bbs> list = new ArrayList<>();
try {
PreparedStatement psmt = conn.prepareStatement(SQL);
psmt.setInt(1, getNext() - (pageNumber-1) * 10);
rs = psmt.executeQuery();
while (rs.next()) {
Bbs bbs = new Bbs();
bbs.setBbsID(rs.getInt(1));
bbs.setBbsTitle(rs.getString(2));
bbs.setUserID(rs.getString(3));
bbs.setBbsDate(rs.getString(4));
bbs.setBbsContent(rs.getString(5));
bbs.setBbsAvailable(rs.getInt(1));
list.add(bbs);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}⚡ 다음 페이지가 있는지 확인하는 nextPage() 메서드
public boolean nextPage(int pageNumber) {
String SQL = "SELECT * FROM BBS WHERE bbsID < ? AND bbsAvailable = 1 ORDER BY bbsID DESC LIMIT 10";
try {
PreparedStatement psmt = conn.prepareStatement(SQL);
psmt.setInt(1, getNext() - (pageNumber - 1) * 10);
rs = psmt.executeQuery();
if (rs.next()) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
다음 페이지가 있으면 true, 없으면 false 반환
3. bbs.jsp 페이지에서 글목록 불러오기
이제 실제로 글목록을 보여주기 위해서 이제 게시판 메인 화면으로 돌아가자.
bbs.BbsDao, bbs.Bbs, ArrayList 임포트 해 준다.

스크립트릿 안에 기본적으로 pageNumber를 1 로 설정했다.
파라미터 값을 받아와서 pageNumber로 설정해주자. `request.getParameter`는 항상 `문자열(String)`로 값을 반환하므로 반드시 `Integer.parseInt`로 형변환 해 주어야 한다.

이제 body 안에 스크립트릿 열어서 bbsDAO 객체 생성해 주고 ArrayList로 글 내용들을 불러온다.
for문돌리면서 한 줄씩 나올 내용을 출력해준다.
📌 게시글 제목에는 `<a>`태그 달아준다. 특정 게시글의 제목을 클릭하면 상세보기 페이지로 이동할 수 있도록 링크를 생성해 주어야 한다. 게시글의 ID와 제목을 사용해서 view.jsp로 넘어갈 수 있도록 해 준다. view.jsp 페이지는 나중에 만들래요
📌 DB에서 서버의 현재 시간 가져올 때 `NOW()`를 쓰는데 기본적으로 YYYY-MM-DD HH:MM:SS 형식으로 날짜와 시간을 반환하기 때문에 시,분 형식으로 바꿔주었다.
<tbody>
<%
BbsDAO bbsDAO = new BbsDAO();
ArrayList<Bbs> list = bbsDAO.getList(pageNumber);
for(int i = 0; i < list.size(); i++) {
%>
<tr>
<td><%= list.get(i).getBbsID() %></td>
<td><a href="view.jsp?bbsID=<%= list.get(i).getBbsID() %>"><%= list.get(i).getBbsTitle() %></a></td>
<td><%= list.get(i).getUserID() %></td>
<td><%= list.get(i).getBbsDate().substring(0, 11) + list.get(i).getBbsDate().substring(11, 13) + "시" + list.get(i).getBbsDate().substring(14, 16) + "분" %></td>
</tr>
<%
}
%>
</tbody>여기까지 하고 테스트
다시 웹브라우저로 돌아와서 새로고침하면 최근에 등록된 데이터부터 화면에 출력되는 걸 확인할 수 있다.

이제 `<table>` 태그 밑에다가 페이지 이동을 위한 `이전`, `다음` 버튼을 달아 주었다.
`style="width: auto;"` 안 넣어주면 버튼이 화면 전체에 꽉참;;
<%
if(pageNumber != 1) {
%>
<a href="bbs.jsp?pageNumber=<%=pageNumber - 1%>" class="btn btn-success btn-arrow-left"
style="width: auto;">이전</a>
<%
} if(bbsDAO.nextPage(pageNumber + 1)) {
%>
<a href="bbs.jsp?pageNumber=<%=pageNumber + 1%>" class="btn btn-success btn-arrow-left"
style="width: auto;">다음</a>
<%
}
%>
새로고침해보니까 버튼이 잘 생성되었음.

이제 게시글 제목에 걸린 하이퍼링크 css효과를 없애주려고 한다.
밑줄이랑 파란 글씨를 없애보자.
<style type="text/css">
a, a:hover {
color:#000000;
text-decoration: none;
}
</style>
오늘은 여기까지 완성!

'Spring&JSP' 카테고리의 다른 글
| [JSP] 게시판 만들기 11 _ 게시글 수정, 삭제 기능 (64) | 2024.12.13 |
|---|---|
| [JSP] 게시판 만들기 11 _ 게시판 보기 기능 (96) | 2024.12.09 |
| [JSP] 게시판 만들기 9 _ 게시판 글쓰기 기능 (write.jsp, BbsDAO.java, writeAction.jsp) (63) | 2024.12.09 |
| [JSP] 게시판 만들기 8 _ 게시판 메인 페이지 만들고 게시판 데이터베이스 구축하기 (70) | 2024.12.08 |
| [JSP] 게시판 만들기 7 _ 회원세션 관리하기 (94) | 2024.12.05 |