【本人禿頂程序員】Spring中的REST分頁

←←←←←←←←←←←← 快!點關注程序員

本文將介紹在REST API中實現分頁的基礎知識。咱們將專一於使用Spring Boot和Spring Data 在Spring MVC中構建REST分頁。web

分頁是一種處理大結果數據集的機制。在REST API中實現分頁並無什麼不一樣,但須要一些額外的思考過程。爲REST API提供流暢有效的分頁能夠增長用戶體驗並有助於構建高效,快速的REST API。咱們使用Spring Boot做爲示例。spring

1.資源與表示

在咱們開始設計分頁API以前,咱們須要清楚地瞭解頁面做爲資源或資源的表示。咱們須要記住許多基本要素sql

一個頁面Page不是REST中的一個資源,而是其請求的屬性。數據庫

以資源名稱Product爲構建分頁的例子,在高層次上咱們確實有如下三個選項來構建分頁。緩存

  • 將產品Product做爲資源並使用查詢字符串來處理分頁以及其餘參數,例如排序等。
  • 第二個選項是將頁面Page用做資源和查詢字符串進行排序。
  • 使用頁面Page做爲資源和URL部分進行排序。

考慮到上述問題,讓咱們嘗試回答一些在設計REST API分頁時有用的問題。bash

  • 您是否將頁面Page視爲頁面中產品的資源?

請記住,REST API不是圍繞任何預約義的規則或規範構建的,全部上述三個選項都是有效的,而且基於上述問題的答案。若是咱們將頁面視爲資源,則選項3是有效選擇;但若是咱們說頁面上的產品是資源,那麼選項3再也不有效(在第1,2頁上的產品可能會在未來更改),就我的而言,我會選擇選項1,由於對我來講,頁面 Page 不是 資源Resouce,它是請求的屬性。架構

2.可發現性

可發現性 有助於使 RESTful API 更加實用和優雅。使REST API 可被發現常常被忽視。如下是REST API可發現性的高級摘要 。app

  • 有了這個功能,REST API在對客戶端的響應中提供完整的URI意味着沒有客戶端須要「組合」URI。
  • 客戶端API獨立於URI結構。
  • 經過以上2點,API更加靈活,容許開發人員在不破壞API的狀況下更改URI架構。(請記住,API提供全部URI,它們不是由客戶端API動態建立的)。

可發現性與REST API中的HATEOAS密切相關。REST API分頁可發現將經過"next","previous","first"和"last"鏈路做爲響應數據的一部分。咱們正在考慮如何在分頁期間將此功能添加到您的API。框架

3.分頁設計考慮因素

在構建REST API分頁界面時,讓咱們快速介紹一些要點。

3.1 限制limit

限制容許API和客戶端控制結果集中請求的結果數。經過傳遞 limit 參數,您能夠指定每一個頁面要返回的項目數.API能夠配置默認限制,但應容許客戶端指定限制。

在上面的請求中,客戶端將限制設置爲50.當心,同時容許客戶將limit 參數設置 , 設置爲極高數量的限制會下降API性能。建議在API設計期間具備最大容許限制。

3.2排序

排序老是與搜索和分頁並排。在設計REST API時,提供靈活性,讓客戶指定排序選項,同時從API返回結果。建議在設計API時使用 sort_by = [attribute name] - [asc / desc]模式.API設計器應將容許的屬性名稱指定爲sort參數。例如,您可使用?name-asc按產品名稱排序或?name-desc反向排序。

4. Maven依賴

咱們在Spring中處理REST分頁時介紹了全部基本內容。咱們在這篇文章中使用瞭如下技術堆棧,但它能夠在任何其餘技術上實現,前提是您在設計時遵循全部基本原則。

  • Spring Boot
  • JPA.
  • Spring Data REST

在本文中使用Spring Data REST的緣由之一是Data REST API支持的開箱即用功能。

咱們將在pom.xml中添加如下依賴項

  1. Spring Boot JPA
  2. Spring Boot Data REST
  3. HATEOS和Web
<dependencies>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-rest</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-hateoas</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <dependency>
      <groupId>org.hsqldb</groupId>
      <artifactId>hsqldb</artifactId>
      <scope>runtime</scope>
   </dependency>
</dependencies>
複製代碼

4.1 REST控制器:

@RestController
public class ProductRESTController {

 @Autowired
 private ProductService productService;

 @Autowired private EntityLinks links;

 @GetMapping(value = "/products", produces = MediaType.APPLICATION_JSON_VALUE)
 public ResponseEntity < PagedResources < ProductEntity >> AllProducts(Pageable pageable, PagedResourcesAssembler assembler) {
  Page < ProductEntity > products = productService.findAllProducts(pageable);
  PagedResources < ProductEntity > pr = assembler.toResource(products, linkTo(ProductRESTController.class).slash("/products").withSelfRel());
  HttpHeaders responseHeaders = new HttpHeaders();
  responseHeaders.add("Link", createLinkHeader(pr));
  return new ResponseEntity < > (assembler.toResource(products, linkTo(ProductRESTController.class).slash("/products").withSelfRel()), responseHeaders, HttpStatus.OK);
 }

 private String createLinkHeader(PagedResources < ProductEntity > pr) {
  final StringBuilder linkHeader = new StringBuilder();
  linkHeader.append(buildLinkHeader(pr.getLinks("first").get(0).getHref(), "first"));
  linkHeader.append(", ");
  linkHeader.append(buildLinkHeader(pr.getLinks("next").get(0).getHref(), "next"));
  return linkHeader.toString();
 }

 public static String buildLinkHeader(final String uri, final String rel) {
  return "<" + uri + ">; rel=\"" + rel + "\"";
 }
}
複製代碼

讓咱們快速介紹上面代碼中的幾個要點。

  1. 咱們使用 Pageable做爲控制器的參數之一。這將有助於返回頁面而不是列表。
  2. Pageable具備全部必需的分頁信息。
  3. Pageable在Spring JPA中運行得很是好,而且透明地處理分頁。

4.2 Previous 和Next 連接

每一個頁面響應將返回連接到當前頁面前面和後面的頁,這是基於使用IANA定義連接關係 prev 和 next。可是,若是您當前位於結果的第一頁,則不會呈現任何 prev連接。

咱們來看下面的例子:

{
    "_embedded": {
        "productEntities": [
            ...data...
        ]
    },
    "_links": {
        "first": {
            "href": "http://localhost:8080/products?page=0&size=20"
        },
        "self": {
            "href": "http://localhost:8080/products"
        },
        "next": {
            "href": "http://localhost:8080/products?page=1&size=20"
        },
        "last": {
            "href": "http://localhost:8080/products?page=4&size=20"
        }
    },
    "page": {
        "size": 20,
        "totalElements": 100,
        "totalPages": 5,
        "number": 0
    }
}
複製代碼

讓咱們深刻了解響應數據中的一些有趣事實

  • next 連接指向下一頁。last 連接指向的最後一個結果集。
  • self 連接提供整個系列。
  • 底部 page 提供有關分頁的信息,包括頁面大小,總結果,總頁數和當前頁碼。

4.3使用連接頭

HTTP標頭是REST API的關鍵方面.HTTP連接標頭還可用於將分頁信息傳遞給客戶端。經過上述測試,系統將返回如下附加信息做爲Link HTTP標頭的一部分。

Link →<http://localhost:8080/products?page=0&size=20>; rel="first", <http://localhost:8080/products?page=1&size=20>; rel="next"
複製代碼

rel="next" 意思是下一頁是 page=2;rel="first" 意思是第一頁老是依賴page=2.於提供給你的這些連接關係。不要試圖猜想或構建本身的URL。Spring PagedResource提供全部這些信息做爲結果的一部分,咱們只須要確保從這些信息中構建正確的HTTP頭。在咱們的控制器示例中,咱們在createLinkHeader方法中構建標頭。

private String createLinkHeader(PagedResources < ProductEntity > pr) {
 final StringBuilder linkHeader = new StringBuilder();
 linkHeader.append(buildLinkHeader(pr.getLinks("first").get(0).getHref(), "first"));
 linkHeader.append(", ");
 linkHeader.append(buildLinkHeader(pr.getLinks("next").get(0).getHref(), "next"));
 return linkHeader.toString();
}

public static String buildLinkHeader(final String uri, final String rel) {
 return "<" + uri + ">; rel=\"" + rel + "\"";
}
複製代碼

總結

在這篇文章中,咱們學習瞭如何在Spring和Spring Boot中實現 REST分頁。咱們討論瞭如何構建響應以及在REST API響應中使用連接HTTP標頭的重要性。

歡迎你們加入粉絲羣:963944895,羣內免費分享Spring框架、Mybatis框架SpringBoot框架、SpringMVC框架、SpringCloud微服務、Dubbo框架、Redis緩存、RabbitMq消息、JVM調優、Tomcat容器、MySQL數據庫教學視頻及架構學習思惟導圖

寫在最後:

禿頂程序員的不易,看到這裏,點了關注吧!點關注,不迷路,持續更新!!!

相關文章
相關標籤/搜索