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;
}
}
透過 REST 存取 JPA 資料
您將建構的內容
您將建構一個 Spring 應用程式,讓您可以使用 Spring Data REST 建立和檢索儲存在資料庫中的 Person
物件。Spring Data REST 結合了 Spring HATEOAS 和 Spring Data JPA 的功能,並自動將它們結合在一起。
Spring Data REST 也支援 Spring Data Neo4j、Spring Data Gemfire 和 Spring Data MongoDB 作為後端資料儲存區,但這些不屬於本指南的一部分。 |
您需要的東西
-
約 15 分鐘
-
慣用的文字編輯器或 IDE
-
Java 17 或更高版本
如何完成本指南
若要在您的本機環境中查看最終結果,您可以執行下列其中一項操作
-
下載 並解壓縮本指南的原始碼儲存庫
-
使用 Git 複製儲存庫:
git clone https://github.com/spring-guides/gs-accessing-data-rest.git
-
Fork 儲存庫,讓您可以透過提交 pull request 來請求變更本指南
從 Spring Initializr 開始
您可以使用這個預先初始化的專案,然後按一下 Generate 以下載 ZIP 檔案。此專案已設定為符合本教學課程中的範例。
若要手動初始化專案
-
導覽至 https://start.spring.io。此服務會提取應用程式所需的所有相依性,並為您完成大部分的設定。
-
選擇 Gradle 或 Maven 以及您想要使用的語言。本指南假設您選擇 Java。
-
按一下Dependencies,然後選取 Rest Repositories、Spring Data JPA 和 H2 Database。
-
按一下Generate。
-
下載產生的 ZIP 檔案,這是一個已使用您的選擇設定的 Web 應用程式的封存檔。
如果您的 IDE 具有 Spring Initializr 整合,您可以從您的 IDE 完成此流程。 |
您也可以從 Github fork 專案,並在您的 IDE 或其他編輯器中開啟它。 |
建立 Domain 物件
建立新的 domain 物件來呈現 person,如下列清單所示 (在 src/main/java/com/example/accessingdatarest/Person.java
中)
Person
物件具有名字和姓氏。(還有一個 ID 物件已設定為自動產生,因此您無需處理它。)
建立 Person Repository
接下來,您需要建立一個簡單的 repository,如下列清單所示 (在 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);
}
此 repository 是一個介面,可讓您執行各種涉及 Person
物件的操作。它透過擴展 Spring Data Commons 中定義的 PagingAndSortingRepository
介面來取得這些操作。
在執行階段,Spring Data REST 會自動建立此介面的實作。然後它使用 @RepositoryRestResource 註解來指示 Spring MVC 在 /people
建立 RESTful 端點。
@RepositoryRestResource 不是 repository 匯出所必需的。它僅用於變更匯出詳細資訊,例如使用 /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
中的 main 方法來執行應用程式。您可以從 IDE 執行程式,或透過在專案根目錄中執行下列 Gradle 命令
./gradlew bootRun
或者,您可以使用 Maven 來執行應用程式,使用命令
./mvnw spring-boot:run
測試應用程式
現在應用程式正在執行中,您可以測試它。您可以使用任何您想要的 REST client。下列範例使用 *nix 工具 curl
。
首先,您想要查看頂層服務。下列範例示範如何執行此操作
$ curl https://127.0.0.1:8080 { "_links" : { "people" : { "href" : "https://127.0.0.1:8080/people{?page,size,sort}", "templated" : true } } }
前面的範例提供了此伺服器提供的功能的第一瞥。有一個 people
連結位於 https://127.0.0.1:8080/people
。它有一些選項,例如 ?page
、?size
和 ?sort
。
Spring Data REST 使用 HAL 格式 作為 JSON 輸出。它很彈性,並提供了一種方便的方式來提供與所服務資料相鄰的連結。 |
下列範例示範如何查看 person 記錄 (目前沒有)
$ curl https://127.0.0.1:8080/people { "_embedded" : { "people" : [] }, "_links" : { "self" : { "href" : "https://127.0.0.1:8080/people{?page,size,sort}", "templated" : true }, "search" : { "href" : "https://127.0.0.1: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://127.0.0.1:8080/people HTTP/1.1 201 Created Server: Apache-Coyote/1.1 Location: https://127.0.0.1:8080/people/1 Content-Length: 0 Date: Wed, 26 Feb 2014 20:26:55 GMT
-
-i
:確保您可以查看包含標頭的回應訊息。顯示新建立的Person
的 URI。 -
-H "Content-Type:application/json"
:設定內容類型,以便應用程式知道 payload 包含 JSON 物件。 -
-d '{"firstName": "Frodo", "lastName": "Baggins"}'
:是要傳送的資料。 -
如果您使用的是 Windows,則上述命令將在 WSL 上運作。如果您無法安裝 WSL,您可能需要將單引號替換為雙引號,並 escape 現有的雙引號,即
-d "{\"firstName\": \"Frodo\", \"lastName\": \"Baggins\"}"
。
請注意,POST 操作的回應如何包含 Location 標頭。這包含新建立資源的 URI。Spring Data REST 也有兩種方法 (RepositoryRestConfiguration.setReturnBodyOnCreate(…) 和 setReturnBodyOnUpdate(…) ),您可以使用它們來設定框架以立即傳回剛建立的資源的表示形式。RepositoryRestConfiguration.setReturnBodyForPutAndPost(…) 是一種快捷方式方法,可為建立和更新操作啟用表示形式回應。 |
您可以查詢所有 person,如下列範例所示
$ curl https://127.0.0.1:8080/people { "_links" : { "self" : { "href" : "https://127.0.0.1:8080/people{?page,size,sort}", "templated" : true }, "search" : { "href" : "https://127.0.0.1:8080/people/search" } }, "_embedded" : { "people" : [ { "firstName" : "Frodo", "lastName" : "Baggins", "_links" : { "self" : { "href" : "https://127.0.0.1:8080/people/1" } } } ] }, "page" : { "size" : 20, "totalElements" : 1, "totalPages" : 1, "number" : 0 } }
people
物件包含一個包含 Frodo
的清單。請注意它如何包含 self
連結。Spring Data REST 也使用 Evo Inflector 來複數化實體名稱以進行分組。
您可以直接查詢個別記錄,如下所示
$ curl https://127.0.0.1:8080/people/1 { "firstName" : "Frodo", "lastName" : "Baggins", "_links" : { "self" : { "href" : "https://127.0.0.1:8080/people/1" } } }
這可能看起來純粹是基於 Web 的。但是,在幕後,有一個 H2 關聯式資料庫。在生產環境中,您可能會使用真正的資料庫,例如 PostgreSQL。 |
在本指南中,只有一個 domain 物件。在更複雜的系統中,domain 物件彼此相關,Spring Data REST 會呈現額外的連結,以協助導覽到連線的記錄。 |
您可以找到所有自訂查詢,如下列範例所示
$ curl https://127.0.0.1:8080/people/search { "_links" : { "findByLastName" : { "href" : "https://127.0.0.1:8080/people/search/findByLastName{?name}", "templated" : true } } }
您可以看到查詢的 URL,包括 HTTP 查詢參數 name
。請注意,這與嵌入在介面中的 @Param("name")
註解相符。
下列範例示範如何使用 findByLastName
查詢
$ curl https://127.0.0.1:8080/people/search/findByLastName?name=Baggins { "_embedded" : { "persons" : [ { "firstName" : "Frodo", "lastName" : "Baggins", "_links" : { "self" : { "href" : "https://127.0.0.1:8080/people/1" } } } ] } }
由於您將其定義為在程式碼中傳回 List<Person>
,因此它會傳回所有結果。如果您將其定義為僅傳回 Person
,它會選擇一個 Person
物件傳回。由於這可能是不可預測的,因此您可能不希望對可能傳回多個條目的查詢執行此操作。
您也可以發出 PUT
、PATCH
和 DELETE
REST 呼叫,以分別取代、更新或刪除現有記錄。下列範例使用 PUT
呼叫
$ curl -X PUT -H "Content-Type:application/json" -d '{"firstName": "Bilbo", "lastName": "Baggins"}' https://127.0.0.1:8080/people/1 $ curl https://127.0.0.1:8080/people/1 { "firstName" : "Bilbo", "lastName" : "Baggins", "_links" : { "self" : { "href" : "https://127.0.0.1:8080/people/1" } } }
下列範例使用 PATCH
呼叫
$ curl -X PATCH -H "Content-Type:application/json" -d '{"firstName": "Bilbo Jr."}' https://127.0.0.1:8080/people/1 $ curl https://127.0.0.1:8080/people/1 { "firstName" : "Bilbo Jr.", "lastName" : "Baggins", "_links" : { "self" : { "href" : "https://127.0.0.1:8080/people/1" } } }
PUT 會取代整個記錄。未提供的欄位會被取代為 null 。您可以使用 PATCH 來更新項目的子集。 |
您也可以刪除記錄,如下列範例所示
$ curl -X DELETE https://127.0.0.1:8080/people/1 $ curl https://127.0.0.1:8080/people { "_links" : { "self" : { "href" : "https://127.0.0.1:8080/people{?page,size,sort}", "templated" : true }, "search" : { "href" : "https://127.0.0.1:8080/people/search" } }, "page" : { "size" : 20, "totalElements" : 0, "totalPages" : 0, "number" : 0 } }
此超媒體驅動介面的一個便利之處在於,您可以使用 curl (或任何您喜歡的 REST client) 探索所有 RESTful 端點。您無需與您的客戶交換正式合約或介面文件。
摘要
恭喜!您已開發出一個具有超媒體為基礎的 RESTful 前端和 JPA 為基礎的後端的應用程式。