페이징처리
이전 레거시 방식에서는 페이징처리된 목록을 조회해올때
rownum으로 정렬하기위해 인라인 안에 인라인을 넣어야만 했었다.
해당 과정을 Mybatis에서 제공하는 RowBounds을 사용하면 간단하게 처리할 수 있다.
또한 페이징 데이터들을 구할때 모듈화(메소드로 정리하는것)를 활용해보자.
코드 리펙토링/ 코드모듈화
- 페이징처리에 필요한 데이터들은 다음과 같다
listCount : 총게시글 수 (select문으로 조회 필요)
currentPage : 요청한 페이지 번호 (클라이언트의요청에 따름)
pageLimit : 페이징바의 페이지갯수 (설계자가 정한다)
boardLimit : 한페이지에 보이는 게시글 갯수 (설계자가 정한다)
maxPage : 총 페이지 수
startPage : 페이징바의 시작 수
endPage : 페이징바의 끝 수 - 이때 마지막 3개 데이터는 위 4개 데이터를 연산하여 구한다.
- Pagination 클래스를 만들어서 해당과정을 static 메소드로 정리해보자.
public class Pagination {
public static PageInfo getPageInfo(int listCount, int currentPage, int pageLimit, int boardLimit) {
int maxPage = (int)Math.ceil((double)listCount/boardLimit);
int startPage = (currentPage-1)/pageLimit * pageLimit +1;
int endPage = startPage+pageLimit -1;
if(endPage>maxPage) {
endPage = maxPage;
};
PageInfo pi = new PageInfo(listCount, currentPage, pageLimit, boardLimit, maxPage, startPage, endPage);
return pi;
}
}
RowBounds 페이징을 위한 준비
- Controller 단
1. 페이징을 위한 조회(listCount, 총 게시글 수)를 해온다.
2. getPageInfo() 메소드를 통해 PageInfo 객체를 만든다.
3. 목록을 조회할 Sercive메소드를 호출하며 PageInfo 객체를 보낸다.
4. PageInfo 객체와 ArrayList<Board> 객체를 request에 담은 후 포워딩 한다. - Service 단
1. SqlSession 객체를 만든후 PageInfo객체와 함께 Dao메소드에 보낸다. - Dao 단
1. PageInfo객체의 데이터를 이용해서 offset과 limit의 데이터를 만든다.
2. offset과 limit을 매개변수로 넣어 RowBounds객체를 만든다.
3. selectList(String, Object, RowBounds) 메소드를 실행한다. - mapper 단
1. 전체 리스트를 조회해오는 select문을 작성한다.
(board_no기준으로 내림차순하는것을 잊지 않는다)
Dao상세 : RowBounds와 selectList()
- RowBounds :
Mybatis에서 페이징처리를 위해 제공하는 클래스.
RowBounds객체 생성시, 몇개의 데이터를 건너뛰고 몇개의 데이터를 조회할지 설정 가능하다.
new RowBounds(offset, limit) - offset :
- 몇개의 게시글을 건너뛸건지에 대한 값
= (currentPage-1)*boardLimit - limit :
- 몇개의 게시글을 조회할건지에 대한 값
= boardLimit
| currentPage => boardLimit이 5일때 보이는 글번호 |
offset(건너뛸 숫자) | limit(조회할 숫자) |
| 1 => 1~5번글 조회 | 0 | 5 |
| 2 => 6~10번글 조회 | 5 | 5 |
| 3 => 11~15번글 조회 | 10 | 5 |
| 결론 | (currentPage-1)*boardLimit | boardLimit |
- selectList(String, Object, RowBounds) :
selectList()는 매개변수 3개짜리가 오버로딩 되어있어서 RowBounds객체를 보낼 수 있다.
만약 sql이 완성되어 객체를 넘길필요가 없다면 두번째 자리에 null을 쓰면 된다.
ex) selectList("boardMapper.selectList", null, rowBounds); - selectList는 List<Object>로 반환하기 때문에 ArrayList로 강제형변환 해주는 것을 잊지말자
public ArrayList<Board> selectSearchList(SqlSession sqlSession, HashMap<String, String> map, PageInfo pi){
int offset = (pi.getCurrentPage()-1)*pi.getBoardLimit();
int limit = pi.getBoardLimit();
RowBounds rowBounds = new RowBounds(offset, limit);
return (ArrayList)sqlSession.selectList("boardMapper.selectSearchList", map, rowBounds);
}
ROWNUM vs RowBounds
- 기존 ROWNUM방식과 마이바티스의 RowBounds방식은 각각의 장단점이 있다.
| ROWNUM | RowBounds | |
| 장점 | 대량의 데이터도 빠르게 페이징 처리를 하여 가져올 수 있다. | 구현이 쉽고, 코드의 유지보수가 간편하다 |
| 단점 | 페이징 처리를 구현하기 위한 코드가 복잡하다. | 대량의 데이터를 사용할 경우 수행속도가 늦다 |
페이징: 화면꾸미기
가지고 온 데이터를 바탕으로 페이징 화면을 구현하는것을 연습해보자.
만약 검색결과를 나타내는 페이징데이터가 있을경우,
화면을 어떻게 구성해야하는지도 알아본다.
기본 : 단일 페이징 화면
- 검색기능이 없는 목록화면을 꾸며본다.
- 이때, 액션태그와 EL구문을 사용해서 자바구문 없이 코드를 짜보도록 한다.
<!-- 목록 영역 -->
<c:forEach var="b" items="${ list }">
<tr>
<td>${ b.boardNo }</td>
<td>${ b.boardTitle }</td>
<td>${ b.boardWriter }</td>
<td>${ b.count }</td>
<td>${ b.createDate }</td>
</tr>
</c:forEach>
...
<!-- 페이징 영역 -->
<c:if test="${ pi.currentPage ne 1 }"> <!-- 내가 보고있는 페이지가 1이 아닐경우 -->
<a href="list.bo?cpage=${ pi.currentPage -1 }">[이전]</a>
</c:if>
<c:forEach var="p" begin="${ pi.startPage }" end="${ pi.endPage }">
<a href="list.bo?cpage=${ p }">${ p }</a>
</c:forEach>
<c:if test="${ pi.currentPage ne pi.maxPage }"> <!-- 내가 보고있는 페이지가 마지막페이지가 아닐경우 -->
<a href="list.bo?cpage=${ pi.currentPage +1 }">[다음]</a>
</c:if>
심화 : 검색 페이징이 덧붙여진 화면
- 목록화면과 검색결과화면이 동일하다면 목록과 페이징바의 구성요소를 공유하게 된다.
>> request에 데이터를 담을때 동일한 키값으로 담는다.
(검색결과list==목록list, 검색결과pageInfo==목록pageInfo) - 검색 결과를 표시할 jsp단에서는 2가지 조정이 필요하다.
1. 사용자가 선택한 검색조건과 검색어를 표시한다.
>> controller단에서 condition과 keyword를 request에 담아놓은 후 화면에서 활용한다.
2. 일반목록의 기능만 하는 페이징바를 검색목록의 기능도 하도록 바꾸어야한다.
>> request에 condition이 들어있느냐 여부로 기능을 스위치한다.
<!-- ----------사용자가 입력한 검색어 표기하기---------- -->
<input type="text" name="keyword" value="${ keyword }">
<!-- ----------사용자가 선택한 검색조건 표기하기---------- -->
<script>
document.querySelector("#search-area option[value=${condition}]").selected = true;
</script>
<!-- ----------페이징바를 동적으로 스위치하기---------- -->
<div id="paging-area">
<c:choose>
<c:when test="${ empty condition }"> <!-- 일반목록인경우 -->
<c:if test="${ pi.currentPage ne 1 }">
<a href="list.bo?cpage=${ pi.currentPage -1 }">[이전]</a>
</c:if>
<c:forEach var="p" begin="${ pi.startPage }" end="${ pi.endPage }">
<a href="list.bo?cpage=${ p }">[${ p }]</a>
</c:forEach>
<c:if test="${ pi.currentPage ne pi.maxPage }">
<a href="list.bo?cpage=${ pi.currentPage +1 }">[다음]</a>
</c:if>
</c:when>
<c:otherwise> <!-- 검색목록인경우 -->
<c:if test="${ pi.currentPage ne 1 }">
<a href="search.bo?cpage=${ pi.currentPage -1 }&condition=${condition}&condition=${keyword}">[이전]</a>
</c:if>
<c:forEach var="p" begin="${ pi.startPage }" end="${ pi.endPage }">
<a href="search.bo?cpage=${ p }&condition=${condition}&condition=${keyword}">[${ p }]</a>
</c:forEach>
<c:if test="${ pi.currentPage ne pi.maxPage }">
<a href="list.bo?cpage=${ pi.currentPage +1 }&condition=${condition}&condition=${keyword}">[다음]</a>
</c:if>
</c:otherwise>
</c:choose>
</div>

'Framework > MyBatis' 카테고리의 다른 글
| <selectKey> : insert + select를 한번에 (0) | 2023.04.20 |
|---|---|
| 스프링에서 직접 트랜잭션 제어하기 : @Transactional (0) | 2023.04.19 |
| [03] SQL문 응용태그 : 동적 SQL, <association>, <collection> (0) | 2023.02.15 |
| [01] Mybatis의 CRUD 방식 (0) | 2023.02.13 |
| [00] 프레임워크 개념 / mybatis 준비 / Filter 활용 (0) | 2023.02.13 |
댓글