Extension for Spring Data REST
虽然建议用户对 REST 数据访问端点使用 REST 数据和 Panache,但 Quarkus 提供了 Spring Data REST 的兼容层,采用 spring-data-rest
拓展的形式。
- Prerequisites
- Solution
- Creating the Maven project
- Define the Entity
- Configure database access properties
- Prepare the data
- Define the repository
- Update the test
- Package and run the application
- Run the application as a native binary
- Supported Spring Data REST functionalities
- Important Technical Note
- More Spring guides
Prerequisites
如要完成本指南,您需要:
-
Roughly 15 minutes
-
An IDE
-
安装了 JDK 17+,已正确配置
JAVA_HOME
-
Apache Maven ${proposed-maven-version}
-
如果你想使用 Quarkus CLI, 则可以选择使用
-
如果你想构建一个本机可执行文件(或如果你使用本机容器构建,则使用 Docker),则可以选择安装 Mandrel 或 GraalVM 以及 configured appropriately
Solution
我们建议您遵循接下来的部分中的说明,按部就班地创建应用程序。然而,您可以直接跳到完成的示例。
克隆 Git 存储库: git clone $${quickstarts-base-url}.git
,或下载 $${quickstarts-base-url}/archive/main.zip[存档]。
解决方案位于 spring-data-rest-quickstart
directory 中。
Creating the Maven project
首先,我们需要一个新项目。使用以下命令创建一个新项目:
quarkus create app {create-app-group-id}:{create-app-artifact-id} \
--no-code
cd {create-app-artifact-id}
要创建一个 Gradle 项目,添加 --gradle
或 --gradle-kotlin-dsl
选项。
有关如何安装和使用 Quarkus CLI 的详细信息,请参见 Quarkus CLI 指南。
mvn {quarkus-platform-groupid}:quarkus-maven-plugin:{quarkus-version}:create \
-DprojectGroupId={create-app-group-id} \
-DprojectArtifactId={create-app-artifact-id} \
-DnoCode
cd {create-app-artifact-id}
要创建一个 Gradle 项目,添加 -DbuildTool=gradle
或 -DbuildTool=gradle-kotlin-dsl
选项。
适用于 Windows 用户:
-
如果使用 cmd,(不要使用反斜杠
\
,并将所有内容放在同一行上) -
如果使用 Powershell,将
-D
参数用双引号引起来,例如"-DprojectArtifactId={create-app-artifact-id}"
此命令生成带 spring-data-rest
拓展的项目。
如果已配置 Quarkus 项目,则可以通过在项目基础目录中运行以下命令将其添加到项目中:
quarkus extension add {add-extension-extensions}
./mvnw quarkus:add-extension -Dextensions='{add-extension-extensions}'
./gradlew addExtension --extensions='{add-extension-extensions}'
这会将以下内容添加到构建文件中:
<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
都得到支持,且可以互换。
Define the Entity
在整个本指南的过程中,将使用以下 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;
}
}
Configure database access properties
将以下属性添加到 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.database.generation=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
。
Prepare the data
为了更轻松地展示 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 将在应用程序启动时执行这些查询。
Define the repository
现在是定义用于访问 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 资源。
Update the test
若要测试 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
Package and run the application
Quarkus 开发模式适用于已定义的存储库,就像适用于任何其他 Quarkus 扩展一样,大大提高了开发周期中的生产力。可以使用以下命令像平常一样在开发模式下启动应用程序:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
Run the application as a native binary
当然,你可以根据 Building native executables 指南的说明创建一个本机可执行文件。
Supported Spring Data REST functionalities
Quarkus 目前支持 Spring Data REST 功能的子集,即最有用和最常用的功能。
What is supported
以下部分介绍了 Spring Data REST 最重要的受支持功能。
Automatic REST endpoint generation
扩展以下任何 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
标头指定你更喜欢哪一种。
Exposing many entities
如果一个数据库包含许多实体,一次全部返回可能不是一个好主意。PagingAndSortingRepository
允许 spring-data-rest
扩展分块访问数据。
在 FruitsRepository
中用 PagingAndSortingRepository
替换 CrudRepository
:
package org.acme.spring.data.rest;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface FruitsRepository extends PagingAndSortingRepository<Fruit, Long> {
}
现在 GET /fruits
将接受三个新查询参数: sort
、page
和 size
。
Query parameter | Description | Default value | Example values |
---|---|---|---|
|
对由列表操作返回的实体排序 |
"" |
|
|
从 0 开始的页码。将无效值解释为 0。 |
0 |
0, 11, 100 |
|
页面大小。最小接受值是 1。任何低值都将解释为 1。 |
20 |
1, 11, 100 |
对于分页响应,spring-data-rest
还返回了一组链接头,可以用来访问其他页面:第一页、前一页、下一页和最后一页。
Fine tuning endpoints generation
这使用户可以指定应公开哪种方法以及应使用什么路径对其进行访问。Spring Data REST 提供了可以使用以下两种注解:@RepositoryRestResource
和 @RestResource
.spring-data-rest
扩展支持这些注解的 exported
, path
collectionResourceRel
属性。
例如,假设可以按 /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 operation | CrudRepository | PagingAndSortingRepository and JpaRepository |
---|---|---|
Get by ID |
|
|
List |
|
|
Create |
|
|
Update |
|
|
Delete |
|
|
Securing endpoints
此扩展会自动使用 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();
}
请注意,此功能由 REST Data with Panache 扩展提供,此扩展在其内部使用。因此,纯 Spring Boot 应用程序的行为可能不同。
Important Technical Note
请注意,Quarkus 中的 Spring 支持不会启动 Spring 应用程序上下文,也不会运行任何 Spring 基础架构类。Spring 类和注释仅用于读取元数据和/或用作用户代码方法返回类型或参数类型。
More Spring guides
Quarkus 还有更多 Spring 兼容性功能。请参阅以下指南以获取更多详情: