1. 程式人生 > >Spring Data 查詢分頁 -- 分頁結果返回

Spring Data 查詢分頁 -- 分頁結果返回

針對資料查詢中的分頁請求引數和分頁結果返回,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的繼承結構

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());
	}