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이 아닐 때, < 버튼 클릭 시 currentPage-1로 이동
· i가 startPage부터 endPage까지 반복하는 동안,
i가 currentPage가 아닐 때, i 버튼 클릭 시 i번 페이지로 이동
그 외의 경우(i가 currentPage일 때)에는 i 버튼 클릭 시 페이지 이동X(disabled)
· currentPage가 maxPage가 아닐 때, > 버튼 클릭 시 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%>
'"><</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%>
'">></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;
}