針對數據查詢中的分頁請求參數和分頁結果返回,Spring 做了建模抽象並提供了相應的工具實現,這部分模型和工具包含在包spring-data-commons中,本文對其中分頁結果返回部分做一下梳理,方便在開發中使用 。
分頁結果返回
接口Page
– 建模分頁結果集合的一頁
接口方法 | 介紹 |
---|---|
int getTotalPages() | 獲取整個數據集合的總頁數 |
int getTotalElements() | 獲取整個數據集合的總記錄數 |
<S> Page<S> map(Converter<? super T, ? extends S> converter) | 將該頁數據內的每條記錄使用converter做轉換後構造並返回一個新的Page對象 |
接口Page
繼承自接口Slice
,所以一個Page
對象除了以上能力之外,還具備一個接口Slice
所定義的能力。下面我們來看接口Slice
的定義。
接口Slice
– 建模一個記錄集合中連續的若干條記錄(一片數據)
接口Slice
– 建模一個記錄集合中連續的若干條記錄(一片數據),同時如果存在上/下一片數據的話,提供方法可獲取相應的Pageable
對象。
接口方法 | 介紹 |
---|---|
int getNumber() | 將整個數據集合的分成若干片,此函數返回當前片在所有片中的索引,可以理解成分頁數據的頁碼 |
int getSize() | 返回當前數據片中可容納數據記錄的條數,可以理解成分頁數據的頁面大小 |
int getNumberOfElements() | 返回當前數據片中實際包含的數據記錄的條數 |
List <T> getContent() | 返回當前數據片內的數據記錄集合 |
boolean hasContent() | 返回當前數據片內的是否包含數據記錄 |
Sort getSort() | 返回當前數據片內的排序參數 |
boolean isFirst() | 返回當前數據片是否是整個數據集合所有分片的第一個數據片, 注意 : 第一個數據分片的索引是0 |
boolean isLast() | 返回當前數據片是否是整個數據集合所有分片的最後一個數據片 |
boolean hasPrevious() | 返回當前數據片是否已經是整個數據集合所有分片的第一個數據片 |
boolean hasNext() | 返回當前數據片是否已經是整個數據集合所有分片的最後一個數據片 |
Pageable nextPageable() | 返回當前數據片的下一片數據的分頁查詢對象,如果不存在下一片數據,則返回null |
Pageable previousPageable() | 返回當前數據片的上一片數據的分頁查詢對象,如果不存在上一片數據,則返回null |
<S> Slice<S> map(Converter<? super T, ? extends S> converter) | 將該片數據內的每條記錄使用converter做轉換後構造並返回一個新的Slice對象 |
抽象類 Chunk
– 實現了接口Slice
定義的hasNext()
之外的所有接口方法
類 Chunk
實現了接口Slice
定義的除hasNext()
之外的所有接口方法,該類用於有一個Pageable
配置限定的一部分記錄,從字面上來理解,可以稱作是一個"數據塊"。因爲Chunk
本身不包含整個數據集合中總記錄數的信息,所以接口方法hasNext()
交由具體的實現類來提供。
類 Chunk
是抽象類,所以在真正構造表示分頁數據的對象時並不使用類 Chunk
,而是使用其實現類PageImpl
。
實現類 PageImpl
接口Page
的基礎實現
實現類 PageImpl
繼承自Chunk
,這是一個完全實現了所有接口Page
/Slice
定義了的方法的實現類。在真正構造分頁數據對象時,主要使用該類。
基於以下三個基本信息,可以構造一個PageImpl
對象 :
- 分頁數據記錄集合,
- 分頁數據記錄集合對應的
Pageable
對象,也就是相應的分頁請求參數對象, - 整個數據集合的記錄總數。
下面我們通過一張圖來看PageImpl
,Page
,Slice
,Chunk
之間的關係 :
PageImpl
使用的一個例子
該代碼片段摘自Spring
的工具類PageableExecutionUtils
,這是一個用於處理分頁查詢請求的工具類,當分頁查詢結果返回時,該類都是使用PageImpl
包裝結果集合爲一個Page
對象。
/**
* 使用 當前返回的分頁查詢結果集合 content, 當前分頁請求參數 pageable,和 整個記錄集合總記錄數獲取工具 構造一個
* Page 對象並返回。
*
* 這是一個靜態泛型方法,這裏 T 表示記錄的類型。
*
* @param content 分頁查詢結果的記錄集合,不允許爲 null。
* @param pageable 分頁查詢請求參數,可以爲 null,這個參數時發起分頁請求時根據請求參數構造的。
* @param totalSupplier 用於計算整個數據集合總記錄數的工具,不能爲 null.
**/
public static <T> Page<T> getPage(List<T> content, Pageable pageable, TotalSupplier totalSupplier) {
Assert.notNull(content, "Content must not be null!");
Assert.notNull(totalSupplier, "TotalSupplier must not be null!");
if (pageable == null || pageable.getOffset() == 0) {
// 查詢結果沒有被要求分頁,或者處於請求第一頁的情況
if (pageable == null || pageable.getPageSize() > content.size()) {
// 1.查詢結果沒有被要求分頁,或者
// 2.查詢結果被要求分頁,但是處於第一頁,並且頁尺寸大於實際記錄數量
return new PageImpl<T>(content, pageable, content.size());
}
// 查詢結果被要求分頁,並且尚未獲取整個數據記錄集合中的總記錄數
return new PageImpl<T>(content, pageable, totalSupplier.get());
}
if (content.size() != 0 && pageable.getPageSize() > content.size()) {
// 查詢結果被要求分頁,並且判斷出當前正在查詢整個數據集合的最後一頁
return new PageImpl<T>(content, pageable, pageable.getOffset() + content.size());
}
// 其他情況:統一使用 當前返回的分頁查詢結果集合 content, 當前分頁請求參數 pageable,
// 和 整個記錄集合總記錄數獲取工具 構造一個 PageImpl對象。
return new PageImpl<T>(content, pageable, totalSupplier.get());
}