국비 65- 게시글 목록 조회(페이지네이션)

냐아암·2023년 8월 7일
0

국비

목록 보기
81/114

게시글 목록 조회

<ul>
		<li><a href="${contextPath}/board/list?type=1">공지사항</a></li>
		<li><a href="${contextPath}/board/list?type=2">자유게시판</a></li>
		<li><a href="${contextPath}/board/list?type=3">질문게시판</a></li>
		<li><a href="#">FAQ</a></li>
		<li><a href="#">1:1 문의</a></li>
	</ul>

package edu.kh.community.board.controller;

import java.io.IOException;
import java.util.Map;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import edu.kh.community.board.model.service.BoardService;

@WebServlet("/board/list")
public class BoardListServlet extends HttpServlet{
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		try {
			
			// 쿼리스트링 얻어오기 == 파라미터 얻어오기
			
			int type = Integer.parseInt(req.getParameter("type"));
			
			// nav 메뉴(공지사항, 자유게시판, 질문게시판) 선택 시
			// 쿼리스트링에 cp가 없음 --> cp = 1 고정
			int cp = 1;
			
			// 페이지네이션 번호 선택 시
			// 쿼리스트링에 cp가 있음 --> cp = 쿼리스트링 cp값
			if(req.getParameter("cp") != null) { // 쿼리스트링에 "cp"가 존재한다면
				cp = Integer.parseInt(req.getParameter("cp"));
			}
					
			
			BoardService service = new BoardService();
			
			// 게시판 이름, 페이지네이션 객체, 게시글 리스트를 한 번에 반환하는 service 호출
			Map<String, Object> map = null;
			
			if(req.getParameter("key") == null) { // 일반 목록 조회
				map = service.selectBoardList(type,cp);
			} else {
				String key = req.getParameter("key");
				String query = req.getParameter("query");
				
				map = service.searchBoardList(type, cp, key, query);
				
			}
			
			// request 범위로 map 세팅
			req.setAttribute("map", map);
			
			String path = "/WEB-INF/views/board/boardList.jsp";
			
			RequestDispatcher dispatcher = req.getRequestDispatcher(path);
			
			dispatcher.forward(req, resp);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

}

페이지네이션

package edu.kh.community.board.model.vo;

public class Pagination {
	// 페이지네이션(페이징 처리)에 필요한 모든 값들을 저장하고 있는 객체
	
	private int currentPage;	 // 현재 페이지 번호
	private int listCount;		 // 전체 게시글 수
	
	private int limit = 10;		 // 한 페이지에 보여질 게시글의 수
	private int pageSize = 10;	 // 목록 하단 페이지 번호의 노출 개수
	
	private int maxPage;		 // 제일 큰 페이지 번호 == 마지막 페이지 번호
	private int startPage;		 // 목록 하단에 노출된 페이지의 시작 번호
	private int endPage;		 // 목록 하단에 노출된 페이지의 끝 번호
	
	private int prevPage;		 // 목록 하단에 노출된 번호의 이전 목록 끝 번호
	private int nextPage;		 // 목록 하단에 노출된 번호의 다음 목록 시작 번호
	
	
	// 생성자
	public Pagination(int currentPage, int listCount) {
		this.currentPage = currentPage;
		this.listCount = listCount;
		
		calculatePagination();
	}


	public int getCurrentPage() {
		return currentPage;
	}


	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
		
		calculatePagination();
	}


	public int getListCount() {
		return listCount;
	}


	public void setListCount(int listCount) {
		this.listCount = listCount;
		
		calculatePagination();
	}


	public int getLimit() {
		return limit;
	}


	public void setLimit(int limit) {
		this.limit = limit;
		
		calculatePagination();
	}


	public int getPageSize() {
		return pageSize;
	}


	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
		
		calculatePagination();
	}


	public int getMaxPage() {
		return maxPage;
	}


	public void setMaxPage(int maxPage) {
		this.maxPage = maxPage;
	}


	public int getStartPage() {
		return startPage;
	}


	public void setStartPage(int startPage) {
		this.startPage = startPage;
	}


	public int getEndPage() {
		return endPage;
	}


	public void setEndPage(int endPage) {
		this.endPage = endPage;
	}


	public int getPrevPage() {
		return prevPage;
	}


	public void setPrevPage(int prevPage) {
		this.prevPage = prevPage;
	}


	public int getNextPage() {
		return nextPage;
	}


	public void setNextPage(int nextPage) {
		this.nextPage = nextPage;
	}


	@Override
	public String toString() {
		return "Pagination [currentPage=" + currentPage + ", listCount=" + listCount + ", limit=" + limit
				+ ", pageSize=" + pageSize + ", maxPage=" + maxPage + ", startPage=" + startPage + ", endPage="
				+ endPage + ", prevPage=" + prevPage + ", nextPage=" + nextPage + "]";
	}
	
	// 페이징 처리에 필요한 값을 계산하는 메소드
	private void calculatePagination() {
		
		// 전체 게시글 수 : 500 // 보여지는 게시글 수 : 10
		// -> 마지막 페이지 번호는? 500 / 10 = 50
		
		// 전체 게시글 수 : 501 // 보여지는 게시글 수 : 10
		// -> 마지막 페이지 번호는? 501 / 10 = 51 (50.1 올림)
		
		maxPage = (int)Math.ceil((double)listCount / limit);
		
		// * startPage ; 목록 하단에 노출된 페이지의 시작 번호
		
		// 현재 페이지가 1~10인 경우 : 1
		// 현재 페이지가 11~20인 경우 : 11
		// 현재 페이지가 21~30인 경우 : 21
		
		startPage = (currentPage - 1) / pageSize * pageSize + 1;
		// 빼기 1 안 해도 결과 같은데.. 암튼 주의하기
		
		// * endPage; 목록 하단에 노출된 페이지의 끝 번호
		
		// 현재 페이지가 1~10인 경우 : 10
		// 현재 페이지가 11~20인 경우 : 20
		// 현재 페이지가 21~30인 경우 : 30
		
		endPage = startPage + (pageSize - 1);
		
		// 만약 endPage가 maxPage를 초과하는 경우
		if(endPage > maxPage) {
			endPage = maxPage;
		}
		
		// *prevPage(<) : 목록 하단에 노출된 번호의 이전 목록 끝 번호
		// *nextPage(>) : 목록 하단에 노출된 번호의 다음 목록 시작 번호
		
		// 현재 페이지가 1~10일 경우
		// < : 1 페이지 
		// > : 11 페이지
		
		// 현재 페이지가 11~20일 경우
		// < : 10 페이지
		// > : 21 페이지
		
		// 현재 페이지가 41~50일 경우(maxPage가 50)
		// < : 40
		// > : 50
		
		if(currentPage <= pageSize) { // ex) 페이지가 1~10 사이
			prevPage = 1;
		} else {
			prevPage = startPage - 1;
		}
		
		if(endPage == maxPage) {
			nextPage = maxPage;
		} else {
			nextPage = endPage + 1;
		}
		
		
		
		
		
		
		
	}
	

}

Servlet

map = service.selectBoardList(type,cp);

service

/** 게시글 목록 조회 service
	 * @param type
	 * @param cp
	 * @return map
	 * @throws Exception
	 */
	public Map<String, Object> selectBoardList(int type, int cp) throws Exception{
		
		Connection conn = getConnection();
		
		// 1. 게시판 이름 조회 DAO 호출
		String boardName = dao.selectBoardName(conn, type);
		
		// 2-1. 특정 게시판 전체 게시글 수 조회 DAO 호출
		int listCount = dao.getListCount(conn, type);
		
		// 2-2. 전체 게시글 수 + 현재 페이지(cp)를 이용해 페이지네이션 객체 생성
		Pagination pagination = new Pagination(cp, listCount);
		
		// 3. 게시글 목록 조회
		List<Board> boardList = dao.selectBoardList(conn, pagination, type);
		
		// 4. Map 객체를 생성하여 1,2,3 결과 객체를 모두 저장
		Map<String, Object> map = new HashMap<String, Object>();
		
		map.put("boardName", boardName);
		map.put("pagination", pagination);
		map.put("boardList", boardList);
		
		close(conn);
		
		return map; // Map 객체 반환
	}

DAO

/** 게시판 이름 조회 DAO
	 * @param conn
	 * @param type
	 * @return boardName
	 * @throws Exception
	 */
	public String selectBoardName(Connection conn, int type) throws Exception {
		
		String boardName = null;
		
		try {
			
			
			String sql = prop.getProperty("selectBoardName");
			
			pstmt = conn.prepareStatement(sql);
			
			pstmt.setInt(1, type);
			
			rs = pstmt.executeQuery();
			
			if(rs.next()) {
				boardName = rs.getString(1);
			}
			
			
		} finally {
			close(rs);
			close(pstmt);
		}
		
		return boardName;
	}
<!-- 게시판 이름 조회 -->
	<entry key="selectBoardName">
		SELECT BOARD_NM FROM BOARD_TYPE 
		WHERE BOARD_CD = ?
	</entry>

/** 특정 게시판 글 수 조회 DAO
	 * @param conn
	 * @param type
	 * @return ListCount
	 * @throws Exception
	 */
	public int getListCount(Connection conn, int type) throws Exception {
		
		int listCount = 0;
		
		try {
			
			String sql = prop.getProperty("getListCount");
			
			pstmt = conn.prepareStatement(sql);
			
			pstmt.setInt(1, type);
			
			rs = pstmt.executeQuery();
			
			if(rs.next()) {
				listCount = rs.getInt(1);
			}
			
		} finally {
			close(rs);
			close(pstmt);
		}
		
		
		return listCount;
	}
<!-- 특정 게시판 글 수 조회 -->
	<entry key="getListCount">
		SELECT COUNT(*) FROM BOARD 
		WHERE BOARD_CD = ?
		AND BOARD_ST = 'N'
	</entry>

/** 특정 게시판 글 목록 조회 DAO
	 * @param conn
	 * @param pagination
	 * @param type
	 * @return boarList
	 * @throws Exception
	 */
	public List<Board> selectBoardList(Connection conn, Pagination pagination, int type) throws Exception {
		
		List<Board> boardList = new ArrayList<Board>();
		
		try {
			
			String sql = prop.getProperty("selectBoardList");
			
			// BETWEEN 구문에 들어갈 범위 계산
			int start = (pagination.getCurrentPage()-1) * pagination.getLimit() +1;
			
			int end = start + pagination.getLimit() -1;
			
			pstmt = conn.prepareStatement(sql);
			
			pstmt.setInt(1, type);
			pstmt.setInt(2, start);
			pstmt.setInt(3, end);
			
			rs = pstmt.executeQuery();
			
			while(rs.next()) {
				Board board = new Board();
				
				board.setBoardNo(rs.getInt("BOARD_NO"));
				board.setBoardTitle(rs.getString("BOARD_TITLE"));
				board.setMemberNickname(rs.getString("MEMBER_NICK"));
				board.setCreateDate(rs.getString("CREATE_DT"));
				board.setReadCount(rs.getInt("READ_COUNT"));
				board.setThumbnail(rs.getString("THUMBNAIL"));
				
				boardList.add(board);
			}
			
			
		} finally {
			close(rs);
			close(pstmt);
		}
		
		return boardList;
	}

jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 


<!-- map에 저장된 값을 각각 변수에 저장 -->
<c:set var="boardName" value="${map.boardName}" />
<c:set var="pagination" value="${map.pagination}" />
<c:set var="boardList" value="${map.boardList}" />

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>${boardName}</title>

    <link rel="stylesheet" href="${contextPath}/resources/css/boardList-style.css">

    <link rel="stylesheet" href="${contextPath}/resources/css/main-style.css">

    <script src="https://kit.fontawesome.com/8f020b2fa9.js" crossorigin="anonymous"></script>
</head>
<body>
    <main>
        <jsp:include page="/WEB-INF/views/common/header.jsp" />

       <%-- 검색을 진행한 경우 key, query를 쿼리스트링 형태로 저장한 변수 생성 --%>
       <c:if test="${!empty param.key}">
            <c:set var="sURL" value="&key=${param.key}&query=${param.query}" />
       </c:if>

       

        <section class="board-list">

            <h1 class="board-name">${boardName}</h1>

            <c:if test="${!empty param.key}">
                <h3 style="margin-left: 30px;">"${param.query}" 검색 결과</h3>
            </c:if>

            <div class="list-wrapper">

                <table class="list-table">
                    <thead>
                        <tr>
                            <th>글번호</th>
                            <th>제목</th>
                            <th>작성자</th>
                            <th>작성일</th>
                            <th>조회수</th>
                        </tr>
                    </thead>

                    <tbody>

                        <c:choose>

                            <c:when test="${empty boardList}">
                                <!-- 게시글 목록 조회 결과가 비어있다면 -->
                                <tr>
                                    <th colspan="5">게시글이 존재하지 않습니다.</th>
                                </tr>
                                
                            </c:when>

                            <c:otherwise>
                                <!-- 게시글 목록 조회 결과가 비어있지 않다면 -->

                                <!-- 향상된 for문처럼 사용 -->
                                <c:forEach var="board" items="${boardList}">

                                    <tr>
                                        <td>${board.boardNo}</td>
                                        <td>
                                            <c:if test="${!empty board.thumbnail}">
                                                <img src="${contextPath}${board.thumbnail}" class="list-thumbnail">
                                            </c:if>
                                        
                                            <a href="detail?no=${board.boardNo}&cp=${pagination.currentPage}&type=${param.type}${sURL}">${board.boardTitle}</a>
                                        </td>
                                        <td>${board.memberNickname}</td>
                                        <td>${board.createDate}</td>
                                        <td>${board.readCount}</td>
                                    </tr>

                                </c:forEach>

                            </c:otherwise>

                        </c:choose>

                    </tbody>

                </table>

            </div>

            <div class="btn-area">

                <c:if test="${!empty loginMember}">
                    <!-- /community/board/write -->
                    <button id="insertBtn" onclick="location.href='write?mode=insert&type=${param.type}&cp=${param.cp}'">글쓰기</button>
                </c:if>

            </div>

           

            <div class="pagination-area">

                <!-- 페이지네이션 a태그에 사용될 공통 주소를 저장한 변수 선언 -->
                <c:set var="url" value="list?type=${param.type}&cp="></c:set>


                <ul class="pagination">

                    <!-- 첫 페이지로 이동 -->
                    <li><a href="${url}1${sURL}">&lt;&lt;</a></li>

                    <!-- 이전 목록 마지막 번호로 이동 -->
                    <li><a href="${url}${pagination.prevPage}${sURL}">&lt;</a></li>

                    
                    <!-- 범위가 정해진 일반 for문 사용 -->
                    <c:forEach var="i" begin="${pagination.startPage}" end="${pagination.endPage}" step="1">

                    <c:choose>
                        <c:when test="${i == pagination.currentPage}">
                            <li><a class="current">${i}</a></li>
                        </c:when>

                        <c:otherwise>
                            <li><a href="${url}${i}${sURL}">${i}</a></li>
                        </c:otherwise>

                    </c:choose>

                    </c:forEach>
                  

                    <!-- 다음 목록 시작 번호로 이동 -->
                    <li><a href="${url}${pagination.nextPage}${sURL}">&gt;</a></li>

                    <!-- 끝 페이지로 이동 -->
                    <li><a href="${url}${pagination.maxPage}${sURL}">&gt;&gt;</a></li>
                </ul>
            </div>

            <!-- /board/list?type=1&cp=3 -->

            <!-- /board/list?type=1&key=t&query=안녕 -->
            <form action="list" method="get" id="boardSearch" onsubmit="return searchValidate()">
                <input type="hidden" name="type" value="${param.type}">

                <select name="key" id="search-key">
                    <option value="t">제목</option>
                    <option value="c">내용</option>
                    <option value="tc">제목 + 내용</option>
                    <option value="w">작성자</option>

                </select>
                
                <input type="text" name="query" id="search-query" placeholder="검색어를 입력해주세요.">

                <button>검색</button>
            </form>

        </section>
    </main>

    <div class="modal">
        <span id="modal-close">&times;</span>
        <img id="modal-image" src="${contextPath}/resources/images/user.png">
    </div>

    <jsp:include page="/WEB-INF/views/common/footer.jsp" />

    <script src="${contextPath}/resources/js/board/board.js"></script>
</body>
</html>
profile
개발 일지

0개의 댓글