You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quarkus中如何将MicroProfile/OpenAPI注解移至接口生成Swagger文件并保持代码整洁

问题

在Quarkus中,我需要定义API以生成可提供给消费者的Swagger-UI JSON/YAML文件。目前在REST端点中定义大量注解可实现该需求,示例代码如下:

@POST
@Operation(summary = "creates a new product")
@APIResponse(responseCode = "201", description = "product creation successful")
@APIResponse(responseCode = "500", description = "Server unavailable")
@Path("/")
@RequestBody(content = @Content(examples = {
    @ExampleObject(
        name = CreateProductRequest.EXAMPLE1_NAME,
        description = CreateProductRequest.EXAMPLE1_DESCRIPTION,
        value = CreateProductRequest.EXAMPLE1_VALUE
    )
}))
@APIResponse(content = @Content(examples = {
    @ExampleObject(
        name = CreateProductResponse.EXAMPLE1_NAME,
        description = CreateProductResponse.EXAMPLE1_DESCRIPTION,
        value = CreateProductResponse.EXAMPLE1_VALUE
    )
}))
@ResponseStatus(201)
public CreateProductResponse create(CreateProductRequest createProductRequest) throws ValidationException {
    return productManager.create(new RequestContext(1, 1), createProductRequest);
}

但这种方式会让REST端点代码几乎难以阅读(这已是较简短的示例)。我期望通过定义接口并让REST端点实现的方式解决该问题,但尝试的方案并未生效——框架完全忽略接口中的注解,生成的swagger.json/yaml文件中不会包含这些注解信息,我的尝试代码如下:

@Path("/api/v1/products")
public class ProductControllerV1 implements ProductApiV1 {

    @POST
    @Path("/")
    @Override
    public CreateProductResponse create(CreateProductRequest createProductRequest) throws ValidationException {
        return productManager.create(new RequestContext(1, 1), createProductRequest);
    }
}
@Tag(
    name = "Product Controller V1",
    description = "Product Operations, for testing many different use-cases"
)
@Path("/api/v1/products")
public interface ProductApiV1 {

    @POST
    @Operation(summary = "creates a new product")
    @APIResponse(responseCode = "201", description = "product creation successful")
    @APIResponse(responseCode = "500", description = "Server unavailable")
    @Path("/")
    @RequestBody(content = @Content(examples = {
        @ExampleObject(
            name = CreateProductRequest.EXAMPLE1_NAME,
            description = CreateProductRequest.EXAMPLE1_DESCRIPTION,
            value = CreateProductRequest.EXAMPLE1_VALUE
        )
    }))
    @APIResponse(content = @Content(examples = {
        @ExampleObject(
            name = CreateProductResponse.EXAMPLE1_NAME,
            description = CreateProductResponse.EXAMPLE1_DESCRIPTION,
            value = CreateProductResponse.EXAMPLE1_VALUE
        )
    }))
    @ResponseStatus(201)
    CreateProductResponse create(CreateProductRequest createProductRequest) throws ValidationException;
}

现寻求帮助:

  1. 确认通过接口定义注解的方案是否可行,并提供Quarkus中此类接口的定义示例;
  2. 提供更优实现方案,在保持REST端点简洁易维护的同时,仍能在源码附近维护Swagger-UI的API定义。

回答

1. 接口定义注解方案的可行性与示例

该方案完全可行,问题出在Quarkus默认不会自动继承接口上的OpenAPI注解。只需给接口添加@InheritedOpenAPIDefinition注解,即可让框架识别接口中的注解并继承到实现类。

修正后的接口示例:

@InheritedOpenAPIDefinition
@Tag(
    name = "Product Controller V1",
    description = "Product Operations, for testing many different use-cases"
)
@Path("/api/v1/products")
public interface ProductApiV1 {

    @POST
    @Operation(summary = "creates a new product")
    @APIResponse(responseCode = "201", description = "product creation successful")
    @APIResponse(responseCode = "500", description = "Server unavailable")
    @Path("/")
    @RequestBody(content = @Content(examples = {
        @ExampleObject(
            name = CreateProductRequest.EXAMPLE1_NAME,
            description = CreateProductRequest.EXAMPLE1_DESCRIPTION,
            value = CreateProductRequest.EXAMPLE1_VALUE
        )
    }))
    @APIResponse(content = @Content(examples = {
        @ExampleObject(
            name = CreateProductResponse.EXAMPLE1_NAME,
            description = CreateProductResponse.EXAMPLE1_DESCRIPTION,
            value = CreateProductResponse.EXAMPLE1_VALUE
        )
    }))
    @ResponseStatus(201)
    CreateProductResponse create(CreateProductRequest createProductRequest) throws ValidationException;
}

实现类可简化为:

@Path("/api/v1/products")
public class ProductControllerV1 implements ProductApiV1 {

    @Override
    public CreateProductResponse create(CreateProductRequest createProductRequest) throws ValidationException {
        return productManager.create(new RequestContext(1, 1), createProductRequest);
    }
}

@InheritedOpenAPIDefinition是核心,它会告知Quarkus的OpenAPI扩展将接口上的注解同步到实现类中。

2. 更优实现方案

除接口继承外,还有两种更简洁的方案:

方案一:自定义注解聚合

将重复的OpenAPI注解封装到自定义注解中,减少端点代码的注解冗余:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Operation(summary = "creates a new product")
@APIResponse(responseCode = "201", description = "product creation successful")
@APIResponse(responseCode = "500", description = "Server unavailable")
@RequestBody(content = @Content(examples = {
    @ExampleObject(
        name = CreateProductRequest.EXAMPLE1_NAME,
        description = CreateProductRequest.EXAMPLE1_DESCRIPTION,
        value = CreateProductRequest.EXAMPLE1_VALUE
    )
}))
@APIResponse(content = @Content(examples = {
    @ExampleObject(
        name = CreateProductResponse.EXAMPLE1_NAME,
        description = CreateProductResponse.EXAMPLE1_DESCRIPTION,
        value = CreateProductResponse.EXAMPLE1_VALUE
    )
}))
@ResponseStatus(201)
public @interface CreateProductApi {
}

端点方法只需使用这个自定义注解:

@POST
@Path("/")
@CreateProductApi
public CreateProductResponse create(CreateProductRequest createProductRequest) throws ValidationException {
    return productManager.create(new RequestContext(1, 1), createProductRequest);
}

方案二:独立OpenAPI配置文件

将Swagger定义单独写在src/main/resources/META-INF/openapi.yaml(或.json)文件中,与代码分离但保持在源码目录内。此时端点代码仅保留基础REST注解:

@POST
@Path("/")
@ResponseStatus(201)
public CreateProductResponse create(CreateProductRequest createProductRequest) throws ValidationException {
    return productManager.create(new RequestContext(1, 1), createProductRequest);
}

对应的openapi.yaml示例:

openapi: 3.0.3
info:
  title: Product API
  version: 1.0.0
paths:
  /api/v1/products/:
    post:
      summary: creates a new product
      requestBody:
        content:
          application/json:
            examples:
              example1:
                name: ${CreateProductRequest.EXAMPLE1_NAME}
                description: ${CreateProductRequest.EXAMPLE1_DESCRIPTION}
                value: ${CreateProductRequest.EXAMPLE1_VALUE}
      responses:
        '201':
          description: product creation successful
          content:
            application/json:
              examples:
                example1:
                  name: ${CreateProductResponse.EXAMPLE1_NAME}
                  description: ${CreateProductResponse.EXAMPLE1_DESCRIPTION}
                  value: ${CreateProductResponse.EXAMPLE1_VALUE}
        '500':
          description: Server unavailable
tags:
  - name: Product Controller V1
    description: Product Operations, for testing many different use-cases

Quarkus会自动加载该文件,并与代码中的注解合并生成最终的Swagger-UI文件,还支持通过${}引用代码中的常量。


内容的提问来源于stack exchange,提问作者funkrusher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 14:39:49