使用 REST 訪問 JPA 資料

本指南將引導您建立一個應用程式,該應用程式透過基於超媒體的 RESTful 前端訪問關係型 JPA 資料。

您將構建什麼

您將構建一個 Spring 應用程式,該應用程式允許您使用 Spring Data REST 建立和檢索儲存在資料庫中的 Person 物件。Spring Data REST 結合了 Spring HATEOASSpring Data JPA 的功能,並自動將它們組合在一起。

Spring Data REST 還支援 Spring Data Neo4jSpring Data GemfireSpring Data MongoDB 作為後端資料儲存,但這些不是本指南的一部分。

你需要什麼

  • 大約 15 分鐘

  • 一個喜歡的文字編輯器或 IDE

  • Java 17 或更高版本

如何完成本指南

與大多數 Spring 入門指南一樣,您可以從頭開始並完成每個步驟,或者透過檢視此儲存庫中的程式碼直接跳到解決方案。

在您的本地環境中檢視最終結果,您可以執行以下操作之一

從 Spring Initializr 開始

您可以使用這個預初始化專案,然後點選生成下載一個 ZIP 檔案。該專案已配置為符合本教程中的示例。

手動初始化專案

  1. 導航到 https://start.spring.io。此服務會為您拉取應用程式所需的所有依賴項,併為您完成大部分設定。

  2. 選擇 Gradle 或 Maven 以及您想要使用的語言。本指南假設您選擇了 Java。

  3. 點選 Dependencies 並選擇 Rest RepositoriesSpring Data JPAH2 Database

  4. 單擊生成

  5. 下載生成的 ZIP 檔案,這是一個已根據您的選擇配置好的 Web 應用程式存檔。

如果您的 IDE 集成了 Spring Initializr,您可以從 IDE 中完成此過程。
您還可以從 Github fork 該專案並在您的 IDE 或其他編輯器中開啟它。

建立領域物件

建立一個新的域物件來表示一個人,如以下清單(在 src/main/java/com/example/accessingdatarest/Person.java 中)所示:

package com.example.accessingdatarest;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Person {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;

  private String firstName;
  private String lastName;

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
}

Person 物件有一個名字和一個姓氏。(還有一個 ID 物件被配置為自動生成,所以您無需處理它。)

建立 Person 倉庫

接下來,您需要建立一個簡單的倉庫,如以下清單(在 src/main/java/com/example/accessingdatarest/PersonRepository.java 中)所示:

package com.example.accessingdatarest;

import java.util.List;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

@RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long>, CrudRepository<Person,Long> {

  List<Person> findByLastName(@Param("name") String name);

}

此倉庫是一個介面,允許您執行涉及 Person 物件的各種操作。它透過擴充套件 Spring Data Commons 中定義的 PagingAndSortingRepository 介面來獲取這些操作。

在執行時,Spring Data REST 會自動建立此介面的實現。然後它使用 @RepositoryRestResource 註解來指示 Spring MVC 在 /people 建立 RESTful 端點。

匯出儲存庫不需要 @RepositoryRestResource。它僅用於更改匯出詳細資訊,例如使用 /people 而不是預設值 /persons

在這裡,您還定義了一個自定義查詢,用於根據 lastName 檢索 Person 物件列表。您可以在本指南稍後看到如何呼叫它。

Spring Boot 會自動啟動 Spring Data JPA,以建立 PersonRepository 的具體實現,並將其配置為使用 JPA 與後端記憶體資料庫通訊。

Spring Data REST 構建在 Spring MVC 之上。它建立了一系列 Spring MVC 控制器、JSON 轉換器和其他 Bean,以提供 RESTful 前端。這些元件連線到 Spring Data JPA 後端。當您使用 Spring Boot 時,這一切都是自動配置的。如果您想透過檢視 Spring Data REST 中的 RepositoryRestMvcConfiguration 來了解其工作原理。

執行應用程式

您現在可以透過執行 AccessingDataRestApplication 中的主方法來執行應用程式。您可以從 IDE 執行程式,或者在專案根目錄中執行以下 Gradle 命令:

./gradlew bootRun

或者,您可以使用 Maven 執行應用程式,命令如下:

./mvnw spring-boot:run

測試應用程式

現在應用程式正在執行,您可以對其進行測試。您可以使用任何您喜歡的 REST 客戶端。以下示例使用 *nix 工具 curl

首先,您想檢視頂層服務。以下示例展示瞭如何操作:

$ curl https://:8080
{
  "_links" : {
    "people" : {
      "href" : "https://:8080/people{?page,size,sort}",
      "templated" : true
    }
  }
}

前面的例子首次展示了這個伺服器所提供的內容。在 https://:8080/people 處有一個 people 連結。它有一些選項,例如 ?page?size?sort

Spring Data REST 使用 HAL 格式進行 JSON 輸出。它靈活方便,提供了一種在所服務資料旁邊提供連結的方法。

以下示例展示瞭如何檢視人員記錄(目前沒有):

$ curl https://:8080/people
{
  "_embedded" : {
    "people" : []
  },
  "_links" : {
    "self" : {
      "href" : "https://:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "https://:8080/people/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}

目前沒有元素,因此也沒有頁面。是時候建立一個新的 Person 了!以下清單顯示瞭如何操作:

$ curl -i -H "Content-Type:application/json" -d '{"firstName": "Frodo", "lastName": "Baggins"}' https://:8080/people
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: https://:8080/people/1
Content-Length: 0
Date: Wed, 26 Feb 2014 20:26:55 GMT
  • -i: 確保您可以看到響應訊息,包括頭部。顯示新建立的 Person 的 URI。

  • -H "Content-Type:application/json": 設定內容型別,以便應用程式知道有效負載包含一個 JSON 物件。

  • -d '{"firstName": "Frodo", "lastName": "Baggins"}': 正在傳送的資料。

  • 如果您在 Windows 上,上述命令將在 WSL 上執行。如果您無法安裝 WSL,您可能需要將單引號替換為雙引號並轉義現有的雙引號,即 -d "{\"firstName\": \"Frodo\", \"lastName\": \"Baggins\"}"

請注意,POST 操作的響應中包含了 Location 頭部。它包含了新建立資源的 URI。Spring Data REST 還提供了兩種方法(RepositoryRestConfiguration.setReturnBodyOnCreate(…)setReturnBodyOnUpdate(…)),您可以使用它們來配置框架,使其立即返回剛剛建立的資源的表示。RepositoryRestConfiguration.setReturnBodyForPutAndPost(…) 是一個快捷方法,用於為建立和更新操作啟用表示響應。

您可以查詢所有人員,如下例所示:

$ curl https://:8080/people
{
  "_links" : {
    "self" : {
      "href" : "https://:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "https://:8080/people/search"
    }
  },
  "_embedded" : {
    "people" : [ {
      "firstName" : "Frodo",
      "lastName" : "Baggins",
      "_links" : {
        "self" : {
          "href" : "https://:8080/people/1"
        }
      }
    } ]
  },
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}

people 物件包含一個列表,其中包含 Frodo。請注意它如何包含一個 self 連結。Spring Data REST 還使用 Evo Inflector 將實體名稱複數化以進行分組。

您可以直接查詢單個記錄,如下所示:

$ curl https://:8080/people/1
{
  "firstName" : "Frodo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "https://:8080/people/1"
    }
  }
}
這可能看起來純粹是基於網路的。然而,在幕後,有一個 H2 關係型資料庫。在生產環境中,您可能會使用一個真實的資料庫,例如 PostgreSQL。
在本指南中,只有一個領域物件。在一個更復雜的系統中,如果領域物件之間存在關聯,Spring Data REST 會渲染額外的連結以幫助導航到連線的記錄。

您可以找到所有自定義查詢,如下例所示:

$ curl https://:8080/people/search
{
  "_links" : {
    "findByLastName" : {
      "href" : "https://:8080/people/search/findByLastName{?name}",
      "templated" : true
    }
  }
}

您可以看到查詢的 URL,包括 HTTP 查詢引數 name。請注意,這與嵌入在介面中的 @Param("name") 註解匹配。

以下示例展示瞭如何使用 findByLastName 查詢:

$ curl https://:8080/people/search/findByLastName?name=Baggins
{
  "_embedded" : {
    "persons" : [ {
      "firstName" : "Frodo",
      "lastName" : "Baggins",
      "_links" : {
        "self" : {
          "href" : "https://:8080/people/1"
        }
      }
    } ]
  }
}

因為您在程式碼中將其定義為返回 List<Person>,所以它會返回所有結果。如果您將其定義為只返回 Person,它會選擇一個 Person 物件返回。由於這可能是不可預測的,對於可能返回多個條目的查詢,您可能不希望這樣做。

您還可以發出 PUTPATCHDELETE REST 呼叫,分別用於替換、更新或刪除現有記錄。以下示例使用 PUT 呼叫:

$ curl -X PUT -H "Content-Type:application/json" -d '{"firstName": "Bilbo", "lastName": "Baggins"}' https://:8080/people/1
$ curl https://:8080/people/1
{
  "firstName" : "Bilbo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "https://:8080/people/1"
    }
  }
}

以下示例使用 PATCH 呼叫:

$ curl -X PATCH -H "Content-Type:application/json" -d '{"firstName": "Bilbo Jr."}' https://:8080/people/1
$ curl https://:8080/people/1
{
  "firstName" : "Bilbo Jr.",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "https://:8080/people/1"
    }
  }
}
PUT 替換整個記錄。未提供的欄位將被替換為 null。您可以使用 PATCH 更新部分專案。

您還可以刪除記錄,如下例所示:

$ curl -X DELETE https://:8080/people/1
$ curl https://:8080/people
{
  "_links" : {
    "self" : {
      "href" : "https://:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "https://:8080/people/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}

這種超媒體驅動的介面的一個便利之處在於,您可以使用 curl(或任何您喜歡的 REST 客戶端)發現所有 RESTful 端點。您無需與客戶交換正式的合同或介面文件。

總結

恭喜!您已經開發了一個具有基於超媒體的 RESTful 前端和基於 JPA 的後端的應用程式。

獲取程式碼