PagingVO라는 entity를 새로 만들어 현재페이지, 시작페이지, 끝페이지, 총 개시글수, 페이지당 글 갯수, 마지막페이지,
기본적으로 수업시간의 bbs프로젝트에서 사용했던 방법을 끌어올 예정.
검색기능에 대한 부분은 추후 같은방식으로 할지 다르게 해볼지 고민해보기.
- PageVO -
public class PageVO {
private int pageNum; // 현재페이지
private int amount; // 한 페이지의 게시글 수
private int skip; // 스킵할 게시글 수 ((page - 1) * amount)
// 기본생성자 => 기본세팅: pageNum = 1, amount = 10
public PageVO() {
this(1, 10);
}
public PageVO(int pageNum, int amount) {
this.pageNum = pageNum;
this.amount = amount;
this.skip = (pageNum - 1) * amount;
}
public int getPageNum() {
return pageNum;
}
// 새로 페이지 수를 설정했을 때 skip도 계산
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
this.skip = (pageNum - 1) * amount;
}
public int getAmount() {
return amount;
}
// 페이지 당 데이터 갯수를 바꿀때에도 skip을 다시 계산
public void setAmount(int amount) {
this.amount = amount;
this.skip = (pageNum - 1) * amount;
}
public int getSkip() {
return skip;
}
public void setSkip(int skip) {
this.skip = skip;
}
@Override
public String toString() {
return "PageVO [pageNum=" + pageNum + ", amount=" + amount + ", skip=" + skip + "]";
}
}
뛰어넘을 게시글 수 skip
은 현재 페이지pageNum
과 한 페이지당 게시글 수amount
를 기준으로 계산하여 구하는 값이므로 두 멤버변수의 값이 바뀔 때마다 새로 산출해야 함.
생성자의 this(1, 10)
은 멤버변수인 pageNum과 amount에 초기값을 설정해준다.
skip
은 계산으로 구하는 변수이므로 초기값할당 안함.
=> 생성자는 멤버변수를 초기화하는 역할을 한다. java의 this
와 생성자에 대한 용법은 링크 참고.
- StudyBoardMapper.interface -
public List<StudyBoardVO> getListPaging(PageVO page); // 페이징을 적용한 전체 게시글 가져오기. pageNum과 amount를 입력받아 객체 page생성. 없으면 기본값(1, 10) 적용.
기존의 전체게시글 조회는 두고 추가로 작성.
기존 메서드는 페이지네이션까지 적용 후 주석or삭제.
- StudyBoardMapper.xml -
<!-- 페이징 적용 게시판 목록 -->
<select id="getListPaging" resultType="StudyBoardVO">
SELECT * FROM (
SELECT sno, title, writer, regdate, updatedate, hit, like_no
FROM studyboard ORDER BY sno DESC) as T1
LIMIT #{skip}, #{amount}
</select>
- StudyBoardMapperTest -
@Test
public void testGetListPaging() {
PageVO page = new PageVO();
List<StudyBoardVO> list = sBoardMapper.getListPaging(page);
list.forEach(board -> log.info("" + board));
}
여기서는 new PageVO()
에 따로 값을 넣지않아 생성자의 기본값인 (1, 10)
으로 페이징이 적용됨.
만약 현재 페이지와 한 페이지당 게시글 수를 변경하고싶다면 new PageVO(2, 5)
처럼 생성자에 값을 지정해주면 됨.
new PageVO(pageNum, amount)
임을 참고.
가장 마지막 번호의 게시글부터 10개의 게시글이 출력됨을 확인.
- StudyBoardService.interface -
public List<StudyBoardVO> getListPaging(PageVO page); // 페이징 적용 게시글목록
- StudyBoardServiceImpl -
@Override
public List<StudyBoardVO> getListPaging(PageVO page) {
// 페이징 적용 공부게시판 전체 가져오기
return sBoardMapper.getListPaging(page);
}
- StudyBoardController -
@GetMapping("/list")
public String studyListGET(PageVO page, Model model) {
model.addAttribute("studyboard", sBoardService.getListPaging(page));
return "studyBoard/studyList";
}
앞서 사용하던 studyListGET
메서드는 주석처리or삭제 후 페이징이 적용된 버전으로 추가.
http://localhost:8080/studyboard/list
페이징이 적용되어 10개의 게시글만 출력됨.
http://localhost:8080/studyboard/list?pageNum=2&amount=12
pageNum과 amount의 값을 주소창에 직접 기입해 값을 변경하는것도 가능.
- PageMakerDTO -
@Data
public class PageMakerDTO {
private int startPage; // 시작 페이지
private int endPage; // 끝 페이지
private boolean prev, next; // 이전, 다음페이지 존재유무
private int total; // 전체 게시글 수
private PageVO pageVo; // 현재 페이지, 페이지당 게시글 표시 수 정보
public PageMakerDTO(int total, PageVO page) {
this.total = total;
this.pageVo = page;
// 마지막 페이지(현제 페이지네이션바의 마지막 숫자): 10 단위로 표시 1~10, 11~20
// Math.ceil은 올림함수
this.endPage = (int)(Math.ceil(pageVo.getPageNum() / 10.0)) * 10;
// 시작 페이지
this.startPage = this.endPage - 9;
// 실제 마지막 페이지 (총 마지막 페이지)
int realEnd = (int)(Math.ceil(total * 1.0 / pageVo.getAmount()));
// 전체 마지막 페이지(realEnd)가 화면에 보이는 마지막 페이지(endPage)보다 작은 경우
if (realEnd < this.endPage) {
this.endPage = realEnd; // 화면에 보일 마지막 페이지를 전체 마지막 페이지로 변경
}
// < 이전페이지 참? 시작 페이지(startPage)값이 1보다 큰 경우 true
this.prev = this.startPage > 1;
// < 다음페이지 참? 마지막 페이지(endPage)값이 1보다 큰 경우 true
this.next = this.endPage < realEnd;
}
}
페이지 계산을 위한 클래스.
페이지네이션바에 나타날 시작페이지startPage
, 페이지네이션바에 나타날 끝페이지endPage
를 계산.
전체 첫페이지는 1부터로 고정일 수 밖에 없으며, 전체 마지막페이지는 페이지네이션과는 관계없으므로(이 부분은 페이징에서 처리) 여기서 시작페이지와 끝페이지는 페이지네이션바에 노출될 페이지수를 칭함.
- StudyBoardMapper.interface -
public int getTotal(); // 게시글 총 갯수
- StudyBoardMapper.xml -
<!-- 게시글 총 갯수 -->
<select id="getTotal" resultType="int">
SELECT count(*) FROM studyboard
</select>
studyboard
테이블에 저장된 데이터의 총 갯수를 구함.
- StudyBoardMapperTest -
@Test // 총 게시글 구하기
public void testGetTotal() {
int result = sBoardMapper.getTotal();
log.info("총 게시글 수: " + result);
}
총 게시글 수를 구하는 테스트.
- StudyBoardService.interface -
public int getTotal(); // 게시글 총 갯수
- StudyBoardServiceImpl -
@Override
public int getTotal() {
// 전체 게시글 수
return sBoardMapper.getTotal();
}
- StudyBoardController -
@GetMapping("/list")
public String studyListGET(PageVO page, Model model) {
model.addAttribute("studyboard", sBoardService.getListPaging(page));
int total = sBoardService.getTotal();
PageMakerDTO pmk = new PageMakerDTO(total, page);
model.addAttribute("pmk", pmk);
return "studyBoard/studyList";
}
- studyList.html -
<nav th:if="${pmk.endPage > 0}">
<ul>
<li>
<a href="javascript:;">
<span>이전</span>
</a>
</li>
<li class="page-item" th:each="number : ${#numbers.sequence(1,pmk.endPage)}">
<a class="page-link" href="javascript:;" th:text="${number}"></a>
</li>
<li>
<a href="javascript:;">
<span>다음</span>
</a>
</li>
</ul>
</nav>
number
는 컨트롤러에서 넘어온 pmk.endPage
의 값을 이용해 얻은 임시적인 변수.
Thymeleaf의 문법 numbers.sequence
을 사용하여 얻은 수.
참고
number
의 값은 forEach문을 통해 얻었으므로 반복문 내에서만 사용할 수 있는 지역변수이다.
=> 1부터 endPage의 값까지 forEach문으로 반복시
http://localhost:8080/studyboard/list
현재 총 게시글 수가 34개이므로 한 페이지당 10개의 게시글을 보여준다고 했을때 총 4페이지가 나오는게 맞음.