저번장에서 비즈니스 계층과 영속 계층 수정했습니다.
하지만 controller는 구현하지 않았기 때문에 controller를 구현하도록 하겠습니다.
저희가 해야하는 작업은 페이징 작업할 때 화면 하단에 다음과 같은 페이지 번호를 출력해야 합니다.
- 시작 페이지 번호(StartPage) : 화면상에서 10개의 페이지 번호를 출력한다고 한다면 현재 페이지가 1에서 10사이에 있는 번호라면 시작 페이지는 1이 출력이 되야하고, 현재페이지가 13이면 시작 페이지는 11이 되야 합니다.
- 맨끝 페이지 번호(endPage) : 시작 페이지 번호부터 몇개의 번호를 보여줘야 하는지를 결정해야 합니다. 이때 전체 데이터의 개수가 필요합니다. 예를 들어 전체 데이터가 89개이고 현재 페이지가 3페이지면 시작 페이지 번호는 1이고, 끝페이지번호를 89개이니까 9페이지가 되야겠죠
- 이전 페이지(perv) : 현재 페이지의 시작 페이지가 11페이지면 이전 버튼을 클릭하여 이전 페이지를 조회해야합니다.
- 다음 페이지(next) : 현재 페이지의 끝페이지(10페이지) 이후에 더 많은 데이터가 존재하면 다음 페이지로 이동할 수 있도록 다음페이지로 가는 버튼을 만들어야 합니다.
그리고 현재 페이지이면 현재 페이지라고 사용자가 알기 쉽도록 파란색으로 활성화 시키겠습니다.
이제 페이지 번호를 출력하는 기능을 처리하는 PageMaker 클래스를 생성하겠습니다.
PageMaker.java 생성
PageMaker 설계를 위해 필요한 데이터를 살펴 보겠습니다.
- 외부에서 입력되는 데이터 : page, perPageNum (Criteria)
- DB에서 계산되는 데이터 : totalDataCount(데이터 전체 개수)
- 계산을 통해 만들어지는 데이터 : startPage(시작페이지), endPage(끝페이지), prev(이전 버튼 활성화 여부), next(다음 버튼 활성화 여부), 맨처음(firstPage), 맨 끝(finalPage)
package kr.co.web.domain;
public class PageMaker {
private int displayPageCnt = 10; // 화면에 보여질 페이지 번호 수
private int totalDataCount; // 실제 게시물 수
private int startPage; // 현재 페이지 기준 시작 페이지 번호
private int endPage; // 현재 페이지 기준 끝 페이지 번호
private boolean prev; // 이전 버튼 활성화 여부
private boolean next; // 다음 버튼 활성화 여부
private Criteria cri; //page(현재 페이지), perPageNum(페이지 당 보여질 게시물의 수)
private int finalPage; // 맨끝
private int firstPage; // 맨처음
public PageMaker(Criteria cri) {
this.cri = cri;
}
public int getDisplayPageCnt() {
return displayPageCnt;
}
public void setDisplayPageCnt(int displayPageCnt) {
this.displayPageCnt = displayPageCnt;
}
public int getTotalDataCount() {
return totalDataCount;
}
public void setTotalDataCount(int totalDataCount) {
this.totalDataCount = totalDataCount;
calcData();
}
//startPagem endPage, prev, next, firstPagem finalPage 계산
public void calcData() {
int page = this.cri.getPage();
int perPageNum = this.cri.getPerPageNum();
// 현재 페이지가 2면 2/10 = 0.2 Math.ceil객체를 이용하여 무조건 올림 하면 1 * displayPageCnt = 10
this.endPage = (int)(Math.ceil(page / (double)displayPageCnt) * displayPageCnt);
// endPage - 화면에 보여줄 페이지수를 한뒤 + 1을 하면 된다.
this.startPage = (this.endPage - displayPageCnt) + 1;
// 전체 게시물 수를 통한 endPage
// 데이터가 89 개면 9페이지까지 출력
int tempEndPage = (int)(Math.ceil(totalDataCount / (double)perPageNum));
if(this.endPage > tempEndPage) {
this.endPage = tempEndPage;
}
this.prev = startPage == 1? false : true;
this.next = (endPage * perPageNum) <= totalDataCount ? true : false;
// 맨끝
// +1하는 이유는 저렇게 계산하면 맨끝에서 2번째 페이지가 출력되기때문.
this.finalPage = (int)(Math.ceil(totalDataCount / (double)perPageNum)+1);
// 맨처음
this.firstPage = 1;
}
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 boolean isPrev() {
return prev;
}
public void setPrev(boolean prev) {
this.prev = prev;
}
public boolean isNext() {
return next;
}
public void setNext(boolean next) {
this.next = next;
}
public Criteria getCri() {
return cri;
}
public void setCri(Criteria cri) {
this.cri = cri;
}
public int getFinalPage() {
return finalPage;
}
public void setFinalPage(int finalPage) {
this.finalPage = finalPage;
}
public int getFirstPage() {
return firstPage;
}
public void setFirstPage(int firstPage) {
this.firstPage = firstPage;
}
}
PageMaker는 끝페이지를 구하기 위해서 DB로부터 전체 데이터의 개수를 받아와야 합니다.
전체 데이터의 개수를 가져오기 위해 mapper와 service, dao를 추가하겠습니다.
<!-- 전체 데이터 구하기 -->
<select id="totalCount" resultType="int">
select count(board_number)
from board
</select>
<!-- BoardService.java -->
public int totalCount(Criteria cri) throws Exception;
<-- BoardServiceImpl.java -->
@Override
public int totalCount(Criteria cri) throws Exception {
return boardDAO.totalCount(cri);
}
<!-- BoardDAO.java -->
public int totalCount(Criteria cri) throws Exception;
<!-- BoardDAOImpl.java -->
@Override
public int totalCount(Criteria cri) throws Exception {
return session.selectOne(TOTALCOUNT, cri);
}
전체 게시물의 개수를 구하는데 Criteria를 전달하는 것을 볼 수 있는데요
이는 페이징을 구현한 뒤에 검색기능을 추가할 것인데
예를 들어 '안녕' 이라는 검색을 하면 안녕을 포함하는 게시글이 총 몇개인지도 알아야 하기 때문에
Criteria 값도 나중을 위해 미리 전달하는 것입니다.
이제 게시물의 총 개수를 구하는 기능이 잘 구현되었는지 TEST를 해야겠죠?
아까 만들었던 pageTest.java에 메서드만 추가하겠습니다.
<!-- pageTest.java -->
package kr.co.web;
import java.util.List;
import javax.inject.Inject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.ContextConfiguration;
import kr.co.web.domain.BoardVO;
import kr.co.web.domain.Criteria;
import kr.co.web.service.BoardService;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
//Runner 클래스(테스트 메소드를 실행하는 클래스) 를 SpringJUnit4ClassRunner로 함
@RunWith(SpringJUnit4ClassRunner.class)
//location 속성 경로에 있는 xml 파일을 이용해서 스프링이 로딩됨
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/**/root-context.xml")
public class pageTest {
@Inject
private BoardService service;
private static Logger logger = LoggerFactory.getLogger(pageTest.class);
@Test
public void listPageTest() throws Exception{
Criteria cri = new Criteria();
cri.setPage(1);
cri.setPerPageNum(10);
List<BoardVO> boards = service.listPage(cri);
for (BoardVO board : boards) {
logger.info(board.getBoard_number()+ ":" + board.getTitle());
}
}
@Test
public void getTotalCountTest() throws Exception {
Criteria cri = new Criteria();
Integer totalCount = service.totalCount(cri);
logger.info("totalCount: "+totalCount.toString());
}
}
이제 JUnit TEST를 해보겠습니다.
정상적으로 게시물의 총 갯수와 10개의 게시물이 무사히 출력됐습니다!!