WEB 小案例 -- 網上書城(二)
寒假結束了,自己的頹廢時間同樣結束了,早該繼續寫博客了,盡管我的格式以及內容由於各種原因老被卡,但必須堅持寫下去!!!
上次我們對於本案例的數據庫部分進行了闡述,這次主要接著上次的內容分享本案例的翻頁操作,其演示如下:
GIF 中主要演示了翻頁操作,首先進入該頁面前先查詢數據庫中所有書籍的數量,根據每頁顯示的數量生成首頁部分數據。
1. 點擊 “下一頁”,當前第幾頁數字改變,頁面顯示下一頁書籍信息;
2. 點擊 “上一頁”,當前第幾頁數字改變,頁面顯示上一頁書籍信息;
3. 點擊 “末頁”,根據數據庫信息顯示最後一頁的信息,此時頁面上沒有 “下一頁” 超鏈接;
4. 點擊 “首頁”,頁面信息跳轉到首頁信息,此時頁面上沒有 “上一頁” 超鏈接;
5. 可以在輸入框中輸入數字直接跳轉到你輸入的頁面,倘若輸入錯誤的數字以及非數字將會跳轉到首頁
一、 操作準備條件
1. 我們將顯示頁面封裝為一個類(Page<T>,頁面所要顯示的不僅僅是 Book,也可能是其他類型所以為其加上泛型),其包含的成員變量有當前頁面所要顯示的書籍的列表(List<T> pageList),當前頁頁碼(int pageNo),每頁可顯示的書籍數量(int pageSize)以及對於該數據庫共多少頁(long totalItemNum),在本類中我們還利用 totalItemNum 和 pageSize 獲得對於當前數據庫中的數據共有多少頁(int totalPageNum),我們還根據當前頁碼進行判斷是否存在下一頁或者上一頁並獲取下一頁和上一頁的頁碼。
1 package com.book.store.web; 2 3 import java.util.List; 4 5 /** 6 * 封裝首頁顯示的頁面 7 */ 8 public class Page<T> { 9 private int pageNo; 10 private List<T> pageList; 11 private int pageSize; 12 private long totalItemNum; 13 14 /* 15 * 在這裏我們將每頁可顯示的書籍數量設為 516 * */ 17 public Page(int pageNo) { 18 pageSize = 5; 19 this.pageNo = pageNo; 20 } 21 22 /* 23 * 對輸入的頁碼進行糾正判斷,若小於 0 則使其等於 1,若大於最大的頁碼則使其等於頁碼的最大值並返回 24 * */ 25 public int getPageNo() { 26 if (pageNo < 0) { 27 pageNo = 1; 28 } 29 30 if (pageNo > getTotalPageNum()) { 31 pageNo = getTotalPageNum(); 32 } 33 return pageNo; 34 } 35 36 public int getPageSize() { 37 return pageSize; 38 } 39 40 public List<T> getPageList() { 41 return pageList; 42 } 43 44 public void setPageList(List<T> pageList) { 45 this.pageList = pageList; 46 } 47 48 public long getTotalItemNum() { 49 return totalItemNum; 50 } 51 52 public void setTotalItemNum(long totalItemNum) { 53 this.totalItemNum = totalItemNum; 54 } 55 /* 56 * 根據 totalItemNum 和 pageSize 獲取總頁數 57 * */ 58 public int getTotalPageNum() { 59 int flag = (int) (getTotalItemNum() % getPageSize()); 60 int totalPageNum = (int) (getTotalItemNum() / getPageSize()); 61 if (flag > 0) { 62 totalPageNum++; 63 } 64 return totalPageNum; 65 } 66 /* 67 * 判斷是否有下一頁 68 * */ 69 public boolean isHasNext() { 70 if (getPageNo() == getTotalPageNum()) { 71 return false; 72 } 73 return true; 74 } 75 /* 76 * 判斷是否有上一頁 77 * */ 78 public boolean isHasPrev() { 79 if (getPageNo() == 1) { 80 return false; 81 } 82 return true; 83 } 84 /* 85 * 獲取下一個的 頁碼 86 * */ 87 public int getNextPage() { 88 if (isHasNext()) { 89 return pageNo + 1; 90 } 91 return pageNo; 92 } 93 /* 94 * 獲取上一頁的頁碼 95 * */ 96 public int getPrevPage() { 97 if (isHasPrev()) { 98 return pageNo - 1; 99 } 100 return pageNo; 101 } 102 103 @Override 104 public String toString() { 105 return "Page{" + 106 "pageNo=" + pageNo + 107 ", pageList=" + pageList + 108 ", pageSize=" + pageSize + 109 ", totalItemNum=" + totalItemNum + 110 ‘}‘; 111 } 112 }
2. 封裝查詢條件為一個單獨的類( CriteriaBook),其包括頁面上部的查詢條件最低價(int minPrice)和最高價(int maxPrice)區間和頁面底部轉到多少頁的條件(int pageNo),並為其賦初值,極端值。
package com.book.store.web; /** * 封裝查詢條件的類 */ public class CriteriaBook { private int minPrice = 0; private int maxPrice = Integer.MAX_VALUE; private int pageNo; public CriteriaBook() {} @Override public String toString() { return "CriteriaBook{" + "minPrice=" + minPrice + ", maxPrice=" + maxPrice + ", pageNo=" + pageNo + ‘}‘; } public CriteriaBook(int minPrice, int maxPrice, int pageNo) { this.minPrice = minPrice; this.maxPrice = maxPrice; this.pageNo = pageNo; } public int getMinPrice() { return minPrice; } public void setMinPrice(int minPrice) { this.minPrice = minPrice; } public int getMaxPrice() { return maxPrice; } public void setMaxPrice(int maxPrice) { this.maxPrice = maxPrice; } public int getPageNo() { return pageNo; } public void setPageNo(int pageNo) { this.pageNo = pageNo; } }
二、 編寫思路以及步驟
1. 在到達顯示頁面之前我們首先需要其顯示首頁信息,因為我們通過一個頁面重定向到 Servlet 中,在 Servlet 中獲取首頁信息後將其包裝在 request 中轉發到顯示頁面!
1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <html> 3 <head> 4 <title>BookStore</title> 5 </head> 6 <body> 7 <h3><% 8 /* 9 * /days_1212_JavaWebBookStore,query 方法中負責封裝數據並返回顯示頁面 10 * */ 11 response.sendRedirect(request.getContextPath() + "/query.do"); 12 System.out.println(request.getContextPath()); 13 %></h3> 14 </body> 15 </html>
2. query 方法要封裝信息就需要查詢數據庫,所以為了 query 方法的簡潔明了我們將邏輯方法置於一個單獨的類。在 query 方法中我們將查詢條件都賦初值,以免在沒有查詢條件的情況下不會出錯,方法中我們給三個查詢條件分別加以異常處理為了使假若其中一個出錯不會影響其他的查詢條件(以下為Servlet 的 query 方法)。
1 protected void query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 2 // 獲取查詢條件之最低價 3 String minPriceStr = request.getParameter("minPrice"); 4 // 獲取查詢條件之最高價 5 String maxPriceStr = request.getParameter("maxPrice"); 6 // 獲取查詢條件之頁碼 7 String pageNoStr = request.getParameter("pageNo"); 8 // 初始化查詢條件,即無查詢條件的默認值 9 int minPrice = 0; 10 int maxPrice = Integer.MAX_VALUE; 11 int pageNo = 1; 12 13 try { 14 minPrice = Integer.parseInt(minPriceStr); 15 } catch (NumberFormatException e) {} 16 try { 17 maxPrice = Integer.parseInt(maxPriceStr); 18 } catch (NumberFormatException e) {} 19 try { 20 pageNo = Integer.parseInt(pageNoStr); 21 } catch (NumberFormatException e) {} 22 // 構建查詢條件所對應的類 23 CriteriaBook criteriaBook = new CriteriaBook(minPrice, maxPrice, pageNo); 24 // 根據查詢條件獲得首頁顯示信息所構建的類 25 Page<Books> page = bookService.getPage(criteriaBook); 26 // 將首頁需要顯示的信息存入 request 中,用於顯示 27 request.setAttribute("page", page); 28 // 轉發回首頁 29 request.getRequestDispatcher("/showView/bookList.jsp").forward(request, response); 30 }
3. 上述方法中從頁面獲取查詢條件將其封裝為對應的類(CriteriaBook),再根據查詢條件所封裝的類構建 Page 類(BookDao 接口所要實現的功能之一,方法 getPage(CriteriaBook criteriaBook) )!Page 類包括了所要顯示的書籍,根據書籍數量獲得共多少頁,共多少書籍等信息。我們在 getPage 方法中首先新建 Page 對象,然後利用 setXxx 方法為 page 對象賦值。
1 /* 2 * 初始化首頁顯示頁 3 * */ 4 @Override 5 public Page<Books> getPage(CriteriaBook criteriaBook) { 6 // 在新建 page 對象的時候就初始化頁碼(pageNo) 7 Page<Books> page = new Page<Books>(criteriaBook.getPageNo()); 8 // 設置現顯示頁的總數量(需要根據總數量和 pageSize 計算共多少頁) 9 page.setTotalItemNum(getTotalNum(criteriaBook)); 10 // 設置查詢條件的頁碼(利用 Page 類中的 getPageNo 使頁碼合法) 11 criteriaBook.setPageNo(page.getPageNo()); 12 // 初始化顯示頁的 list 集合 13 page.setPageList(getBookList(criteriaBook, 5)); 14 return page; 15 }
4. 上述 getPage(CriteriaBook criteriaBook) 方法中所調用的 getTotalNum(criteriaBook) 方法以及 getBookList(criteriaBook,pageSize) 均需要結合數據庫數據方可完成賦值。
1 /* 2 * 根據查詢條件獲取該條件下商品的總數量 3 * */ 4 @Override 5 public long getTotalNum(CriteriaBook criteriaBook) { 6 String sql = "SELECT COUNT(id) FROM books WHERE price>=? AND price<=?"; 7 long totalNum = (Long) getCount(sql, criteriaBook.getMinPrice(), criteriaBook.getMaxPrice()); 8 return totalNum; 9 } 10 11 /* 12 * 根據查詢條件(最高價、最低價、)和每頁顯示的數量(pageSize)獲取對應商品的 list 集合 13 * */ 14 @Override 15 public List<Books> getBookList(CriteriaBook criteriaBook, int pageSize) { 16 String sql = "SELECT id, author, title, price, publish_date publishDate, sales_count salesCount, store_number storeNumber, remark " + 17 "FROM books WHERE price >= ? AND price <= ? LIMIT ?, ?"; 18 List<Books> booksList = getList(sql,criteriaBook.getMinPrice(), criteriaBook.getMaxPrice(), (criteriaBook.getPageNo() - 1) * pageSize, pageSize); 19 return booksList; 20 }
5. 到這裏我們已經成功將首頁信息獲取到,接下來需要將獲取到的信息顯示到頁面,首先我們將 page 對象添加到 request 域中通過請求轉發至頁面並在頁面利用 JSTL 將其進行顯示。接著為 “上一頁”、“下一頁”、“首頁”、“末頁” 等超鏈接添加響應事件。為上述超鏈接添加超鏈接的時候其 href 屬性是重點,我們利用 href 屬性將其鏈接到 servlet 中的 query 方法中,在 servlet 方法中進行處理對應的操作!
1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 <html> 4 <head> 5 <title>BookList</title> 6 <%@ include file="/commons/queryCondition.jsp" %> 7 </head> 8 <body> 9 <div> 10 <form method="post" action="${pageContext.request.contextPath}/query.do"> 11 Price: <input type="text" size="1" name="minPrice"> - 12 <input type="text" size="1" name="maxPrice"> 13 <button type="submit">Submit</button> 14 </form> 15 <table cellpadding="15"> 16 <c:forEach items="${requestScope.page.pageList}" var="book"> 17 <tr> 18 <td> 19 <a href="${pageContext.request.contextPath}/getBookInfo.do?id=${book.id}&pageNo=${requestScope.page.pageNo}">${book.title}</a><br>${book.author} 20 </td> 21 <td>${book.price}</td> 22 <td><a href="#">加入購物車</a></td> 23 </tr> 24 </c:forEach> 25 </table> 26 <br><br> 27 <span>共${requestScope.page.totalPageNum}頁 當前第${requestScope.page.pageNo}頁</span> 28 <c:if test="${requestScope.page.hasPrev}"> 29 <span><a href="${pageContext.request.contextPath}/query.do?pageNo=1">首頁</a> 30 <a href="${pageContext.request.contextPath}/query.do?pageNo=${requestScope.page.prevPage}">上一頁</a></span> 31 </c:if> 32 <c:if test="${requestScope.page.hasNext}"> 33 <span><a href="${pageContext.request.contextPath}/query.do?pageNo=${requestScope.page.nextPage}">下一頁</a> 34 <a href="${pageContext.request.contextPath}/query.do?pageNo=${requestScope.page.totalPageNum}">尾頁</a></span> 35 </c:if> 36 轉到 <input type="text" size="1" name="toPage" id="pageNo"> 頁 37 </div> 38 </body> 39 </html>
6. 上述代碼中翻頁的超鏈接點擊之後伴隨 nextPageNo 或 prePageNo 參數傳遞到 Servlet 中的 query 方法中進行處理,此時的 query 方法中除了 pageNo(利用 request 參數以及 JSTL 調用 Page 類中的 getXxx 方法結合構造器中的 pageNo 參數得到 nextPageNo 和 prePageNo) 參數其余的均為初始值,所以其處理過程如上顯示首頁一般,至於轉到多少多少頁我們使用 Ajax 及時響應請求並處理!
1 <script type="text/javascript" src="${pageContext.request.contextPath}/jquery-1.7.2.js"></script> 2 <script type="text/javascript"> 3 $(function () { 4 $("#pageNo").change(function () { 5 var $pageVal = $("#pageNo").val() 6 window.location.href = "${pageContext.request.contextPath}/query.do?pageNo=" + $pageVal; 7 }) 8 }); 9 </script>
7. 上述代碼中利用 JS 對 id 為 pageNo 的輸入框進行監測,若其值變化則執行 Ajax 函數,新建變量($pageNo)為其賦值為所輸入的值,然後將請求的發送到 window.location.href ,即 query 方法執行查詢!
至此我們就將本案例中的翻頁操作講述完畢,如果閱讀過程過有更好的方法或者發現什麽問題還望大家可以提出,我將及時更正,謝謝!!!
WEB 小案例 -- 網上書城(二)