1. 程式人生 > >分頁原理淺析

分頁原理淺析

++ 就是 end IV lds 記錄 bject 偽代碼 請求

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
.....

setFirstResult() -->從哪開始查
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了

分頁原理淺析