Quarkus Extension for Spring Web API
虽然鼓励用户使用 Jakarta REST(以前称为 JAX-RS)注解定义 REST 端点,但 Quarkus 通过 `spring-web`扩展程序提供 Spring Web 兼容层。
While users are encouraged to use Jakarta REST (formerly known as JAX-RS) annotations for defining REST endpoints, Quarkus provides a compatibility layer for Spring Web in the form of the spring-web
extension.
本指南解释 Quarkus 应用程序如何利用众所周知的 Spring Web 注解来定义 RESTful 服务。
This guide explains how a Quarkus application can leverage the well known Spring Web annotations to define RESTful services.
Prerequisites
如要完成本指南,您需要:
To complete this guide, you need:
Unresolved directive in spring-web.adoc - include::{includes}/prerequisites.adoc[]
Solution
我们建议您遵循接下来的部分中的说明,按部就班地创建应用程序。然而,您可以直接跳到完成的示例。
We recommend that you follow the instructions in the next sections and create the application step by step. However, you can go right to the completed example.
克隆 Git 存储库: git clone {quickstarts-clone-url}
,或下载 {quickstarts-archive-url}[存档]。
Clone the Git repository: git clone {quickstarts-clone-url}
, or download an {quickstarts-archive-url}[archive].
解决方案位于 spring-web-quickstart
directory 中。
The solution is located in the spring-web-quickstart
directory.
Creating the Maven project
首先,我们需要一个新项目。使用以下命令创建一个新项目:
First, we need a new project. Create a new project with the following command:
Unresolved directive in spring-web.adoc - include::{includes}/devtools/create-app.adoc[]
此命令会生成一个导入 spring-web
扩展的项目。
This command generates a project which imports the spring-web
extension.
如果您已配置好 Quarkus 项目,则可以通过在项目基本目录中运行以下命令来将 spring-web
扩展添加到项目中:
If you already have your Quarkus project configured, you can add the spring-web
extension
to your project by running the following command in your project base directory:
Unresolved directive in spring-web.adoc - include::{includes}/devtools/extension-add.adoc[]
这会将以下内容添加到构建文件中:
This will add the following to your build file:
<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
结合使用才能起作用。
quarkus-spring-web
needs to be complemented with either quarkus-rest-jackson
or quarkus-resteasy-jackson
in order to work.
GreetingController
创建 src/main/java/org/acme/spring/web/GreetingController.java
文件,一个包含 Spring Web 注解以定义我们的 REST 端点的控制器,如下所示:
Create the src/main/java/org/acme/spring/web/GreetingController.java
file, a controller with the Spring Web annotations to define our REST endpoint, as follows:
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
请注意,还创建了该控制器的测试:
Note that a test for the controller has been created as well:
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
使用以下内容运行应用程序:
Run the application with:
Unresolved directive in spring-web.adoc - include::{includes}/devtools/dev.adoc[]
用浏览器打开 [role="bare"][role="bare"]http://localhost:8080/greeting.
Open your browser to [role="bare"]http://localhost:8080/greeting.
结果应为: {"message": "hello"}
.
The result should be: {"message": "hello"}
.
Run the application as a native executable
可以使用以下命令生成本机可执行文件:
You can generate the native executable with:
Unresolved directive in spring-web.adoc - include::{includes}/devtools/build-native.adoc[]
Going further with an endpoint returning JSON
上面的 GreetingController
是一个非常简单的端点的示例。然而,在许多情况下都需要返回 JSON 内容,以下示例说明了如何使用 Spring RestController 来实现该目的:
The GreetingController
above was an example of a very simple endpoint. In many cases however it is required to return JSON content.
The following example illustrates how that could be achieved using a 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;
}
}
}
对应的测试可能如下所示:
The corresponding test could look like:
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 会自动添加到类路径中并得到正确设置。
It should be noted that when using the Spring Web support in Quarkus, Jackson is automatically added to the classpath and properly set up.
Adding OpenAPI and Swagger-UI
通过使用 quarkus-smallrye-openapi
扩展,可以添加对 OpenAPI 和 Swagger-UI 的支持。
You can add support for OpenAPI and Swagger-UI by using the quarkus-smallrye-openapi
extension.
通过运行此命令添加扩展:
Add the extension by running this command:
./mvnw quarkus:add-extension -Dextensions="io.quarkus:quarkus-smallrye-openapi"
这会将以下内容添加到您的 pom.xml
:
This will add the following to your pom.xml
:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
这足以从你的 REST 端点生成基本 OpenAPI 架构文档:
This is enough to generate a basic OpenAPI schema document from your REST Endpoints:
curl http://localhost:8080/q/openapi
你将看到生成的 OpenAPI 模式文档:
You will see the generated OpenAPI schema document:
---
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
Also see the OpenAPI Guide
Adding MicroProfile OpenAPI Annotations
可以使用 MicroProfile OpenAPI 更好地记录你的架构,例如将以下内容添加到 GreetingController
的类级别:
You can use MicroProfile OpenAPI to better document your schema,
example, adding the following to the class level of the 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"))
)
你的端点将会如下所示:
And describe your endpoints like this:
@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 架构:
will generate this OpenAPI schema:
---
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 指南了解更多详情。
Swagger UI is included by default when running in Dev
or Test
mode, and can optionally be added to Prod
mode.
See the Swagger UI Guide for more details.
导航至 localhost:8080/q/swagger-ui/,你将看到 Swagger UI 屏幕:
Navigate to localhost:8080/q/swagger-ui/ and you will see the Swagger UI screen:
Supported Spring Web functionalities
Quarkus 目前支持 Spring Web 提供的部分功能。更具体地说,Quarkus 支持 Spring Web 的 REST 相关功能(考虑使用 @RestController
代替 @Controller
)。
Quarkus currently supports a subset of the functionalities that Spring Web provides. More specifically Quarkus supports the REST related features of Spring Web
(think of @RestController
instead of @Controller
).
Annotations
下表总结了受支持的注释:
The table below summarizes the supported annotations:
Name | Comments |
---|---|
@RestController |
|
@RequestMapping |
|
@GetMapping |
|
@PostMapping |
|
@PutMapping |
|
@DeleteMapping |
|
@PatchMapping |
|
@RequestParam |
|
@RequestHeader |
|
@MatrixVariable |
|
@PathVariable |
|
@CookieValue |
|
@RequestBody |
|
@ResponseStatus |
|
@ExceptionHandler |
Can only be used in a @RestControllerAdvice class, not on a per-controller basis |
@RestControllerAdvice |
Only the @ExceptionHandler capability is supported |
Controller method return types
支持以下方法返回类型:
The following method return types are supported:
-
Primitive types
-
String (which will be used as a literal, no Spring MVC view support is provided)
-
POJO classes which will be serialized via JSON
-
org.springframework.http.ResponseEntity
Controller method parameter types
除了可以用前一表格中的适当 Spring Web 注释进行注释的方法参数之外,jakarta.servlet.http.HttpServletRequest
和 jakarta.servlet.http.HttpServletResponse
也受支持。不过,为了实现此功能,用户需要添加 quarkus-undertow
依赖项。
In addition to the method parameters that can be annotated with the appropriate Spring Web annotations from the previous table,
jakarta.servlet.http.HttpServletRequest
and jakarta.servlet.http.HttpServletResponse
are also supported.
For this to function however, users need to add the quarkus-undertow
dependency.
Exception handler method return types
支持以下方法返回类型:
The following method return types are supported:
-
org.springframework.http.ResponseEntity
-
java.util.Map
Spring ExceptionHandler javadoc
中提到的其他返回类型不受支持。
Other return types mentioned in the Spring ExceptionHandler javadoc
are not supported.
Exception handler method parameter types
以下参数类型受支持,顺序任意:
The following parameter types are supported, in arbitrary order:
-
An exception argument: declared as a general
Exception
or as a more specific exception. This also serves as a mapping hint if the annotation itself does not narrow the exception types through itsvalue()
. -
Request and/or response objects (typically from the Servlet API). You may choose any specific request/response type, e.g.
ServletRequest
/HttpServletRequest
. To use Servlet API, thequarkus-undertow
dependency needs to be added.
Spring ExceptionHandler javadoc
中提到的其他参数类型不受支持。
Other parameter types mentioned in the Spring ExceptionHandler javadoc
are not supported.
Important Technical Note
请注意,Quarkus 中的 Spring 支持不会启动 Spring 应用程序上下文,也不会运行任何 Spring 基础设施类。Spring 类和注释仅用于读取元数据和/或用作用户代码方法返回类型或参数类型。这对最终用户意味着,添加任意 Spring 库不会产生任何影响。此外,Spring 基础设施类(例如 org.springframework.beans.factory.config.BeanPostProcessor
)不会被执行。
Please note that the Spring support in Quarkus does not start a Spring Application Context nor are any Spring infrastructure classes run.
Spring classes and annotations are only used for reading metadata and / or are used as user code method return types or parameter types.
What that means for end users, is that adding arbitrary Spring libraries will not have any effect. Moreover, Spring infrastructure
classes (like org.springframework.beans.factory.config.BeanPostProcessor
for example) will not be executed.
Conversion Table
下表显示了 Spring Web 注释如何转换为 Jakarta REST 注释。
The following table shows how Spring Web annotations can be converted to Jakarta REST annotations.
Spring | Jakarta REST | Comments |
---|---|---|
@RestController |
There is no equivalent in Jakarta REST. Annotating a class with @Path suffices |
|
@RequestMapping(path="/api") |
@Path("/api") |
|
@RequestMapping(consumes="application/json") |
@Consumes("application/json") |
|
@RequestMapping(produces="application/json") |
@Produces("application/json") |
|
@RequestParam |
@QueryParam |
|
@PathVariable |
@PathParam |
|
@RequestBody |
No equivalent in Jakarta REST. Method parameters corresponding to the body of the request are handled in Jakarta REST without requiring any annotation |
|
@RestControllerAdvice |
No equivalent in Jakarta REST |
|
@ResponseStatus |
No equivalent in Jakarta REST |
|
@ExceptionHandler |
No equivalent annotation in Jakarta REST. Exceptions are handled by implementing |
More Spring guides
Quarkus 还有更多 Spring 兼容性功能。请参阅以下指南以获取更多详情:
Quarkus has more Spring compatibility features. See the following guides for more details: