2021. 5. 10. 22:03ㆍJSP 공부
이번에는 JSP 환경에서 페이징 을 알아 봅시다.
페이징
페이징은 아래와 같이, 게시판의 글이 많으면 나눠서 보여주는 것을 말하는 데요
※ 페이징을 구현하기 전에, 글의 개수를 늘렸습니다.
페이징의 특성
1. 반드시 GET 방식으로만 처리한다
2. 이동할 때 페이지 번호, 보여줄 페이지 개수 를 가지고 다녀야 한다 -> 목록 으로 나올 때 현재 페이지를 유지하기 위해
3. 페이징 처리하는 로직을 클래스로 분류한다 -> PageVO클래스는 페에징 관련 모든 페이지를 계산한다
먼저, 페이징을 구현하기 위해서는 각각의 페이지에서 몇개의 게시판 목록을 보여줄지 에 대한 메서드를 먼저 구현해야 합니다.
페이징 구현
그러기 위해서는 게시판의 특성을 잘 생각해 봅시다.
게시판은 최신글이 위에 나타나는 특성을 가지고 있습니다. ( 내림차순 )
각각의 페이지에서는 보여지는 글 목록 ( 글번호 ) 가 다릅니다.
그러면, sql 문을 생각 해 봅시다.
어떠한 기준으로 내림차순을 한 후 번호를 매겨서 원하는 번호만 가져오는 방법. ROWNUM 을 이용하면 되겠죠?
위의 쿼리문 처럼 3중 쿼리문을 작성해주면 됩니다.
그리고 WHERE 조건에 있는 숫자를 조정하면 되겠죠?
물음표에 들어가는 숫자에 따라서 화면에서 보여지는 각각의 페이지 마다 글개수 가 달라지겠습니다.
그러면, 물음표에 들어가는 숫자를 어떻게 넣어주면 될까요?
예를 들어서 1 페이지 마다 10개씩 보여진다고 생각을 해보면,
1 페이지 = 1 ~ 10 -> rn > 0 and rn <= 10
2 페이지 = 11 ~ 20 -> rn > 10 and rn <= 20
3 페이지 = 21 ~ 30 -> rn > 20 and rn <= 30
이런 식으로 나오겠죠?
첫번째 물음표 = (현재 페이지 - 1) * 보여줄 게시글 개수
두번째 물음표 = 현재 페이지 * 보여줄 게시글 개수
가 되겠네요
그러면 pageNum(페이지 번호) 와 amount(보여줄 게시글 수) 를 매개변수로 받아서 뿌려주면 되겠습니다.
public List<BoardVO> getList(int pageNum, int amount){
List<BoardVO> list = new ArrayList<>();
String sql = "select * "
+ "from (select rownum rn,"
+ " a.* "
+ "from (select *"
+ " from board order by bno desc) a ) "
+ "where rn > ? and rn <= ?";
try {
conn = ds.getConnection(); // 연결
pstmt = conn.prepareStatement(sql); // sql준비
pstmt.setInt(1, (pageNum - 1) * amount);
pstmt.setInt(2, pageNum * amount);
rs = pstmt.executeQuery(); // sql문 실행
while(rs.next()) {
// 한바퀴 회전당 VO를 하나씩 생성
BoardVO vo = new BoardVO();
vo.setBno(rs.getInt("bno"));
vo.setWriter(rs.getString("writer"));
vo.setTitle(rs.getString("title"));
vo.setContent(rs.getString("content"));
vo.setRegdate(rs.getTimestamp("regdate")); // 날짜형은 Timestamp() or Date()
vo.setHit(rs.getInt("hit"));
list.add(vo);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, pstmt, rs);
}
return list;
}
자 이제, 원하는 개수만큼 잘라서 화면에 나타내 주었습니다.
그러면, 페이지를 구분 지을 수 있도록 해주어야 겠죠? ( PageVO 라는 클래스를 만듭니다. )
페이지를 나타낼 때 필요한 변수들을 생각해 봅시다.
먼저, 화면에 보여질 시작 페이지번호 와 끝 페이지 번호. 이전 , 다음 여부.
현재 조회하는 페이지번호 , 화면에 보여질 게시글 수 , 총 게시글 수 가 필요합니다.
그리고 계산이 좀 필요한데요.
pageNum, amout, total 은 매개변수로 넘겨 받아서 저장을 해주면 됩니다.
하지만, startPage , endPage, prev , next 는 계산을 해주어야 하죠.
1. endPage
ex) 조회하는 페이지 1 -> 끝번호 10
ex) 조회하는 페이지 9 -> 끝번호 10
ex) 조회하는 페이지 11 -> 끝번호 20
공식 = (int)Math.ceil(페이지번호 / 페이지네이션개수) * 페이지네이션개수
2. startPage
공식 = 끝페이지 - 페이지네이션개수 + 1
3. realEnd(진짜 끝번호) 구해서 endPage의 값을 다시 결정
ex) 만약 게시글이 52개라면 -> 진짜 끝번호 6
ex) 만약 게시글이 105개라면 -> 진짜 끝번호 11
공식 = (int)Math.ceil( 전체게시글 수 / 화면에 보여질 게시글 수 )
마지막페이지 도달했을 때 보여져야 하는 끝번호가 달라집니다.
ex) 131개 게시물
1번 페이지 클릭시 -> endPage = 10, realEnd = 14 ( endPage로 세팅 )
11번 페이지 클릭시 -> endPage = 20, realEnd = 14 ( realEnd로 세팅 )
4. prev 결정 ( 이전 글이 있을 경우에만 활성화 )
5. next 결정 ( 다음 글이 있을 경우에만 활성화 )
ex) 131개 게시물
1~10 클릭시 endPage = 10, realEnd = 14 -> 다음버튼 true
11 클릭시 endPage = 14 , realEnd = 14 -> 다음버튼 false
그리고 데이터들이 private 처리 되어 있기 때문에, setter 와 getter 를 만들어 줍니다.
PageVO
public class PageVO {
/*
* 화면에 그려질 pageNation을 계산하는 클래스 ( pageNum, amount값을 가지고 다님 )
*/
private int startPage; // 게시글 화면에 보여질 첫번째 번호
private int endPage; // 게시글 화면에 보여질 마지막 번호
private boolean prev, next; // 이전버튼, 다음버튼 활성화여부
private int pageNum; // 현재 조회하는 페이지번호
private int amount = 10; // 화면에 그려질 데이터
private int total; // 전체게시글 수
// 생성자에서는 객체가 생성될때 계산을 처리
public PageVO(int pageNum, int amount, int total) {
this.pageNum = pageNum;
this.amount = amount;
this.total = total;
// 1. endPage결정
// ex) 조회하는 페이지 1 -> 끝번호 10
// ex) 조회하는 페이지 9 -> 끝번호 10
// ex) 조회하는 페이지 11 -> 끝번호 20
// 공식 = (int)Math.ceil(페이지번호 / 페이지네이션개수) * 페이지네이션개수
this.endPage = (int)Math.ceil(this.pageNum * 0.1) * 10;
// 2. startPage결정
// 공식 = 끝페이지 - 페이지네이션개수 + 1
this.startPage = this.endPage - 10 + 1;
// 3. realEnd(진짜 끝번호) 구해서 endPage의 값을 다시 결정
// 만약 게시글이 52개라면 -> 진짜 끝번호 6
// 만약 게시글이 105개라면 -> 진짜 끝번호 11
// 공식 = (int)Math.ceil(전체게시글수 / 화면에보여질데이터개수)
int realEnd = (int)Math.ceil(this.total / (double)this.amount);
// 마지막페이지 도달했을 때 보여져야 하는 끝번호가 달라집니다.
// ex) 131개 게시물
// 1번 페이지 클릭시 -> endPage = 10, realEnd = 14 ( endPage로 세팅 )
// 11번 페이지 클릭시 -> endPage = 20, realEnd = 14 ( realEnd로 세팅 )
if(this.endPage > realEnd) {
this.endPage = realEnd;
}
// 4. prev결정 ( startPage의 번호는 1, 11, 21... )
this.prev = this.startPage > 1;
// 5. next결정
// ex: 131개 게시물
// 1~10 클릭시 endPage = 10, realEnd = 14 -> 다음버튼 true
// 11 클릭시 endPage = 14 , realEnd = 14 -> 다음버튼 false
this.next = this.endPage < realEnd;
// 확인
System.out.println("시작페이지:" + this.startPage + ", 끝페이지:" + this.endPage);
// GetListService에서 페이지VO 계산처리 코드작성...
}
만들어진 PageVO 를 보면, 전체 게시글 수가 필요하기 때문에, DAO 에 전체 게시글 수를 구하는 메서드를 구합니다.
// 전체 게시글 수
public int getTotal() {
int result = 0;
String sql = "select count(*) as total from board";
try {
conn = ds.getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
if(rs.next()) {
result = rs.getInt("total");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, pstmt, rs);
}
return result;
}
이제 페이징을 구현하기 위한, 모든 준비는 끝이 났습니다.
list.board 로 넘어갈 때, 처리를 해주어야 겠죠?
파일명 : GetListServiceImpl.java
public class GetListServiceImpl implements IBoardService{
@Override
public void execute(HttpServletRequest request, HttpServletResponse response) {
// 1. 화면전환 시에 조회하는 페이지번호 and 화면에 그려질 데이터개수 2개를 전달받음
// 첫 페이지 경우
int pageNum = 1;
int amount = 10;
// 페이지번호를 클릭하는 경우
if(request.getParameter("pageNum") != null && request.getParameter("amount") != null) {
pageNum = Integer.parseInt(request.getParameter("pageNum"));
amount = Integer.parseInt(request.getParameter("amount"));
}
// DAO생성
BoardDAO dao = BoardDAO.getInstance();
// 2. pageVO생성
List<BoardVO> list = dao.getList(pageNum, amount);
int total = dao.getTotal(); // 전체게시글수
PageVO pageVO = new PageVO(pageNum, amount, total);
// 3. 페이지네이션을 화면에 전달
request.setAttribute("pageVO", pageVO);
// 화면에 가지고 나갈 list를 request에 저장 !!
request.setAttribute("list", list);
}
}
위의 코드를 보면 알겠지만, pageNum 과 amount 는 클릭했을 때 그 값이 넘겨져 와야 합니다.
위의 <a> 태그를 보면 pageNum 과 amount 를 get 방식으로 넘겨주고 있습니다.
이전 버튼과 다음 버튼도 조건에 따라 활성화 밑 구현 시켜 주어야 겠죠?
이렇게, 페이징에 대해서 알아 보았습니다.
고생하셨습니다.
※ 아래는 해당하는 게시판 목록 화면의 .jsp 파일 입니다.
<%@ 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" %>
<%@ include file="../include/header.jsp" %>
<style>
.btn {
border: 0;
border-radius: 0; /*윤곽 0*/
padding: 5px 10px;
margin: 20px 0px;
}
</style>
<div class="container">
<h3>My Web게시판</h3>
<div>
<select onchange="change(this)">
<option value="10" ${pageVO.amount eq 10 ? 'selected' : '' }>10개씩 보기</option>
<option value="20" ${pageVO.amount eq 20 ? 'selected' : '' }>20개씩 보기</option>
<option value="50" ${pageVO.amount eq 50 ? 'selected' : '' }>50개씩 보기</option>
<option value="100" ${pageVO.amount eq 100 ? 'selected' : '' }>100개씩 보기</option>
</select>
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>글 번호</th>
<th>작성자</th>
<th>제목</th>
<th>날짜</th>
<th>조회수</th>
</tr>
</thead>
<tbody>
<c:forEach var="vo" items="${list }">
<tr>
<td>${vo.bno }</td>
<td>${vo.writer}</td>
<td><a href="getContent.board?bno=${vo.bno }">${vo.title }</a></td>
<td><fmt:formatDate value="${vo.regdate }" pattern="yyyy년 MM월dd일 HH시 mm분 ss초" /></td>
<td>${vo.hit }</td>
</tr>
</c:forEach>
</tbody>
<tbody>
<tr>
<td colspan="5" align="center">
<ul class="pagination pagination-sm">
<!-- 2. 이전버튼 활성화 여부 -->
<c:if test="${pageVO.prev }">
<li><a href="list.board?pageNum=${pageVO.startPage - 1 }&amount=${pageVO.amount}">이전</a></li>
</c:if>
<!-- 1. 페이지번호 처리 -->
<c:forEach var="num" begin="${pageVO.startPage }" end="${pageVO.endPage }">
<li class="${pageVO.pageNum eq num ? 'active' : '' }">
<a href="list.board?pageNum=${num }&amount=${pageVO.amount}">${num }</a></li>
</c:forEach>
<!-- 3. 다음버튼 활성화 여부 -->
<c:if test="${pageVO.next }">
<li><a href="list.board?pageNum=${pageVO.endPage + 1 }&amount=${pageVO.amount}">다음</a></li>
</c:if>
</ul>
<input type="button" value="글 작성" class="btn btn-default pull-right" onclick="location.href='write.board'">
</td>
</tr>
</tbody>
</table>
</div>
<%@ include file="../include/footer.jsp" %>
<script>
function change(a){
//console.log(a);
//console.log(a.value);
location.href="list.board?pageNum=1&amount=" + a.value;
}
</script>
'JSP 공부' 카테고리의 다른 글
Day59 - [JSP]필터 (0) | 2021.05.10 |
---|---|
Day 58 -[JSP]MVC2 게시판 만들기 (0) | 2021.05.09 |
Day57 - [JSP]URL패턴 , MVC2 전체적인 컴포넌트 설계 (0) | 2021.05.06 |
Day56 - [JSP]연결풀(Connection pool) (0) | 2021.05.05 |
Day56 - [JSP]JSTL (0) | 2021.05.05 |