编辑此页面

Quarkus Spring Web API 扩展

尽管用户被鼓励使用 Jakarta REST(以前称为 JAX-RS)注解来定义 REST 端点,但 Quarkus 以 spring-web 扩展的形式提供了 Spring Web 的兼容层。

本指南将介绍 Quarkus 应用程序如何利用众所周知的 Spring Web 注解来定义 RESTful 服务。

先决条件

要完成本指南,您需要

要完成本指南,您需要

  • 大约 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-web-quickstart 目录中。

创建 Maven 项目

首先,我们需要一个新项目。使用以下命令创建一个新项目

CLI
quarkus create app org.acme:spring-web-quickstart \
    --extension='spring-web,rest-jackson' \
    --no-code
cd spring-web-quickstart

要创建 Gradle 项目,请添加 --gradle--gradle-kotlin-dsl 选项。

有关如何安装和使用 Quarkus CLI 的更多信息,请参阅 Quarkus CLI 指南。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.24.4:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=spring-web-quickstart \
    -Dextensions='spring-web,rest-jackson' \
    -DnoCode
cd spring-web-quickstart

要创建 Gradle 项目,请添加 -DbuildTool=gradle-DbuildTool=gradle-kotlin-dsl 选项。

对于 Windows 用户

  • 如果使用 cmd,(不要使用反斜杠 \ 并将所有内容放在同一行上)

  • 如果使用 Powershell,请将 -D 参数用双引号括起来,例如 "-DprojectArtifactId=spring-web-quickstart"

此命令将生成一个导入 spring-web 扩展的项目。

如果您已经配置了 Quarkus 项目,您可以通过在项目根目录中运行以下命令将 spring-web 扩展添加到您的项目中

CLI
quarkus extension add spring-web,rest-jackson
Maven
./mvnw quarkus:add-extension -Dextensions='spring-web,rest-jackson'
Gradle
./gradlew addExtension --extensions='spring-web,rest-jackson'

这会将以下内容添加到您的构建文件中

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-spring-web</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-rest-jackson</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-spring-web")
implementation("io.quarkus:quarkus-rest-jackson")

quarkus-spring-web 需要与 quarkus-rest-jacksonquarkus-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"));
    }

}

打包并运行应用程序

使用以下命令运行应用程序

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

在浏览器中打开 https://:8080/greeting

结果应为:{"message": "hello"}

将应用程序作为原生可执行文件运行

您可以使用以下命令生成原生可执行文件

CLI
quarkus build --native
Maven
./mvnw install -Dnative
Gradle
./gradlew build -Dquarkus.native.enabled=true

进一步使用返回 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 会被自动添加到类路径并正确设置。

添加 OpenAPI 和 Swagger-UI

您可以使用 quarkus-smallrye-openapi 扩展来添加对 OpenAPISwagger-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 https://: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

另请参阅 OpenAPI 指南

添加 MicroProfile OpenAPI 注解

您可以使用 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://apache.ac.cn/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://apache.ac.cn/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

使用 Swagger UI

Swagger UI 在 DevTest 模式下运行时默认包含,并且可以选择性地添加到 Prod 模式。有关更多详细信息,请参阅 Swagger UI 指南。

导航到 localhost:8080/q/swagger-ui/,您将看到 Swagger UI 屏幕

Swagger UI

支持的 Spring Web 功能

Quarkus 目前支持 Spring Web 提供的一部分功能。更具体地说,Quarkus 支持 Spring Web 的 REST 相关功能(考虑 @RestController 而不是 @Controller)。

注解

下表总结了支持的注解

表 1. 支持的 Spring Web 注解
名称 注释

@RestController

@RequestMapping

@GetMapping

@PostMapping

@PutMapping

@DeleteMapping

@PatchMapping

@RequestParam

@RequestHeader

@MatrixVariable

@PathVariable

@CookieValue

@RequestBody

@ResponseStatus

@ExceptionHandler

只能在 @RestControllerAdvice 类中使用,不能在每个控制器基础上使用

@RestControllerAdvice

仅支持 @ExceptionHandler 功能

控制器方法返回类型

支持以下方法返回类型

  • 基本类型

  • String(将用作字面量,不提供 Spring MVC 视图支持)

  • POJO 类(将通过 JSON 序列化)

  • org.springframework.http.ResponseEntity

控制器方法参数类型

除了可以被前面表格中相应 Spring Web 注解注解的方法参数之外,还支持 jakarta.servlet.http.HttpServletRequestjakarta.servlet.http.HttpServletResponse。但是,要使其工作,用户需要添加 quarkus-undertow 依赖。

异常处理方法返回类型

支持以下方法返回类型

  • org.springframework.http.ResponseEntity

  • java.util.Map

Spring ExceptionHandler javadoc 中提到的其他返回类型不支持。

异常处理方法参数类型

支持以下参数类型,顺序任意

  • 异常参数:声明为通用 Exception 或更具体的异常。如果注解本身没有通过其 value() 缩小异常类型,这也可作为映射提示。

  • 请求和/或响应对象(通常来自 Servlet API)。您可以选择任何特定的请求/响应类型,例如 ServletRequest / HttpServletRequest。要使用 Servlet API,需要添加 quarkus-undertow 依赖。

Spring ExceptionHandler javadoc 中提到的其他参数类型不支持。

重要的技术说明

请注意,Quarkus 中的 Spring 支持不会启动 Spring Application Context,也不会运行任何 Spring 基础设施类。Spring 类和注解仅用于读取元数据和/或用作用户代码的方法返回类型或参数类型。这意味着对于最终用户来说,添加任意 Spring 库将不会产生任何效果。此外,Spring 基础设施类(例如 org.springframework.beans.factory.config.BeanPostProcessor)将不会被执行。

转换表

下表显示了如何将 Spring Web 注解转换为 Jakarta REST 注解。

Spring Jakarta REST 注释

@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 中没有等价的注解。异常通过实现 jakarta.ws.rs.ext.ExceptionMapper 来处理

相关内容