Programming Language/Javascript, ...

웹페이지 만들기(6) - 일반 게시판(목록 조회, 페이징 처리)

Ma_Sand 2022. 5. 11. 18:32
반응형

menubar

<div class="menu"><a href="<%=contextPath%>/list.bo?cpage=1">일반게시판</a></div>

 

 

 

 

Board

- DB에 있는 Board 테이블의 컬럼명과 컬럼타입을 java로 필드부에 선언한다.

- 기본 생성자와 매개변수 생성자, setter/getter 메소드, toString 메소드를 생성한다.

public class Board {
    private int boardNo; //	BOARD_NO	NUMBER
    private int boardType; //	BOARD_TYPE	NUMBER
    private String category;  // 작성 시 번호로 작성, 조회 시 카테고리명으로 조회 //CATEGORY_NO	NUMBER
    private String boardTitle; //	BOARD_TITLE	VARCHAR2(100 BYTE)
    private String boardContent; //	BOARD_CONTENT	VARCHAR2(4000 BYTE)
    private String boardWriter; //	BOARD_WRITER	NUMBER
    private int count; //	COUNT	NUMBER
    private Date createDate; //	CREATE_DATE	DATE
    private String status; //	STATUS	VARCHAR2(1 BYTE)
	
    public Board() {
        super();
    }
    public Board(int boardNo, int boardType, String categoryNo, String boardTitle
               , String boardContent, String boardWriter, int count, Date createDate
               , String status) {
        super();
        this.boardNo = boardNo;
        this.boardType = boardType;
        this.category = categoryNo;
        this.boardTitle = boardTitle;
        this.boardContent = boardContent;
        this.boardWriter = boardWriter;
        this.count = count;
        this.createDate = createDate;
        this.status = status;
    }
	
    public Board(int boardNo, String category, String boardTitle, String boardWriter
               , int count, Date createDate) {
        super();
        this.boardNo = boardNo;
        this.category = category;
        this.boardTitle = boardTitle;
        this.boardWriter = boardWriter;
        this.count = count;
        this.createDate = createDate;
    }
    public int getBoardNo() {
        return boardNo;
    }
    public void setBoardNo(int boardNo) {
        this.boardNo = boardNo;
    }
    public int getBoardType() {
        return boardType;
    }
    public void setBoardType(int boardType) {
        this.boardType = boardType;
    }
    public String getCategory() {
        return category;
    }
    public void setCategory(String category) {
        this.category = category;
    }
    public String getBoardTitle() {
        return boardTitle;
    }
    public void setBoardTitle(String boardTitle) {
        this.boardTitle = boardTitle;
    }
    public String getBoardContent() {
        return boardContent;
    }
    public void setBoardContent(String boardContent) {
        this.boardContent = boardContent;
    }
    public String getBoardWriter() {
        return boardWriter;
    }
    public void setBoardWriter(String boardWriter) {
        this.boardWriter = boardWriter;
    }
    public int getCount() {
        return count;
    }
    public void setCount(int count) {
        this.count = count;
    }
    public Date getCreateDate() {
        return createDate;
    }
    public void setCreateDate(Date createDate) {
    this.createDate = createDate;
    }
    public String getStatus() {
        return status;
    }
    public void setStatus(String status) {
        this.status = status;
    }
    @Override
    public String toString() {
        return "Board [boardNo=" + boardNo + ", boardType=" + boardType + ", category=" 
                + category + ", boardTitle=" + boardTitle + ", boardContent=" 
                + boardContent + ", boardWriter=" + boardWriter + ", count=" + count
                + ", createDate=" + createDate + ", status=" + status + "]";
    }
}

 

 

 

 

boardListView

- 메뉴바.jsp를 include하여 메뉴바에서 일반게시판을 클릭했을 때 해당 화면이 보이도록 한다.

- 게시글 목록을 테이블로 형성한다.

  · 게시글이 없으면 리스트를 isEmpty()로 확인해서 '작성된 게시글이 없다'고 출력 

  · 게시글이 있으면 Board 객체를 향상된 for문으로 list를 뽑아 출력

- 페이징 처리

  · 맨 위에 스크립틀릿으로 Controller에서 작성한 변수들을 객체로 모아놓은 PageInfo와 ArrayList<Board>로

     선언한 리스트를 작성

  · PageInfo에서 선언한 변수 중 필요한 부분만 가져와 getter 메소드를 이용하여 스크립틀릿에 작성

  · currentPage(현재 페이지)가 1이 아닐 때, &lt; 버튼 클릭 시 currentPage-1로 이동

  · i가 startPage부터 endPage까지 반복하는 동안,

      i가 currentPage가 아닐 때, i 버튼 클릭 시 i번 페이지로 이동

      그 외의 경우(i가 currentPage일 때)에는 i 버튼 클릭 시 페이지 이동X(disabled)

  · currentPage가 maxPage가 아닐 때, &gt; 버튼 클릭 시 currentPage+1로 이동

<%@ page import="com.kh.common.PageInfo, java.util.ArrayList, com.kh.board.model.vo.Board" %>
<%
    PageInfo pi = (PageInfo)request.getAttribute("pi");
    ArrayList<Board> list = (ArrayList<Board>)request.getAttribute("list");
	
    int currentPage = pi.getCurrentPage();
    int startPage = pi.getStartPage();
    int endPage = pi.getEndPage();
    int maxPage = pi.getMaxPage();
%>


<%@ include file="/views/common/menubar.jsp"%>
    <div class="outer">
        <br>
        <h2 align="center">일반게시판</h2>
        <table align="center" class="list-area">
            <thead>
                <tr>
                    <th width="70">글번호</th>
                    <th width="70">카테고리</th>
                    <th width="300">제목</th>
                    <th width="100">작성자</th>
                    <th width="50">조회수</th>
                    <th width="100">작성일</th>
                </tr>
            </thead>
            <tbody>
                <%if(list.isEmpty()) {%>
                    <tr>
                        <td colspan="6">작성된 게시글이 없습니다.</td>
                    </tr>
                <%} else{%>
                    <%for(Board b : list) {%>
                        <tr>
                            <td><%=b.getBoardNo() %></td>
                            <td><%=b.getCategory() %></td>
                            <td><%=b.getBoardTitle() %></td>
                            <td><%=b.getBoardWriter() %></td>
                            <td><%=b.getCount() %></td>
                            <td><%=b.getCreateDate() %></td>
                        </tr>
                    <%} %>
                <%} %>
            </tbody>
        </table>
        <div class="paging-area" align="center">
            <%if(currentPage != 1) {%>
            <button onclick="location.href='<%=contextPath%>/list.bo?cpage=<%=currentPage-1%>
            '">&lt;</button>
            <%} %>
            <%for(int i = startPage; i < endPage + 1; i++) {%>
                <%if(i != currentPage) {%>
                <button onclick="location.href='<%=contextPath%>/list.bo?cpage=<%=i%>'">
                <%=i %></button>
                <%} else {%>
                    <button disabled><%=i %></button>
                <%} %>
            <%} %>
            <%if(currentPage != maxPage) {%>
            <button onclick="location.href='<%=contextPath%>/list.bo?cpage=<%=currentPage+1%>
            '">&gt;</button>
            <%} %>
        </div>
    </div>

 

 

 

 

BoardListController

- servlet으로 작성한다.

- 페이징 처리할 controller

- 매핑값 list.bo

- maxPage(페이지의 총 개수) 구하기

  · listCount(게시글의 총 개수)를 double 타입으로 형변환한 후 listCount를 boardLimit(한 페이지에서 보여지는

     게시글의 개수)으로 나눈다.

  · 이때 listCount가 97이고 boardLimit이 10일 경우에 maxPage가 9.7이 되는데 어떠한 사이트를 보든

     9.7페이지란 없다. 이와 같이 보통의 게시판들은 새로운 글이 계속 올라와서 listCount/boardLimit을 했을 때

     나머지가 0이 되는 경우는 거의 없으므로 Math.ceil() 메소드를 사용하여 올림 처리를 해주면 된다.

  · Math.ceil()은 double형으로 반환되므로 해당 결과값을 int 타입으로 형변환해준다.

- startPage(페이지 하단에 보여지는 페이징의 시작 숫자) 구하기

  · pageLimit=5일 때 startPage는 1, 6, 11, 16, ..., (5n+1)

     pageLimit=10일 때 startPage는 1, 11, 21, 31, ..., (10n+1)

     ⇒ startPage = n*pageLimit+1

  · startPage=1일 경우 n=0, startPage=11일 경우 n=1이고, pageLimit이 10이므로 페이지 하단에 보여지는

     페이징은 1~10 / 11~20이 된다. 그런데 이때 페이징 10은 10으로 나누면 1이 나오고, 20은 2가 나와서

     페이징 10, 20은 각각 다음 페이지에서 처리되어 1~9 / 10~19 / 20~29가 된다.

  · 이럴 땐 해당 범위에다 -1을 해주면 해결된다. 

     ⇒ n = (currentPage-1)/pageLimit

     ⇒ startPage = (currentPage-1)/pageLimit * pageLimit + 1

- endPage(페이지 하단에 보여지는 페이징 끝 숫자) 구하기

  · pageLimit=10일 때, startPage=1, endPage=10 / startPage=11, endPage=20

     ⇒ endPage = startPage + pageLimit - 1

@WebServlet("/list.bo")
public class BoardListController extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    public BoardListController() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        int listCount; // 현재 총 게시글 개수
        int currentPage; // 현재 페이지(사용자가 요청한 페이지)
        int pageLimit; // 페이지 하단에 보이는 페이징 페이지 처리 최대 개수
        int boardLimit; // 한 페이지에서 보여줄 게시글의 개수
        int maxPage; // 맨뒤 페이지의 페이지 수(총 페이지 개수)
        int startPage; // 페이지 하단에 보여질 페이징 시작 수
        int endPage; // 페이지 하단에 보여질 페이징 끝 수
		
        listCount = new BoardService().selectListCount();
        currentPage = Integer.parseInt(request.getParameter("cpage"));
        pageLimit = 10;
        boardLimit = 10;
		
        maxPage = (int)(Math.ceil((double)listCount / boardLimit));
        startPage = (currentPage-1)/pageLimit * pageLimit + 1;
        endPage = startPage + pageLimit - 1;
		
        // maxPage가 11일 경우, 원래대로 작성하면 endPage가 20이 나오므로 11로 변경해주는
        // 처리를 해야 한다.
        if(endPage > maxPage) {
            endPage = maxPage;
        }
		
        // 1. 페이징바를 만들 때 필요한 객체
        PageInfo pi = new PageInfo(listCount, currentPage, pageLimit, boardLimit, maxPage, startPage, endPage);
		
        // 2. 사용자가 요청한 페이지(currentPage)에 보여질 게시글 리스트 요청
        ArrayList<Board> list = new BoardService().selectList(pi);
		
        request.setAttribute("pi", pi);
        request.setAttribute("list", list);
        request.getRequestDispatcher("views/board/boardListView.jsp").forward(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

 

 

 

 

PageInfo

- 위의 BoardListController에서 선언된 변수가 많으므로 PageInfo에 모아서 처리한다.

public class PageInfo {
    int listCount;
    int currentPage;
    int pageLimit;
    int boardLimit;
    int maxPage;
    int startPage;
    int endPage;
	
    public PageInfo() {
        super();
    }
    public PageInfo(int listCount, int currentPage, int pageLimit, int boardLimit, int maxPage, int startPage,
            int endPage) {
        super();
        this.listCount = listCount;
        this.currentPage = currentPage;
        this.pageLimit = pageLimit;
        this.boardLimit = boardLimit;
        this.maxPage = maxPage;
        this.startPage = startPage;
        this.endPage = endPage;
    }
    public int getListCount() {
        return listCount;
    }
    public void setListCount(int listCount) {
        this.listCount = listCount;
    }
    public int getCurrentPage() {
        return currentPage;
    }
    public void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }
    public int getPageLimit() {
        return pageLimit;
    }
    public void setPageLimit(int pageLimit) {
        this.pageLimit = pageLimit;
    }
    public int getBoardLimit() {
        return boardLimit;
    }
    public void setBoardLimit(int boardLimit) {
        this.boardLimit = boardLimit;
    }
    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;
    }
    @Override
    public String toString() {
        return "PageInfo [listCount=" + listCount + ", currentPage=" + currentPage + ", pageLimit=" + pageLimit
                + ", boardLimit=" + boardLimit + ", maxPage=" + maxPage + ", startPage=" + startPage + ", endPage="
                + endPage + "]";
    }
}

 

 

 

 

BoardService

- BoardListController에서 넘어온 selectListCount()와 selectList(PageInfo pi)를 받아 BoardDao로 넘기고,

   다시 받아 Controller로 넘긴다.

- Connection 객체 생성

public int selectListCount() {
    Connection conn = getConnection();
    int listCount = new BoardDao().selectListCount(conn);
		
    close(conn);
		
    return listCount;
}

public ArrayList<Board> selectList(PageInfo pi) {
    Connection conn = getConnection();
    ArrayList<Board> list = new BoardDao().selectList(conn, pi);
    close(conn);
		
    return list;
}

 

 

 

board-mapper

- xml 파일로 작성한다.

- selectListCount는 Board 테이블에서 STATUS가 'Y'이고 BOARD_TYPE이 1인 것 중 모든 조회수를 조회한다.

- selectList

  · Board 테이블(별칭 B)에서 BOARD_NO과 CATEGORY_NAME, BOARD_TITLE, USER_NAME, COUNT,

     CREATE_DATE를 조회한다. 이때 MEMBER 테이블의 USER_NO를 BOARD_WRITER와 조인하고, 

     CATEGORY 테이블의 CATEGORY_NO와 조인한다. 그리고 이 구문의 조건은 B의 STATUS가 'Y'이고

     BOARD_TYPE이 1이어야 한다.

  · 위의 테이블을 별칭 A로 놓고 ROWNUM(별칭 RNUM)을 A와 함께 조회한다.

  · 그리고 RNUM과 A.*를 조회한 구문을 하나의 테이블로 놓고, 이 테이블에서 RNUM이 위치홀더 사이인

     것을 모두 조회한다.

<entry key="selectListCount">
    SELECT COUNT(*) COUNT
    FROM BOARD
    WHERE STATUS='Y'
    AND BOARD_TYPE=1
</entry>
	
<entry key="selectList">
    SELECT * 
    FROM
        (
        SELECT ROWNUM RNUM, A.*
        FROM
            (
            SELECT BOARD_NO, CATEGORY_NAME, BOARD_TITLE, USER_NAME, COUNT, CREATE_DATE
            FROM BOARD B
            JOIN MEMBER ON (BOARD_WRITER = USER_NO)
            JOIN CATEGORY USING (CATEGORY_NO)
            WHERE B.STATUS='Y'
            AND BOARD_TYPE = '1'
            ORDER BY CREATE_DATE DESC
            ) A
        )
    WHERE RNUM BETWEEN ? AND ?
</entry>

 

 

 

 

BoardDao

- Properties를 이용하기 위해 Properties 객체 생성 후 board-mapper.xml을 가져온다.

  · Properties변수명.loadFromXML(new FileInputStream(해당Dao.class.getResource(xml파일경로).getPath()));

- selectListCount()는 나올 행이 하나이기 때문에 while문이 아니라 if문으로 작성한다.

- selectList()는 결과값이 여러 행으로 나올 수 있기 때문에 list를 만들고 while문으로 작성한다.

  · 위치홀더에 넣을 범위 구하기

    boardLimit=10일 때 currentPage=1이면 시작값 1, 끝값 10이고

                               currentPage=2이면 시작값 11, 끝값 20이다.

    시작값 = (currentPage-1) * boardLimit + 1

    끝값 = currentPage * boardLimit

public int selectListCount(Connection conn) {
    int listCount = 0;
    PreparedStatement pstmt = null;
    ResultSet rset = null;
    String sql = prop.getProperty("selectListCount");
    try {
        pstmt = conn.prepareStatement(sql);
        rset = pstmt.executeQuery();
			
        if(rset.next()) {
            listCount = rset.getInt("COUNT");
        } 
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        close(rset);
        close(pstmt);
    }
    return listCount;
}

public ArrayList<Board> selectList(Connection conn, PageInfo pi) {
    ArrayList<Board> list = new ArrayList<>();
    PreparedStatement pstmt = null;
    ResultSet rset = null;
    String sql = prop.getProperty("selectList");
		
    try {
        pstmt = conn.prepareStatement(sql);

        int startRow = (pi.getCurrentPage()-1) * pi.getBoardLimit() +1;
        int endRow = pi.getCurrentPage() * pi.getBoardLimit();
			
        pstmt.setInt(1, startRow);
        pstmt.setInt(2, endRow);
			
        rset = pstmt.executeQuery();
			
        while(rset.next()) {
            list.add(new Board(rset.getInt("BOARD_NO")
                             , rset.getString("CATEGORY_NAME")
                             , rset.getString("BOARD_TITLE")
                             , rset.getString("USER_NAME")
                             , rset.getInt("COUNT")
                             , rset.getDate("CREATE_DATE")));
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        close(rset);
        close(pstmt);
    }
    return list;
}

 

반응형