스프링 MVC

준비중..

스프링 MVC

스프링을 사용한 웹서비스 만들기

23 페이지 네이션

# 페이지 네이션 --- ## Step 1: 첫 페이지 출력하기 ![Imgur](https://i.imgur.com/Njz1pod.png) ### view 페이지네이션 UI를 추가. (ref. https://getbootstrap.com/docs/3.3/components/#pagination) ``` <nav aria-label="Page navigation example"> <ul class="pagination justify-content-center"> <li class="page-item"> <a class="page-link" href="#" aria-label="Previous"> <span aria-hidden="true">&laquo;</span> </a> </li> <li class="page-item"><a class="page-link" href="#">1</a></li> <li class="page-item"><a class="page-link" href="#">2</a></li> <li class="page-item"><a class="page-link" href="#">3</a></li> <li class="page-item"> <a class="page-link" href="#" aria-label="Next"> <span aria-hidden="true">&raquo;</span> </a> </li> </ul> </nav> ``` ### Controller 리뷰 맵퍼 호출 변경 ``` @RequestMapping(value = "/books/{id}", method = RequestMethod.GET) public String show(@PathVariable int id, Model model, Principal principal, Paging paging) { Book book = bookMapper.getBook(id); model.addAttribute("book", book); // 기존 리뷰들 List<Review> reviews = reviewMapper.getReviews(id, paging); model.addAttribute("reviews", reviews); model.addAttribute("paging", paging); // 폼 태그에서 modelAttribute="review" 속성을 읽어올 수 있어야함. if (!model.containsAttribute("review")) { Review review = new Review(); review.setBookId(id); String email = principal.getName(); int userId = userMapper.getUserIdByEmail(email); review.setUserId(userId); model.addAttribute("review", review); } // rating opts Map<Integer, String> ratingOptions = new HashMap<Integer, String>(); ratingOptions.put(5, "★★★★★"); ratingOptions.put(4, "★★★★☆"); ratingOptions.put(3, "★★★☆☆"); ratingOptions.put(2, "★★☆☆☆"); ratingOptions.put(1, "★☆☆☆☆"); ratingOptions.put(0, "☆☆☆☆☆"); model.addAttribute("ratingOptions", ratingOptions); return "books/show"; } ``` ### Mapper ``` @Select("SELECT * FROM reviews WHERE book_id = #{bookId} ORDER BY id DESC LIMIT #{p.rows} OFFSET (#{p.index} - 1) * #{p.rows}") @Results(value = { @Result(property = "id", column = "id"), @Result(property = "text", column = "text"), @Result(property = "bookId", column = "book_id"), @Result(property = "userId", column = "user_id"), @Result(property = "user", column = "id", javaType = User.class, one = @One(select = "getUserById")) }) List<Review> getReviews(@Param("bookId") int bookId, @Param("p") Paging paging); ``` ### VO ``` public class Paging { private int index; // 출력할 페이지 번호 private int rows; // 페이지 별 출랙 갯수 public Paging() { index = 1; rows = 50; } } ``` --- ## Step 2: 페이징 번호 출력하기 ![Imgur](https://i.imgur.com/rwkP51k.png) ### View ``` <nav aria-label="Page navigation example"> <ul class="pagination justify-content-center"> <!-- prev --> <li class="page-item"> <a class="page-link" href="#" aria-label="Previous"> <span aria-hidden="true">&laquo;</span> </a> </li> <!-- paging nums --> <c:forEach var="i" begin="${paging.start}" end="${paging.end}" step="1"> <li class="page-item"><a class="page-link" href="#">${ i }</a></li> </c:forEach> <!-- next --> <li class="page-item"> <a class="page-link" href="#" aria-label="Next"> <span aria-hidden="true">&raquo;</span> </a> </li> </ul> </nav> ``` ### Controller ``` @RequestMapping(value = "/books/{id}", method = RequestMethod.GET) public String show(@PathVariable int id, Model model, Principal principal, Paging paging) { Book book = bookMapper.getBook(id); model.addAttribute("book", book); // 기존 리뷰들 List<Review> reviews = reviewMapper.getReviews(id, paging); model.addAttribute("reviews", reviews); // 페이징 paging.setTotal(reviewMapper.getReviewsCnt(id)); model.addAttribute("paging", paging); // 폼 태그에서 modelAttribute="review" 속성을 읽어올 수 있어야함. if (!model.containsAttribute("review")) { Review review = new Review(); review.setBookId(id); String email = principal.getName(); int userId = userMapper.getUserIdByEmail(email); review.setUserId(userId); model.addAttribute("review", review); } // rating opts Map<Integer, String> ratingOptions = new HashMap<Integer, String>(); ratingOptions.put(5, "★★★★★"); ratingOptions.put(4, "★★★★☆"); ratingOptions.put(3, "★★★☆☆"); ratingOptions.put(2, "★★☆☆☆"); ratingOptions.put(1, "★☆☆☆☆"); ratingOptions.put(0, "☆☆☆☆☆"); model.addAttribute("ratingOptions", ratingOptions); return "books/show"; } ``` ### Mapper ``` @Select("SELECT COUNT(*) FROM reviews WHERE book_id = #{bookId}") int getReviewsCnt(int id); ``` ### VO ``` public class Paging { private int index; // 출력할 페이지 번호 private int rows; // 페이지 별 출력 갯수 private int total; // 검색 결과 총 갯수 public Paging() { index = 1; rows = 50; } public void setTotal(int total) { this.total = total; } public int getStart() { return 1; } public int getEnd() { int totalPagesCnt = (int) Math.ceil(1.0 * total / rows); return totalPagesCnt; } } ``` --- ## Step 3: 페이지 개수 제한하기 아래와 같이 너무많은 페이지가 보여지지 않게 하려면? ![Imgur](https://i.imgur.com/0Vfflv2.png) ### VO ``` public class Paging { private int index; // 출력할 페이지 번호 private int rows; // 페이지 별 출력 갯수 private int total; // 검색 결과 총 갯수 private int pageLimit; // 출력할 페이지 번호 갯수 public Paging() { index = 1; rows = 1; pageLimit = 5; } public void setTotal(int total) { this.total = total; } public int getStart() { return 1; } public int getEnd() { int totalPagesCnt = (int) Math.ceil(1.0 * total / rows); int start = getStart(); int end = start + pageLimit - 1; return Math.min(end, totalPagesCnt); } } ``` ### 결과화면 ![Imgur](https://i.imgur.com/Fv5xeVb.png) --- ## Step 4: 해당 페이지 내용 링크 걸기 ![Imgur](https://i.imgur.com/PihGxby.png) ### View ``` <nav aria-label="Page navigation example"> <ul class="pagination justify-content-center"> <!-- prev --> <li class="page-item"> <a class="page-link" href="<c:url value="/books/${ book.id }?pageNum=1#reviews" />" aria-label="Previous"> <span aria-hidden="true">&laquo;</span> </a> </li> <!-- paging nums --> <c:forEach var="i" begin="${paging.start}" end="${paging.end}" step="1"> <li class="page-item" id="review-page-index-${i}"><a class="page-link" href="<c:url value="/books/${ book.id }?pageNum=${i}#reviews" />">${ i }</a></li> </c:forEach> <!-- next --> <li class="page-item"> <a class="page-link" href="<c:url value="/books/${ book.id }?pageNum=${paging.lastPageNum}#reviews" />" aria-label="Next"> <span aria-hidden="true">&raquo;</span> </a> </li> </ul> </nav> <Script> $.urlParam = function(name){ var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href); if (results == null){ return null; } else{ return results[1] || 0; } } var pageNum = $.urlParam('pageNum') if (pageNum == null) { pageNum = 1; } $("#review-page-index-" + pageNum).addClass("active"); </Script> ``` ### VO ``` public class Paging { private int index; // 출력할 페이지 번호 private int rows; // 페이지 별 출랙 갯수 private int total; // 검색 결과 총 갯수 private int pageLimit; // 출력할 페이지 번호 갯수 public Paging() { index = 1; rows = 3; pageLimit = 5; } public void setTotal(int total) { this.total = total; } public int getStart() { return Math.max(1, index - (pageLimit / 2)); } public int getEnd() { int totalPagesCnt = (int) Math.ceil(1.0 * total / rows); int start = getStart(); int end = start + pageLimit - 1; return Math.min(end, totalPagesCnt); } public int getLastPageNum() { return (int) Math.ceil(1.0 * total / rows); } public void setIndex(int pageNum) { index = pageNum; } @Override public String toString() { return "Paging [index=" + index + ", rows=" + rows + ", total=" + total + ", pageLimit=" + pageLimit + "]"; } } ``` ### Controller ``` // https://stackoverflow.com/questions/41620395/spring-set-default-pathvariable // https://acuriouscoder.net/optional-path-variables-in-spring-mvc/ // https://stackoverflow.com/questions/17934972/get-query-string-values-in-spring-mvc-controller @RequestMapping(value = "/books/{id}", method = RequestMethod.GET) public String show(@PathVariable int id, Model model, Principal principal, Paging paging, @RequestParam(value="pageNum", required=false) Optional<Integer> pageNum) { Book book = bookMapper.getBook(id); model.addAttribute("book", book); // 기존 리뷰들 if (pageNum.isPresent()) { paging.setIndex(pageNum.get()); } List<Review> reviews = reviewMapper.getReviews(id, paging); model.addAttribute("reviews", reviews); // 페이징 paging.setTotal(reviewMapper.getReviewsCnt(id)); model.addAttribute("paging", paging); // 폼 태그에서 modelAttribute="review" 속성을 읽어올 수 있어야함. if (!model.containsAttribute("review")) { Review review = new Review(); review.setBookId(id); String email = principal.getName(); int userId = userMapper.getUserIdByEmail(email); review.setUserId(userId); model.addAttribute("review", review); } // rating opts Map<Integer, String> ratingOptions = new HashMap<Integer, String>(); ratingOptions.put(5, "★★★★★"); ratingOptions.put(4, "★★★★☆"); ratingOptions.put(3, "★★★☆☆"); ratingOptions.put(2, "★★☆☆☆"); ratingOptions.put(1, "★☆☆☆☆"); ratingOptions.put(0, "☆☆☆☆☆"); model.addAttribute("ratingOptions", ratingOptions); return "books/show"; } ``` --- ## Step 5: 리뷰가 바로 보여 질 수 있게.. ### View ``` <table class="table table-stripped" id="reviews"> ... <nav aria-label="Page navigation"> <ul class="pagination"> <!-- first --> <li><a href="<c:url value="/books/${ book.id }?pageNum=1#reviews" />" aria-label="Previous"><spanaria-hidden="true">&laquo;</span></a></li> <c:forEach var="i" begin="${paging.start}" end="${paging.end}" step="1"> <li><a href="<c:url value="/books/${ book.id }?pageNum=${i}#reviews" />">${i}</a></li> </c:forEach> <!-- last --> <li><a href="<c:url value="/books/${ book.id }?pageNum=${paging.lastPageNum}#reviews" />" aria-label="Next"> <span aria-hidden="true">&raquo;</span></a></li> </ul> </nav> ``` --- ## Ref. + https://okky.kr/article/283315 + http://handcoding.tistory.com/15 + https://handam.tistory.com/41