分頁原理淺析
1.關於分頁
只討論分頁,即顯示數據,不做任何過濾(搜索)和排序,僅僅是顯示數據
1.1hibernate的分頁
mysql用limit來作分頁,核心參數有兩個,start與size,即開始的位置與每頁顯示的數量,但是我們在用hibernate時發現使用他提供的
setFirstResult((page-1)*pageSize).setMaxResults(pageSize)也可以完成分頁
解釋下page和pageSize,page表示當前頁,也就是當前是第多少頁,pageSize依然表示本頁的數據量
page與start的關系為start=(page-1)*pageSize,以每頁2條數據為例,
select * from table limit 0,2 ---->第一頁數據是 1,2 start=0,page=1
select * from table limit 2,2 ---->第二頁數據是 3,4 start=2,page=2
select * from table limit 4,2 ---->第三頁數據是 5,6 start=4,page=3
.....
setMaxResults() -->查多少
1.2 實際使用
1.2.1 以jquery DataTable分頁為例
真正開發的時候我們顯示數據的時候,往往使用各種分頁插件,他們的分頁略有不同,但原理都是一樣的,即通過點擊頁碼,觸發ajax,發送當前頁碼(page)以及本頁要顯示的數據量(pageSize)給
後臺處理,以jquery DataTable為例, 其發送給後臺的參數就有start,代表第一條數據的起始位置比如 0代表第一條數據,當然還有length,但是你可能會見到這種寫法,這種寫法是公式的反推:page=(start / length) +1,先利用DataTable的ajax向servlet發送請求,發送的信息如下圖
事實上沒有必要再去計算出page,因為DataTable主動提供了start參數,這裏通過打印的形式來再次證明start與page的關系,(每頁顯示數據設置為2) 與我們上面1.1所寫的相互對照,發現打印的結果沒什麽問題
具體使用請參考https://www.cnblogs.com/tele-share/p/8667434.html
1.2.2 以bootstrap-paginator為例
然而大多數情況下,分頁插件不會直接提供start,只會提供page參數(因為對於一個插件來說,告訴你現在是第幾頁更加直接明了),比如bootstrap-paginator,這個時候你可以現在前臺計算出start然後傳遞start和size或者傳遞page和size,在後臺進行計算
(事實上在使用bootstrap-paginator的時候你需要兩次ajax,第一次查詢數據量,第二次才是顯示數據)
具體使用請參考http://www.cnblogs.com/tele-share/p/8982910.html
通過上面的分析我們可以發現分頁的核心參數是start和size,page,但是僅僅有這兩個參數顯然還不夠
1.2.3封裝Page類(顯示用的DataTable)
當你使用分頁插件的時候,不可避免的要去顯示""共計有多少條記錄","共計多少頁",此外你必須告訴你的分頁插件,你的數據總量,總頁數以及你每次查詢到的本頁的結果集,用戶輸入的關鍵詞在切換到下一頁
時是要仍然需要顯示在搜索框中,經過以上的分析我們發現這個時候封裝一個Page類就很有必要了(當然不封裝也可以),這個page類通常包括這些屬性:總頁數,總頁碼,當前頁,每頁顯示數據,關鍵詞,搜索的域
以及查詢到的結果集.
1 /*
2 * 分頁對象
3 *
4 */
5 public class Page<T> {
6 private Integer pageSize;//每頁顯示條數
7 private Integer page;//當前頁
8 private Integer pageTotal;//總頁數----->用於顯示當前共多少頁
9 private Integer recordsTotal;//總記錄數----->顯示當前共有多少條記錄
10 private String keywords;//關鍵字 假設只有一個
11 private String[] fields;
12 private List<T> list = new ArrayList<T>();
13
14 public Integer getPageTotal() {
15 return pageTotal;
16 }
17 public void setPageTotal(Integer pageTotal) {
18 this.pageTotal = pageTotal;
19 }
20 public Integer getRecordsTotal() {
21 return recordsTotal;
22 }
23 public void setRecordsTotal(Integer recordsTotal) {
24 this.recordsTotal = recordsTotal;
25 }
26 public List<T> getList() {
27 return list;
28 }
29 public void setList(List<T> list) {
30 this.list = list;
31 }
32 public Integer getPageSize() {
33 return pageSize;
34 }
35 public void setPageSize(Integer pageSize) {
36 this.pageSize = pageSize;
37 }
38 public Integer getPage() {
39 return page;
40 }
41 public void setPage(Integer page) {
42 this.page = page;
43 }
44 public String getKeywords() {
45 return keywords;
46 }
47 public void setKeywords(String keywords) {
48 this.keywords = keywords;
49 }
50 public String[] getFields() {
51 return fields;
52 }
53 public void setFields(String[] fields) {
54 this.fields = fields;
55 }
56 }
在servlet中要接收page,pageSize,keywords(關鍵字),fields(搜索域),這二者構成了查詢條件,接下來首先要根據關鍵字和域對象去查詢總量,得到總數據量後要來計算總頁數
總頁數可以用Math中的ceil()方法來計算,當熱if else也可以
1 //封裝page對象
2 @Override
3 public <T> Page<T> getPage(String keywords, String[] fields, Class clazz, int page, int pageSize) {
4 Page<T> pageBean = new Page<T>();
5 pageBean.setKeywords(keywords);
6 pageBean.setFields(fields);
7 pageBean.setPageSize(pageSize);
8 pageBean.setPage(page);
9 int start = (page-1)*pageSize;
10 List list = this.Page(keywords, fields, clazz,start,pageSize);//查詢的每頁的結果集
11 pageBean.setList(list);
12 Integer recordsTotal = bookDao.getCount(keywords, fields);
13 pageBean.setRecordsTotal(recordsTotal);
14 Integer pageTotal = 0;
15 /*if(recordsTotal % pageSize == 0) {
16 pageTotal = recordsTotal / pageSize;
17 }else {
18 pageTotal = (recordsTotal / pageSize) + 1;
19 }*/
20 pageTotal = (int) Math.ceil(recordsTotal / pageSize);//向上取整
21 pageBean.setPageTotal(pageTotal);
22 return pageBean;
23 }
如果你是從數據庫取數據的話到這個地方難點已經解決完了,因為這些分頁參數你都有了,接下來只要傳參數給數據庫就好了,但如果你沒有使用數據庫,你的數據是采集到本地磁盤上,然後用lucene建立索引庫查詢的話,你還要自己實現底層的分頁方法,底層的分頁處理,應當是遍歷查詢出的結果集然後封裝每一頁的數據,以下是偽代碼
1 List list = new ArrayList();
2 List<Document> docList = search(query);//docList是查詢的總數據集
3 int end = Math.min(start+size,docList.size());//也可以用if else判斷
4 for(int i=start;i<end;i++){
5 Document document = docList.get(i);
6 Object object = document2javabean(document, clazz);
7 list.add(object);
8 }
這樣做完之後,這個list裏面就是每一頁的數據了
總結:
1.封裝page類有時並不是很必要,裏面的一些屬性,也是看情況添加,但只要你封裝Page對象,那麽page和pageSize這兩個屬性少不了的
2.分頁插件多種多樣,各種參數眼花繚亂,但一些參數很固定,如總數據量,總頁數,當前頁,每頁數據量等,把這些參數處理好,分頁基本就ok了
分頁原理淺析