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 仓库,这样您就可以通过提交拉取请求来请求对本指南的更改
从 Spring Initializr 开始
您可以使用这个预初始化项目,然后点击生成下载一个 ZIP 文件。该项目已配置为符合本教程中的示例。
手动初始化项目
-
导航到 https://start.spring.io。此服务会为您拉取应用程序所需的所有依赖项,并为您完成大部分设置。
-
选择 Gradle 或 Maven 以及您想要使用的语言。本指南假设您选择了 Java。
-
点击 Dependencies 并选择 Rest Repositories、Spring Data JPA 和 H2 Database。
-
单击生成。
-
下载生成的 ZIP 文件,这是一个已根据您的选择配置好的 Web 应用程序存档。
| 如果您的 IDE 集成了 Spring Initializr,您可以从 IDE 中完成此过程。 |
| 您还可以从 Github fork 该项目并在您的 IDE 或其他编辑器中打开它。 |
创建领域对象
创建一个新的域对象来表示一个人,如以下清单(在 src/main/java/com/example/accessingdatarest/Person.java 中)所示:
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 对象返回。由于这可能是不可预测的,对于可能返回多个条目的查询,您可能不希望这样做。
您还可以发出 PUT、PATCH 和 DELETE 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 的后端的应用程序。