@目錄
項目案例: mysql + commons-dbutils+itcast-tools+BaseServlet + 分頁+JSP+JSTL+EL+MVC模式
什么是分頁?
如上所示,就是分頁 ,不用多說了
子模塊功能的問題分析 和 解決方案
@總功能分析 常規JDBC中,點擊查詢或輸入條件查詢,在頁面中可顯示查詢出的所有記錄,有多少記錄就顯示多少。在這種項目的基礎上增加分頁功能 。 @分頁功能的宗旨 是無論什么樣的查詢,顯示出的記錄都是當前頁的記錄 。 所以,我們必須得向系統說明我們當前是要顯示第幾頁的數據 。 自然,需要一個PageBean類
public class PageBean<T> { private int pageCode ;//當前頁碼 // private int totalPage ;//總頁數,總頁數應該由計算獲取 private int totalRecord;//總記錄數 private int pageSize;//每頁記錄數,這是參數是定做這個軟件的甲方提出來的,在Servlet中直接定義為10了 private List<T> beanList;//當前頁的記錄集合,方便整頁記錄的轉移 private String url ;//Url后的條件,條件查詢設置的 }
這個PageBean類中封裝了當前頁、總記錄數、當前頁所有記錄的集合等,系統通過當前頁碼這個參數返回pageSize條記錄放在beanList集合中返回顯示。
@子模塊功能1 中首頁的pageCode是1,尾頁的pageCode是totalPage,上一頁和下一頁分別是pageCode-1 和pageCode+1 。
@子模塊功能2 先來分析一個功能 : 當前頁在頁碼列表中是第幾個位置 ?
從上述兩張圖片中,點擊1頁碼,當前頁處於列表的第1個位置,點擊2頁碼,當前頁處於列表的第2個位置,..........,點擊6頁碼,當前頁處於列表的第6個位置,但是當點擊7頁碼時,當前頁還是處於列表的第6個位置 。 也就是說,假如每次一行只能顯示10個頁碼,1~6頁碼的當前頁的位置還是1~6,列表從頁碼1~頁碼10。 但是7~10頁碼的當前頁的位置始終位於頁碼列表的第6個位置 ,列表從【頁碼2~頁碼11】~【頁碼X~頁碼totalPage】。其實非常好解決 ,列表頭尾的判定 還是利用pageCode , begin = pageCode - 5 , end = pageCode + 4 。
@解決
- 如果 totalPage <= 10(列表長度),那么 begin = 1,end = totalPage ;
- 使用公式計算;begin = pc-5 , end = pc + 4;
- 頭溢出:當 begin < 1 時 , 讓 begin = 1 ;
- 尾溢出:當 end > totalPage 時 , 讓 end = totalPage
有條件查和無條件查詢的影響 和 解決方案
@產生一個問題 分頁使得有條件查詢產生一個嚴重問題 , 通過條件查詢出40條記錄,分4頁顯示,只有第一頁是該條件下的記錄,其余3頁都是不帶條件的記錄 。所以我們必須告訴系統我們的條件是什么,每一頁都要帶着條件去查詢和返回 。
@解決 在pageBean中設置url參數 , 這個參數將會攜帶這條件傳遞到Servlet中 。
項目案例(mvc+jdbc+c3p0+BaseServlet+mysql+JSP+EL+JSTL)
@使用 mysql數據庫,c3p0數據庫連接池,
采用commons-dbutils組件,封裝好的JdbcUtils工具類和TxQueryRunner工具類輔助JDBC , (學習地址 : http://www.cnblogs.com/zyuqiang/p/7218083.html)
BaseServlet輔助類
JSP+EL+JSTL
@數據庫

1 CREATE TABLE t_customer ( 2 username VARCHAR(50) DEFAULT NULL, 3 age INT(11) DEFAULT NULL, 4 balance DOUBLE(20,5) DEFAULT NULL 5 );
@源碼

1 package cn.kmust.pagination.customer.domain; 2 /** 3 * 實體類 4 * 變量名字與數據庫中對應字段名一樣,便於封裝操作 5 * @author ZHAOYUQIANG 6 * 7 */ 8 public class Customer { 9 private String username ; //用戶 10 private int age ; //年齡 11 private double balance ; //資金 12 public String getUsername() { 13 return username; 14 } 15 public void setUsername(String username) { 16 this.username = username; 17 } 18 public int getAge() { 19 return age; 20 } 21 public void setAge(int age) { 22 this.age = age; 23 } 24 public double getBalance() { 25 return balance; 26 } 27 public void setBalance(double balance) { 28 this.balance = balance; 29 } 30 @Override 31 public String toString() { 32 return "Customer [username=" + username + ", age=" + age + ", balance=" 33 + balance + "]"; 34 } 35 public Customer(String username, int age, double balance) { 36 super(); 37 this.username = username; 38 this.age = age; 39 this.balance = balance; 40 } 41 public Customer() { 42 super(); 43 // TODO Auto-generated constructor stub 44 } 45 46 47 48 49 }

1 package cn.kmust.pagination.pageBean.domain; 2 import java.util.List; 3 import java.util.List; 4 /** 5 * 分頁Bean 6 * 把每一頁中的當前頁碼、總頁數、總記錄數、每頁記錄數、當前頁的記錄集合等參數 7 * 封裝到該類的一個對象中,形成PageBean對象 8 * @author ZHAOYUQIANG 9 * 10 */ 11 public class PageBean<T> { 12 private int pageCode ;//當前頁碼 13 // private int totalPage ;//總頁數,總頁數應該由計算獲取 14 private int totalRecord;//總記錄數 15 private int pageSize;//每頁記錄數,這是參數是定做這個軟件的甲方提出來的,在Servlet中直接定義為10了 16 private List<T> beanList;//當前頁的記錄集合,方便整頁記錄的轉移 17 private String url ;//Url后的條件,條件查詢設置的 18 19 public String getUrl() { 20 return url; 21 } 22 public void setUrl(String url) { 23 this.url = url; 24 } 25 public int getPageCode() { 26 return pageCode; 27 } 28 public void setPageCode(int pageCode) { 29 this.pageCode = pageCode; 30 } 31 /* 32 * 計算總頁數,這個頁數是由總記錄和每頁記錄數決定的 33 */ 34 public int getTotalPage() { 35 int totalPage = totalRecord/pageSize ; 36 return totalRecord%pageSize==0 ? totalPage : totalPage+1; 37 } 38 public int getTotalRecord() { 39 return totalRecord; 40 } 41 public void setTotalRecord(int totalRecord) { 42 this.totalRecord = totalRecord; 43 } 44 public int getPageSize() { 45 return pageSize; 46 } 47 public void setPageSize(int pageSize) { 48 this.pageSize = pageSize; 49 } 50 public List<T> getBeanList() { 51 return beanList; 52 } 53 public void setBeanList(List<T> beanList) { 54 this.beanList = beanList; 55 } 56 57 }

1 package cn.kmust.pagination.customer.servlet; 2 3 import java.io.IOException; 4 import java.io.UnsupportedEncodingException; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 import cn.itcast.commons.CommonUtils; 11 import cn.itcast.servlet.BaseServlet; 12 import cn.kmust.pagination.customer.domain.Customer; 13 import cn.kmust.pagination.customer.service.CustomerService; 14 import cn.kmust.pagination.pageBean.domain.PageBean; 15 /** 16 * Web層 17 * 繼承了我們自己寫的BaseServlet類 18 * 要求寫的方法得與service()相同, 19 * 並且.jsp頁面必須傳遞過來一個method參數,如(add、deleter等) 20 * 21 * @author ZHAOYUQIANG 22 * 23 */ 24 public class CustomerServlet extends BaseServlet { 25 /* 26 * 依賴CustomerService 27 */ 28 private CustomerService cstmService = new CustomerService(); 29 /** 30 * 客戶查詢所有 31 * 加入了分頁功能 : 向頁面返回當前頁的所有記錄, 返回的是一個對象,對象中封裝了一個beanList集合 32 * 該集合中存放這當前頁所有記錄 33 * @param request 34 * @param response 35 * @return 36 * @throws ServletException 37 * @throws IOException 38 */ 39 public String queryAll(HttpServletRequest request, HttpServletResponse response) 40 throws ServletException, IOException { 41 /* 42 * 1. 獲取list.jsp頁面傳遞的pc 43 * 2. 給定每頁記錄數ps = 10 。開發者根據客戶的需求,認為規定的 44 * 3. 使用pc和ps調用sevice方法,得到當前頁的PageBean對象(該對象中封裝了 45 * 當前頁的所有記錄的集合等) 46 * 4. 把PageBean保存到request域中 47 * 5. 轉發到list.jsp 48 * 49 */ 50 int pageCode = getCurrentPage(request); 51 int pageSize = 10 ; //每頁10記錄 52 PageBean<Customer> pageBean = cstmService.queryAll(pageCode,pageSize); 53 /* 54 * 因為與條件查詢共用一個list.jsp,所以也需要加url 55 */ 56 pageBean.setUrl(getUrl(request)); 57 request.setAttribute("pageBean", pageBean); 58 return "f:/list.jsp"; 59 60 } 61 62 63 /** 64 * 條件查詢 65 * 具有分頁功能,按照條件查詢,條件也會被帶入分頁中 66 * @param request 67 * @param response 68 * @return 69 * @throws ServletException 70 * @throws IOException 71 */ 72 public String query(HttpServletRequest request, HttpServletResponse response) 73 throws ServletException, IOException { 74 /* 75 * 1. 封裝表單數據到Customer對象中 76 * 只有一個屬性username,是查詢的條件critaria 77 * 2. 得到當前頁碼 pageCode 78 * 3. 給定pageSize 10 79 * 4. 使用pageCode和pageSize以及條件對象,調用service方法得到query, 80 * 返回當前頁的PageBean對象,內封裝了當前頁的所有記錄集合 81 * 5. 把PageBean保存到request域中 82 * 6. 轉發到list.jsp顯示成功信息 83 */ 84 Customer criteria = CommonUtils.toBean(request.getParameterMap(), Customer.class); 85 /* 86 * 處理GET請求方式編碼問題 87 * 因為query.jsp表單使用的是get提交方法 88 */ 89 criteria = encoding(criteria); 90 91 int pageCode = getCurrentPage(request); 92 int pageSize = 10 ; //每頁10記錄 93 PageBean<Customer> pageBean = cstmService.query(criteria,pageCode,pageSize); 94 /* 95 * 得到url,保存到pageBean對象中 96 */ 97 pageBean.setUrl(getUrl(request)); 98 request.setAttribute("pageBean", pageBean); 99 return "f:/list.jsp"; 100 } 101 102 103 /** 104 * 處理GET請求亂碼 105 * 因為BaseSevlet類中只有處理POST請求的亂碼,沒有GET請求的亂碼處理 106 * @param criteria 107 * @return 108 * @throws UnsupportedEncodingException 109 */ 110 private Customer encoding(Customer criteria) throws UnsupportedEncodingException { 111 String username = criteria.getUsername(); 112 113 if(username != null && !username.trim().isEmpty()){ 114 username = new String(username.getBytes("ISO-8859-1"),"utf-8"); 115 criteria.setUsername(username); 116 } 117 return criteria; 118 } 119 120 121 122 123 /** 124 * 獲取pageCode(當前頁碼) 125 * 傳遞到Servlet中的參數都是String類型的,所以需要轉換 126 * pageCode參數如果不存在,說明是第一次調用,當前頁碼默認為第一頁 127 * @param request 128 * @return 129 */ 130 private int getCurrentPage(HttpServletRequest request){ 131 String value = request.getParameter("pageCode"); 132 if(value == null || value.trim().isEmpty()){ 133 return 1 ; 134 } 135 return Integer.parseInt(value); 136 } 137 138 139 /** 140 * 截取url 141 * 條件查詢中需要使用 142 * /項目名/Servlet路徑?參數字符串 143 * @param request 144 * @return 145 */ 146 private String getUrl(HttpServletRequest request){ 147 /* 148 * 1. 獲取項目名 149 * 2. 獲取Servlet路徑 150 * 3. 獲取參數列表 151 * 這個參數是條件 152 */ 153 String contextPath = request.getContextPath(); 154 String servletPath = request.getServletPath(); 155 String queryString = request.getQueryString(); 156 /* 157 * 4. 判斷是否包含pageCode參數 158 * 如果包含需要剪掉,不要這個參數 159 */ 160 if(queryString.contains("&pageCode")){ 161 int index = queryString.lastIndexOf("&pageCode"); 162 queryString = queryString.substring(0,index); 163 } 164 return contextPath+servletPath+"?"+queryString ; 165 } 166 167 }

1 package cn.kmust.pagination.customer.service; 2 3 import java.sql.SQLException; 4 import java.util.List; 5 6 import cn.itcast.jdbc.JdbcUtils; 7 import cn.kmust.pagination.customer.dao.CustomerDao; 8 import cn.kmust.pagination.customer.domain.Customer; 9 import cn.kmust.pagination.pageBean.domain.PageBean; 10 11 12 13 /** 14 * service 層 處理業務 15 * @功能 16 * 1. 條件查詢 17 * 2. 查詢 所有用戶 18 * 3. 查詢 所有記錄行數 19 * @author ZHAOYUQIANG 20 * 21 */ 22 public class CustomerService { 23 /* 24 * 依賴CustomerDao 25 */ 26 CustomerDao cstmDao = new CustomerDao(); 27 /** 28 * 條件查詢 29 * 30 * @param criteria 31 * @param pageCode 32 * @param pageSize 33 * @return 34 */ 35 public PageBean<Customer> query(Customer criteria,int pc,int ps) { 36 return cstmDao.query(criteria,pc,ps); 37 } 38 /** 39 * 查詢所有客戶業務 40 * 具有分頁功能 : 返回PageBean對象 ,對象中封裝了 當前頁所有記錄的集合 41 * @param pc 42 * @param ps 43 * @return 44 */ 45 public PageBean<Customer> queryAll(int pc,int ps){ 46 return cstmDao.queryAll(pc,ps); 47 } 48 49 50 51 }

1 package cn.kmust.pagination.customer.dao; 2 3 import java.sql.ResultSet; 4 import java.sql.SQLException; 5 import java.util.ArrayList; 6 import java.util.List; 7 import java.util.Map; 8 9 import javax.sql.DataSource; 10 11 import org.apache.commons.dbutils.QueryRunner; 12 import org.apache.commons.dbutils.ResultSetHandler; 13 import org.apache.commons.dbutils.handlers.BeanHandler; 14 import org.apache.commons.dbutils.handlers.BeanListHandler; 15 import org.apache.commons.dbutils.handlers.MapHandler; 16 import org.apache.commons.dbutils.handlers.MapListHandler; 17 import org.apache.commons.dbutils.handlers.ScalarHandler; 18 19 import cn.itcast.jdbc.JdbcUtils; 20 import cn.itcast.jdbc.TxQueryRunner; 21 import cn.kmust.pagination.customer.domain.Customer; 22 import cn.kmust.pagination.pageBean.domain.PageBean; 23 24 25 26 27 /** 28 *dao層 29 * 對數據庫的操作 30 * @author ZHAOYUQIANG 31 * 32 */ 33 public class CustomerDao { 34 private QueryRunner qr = new TxQueryRunner(); 35 /** 36 * 對數據庫進行查詢所有客戶操作 37 * 具有分頁功能 : 返回PageBean對象,該對象封裝了當前頁的所有記錄的集合 38 * 當前頁的所有記錄都放到beanList集合中,然后隨當前頁碼等參數封裝到pageBean中返回 39 * @return 40 */ 41 public PageBean<Customer> queryAll(int pc,int ps){ 42 try { 43 /* 44 * 有關數據庫的操作: 45 * 准備sql模版 46 * 調用QueryRunner的query方法 47 */ 48 /*該方法的任務: 49 * 1. 創建PageBean對象 50 */ 51 PageBean<Customer> pageBean = new PageBean<Customer>(); 52 /* 53 * 2. 設置pc和ps,封裝到我pageBean對象 54 */ 55 pageBean.setPageCode(pc); 56 pageBean.setPageSize(ps); 57 /* 58 * 3. 查詢數據庫得到totalRecord(數據庫所有記錄),封裝到我pageBean對象 59 */ 60 String sql = "select count(*) from t_customer"; 61 Number num = (Number)qr.query(sql,new ScalarHandler() ); 62 int totalRecord = num.intValue(); 63 pageBean.setTotalRecord(totalRecord); 64 /* 65 * 4. 查詢數據庫得到BeanList(當前頁記錄的集合),封裝到我pageBean對象 66 * 當前頁到底是第幾頁,當前頁有多少條記錄呢? 67 * 利用mysql的limit子句, (limit 4,10的意思是從第五行記錄開始(包含第五行),查詢10行記錄) 68 * 很明顯當前頁的是從第(pc-1)*ps行開始,查詢ps行記錄。 69 * 根據limit子句的特點,巧妙的設計查詢當前頁的數據 70 * 用order by 通過客戶姓名來排序顯示 71 */ 72 sql = "select * from t_customer order by username limit ?,?"; 73 List<Customer> beanList = qr.query(sql, 74 new BeanListHandler<Customer>(Customer.class),(pc-1)*ps,ps); 75 pageBean.setBeanList(beanList); 76 /* 77 * 5. 返回PageBean對象 78 */ 79 return pageBean ; 80 } catch (SQLException e) { 81 throw new RuntimeException(e); 82 } 83 } 84 /** 85 * 條件查詢 86 * 具有分頁功能 87 * @param criteria 88 * @param pc 89 * @param ps 90 * @return 91 */ 92 public PageBean<Customer> query(Customer criteria,int pc,int ps) { 93 try { 94 /* 95 * 1. 創建PageBean對象 96 * 2. 設置已有屬性,pc和ps(pageCode和pageSize) 97 * 3. 通過條件查詢數據庫得到totalRecord 98 * 4. 查詢數據庫,返回beanList(當前頁記錄的集合) 99 */ 100 PageBean<Customer> pageBean = new PageBean<Customer>(); 101 pageBean.setPageCode(pc); 102 pageBean.setPageSize(ps); 103 /* 104 * 3. 通過條件查詢數據庫得到totalRecord 105 */ 106 String sql1 = null; 107 String username = criteria.getUsername(); 108 if(username != null && !username.trim().isEmpty()){ 109 sql1 = "select count(*) from t_customer where username like ?" ; 110 } 111 Object[] params1 = {"%"+username+"%"}; 112 /* 113 * 3.3. 得到totalRecord 114 */ 115 Number num = (Number)qr.query(sql1, 116 new ScalarHandler(),params1); 117 int totalRecord = num.intValue(); 118 pageBean.setTotalRecord(totalRecord); 119 /* 120 * 4. 查詢數據庫,返回beanList(當前頁記錄的集合) 121 * 還是需要拼湊sql語句,並且需要limit子句 122 * params中需要給出limit后兩個問號對應的值 123 * 124 */ 125 126 String sql2 = "select * from t_customer where username like ? limit ?,?"; 127 128 Object[] params = {"%"+username+"%",(pc-1)*ps,ps}; 129 List<Customer> beanList = qr.query(sql2, 130 new BeanListHandler<Customer>(Customer.class), 131 params); 132 pageBean.setBeanList(beanList); 133 return pageBean ; 134 } catch (SQLException e) { 135 throw new RuntimeException(e); 136 } 137 138 } 139 }
@項目download http://files.cnblogs.com/files/zyuqiang/jdbcStudy_Demo5_pagination.rar