Spring Data REST 的扩展
虽然用户被鼓励使用 Panache REST Data 来生成 REST 数据访问端点,但 Quarkus 通过 spring-data-rest
扩展提供了一个兼容层,用于 Spring Data REST。
先决条件
要完成本指南,您需要
-
大约 15 分钟
-
一个 IDE
-
已安装 JDK 17+ 并正确配置了
JAVA_HOME
-
Apache Maven 3.9.9
-
如果您想使用它,可以选择 Quarkus CLI
-
如果您想构建本机可执行文件(或者如果您使用本机容器构建,则为 Docker),可以选择安装 Mandrel 或 GraalVM 并进行适当的配置
解决方案
我们建议您按照以下章节中的说明,逐步创建应用程序。但是,您可以直接转到完整的示例。
克隆 Git 仓库:git clone https://github.com/quarkusio/quarkus-quickstarts.git
,或下载一个 存档。
解决方案位于 spring-data-rest-quickstart
目录。
创建 Maven 项目
首先,我们需要一个新项目。使用以下命令创建一个新项目
对于 Windows 用户
-
如果使用 cmd,(不要使用反斜杠
\
并将所有内容放在同一行上) -
如果使用 Powershell,请将
-D
参数用双引号括起来,例如"-DprojectArtifactId=spring-data-rest-quickstart"
此命令将生成一个包含 spring-data-rest
扩展的项目。
如果您已配置好 Quarkus 项目,可以通过在项目根目录中运行以下命令,将 spring-data-rest
扩展添加到项目中
quarkus extension add spring-data-rest
./mvnw quarkus:add-extension -Dextensions='spring-data-rest'
./gradlew addExtension --extensions='spring-data-rest'
这会将以下内容添加到您的构建文件中
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-spring-data-rest</artifactId>
</dependency>
implementation("io.quarkus:quarkus-spring-data-rest")
此外,还需要添加以下依赖项
对于测试,您还需要 REST Assured。将其添加到构建文件中
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
testImplementation("io.rest-assured:rest-assured")
注意:resteasy-jackson
和 resteasy-jsonb
都受支持,并且可以互换使用。
定义实体
在本指南的整个过程中,将使用以下 JPA 实体
package org.acme.spring.data.rest;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
@Entity
public class Fruit {
@Id
@GeneratedValue
private Long id;
private String name;
private String color;
public Fruit() {
}
public Fruit(String name, String color) {
this.name = name;
this.color = color;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
配置数据库访问属性
将以下属性添加到 application.properties
中,以配置对本地 PostgreSQL 实例的访问。
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=quarkus_test
quarkus.datasource.password=quarkus_test
quarkus.datasource.jdbc.url=jdbc:postgresql:quarkus_test
quarkus.datasource.jdbc.max-size=8
quarkus.hibernate-orm.schema-management.strategy=drop-and-create
此配置假定 PostgreSQL 将在本地运行。
完成此操作的一个非常简单的方法是使用以下 Docker 命令
docker run -it --rm=true --name quarkus_test -e POSTGRES_USER=quarkus_test -e POSTGRES_PASSWORD=quarkus_test -e POSTGRES_DB=quarkus_test -p 5432:5432 postgres:14.1
如果您计划使用不同的设置,请相应地更改您的 application.properties
。
准备数据
为了更容易地展示 Spring Data REST 在 Quarkus 上的某些功能,应通过将以下内容添加到名为 src/main/resources/import.sql
的新文件中,将一些测试数据插入数据库
INSERT INTO fruit(id, name, color) VALUES (1, 'Cherry', 'Red');
INSERT INTO fruit(id, name, color) VALUES (2, 'Apple', 'Red');
INSERT INTO fruit(id, name, color) VALUES (3, 'Banana', 'Yellow');
INSERT INTO fruit(id, name, color) VALUES (4, 'Avocado', 'Green');
INSERT INTO fruit(id, name, color) VALUES (5, 'Strawberry', 'Red');
Hibernate ORM 将在应用程序启动时执行这些查询。
定义存储库
现在是时候定义将用于访问 Fruit
的存储库了。以典型的 Spring Data 方式,像这样创建一个存储库
package org.acme.spring.data.rest;
import org.springframework.data.repository.CrudRepository;
public interface FruitsRepository extends CrudRepository<Fruit, Long> {
}
上面的 FruitsRepository
扩展了 Spring Data 的 org.springframework.data.repository.CrudRepository
,这意味着 FruitsRepository
可以使用后者提供的所有方法。
spring-data-jpa
扩展将为该存储库生成一个实现。然后 spring-data-rest
扩展将为其生成一个 REST CRUD 资源。
更新测试
要测试 FruitsRepository
的功能,请继续更新 FruitsRepositoryTest
的内容为
package org.acme.spring.data.rest;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.core.IsNot.not;
@QuarkusTest
class FruitsRepositoryTest {
@Test
void testListAllFruits() {
//List all, should have all 3 fruits the database has initially:
given()
.accept("application/json")
.when().get("/fruits")
.then()
.statusCode(200)
.body(
containsString("Cherry"),
containsString("Apple"),
containsString("Banana")
);
//Delete the Cherry:
given()
.when().delete("/fruits/1")
.then()
.statusCode(204);
//List all, cherry should be missing now:
given()
.accept("application/json")
.when().get("/fruits")
.then()
.statusCode(200)
.body(
not(containsString("Cherry")),
containsString("Apple"),
containsString("Banana")
);
//Create a new Fruit
given()
.contentType("application/json")
.accept("application/json")
.body("{\"name\": \"Orange\", \"color\": \"Orange\"}")
.when().post("/fruits")
.then()
.statusCode(201)
.body(containsString("Orange"))
.body("id", notNullValue())
.extract().body().jsonPath().getString("id");
//List all, Orange should be present now:
given()
.accept("application/json")
.when().get("/fruits")
.then()
.statusCode(200)
.body(
not(containsString("Cherry")),
containsString("Apple"),
containsString("Orange")
);
}
}
通过发出以下命令可以轻松运行测试
./mvnw test
./gradlew test
打包并运行应用程序
Quarkus 开发模式就像使用任何其他 Quarkus 扩展一样,可以与定义的存储库配合使用,从而极大地提高您在开发周期中的生产力。应用程序可以像往常一样使用以下命令在开发模式下启动
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
将应用程序作为原生二进制文件运行
当然,您可以通过 构建原生可执行文件 指南中的说明来创建原生可执行文件。
支持的 Spring Data REST 功能
Quarkus 目前支持 Spring Data REST 功能的子集,即最有用且最常用的功能。
支持什么
以下各节描述了 Spring Data REST 最重要的支持功能。
自动 REST 端点生成
扩展了以下任何 Spring Data 存储库的接口都可以自动生成 REST 端点
-
org.springframework.data.repository.CrudRepository
-
org.springframework.data.repository.PagingAndSortingRepository
-
org.springframework.data.jpa.repository.JpaRepository
从上述存储库生成的端点公开五种常见的 REST 操作
-
GET /fruits
- 列出所有实体,如果使用PagingAndSortingRepository
或JpaRepository
,则返回一页。 -
GET /fruits/:id
- 按 ID 返回实体。 -
POST /fruits
- 创建一个新实体。 -
PUT /fruits/:id
- 更新现有实体或使用指定 ID 创建新实体(如果实体定义允许)。 -
DELETE /fruits/:id
- 按 ID 删除实体。
支持两种数据类型:application/json
和 application/hal+json
。前者是默认使用的,但强烈建议使用 Accept
标头指定您偏好的类型。
暴露大量实体
如果数据库包含大量实体,一次返回所有实体可能不是个好主意。PagingAndSortingRepository
允许 spring-data-rest
扩展分块访问数据。
因此,您可以扩展 PagingAndSortingRepository
package org.acme.spring.data.rest;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface FruitsRepository extends CrudRepository<Fruit, Long>, PagingAndSortingRepository<Fruit, Long> {
}
现在 GET /fruits
将接受三个新查询参数:sort
、page
和 size
。
查询参数 | 描述 | 默认值 | 示例值 |
---|---|---|---|
|
对列表操作返回的实体进行排序 |
"" |
|
|
零索引的页码。无效值被解释为 0。 |
0 |
0, 11, 100 |
|
每页大小。接受的最小值为 1。任何较低的值都被解释为 1。 |
20 |
1, 11, 100 |
对于分页响应,spring-data-rest
还返回一组链接标头,可用于访问其他页面:首页、上一页、下一页和尾页。
此外,您可以直接使用 JpaRepository
,它是一个为 JPA 量身定制的更高级别的抽象,而不是同时扩展 PagingAndSortingRepository
和 CrudRepository
。由于 JpaRepository
已经扩展了 PagingAndSortingRepository
和 CrudRepository
,因此它可以直接替换 CrudRepository
。
package org.acme.spring.data.rest;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface FruitsRepository extends JpaRepository<Fruit, Long> {
}
精细调整端点生成
这允许用户指定应公开哪些方法以及用于访问它们的路径。Spring Data REST 提供了两个可以使用的注解:@RepositoryRestResource
和 @RestResource
。spring-data-rest
扩展支持这些注解的 exported
、path
和 collectionResourceRel
属性。
例如,假设 fruits 存储库应该可以通过 /my-fruits
路径访问,并且只允许 GET
操作。在这种情况下,FruitsRepository
将如下所示
package org.acme.spring.data.rest;
import java.util.Optional;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
@RepositoryRestResource(exported = false, path = "/my-fruits")
public interface FruitsRepository extends CrudRepository<Fruit, Long> {
@RestResource(exported = true)
Optional<Fruit> findById(Long id);
@RestResource(exported = true)
Iterable<Fruit> findAll();
}
spring-data-rest
仅使用存储库方法的一个子集进行数据访问。为了自定义 REST 端点,注解正确的方法非常重要
REST 操作 | CrudRepository | PagingAndSortingRepository 和 JpaRepository |
---|---|---|
按 ID 获取 |
|
|
列表 |
|
|
创建 |
|
|
更新 |
|
|
删除 |
|
|
保护端点
此扩展将自动使用 jakarta.annotation.security
包中定义在您的资源接口上的安全注解
import jakarta.annotation.security.DenyAll;
import jakarta.annotation.security.RolesAllowed;
@DenyAll
public interface FruitResource extends CrudRepository<Fruit, Long> {
@RolesAllowed("superuser")
Iterable<Fruit> findAll();
}
请注意,此功能由此扩展在其底层使用的 Panache REST Data 扩展提供。因此,纯 Spring Boot 应用程序的行为可能不同。
重要的技术说明
请注意,Quarkus 中的 Spring 支持不会启动 Spring Application Context,也没有运行任何 Spring 基础设施类。Spring 类和注解仅用于读取元数据和/或用作用户代码方法返回类型或参数类型。