Quarkus Extension for Spring Web API
虽然鼓励用户使用 Jakarta REST(以前称为 JAX-RS)注解定义 REST 端点,但 Quarkus 通过 `spring-web`扩展程序提供 Spring Web 兼容层。 本指南解释 Quarkus 应用程序如何利用众所周知的 Spring Web 注解来定义 RESTful 服务。
- Prerequisites
- Solution
- Creating the Maven project
- GreetingController
- GreetingControllerTest
- Package and run the application
- Run the application as a native executable
- Going further with an endpoint returning JSON
- Adding OpenAPI and Swagger-UI
- Supported Spring Web functionalities
- Important Technical Note
- Conversion Table
- 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-web-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-web
扩展的项目。
如果您已配置好 Quarkus 项目,则可以通过在项目基本目录中运行以下命令来将 spring-web
扩展添加到项目中:
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-web</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-jackson</artifactId>
</dependency>
implementation("io.quarkus:quarkus-spring-web")
implementation("io.quarkus:quarkus-rest-jackson")
quarkus-spring-web
需要与 quarkus-rest-jackson
或 quarkus-resteasy-jackson
结合使用才能起作用。
GreetingController
创建 src/main/java/org/acme/spring/web/GreetingController.java
文件,一个包含 Spring Web 注解以定义我们的 REST 端点的控制器,如下所示:
package org.acme.spring.web;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/greeting")
public class GreetingController {
@GetMapping
public String hello() {
return "hello";
}
}
GreetingControllerTest
请注意,还创建了该控制器的测试:
package org.acme.spring.web;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
@QuarkusTest
public class GreetingControllerTest {
@Test
public void testHelloEndpoint() {
given()
.when().get("/greeting")
.then()
.statusCode(200)
.body(is("hello"));
}
}
Package and run the application
使用以下内容运行应用程序:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
用浏览器打开 [role="bare"][role="bare"]http://localhost:8080/greeting.
结果应为: {"message": "hello"}
.
Run the application as a native executable
可以使用以下命令生成本机可执行文件:
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true
Going further with an endpoint returning JSON
上面的 GreetingController
是一个非常简单的端点的示例。然而,在许多情况下都需要返回 JSON 内容,以下示例说明了如何使用 Spring RestController 来实现该目的:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/greeting")
public class GreetingController {
@GetMapping("/{name}")
public Greeting hello(@PathVariable(name = "name") String name) {
return new Greeting("hello " + name);
}
public static class Greeting {
private final String message;
public Greeting(String message) {
this.message = message;
}
public String getMessage(){
return message;
}
}
}
对应的测试可能如下所示:
package org.acme.spring.web;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
@QuarkusTest
public class GreetingControllerTest {
@Test
public void testHelloEndpoint() {
given()
.when().get("/greeting/quarkus")
.then()
.statusCode(200)
.body("message", is("hello quarkus"));
}
}
应当注意,在 Quarkus 中使用 Spring Web 支持时, Jackson 会自动添加到类路径中并得到正确设置。
Adding OpenAPI and Swagger-UI
通过使用 quarkus-smallrye-openapi
扩展,可以添加对 OpenAPI 和 Swagger-UI 的支持。
通过运行此命令添加扩展:
./mvnw quarkus:add-extension -Dextensions="io.quarkus:quarkus-smallrye-openapi"
这会将以下内容添加到您的 pom.xml
:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
这足以从你的 REST 端点生成基本 OpenAPI 架构文档:
curl http://localhost:8080/q/openapi
你将看到生成的 OpenAPI 模式文档:
---
openapi: 3.0.1
info:
title: Generated API
version: "1.0"
paths:
/greeting:
get:
responses:
"200":
description: OK
content:
'*/*':
schema:
type: string
/greeting/{name}:
get:
parameters:
- name: name
in: path
required: true
schema:
type: string
responses:
"200":
description: OK
content:
'application/json':
schema:
$ref: '#/components/schemas/Greeting'
components:
schemas:
Greeting:
type: object
properties:
message:
type: string
另请参阅 the OpenAPI Guide
Adding MicroProfile OpenAPI Annotations
可以使用 MicroProfile OpenAPI 更好地记录你的架构,例如将以下内容添加到 GreetingController
的类级别:
@OpenAPIDefinition(
info = @Info(
title="Greeting API",
version = "1.0.1",
contact = @Contact(
name = "Greeting API Support",
url = "http://exampleurl.com/contact",
email = "techsupport@example.com"),
license = @License(
name = "Apache 2.0",
url = "https://www.apache.org/licenses/LICENSE-2.0.html"))
)
你的端点将会如下所示:
@Tag(name = "Hello", description = "Just say hello")
@GetMapping(produces=MediaType.TEXT_PLAIN_VALUE)
public String hello() {
return "hello";
}
@GetMapping(value = "/{name}", produces=MediaType.APPLICATION_JSON_VALUE)
@Tag(name = "Hello to someone", description = "Just say hello to someone")
public Greeting hello(@PathVariable(name = "name") String name) {
return new Greeting("hello " + name);
}
将生成此 OpenAPI 架构:
---
openapi: 3.0.1
info:
title: Greeting API
contact:
name: Greeting API Support
url: http://exampleurl.com/contact
email: techsupport@example.com
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
version: 1.0.1
tags:
- name: Hello
description: Just say hello
- name: Hello to someone
description: Just say hello to someone
paths:
/greeting:
get:
tags:
- Hello
responses:
"200":
description: OK
content:
'*/*':
schema:
type: string
/greeting/{name}:
get:
tags:
- Hello to someone
parameters:
- name: name
in: path
required: true
schema:
type: string
responses:
"200":
description: OK
content:
'*/*':
schema:
$ref: '#/components/schemas/Greeting'
components:
schemas:
Greeting:
type: object
properties:
message:
type: string
Using Swagger UI
在 Dev
或 Test
模式下运行时,默认情况下会包含 Swagger UI,并且可以选择将其添加到 Prod
模式中,请参阅 the Swagger UI 指南了解更多详情。
导航至 localhost:8080/q/swagger-ui/,你将看到 Swagger UI 屏幕:
Supported Spring Web functionalities
Quarkus 目前支持 Spring Web 提供的部分功能。更具体地说,Quarkus 支持 Spring Web 的 REST 相关功能(考虑使用 @RestController
代替 @Controller
)。
Annotations
下表总结了受支持的注释:
Name | Comments |
---|---|
@RestController |
|
@RequestMapping |
|
@GetMapping |
|
@PostMapping |
|
@PutMapping |
|
@DeleteMapping |
|
@PatchMapping |
|
@RequestParam |
|
@RequestHeader |
|
@MatrixVariable |
|
@PathVariable |
|
@CookieValue |
|
@RequestBody |
|
@ResponseStatus |
|
@ExceptionHandler |
只能在 @RestControllerAdvice 类中使用,不能基于每个控制器使用 |
@RestControllerAdvice |
只支持 @ExceptionHandler 功能 |
Controller method return types
支持以下方法返回类型:
-
Primitive types
-
String(将用作文本,不提供 Spring MVC 视图支持)
-
将通过 JSON 序列化的 POJO 类
-
org.springframework.http.ResponseEntity
Controller method parameter types
除了可以用前一表格中的适当 Spring Web 注释进行注释的方法参数之外,jakarta.servlet.http.HttpServletRequest
和 jakarta.servlet.http.HttpServletResponse
也受支持。不过,为了实现此功能,用户需要添加 quarkus-undertow
依赖项。
Exception handler method return types
支持以下方法返回类型:
-
org.springframework.http.ResponseEntity
-
java.util.Map
Spring ExceptionHandler javadoc
中提到的其他返回类型不受支持。
Exception handler method parameter types
以下参数类型受支持,顺序任意:
-
异常参数:声明为通用
Exception
或更具体的异常。如果注释本身未通过其value()
缩小异常类型,这也作为映射提示。 -
请求和/或响应对象(通常来自 Servlet API)。你可以选择任何特定请求/响应类型,例如
ServletRequest
/HttpServletRequest
。要使用 Servlet API,需要添加quarkus-undertow
依赖项。
Spring ExceptionHandler javadoc
中提到的其他参数类型不受支持。
Important Technical Note
请注意,Quarkus 中的 Spring 支持不会启动 Spring 应用程序上下文,也不会运行任何 Spring 基础设施类。Spring 类和注释仅用于读取元数据和/或用作用户代码方法返回类型或参数类型。这对最终用户意味着,添加任意 Spring 库不会产生任何影响。此外,Spring 基础设施类(例如 org.springframework.beans.factory.config.BeanPostProcessor
)不会被执行。
Conversion Table
下表显示了 Spring Web 注释如何转换为 Jakarta REST 注释。
Spring | Jakarta REST | Comments |
---|---|---|
@RestController |
Jakarta REST 中没有等效项。使用 @Path 对类进行注释就足够了 |
|
@RequestMapping(path="/api") |
@Path("/api") |
|
@RequestMapping(consumes="application/json") |
@Consumes("application/json") |
|
@RequestMapping(produces="application/json") |
@Produces("application/json") |
|
@RequestParam |
@QueryParam |
|
@PathVariable |
@PathParam |
|
@RequestBody |
Jakarta REST 中没有等效项。请求正文对应的办法参数在 Jakarta REST 中进行处理,无需任何注释 |
|
@RestControllerAdvice |
Jakarta REST 中没有等效项 |
|
@ResponseStatus |
Jakarta REST 中没有等效项 |
|
@ExceptionHandler |
Jakarta REST 中没有等效注释。异常通过实现 |
More Spring guides
Quarkus 还有更多 Spring 兼容性功能。请参阅以下指南以获取更多详情: