JSP 페이징 번호 - JSP peijing beonho

category JSP-HTML-CSS/SOURCECODE 2019. 10. 26. 17:06 by I's

//페이지 글번호 따로 처리하려고 쿼리 수정하는 것보다 
//화면에서 직접 처리 하는 것이 더 나을때도 있다
<c:forEach var="...." items="${....}" varStatus="i">
    ${전체게시글수 - (현재페이지-1)*페이지당 보여지는 게시물수 - i.index}
</c:forEach>

'JSP-HTML-CSS > SOURCECODE' 카테고리의 다른 글

크롬 자동완성 로직이해 & 처리 꼼수  (0)2021.10.26
[JSTL] eq, ne, lt, gt, le, ge 문법  (0)2019.10.27
[HTML] 이미지 겹치기  (0)2019.10.26

tag foreach, JSP, jstl, Paging, varstatus


댓글 0 , 엮인글

댓글을 달아 주세요

댓글을 남겨주세요

이름 NICK*

비밀번호*

홈페이지

공개 비공개

    이번에는 JSP 환경에서 페이징 을 알아 봅시다.

    페이징

    페이징은 아래와 같이, 게시판의 글이 많으면 나눠서 보여주는 것을 말하는 데요

    JSP 페이징 번호 - JSP peijing beonho

    ※ 페이징을 구현하기 전에, 글의 개수를 늘렸습니다.

    페이징의 특성

    1. 반드시 GET 방식으로만 처리한다

    2. 이동할 때 페이지 번호, 보여줄 페이지 개수 를 가지고 다녀야 한다 -> 목록 으로 나올 때 현재 페이지를 유지하기 위해

    3. 페이징 처리하는 로직을 클래스로 분류한다 -> PageVO클래스는 페에징 관련 모든 페이지를 계산한다

    먼저, 페이징을 구현하기 위해서는 각각의 페이지에서 몇개의 게시판 목록을 보여줄지 에 대한 메서드를 먼저 구현해야 합니다.

    페이징 구현

    그러기 위해서는 게시판의 특성을 잘 생각해 봅시다.

    게시판은 최신글이 위에 나타나는 특성을 가지고 있습니다. ( 내림차순 )

    각각의 페이지에서는 보여지는 글 목록 ( 글번호 ) 가 다릅니다.

    그러면, sql 문을 생각 해 봅시다.

    어떠한 기준으로 내림차순을 한 후 번호를 매겨서 원하는 번호만 가져오는 방법. ROWNUM 을 이용하면 되겠죠?

    JSP 페이징 번호 - JSP peijing beonho

    위의 쿼리문 처럼  3중 쿼리문을 작성해주면 됩니다.

    그리고 WHERE 조건에 있는 숫자를 조정하면 되겠죠?

    JSP 페이징 번호 - JSP peijing beonho

    물음표에 들어가는 숫자에 따라서 화면에서 보여지는 각각의 페이지 마다 글개수 가 달라지겠습니다.

    그러면, 물음표에 들어가는 숫자를 어떻게 넣어주면 될까요?

    예를 들어서 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) * 보여줄 게시글 개수

    두번째 물음표 = 현재 페이지 * 보여줄 게시글 개수

    가 되겠네요

    JSP 페이징 번호 - JSP peijing beonho

    그러면 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 라는 클래스를 만듭니다. )

    페이지를 나타낼 때 필요한 변수들을 생각해 봅시다.

    먼저, 화면에 보여질 시작 페이지번호 와 끝 페이지 번호. 이전 , 다음 여부.

    현재 조회하는 페이지번호 , 화면에 보여질 게시글 수 , 총 게시글 수 가 필요합니다.

    JSP 페이징 번호 - JSP peijing beonho

    그리고 계산이 좀 필요한데요.

    pageNum, amout, total 은 매개변수로 넘겨 받아서 저장을 해주면 됩니다.

    하지만, startPage , endPage, prev , next 는 계산을 해주어야 하죠.

    1. endPage

    ex) 조회하는 페이지 1 -> 끝번호 10
    ex) 조회하는 페이지 9 -> 끝번호 10
    ex) 조회하는 페이지 11 -> 끝번호 20

    공식 = (int)Math.ceil(페이지번호 / 페이지네이션개수) * 페이지네이션개수

    JSP 페이징 번호 - JSP peijing beonho

    2. startPage

    공식 = 끝페이지 - 페이지네이션개수 + 1

    JSP 페이징 번호 - JSP peijing beonho

    3. realEnd(진짜 끝번호) 구해서 endPage의 값을 다시 결정

    ex) 만약 게시글이 52개라면 -> 진짜 끝번호 6
    ex) 만약 게시글이 105개라면 -> 진짜 끝번호 11

    공식 = (int)Math.ceil( 전체게시글 수 / 화면에 보여질 게시글 수 )

    JSP 페이징 번호 - JSP peijing beonho

    마지막페이지 도달했을 때 보여져야 하는 끝번호가 달라집니다.
    ex) 131개 게시물
    1번 페이지 클릭시 -> endPage = 10, realEnd = 14 ( endPage로 세팅 )
    11번 페이지 클릭시 -> endPage = 20, realEnd = 14 ( realEnd로 세팅 )

    JSP 페이징 번호 - JSP peijing beonho

    4. prev 결정 ( 이전 글이 있을 경우에만 활성화 )

    JSP 페이징 번호 - JSP peijing beonho

    5. next 결정 ( 다음 글이 있을 경우에만 활성화 )

    ex) 131개 게시물
    1~10 클릭시 endPage = 10, realEnd = 14 -> 다음버튼 true
    11 클릭시 endPage = 14 , realEnd = 14 -> 다음버튼 false

    JSP 페이징 번호 - JSP peijing beonho

    그리고 데이터들이 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 는 클릭했을 때 그 값이 넘겨져 와야 합니다.

    JSP 페이징 번호 - JSP peijing beonho

    위의 <a> 태그를 보면 pageNum 과 amount 를 get 방식으로 넘겨주고 있습니다.

    이전 버튼과 다음 버튼도 조건에 따라 활성화 밑 구현 시켜 주어야 겠죠?

    JSP 페이징 번호 - JSP peijing beonho
    JSP 페이징 번호 - JSP peijing beonho

    이렇게, 페이징에 대해서 알아 보았습니다.

    고생하셨습니다.

    ※ 아래는 해당하는 게시판 목록 화면의 .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 페이징 번호 - JSP peijing beonho