http://localhost:8090/board/list?pageNum=3
이전까지의 내용은 해당 값으로 브라우저에 요청을 하면 페이징을 나누어 이동할 수 있었다.
이번에는 밑에 페이지번호를 추가하여 클릭시 해당 페이지로 이동할 수 있도록 하는 것을 구현하고자 한다.
다음 과정을 통해 진행한다.
페이징은 단순 링크연결이지만, 조회, 수정, 삭제페이지까지 페이지 번호가 계속 유지되어야 하기 때문에 이를 신경써야 한다.
시작보다 끝 페이지 번호를 먼저 구하는 것이 수월하다.
this.endPage = (int)(Math.ceil(페이지번호 / 10.0)) * 10;
10페이지씩 나눈다고 가정한 코드
ceil은 소수점 올림으로 처리한다.
ceil(0.1) = 1
ceil(1) = 1
ceil(1.1) = 2
그러므로 페이지번호가 1~10까진 마지막페이지가 10페이지, 11~20까진 20페이지로 계산할 수 있다.
그러나 페이지수가 10개가 되지 않으면 끝 번호가 10으로 끝나면 되면 안된다. 그럼에도 끝을 먼저 구하는 이유는 시작페이지번호 계산이 수월해지기 때문이다.
this.startPage = this.endPage - 9;
그렇다면 시작번호를 수월하게 구했으니, 전체 데이터 수(total)를 이용해 진짜 마지막 페이지를 구해본다.
total이 80이었을 떄 마지막 번호는 10이아닌 8이되어야한다.
if 이렇게 해서 구한 값이 원래 endPage(10)보다 작으면 endPage값을 8로 변경한다.
realEnd = (int)(Math.ceil(total * 1.0)) / amount));//total이 8일 때 8페이지, 81이면, 9페이지가 됨
if(realEnd < this.endPage)//realEnd가 10보다 작다면, endPage는 작은 값으로 변경
this.endPage = realend;
이전 값은 시작 번호가 1보다 큰 경우일 때 존재한다.
2페이지일 때 1페이지로 넘어가기 위해서.
this.prev = this.startPage > 1;
다음 값은 realEnd가 끝 번호보다 큰 경우에만 존재한다.
현재 2페이지이면, endPage는 10일 때, realEnd가 8페이지 밖에 없다면 다음으로 넘어가는 값은 존재하지 않는다.
realEnd가 22페이지라면 다음으로 넘어가는 값이 필요하다.
this.next = this.endPage < realEnd;
domain에 PageDTO클래스를 작성한다.
@Data
public class PageDTO {
private int startPage;
private int endPage;
private boolean prev, next;
private int total;
private Criteria cri;
public PageDTO(Criteria cri, int total) {
this.cri = cri;
this.total = total;
this.endPage = (int)(Math.ceil(cri.getPageNum() / 10.0)) * 10;
this.startPage = this.endPage - 9;
int realEnd = (int)((Math.ceil(total / 1.0) / cri.getAmount()));
if(realEnd < endPage)
this.endPage = realEnd;
this.prev = this.startPage > 1;
this.next = this.endPage < realEnd;
}
}
여기서 계산된 값들을 Controller에서 View로 전달하기 위해 model에 담아야한다. list메소드를 수정한다.
@GetMapping("/list")
public void list(Criteria cri, Model model)
{
log.info("list: "+ cri);
model.addAttribute("pageMaker", new PageDTO(cri, 123));
model.addAttribute("list", service.getList(cri));
}
테이블 하위단에 해당 JSP를 작성한다.
<div class="pull-right">
<ul class="pagination">
<c:if test="${pageMaker.prev }">
<li class="paginate_button previous" ><a href="#">Previous</a>
</c:if>
<c:forEach var="num" begin="${pageMaker.startPage }"
end="${pageMaker.endPage }">
<li class ="paginate_button"><a href="#">${num }</a></li>
</c:forEach>
<c:if test="${pageMaker.next }">
<li class="paginate_button next"><a href="#">Next</a></li>
</c:if>
</ul>
</div>
<li class ="paginate_button" ${pageMaker.cri.pageNum == num ? "active":"" }"><a href="${num }">${num }</a></li>
<li class="paginate_button next"><a href="${pageMaker.endPage + 1 }">Next</a></li>
a태그의 href속성값으로 번호만을 가지게 변경된다.
해당 버튼을 클릭시 /board/번호로 이동되는 것을 확인할 수 있다.
<form id='actionForm' action="/board/list" method='get'>
<input type='hidden' name='pageNum' value = '${pageMaker.cri.pageNum}'>
<input type='hidden' name='amount' value = '${pageMaker.cri.amount }'>
</form>
<script type="text/javascript">
$(document).ready(function(){
var actionForm = $("#actionForm");
$(".paginate_button a").on("click", function(e){
e.preventDefault();
console.log('click');
actionForm.find("input[name='pageNum']").val($(this).attr("href"));
actionForm.submit();
});
});
</script>
pageNum, amount를 가진 form태그를 만든 후 페이지 버튼을 클릭했을때 이벤트를 처리하도록 스크립트를 작성한다.
해당 값을 가진 객체(actionForm)은 페이지 버튼(paginate_button)이 클릭되었을때, paginate_button의 a태그 href속성값을 actionForm의 pageNum에 넣고 get방식으로 /board/list에 제출한다.
controller의 GetMapping어노테이션을 가진 getList메소드는 해당하는 값을 cri객체에 매핑하고 이를 통해 목록을 출력하게 된다.
게시글을 눌렀을때 list버튼을 누르게 되면, 첫 페이지의 목록이 출력되는데 이는 default로 설정된 값이 cri에 있기 때문에 pageNum, amount를 get페이지에서 list로 넘겨주어야한다.
그렇다면 list페이지에서 게시글을 눌렀을때 현재의 pageNum과 amount를 넘겨주는 것 부터 진행해야한다.
<td>
<a class='move' href='<c:out value="${board.bno }"/>'>
<c:out value="${board.title }"/>
</a>
</td>
기존에는 제목에 href링크를 걸어 bno값만 전달했지만 a태그로 클래스를 묶어서 스크립트에서 나머지 값까지 함께 전달할 것이다.
$(".move").on("click", function(e){
e.preventDefault();
actionForm.append("<input type='hidden' name='bno' value='"+$(this).attr("href")+"'>");
actionForm.attr("action", "/board/get");
actionForm.submit();
});
move버튼이 클릭되었을때, actionForm(pageNum, amount가 담겨있는 form태그)에다가 move라는 이름의 a태그안의 href속성값(c:out)을 가진 input 태그를 덧 붙인다.
actionForm의 속성값 action을 /board/get으로 지정한다.
actionForm을 해당 URL에 제출한다.
그렇다면 제목을 클릭했을때 move on Click이 실행되고, actionForm태그에 있는 내용 + bno값이 추가되어 controller의 get 메소드를 호출하게 된다.
@GetMapping({"/get", "/modify"})
public void get(@RequestParam("bno") int bno, @ModelAttribute("cri") Criteria cri, Model model) {
log.info("get..modify.......: page : "+cri.getPageNum() +"amount"+ cri.getAmount());
model.addAttribute("board", service.get(bno));
}
컨트롤러의 get메소드는 ModelAttribute로 View에서 전달한 값을 Criteria에 매핑시킨다.
cri.get메소드를 수행하면 list페이지에서 전달한 값이 들어오는 것을 확인할 수 있다.
이제 앞서말한 조회페이지에서 list를 눌렀을 때 디폴트 페이지로 넘어가는 이슈를 해결해야한다.
마찬가지로 get페이지에서 pageNum, amount값을 넘겨준다.
get페이지에서는 operForm의 폼태그에 데이터를 담는다.
<form id='operForm' action="/board/modify" method="get">
<input type='hidden' id='bno' name='bno' value='<c:out value="${board.bno }"/>'>
<input type='hidden' id='pageNum' name='pageNum' value='<c:out value="${cri.pageNum }"/>'>
<input type='hidden' id='amount' name='amount' value='<c:out value="${cri.amount}"/>'>
</form>
그리고 동작확인시 해당 게시글이 속한 페이지로 돌아가는 것을 확인할 수 있다.