페이징처리
샘플데이터를 다량으로 만들어서
하단에 페이징 처리를 해보자
<< 이전포스팅에서 완료된 요청 | 이번포스팅에서 구현할 요청 >>
| 기능 | url요청 | 요청시 전달값 | 응답페이지 또는 url재요청 | |
| /web | index.jsp | |||
| 로그인요청 | /login.me | userId=?&userPwd=? | 실패시 | views/common/errorPage.jsp |
| 성공시 | /web url재요청=> index.jsp | |||
| 로그아웃요청 | /logout.me | /web url재요청=> index.jsp | ||
| 회원가입페이지 | /enrollForm.me | views/member/memberEnrollForm.jsp | ||
| 회원가입요청 | /insert.me | userId=? ... 등 | 실패시 | views/common/errorPage.jsp |
| 성공시 | /web url재요청 => index.jsp | |||
| 마이페이지요청 | /myPage.me | 로그인전 | /web url재요청 => index.jsp | |
| 로그인후 | views.member/myPage.jsp | |||
| 정보변경요청 |
/update.me |
userId=? ... 등 | 실패시 | view/common/errorPage.jsp |
| 성공시 | /myPage.me url재요청 | |||
| 공지사항 목록 | /list.no | views/notice/noticeListView.jsp | ||
| 공지사항글쓰기 | /enrollForm.no | views/noticeEnrollForm.jsp | ||
| 공지사항등록 | /insert.no | title=?&content=? | 실패시 | views/common/errorPage.jsp |
| 성공시 | /list.no url재요청 | |||
| 공지 - 상세페이지 | /detail.no | no=? (수기기재) | 실패시 | views/common/errorPage.jsp |
| 성공시 | views/notice/noticeDetailView.jsp | |||
| 공지 - 수정페이지 | /updateForm.no | no=? | views/notice/noticeUpdateForm.jsp | |
| 공지 - 수정요청 | /update.no | no=?&title=?&content=? | 실패시 | views/common/errorPage.jsp |
| 성공시 | /detail.no?no=XX url재요청 | |||
| 일반게시판 목록 | /list.bo | cpage=? | views/board/boardListView.jsp |
준비하기
데이터를 만들어 db에 삽입하고,
페이징을 위한 일반게시판을 만들어본다.
STEP1) 다량의 데이터(엑셀) INSERT하기

- 엑셀의 열은 테이블의 칼럼을 순서대로 쓴다
데이터값으로 SEQUENCE 발생 구문을 넣을 수 있다. - sqldeveloper 데이터삽입 :
테이블 오른클릭 - [데이터임포트] - [찾아보기] - 파일 경로 지정후 열기
>> [헤더]를 체크해서 첫번째 행(컬럼명 쓴 행)은 제외
>> 워크시트가 여러개라면 해당되는것으로 지정
>> [다음] - [임포트방식] : 삽입
>> [다음] - [다음]
- 소스데이터열을 클릭해서 데이터가 잘 들어갔는지 확인
형식이 다른경우 수정하기(Date타입 등)
- SEQUENCE 쓴 칼럼이 넘버타입이라고 경고가 되어있을 것.
(무시해도됨)
>> 완료 누르면 삽입실패 팝업 - 경고무시에 [예]
>> 자동 삽입이 안되고 스크립트 구문이 뜸
>> 스크립트 실행 및 commit - 공공데이터 로 다량의 데이터 얻기 :
https://www.data.go.kr/
>> 정부에서 제공하는 무료데이터
검색했을 때 나오는 CSV가 엑셀파일이다.
STEP2) Board.java
- 생성위치 : com.br.board.model.vo
- 게시글을 저장할 수 있는 vo클래스를 작성한다.
- 필드의 타입은 보통 db와 일치시키지만, 숫자와 문자열 둘다 활용할 경우 String으로 지정한다.
- 작성기능시에는 번호 사용, 조회시에는 명칭을 사용하는 경우
- 이번 예제에서는 category와 boardWriter - 오라클의 Date타입에 매칭되는 필드는 Date타입이 아닌 String으로도 지정할 수 있다.
(이때, 조회 시 to_char 함수를 사용해서 문자열로 변환후 가져올수있다.)
STEP3) Category.java
- 생성위치 : com.br.board.model.vo
- 카테고리를 저장할 수 있는 vo클래스를 작성한다.
STEP4) menubar.jsp(수정)
- 메뉴바의 일반게시판 버튼 클릭시 목록으로 가게끔 href를 작성한다.
처리할 서블릿의 매핑값 list.bo - 요청하는 페이지에 대한 정보 cpage (current page)에 담아 쿼리스트링을 보낸다.
>> 메뉴바에서 버튼클릭시에는 cpage=1로 설정한다.
<div class="menu"><a href="<%=contextPath%>/list.bo?cpage=1">일반게시판</a></div>
서블릿 : 페이징처리에 필요한 변수들 설정하기
페이징에 필요한 변수들을 알아보고,
해당 변수들을 담아 이동시킬 수 있는 vo객체를 만들어
다른게시판의 페이징처리에도 활용한다.
STEP1 ) PageInfo.java
- 생성위치 : com.br.common.model.vo
- 페이징 처리할때마다 데이터들을 담아둘 객체가 필요할때가 있다.
>> 이때 사용할 용도로 vo클래스 생성 - 페이징용 필드 :
1) 값을 마음대로 정하는 정하는 필드
int listCount : 현재 게시글 총 갯수
int currentPage : 사용자가 요청한 페이지(== 현재페이지)
int pageLimit : 페이지 하단에 보여질 페이징바의 페이지 최대갯수(몇개 단위씩 보여지게 할건지)
int boardLimit : 한 페이지에 보여질 게시글의 최대갯수(몇개 단위씩 보여지게 할건지)
2) 상위 4개를 연산하여 구하는 필드
int maxPage : 가장 마지막 페이지 번호 (총 페이지 수)
int startPage : 사용자가 요청한 페이지로 갔을때, 하단의 페이징바의 시작수
int endPage : 사용자가 요청한 페이지로 갔을때, 하단의 페이징바의 끝수
STEP2) BoardListController.java
- 생성위치 : com.br.board.controller
서블릿 / 매핑값 list.bo - 일반게시판 목록을 요청할때 db에서 필요한 데이터를 가져와 포워딩하는 서블릿
이때, cpage라는 키값으로 현재페이지 정보 넘어와야함 - listCount :
db에서 count(*)로 총 게시글 갯수를 구한다. - currentPage :
해당 서블릿 요청시에 쿼리스트링으로 함께 넘어온 값(cpage)을 넣는다.
사용자가 요청한 페이지(== 현재페이지) - pageLimit :
페이징바에 몇개의 페이지씩 표시할건지 정해서 값을 넣는다.
현재 페이지 갯수가 최대값보다 적을시 더 적게 표현된다. - boardLimit :
한 페이지당 몇개의 게시글을 표시할건지 갯수를 정한다. - 나머지 변수는 이어서..
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// * listCount : 총 게시글 갯수
listCount = new BoardService().selectListCount();
// * currentPage : 사용자가 요청한 페이지 (현재 페이지)
currentPage = Integer.parseInt(request.getParameter("cpage"));
// * pageLimit : 페이징바의 페이지 최대 갯수
pageLimit = 10;
// * boardLimit : 한 페이지당 보여질 게시글의 최대 갯수
boardLimit = 10;
.....(계속)
}
STEP3) board-mapper.xml
- 총 게시글 갯수를 구할 sql문을 작성해놓는다.
<entry key="selectListCount">
SELECT
COUNT(*) count
FROM BOARD
WHERE BOARD_TYPE=1
AND STATUS='Y'
</entry>
STEP4) BoardService.java
- 생성위치 : com.br.board.model.service
- 총 게시글 수를 반환할 selectListCount() 메소드 생성
public int selectListCount() {
Connection conn = getConnection();
int listCount = new BoardDao().selectListCount(conn);
close(conn);
return listCount;
}
STEP5) BoardDao.java
- 생성위치 : com.br.board.model.dao
- 필드로 Properties 객체 만들고 기본생성자에서 board-mapper.xml 연결시켜놓기
- selectListCount(conn) 메소드 생성
- 데이터를 꺼낼때는 db에서 조회되는 칼럼명을 그대로 사용해야하는데,
컬럼명이 함수식(ex : COUNT(*) )인 경우 까다로워져서 별칭을 부여하곤 함.
public int selectListCount(Connection conn) {
//select => ResultSet(한행)=> 값 1개로 반환되므로 vo객체에 담을게 아니라 int에 담기
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;
}
STEP6) BoardListController.java (수정)
- 나머지 변수들 3개의 값 구하기
- maxPage
- 제일 마지막 페이지 수
>> 총 게시글(listCount)과 한페이지에 나오는 페이지수(boardLimit)에 따라 마지막 페이지 번호가 결정된다.
>>예) 총 게시글이 100개라면 페이지수는 총10개, 105개라면 11개
>>공식 : (총게시글 / 한페이지당게시글)을 실수값으로 구한 뒤 올림처리
실수값으로 연산하기 위해 하나만 실수형태로 바꾸면 된다.(나머지값은 자동형변환)
Math.ceil() 올림처리한 값을 실수로 반환하므로 다시 int 강제형변환
maxPage = (int)Math.ceil((double)listCount/boardLimit);
- startPage
- 페이징바의 시작수
>> 한번에 보여지는 페이징바의 최대갯수(pageLimit)와 사용자가 요청한 현재페이지(currentPage)에 따라 번호가 결정된다
>> 예) 페이징바가 10개씩 보인다면 startPage는 1, 11, 21, 31, ...
20개씩 보인다면 startPage는 1, 21, 41, 61, ...
>>공식 : startPage = n*pageLimit + 1
**n은 사용자의 요청값(currentPage==cpage)과 관련된 숫자로 요청값이 1~10 이면 n은 0, 11~20이면 1여야함.(페이지리밋은 10일때)
>>이때, n은 나눗셈의 몫(나머지제외)으로 구할 수 있다. n = (currentPage-1)/pageLimit
startPage = (currentPage-1)/pageLimit * pageLimit+1;
- endPage
- 사용자 요청페이지에서의 페이징바 끝수
>>startPage가 1이고 pageLimit이 10이라면 페이징바의 끝수는 11
단, endPage가 maxPage보다 작을경우 maxPage가 endPage가 됨.(페이징바의 끝부분)
endPage = startPage + pageLimit -1;
if(endPage>maxPage) {endPage = maxPage;}
포워딩 및 페이징바 구현
서블릿에서 포워딩을 마치고
목록 페이지 화면구현에서 페이징바를 표현시켜보자
STEP1) board-mapper.xml (수정)
- 현재 요청한 페이지(currentPage)에 보여질 게시글 리스트 boardLimit수 만큼 조회하면 된다.
- date타입을 vo때 계획했던대로 TO_CHAR()로 변경해준다.(함수사용 후 별칭필수)
- ROWNUM 이 1부터 체크하지 않으면 조회 안되는 케이스발생
>> ROWNUM은 데이터들을 걸러낸 후 '1부터' 부여되기 때문에 WHERE절에 1을 제외하면 조회되는 칼럼이 없어진다.(구글 키워드 'rownum=2 is not working')
>> 이때는 별칭을 부여한 후 인라인뷰로 사용하면 된다!
SELECT *
FROM (
SELECT ROWNUM RNUM, A.*
FROM (
SELECT
BOARD_NO
, CATEGORY_NAME
, BOARD_TITLE
, USER_ID
, COUNT
, TO_CHAR(CREATE_DATE, 'YYYY/MM/DD') "CREATE_DATE"
FROM BOARD B
JOIN CATEGORY USING (CATEGORY_NO)
JOIN MEMBER ON (BOARD_WRITER=USER_NO)
WHERE BOARD_TYPE=1
AND B.STATUS='Y'
ORDER
BY BOARD_NO DESC
) A
)
WHERE RNUM BETWEEN ? AND ?
STEP2) BoardListController.java (수정)
- 만들어둔 PageInfo vo클래스로 페이지 데이터 담은 후 요청처리한 후
- 포워딩하기
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
.....(이전내용 : 변수들 값 구하기)
PageInfo pi = new PageInfo(listCount, currentPage, pageLimit, boardLimit, maxPage, startPage, endPage);
// 현재 요청한 페이지(currentPage)에 보여질 게시글 리스트 boardLimit수 만큼 조회
ArrayList<Board> list = new BoardService().selectList(pi);
request.setAttribute("pi", pi);
request.setAttribute("list", list);
//응답페이지 (views/board/boardListView.jsp)
request.getRequestDispatcher("views/board/boardListView.jsp").forward(request, response);
}
STEP3) BoardService.java(수정)
- 필요한 게시글들 조회해오는 selectList(PageInfo pi) 메소드 생성
public ArrayList<Board> selectList(PageInfo pi) {
Connection conn = getConnection();
ArrayList<Board> list = new BoardDao().selectList(conn,pi);
return list;
}
STEP4) BoardDao.java(수정)
- selectList(conn,pi)메소드 생성
- sql을 완성하기 위해 필요한 변수
startRow :
가져올 게시글의 첫번째 글
(currentPage - 1)*boardLimit + 1
endRow :
가져올 게시글의 마지막 글
startRow + boardLimit + 1 - ResultSet 다수를 받을 것이므로 ArrayList<Board>로 담는다.
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);
/*
* boardLimit이 10일때, 보이는 게시글의 rownom 은
* currentPage : 1 => 시작값 1, 끝값 10
* currentPage : 2 => 시작값 11, 끝값 20
*/
int startRow = (pi.getCurrentPage()-1)*pi.getBoardLimit() + 1;
int endRow = startRow + pi.getBoardLimit() -1;
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_id")
, rset.getInt("count")
, rset.getString("create_date")));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rset);
close(pstmt);
}
return list;
}
STEP5) boardListView.jsp
- 생성위치 : webProject/src/main/webapp/views/board
- 상단에 전달받은 데이터들 꺼내놓기
- 사용자가 요청한 페이지에 따라 목록도 달라지 페이징바도 달라지는것 구현
>> 이때 첫페이지에는 이전버튼(<)이 안보이고 마지막페이지에서는 다음버튼(>)이 안보이도록 한다.
.....
<%
PageInfo pi = (PageInfo)request.getAttribute("pi");
<Board> list = (ArrayList<Board>)request.getAttribute("list");
%>
.....
<tr>
<th width="70">글번호</th>
<th width="80">카테고리</th>
<th width="300">제목</th>
<th width="100">작성자</th>
<th width="50">조회수</th>
<th width="100">작성일</th>
</tr>
<% if(list.isEmpty()) { %>
<!-- case1. 게시글이 없을 경우 -->
<tr>
<td colspan="6">조회된 게시글이 없습니다.</td>
</tr>
<%} else { %>
<!-- case2. 게시글이 있을 경우 -->
<% 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>
<%} %>
<%} %>
.....
<!-- 페이징바 영역 -->
<% if(pi.getCurrentPage()>1){ %>
<button onclick="location.href=<%=contextPath%>/list.bo?cpage=<%=pi.getCurrentPage()-1%>"><</button>
<%} %>
<% for(int p=pi.getStartPage(); p<=pi.getEndPage(); p++ ) {%>
<button onclick="location.href='<%=contextPath%>/list.bo?cpage=<%=p%>';"><%=p %></button>
<%} %>
<% if(pi.getCurrentPage() != pi.getMaxPage()) {%>
<button onclick="location.hred=<%=contextPath%>/list.bo?cpage=<%=pi.getCurrentPage()+1%>">></button>
<%} %>

'다양한 기술들 > 레거시 Web 실습' 카테고리의 다른 글
| [10] 게시판심화1 : 상세보기(+첨부파일 조회 및 다운로드) (0) | 2023.01.12 |
|---|---|
| [09] 게시판심화1 : 글쓰기(+파일첨부) (0) | 2023.01.11 |
| [07] 게시판기초 : 상세조회, 수정, 삭제 (0) | 2023.01.09 |
| [06] 게시판기초 : 일반목록, 글쓰기(+권한) (0) | 2023.01.09 |
| [05] 모달을 사용한 비밀번호변경 (0) | 2023.01.06 |
댓글