下载工作台
Spring Boot Web 开发

SpringDoc OpenAPI 文档

试读上半部分 · 解锁后可读全文

第 14 章 · SpringDoc OpenAPI 3 与 Swagger UI

本章目标:在 shop-spring-demo 集成 springdoc-openapi 自动生成 OpenAPI 3 规范;通过 Swagger UI 在线浏览与调试 API;为 ch13 的 DTO/VO 补充 @Schema 注解;配置分组、安全方案(Bearer JWT 占位);理解 OpenAPI 与 ch07 统一响应的文档化策略;产出可交付前端的 openapi.json

学时建议:3~4 小时(含 1 小时文档打磨)

前置ch13 DTO/VO;ch07 REST 统一响应;ch06 Spring Security 基础。


14.1 OpenAPI 3 与 Swagger 的关系

概念说明
OpenAPI Specification (OAS)描述 REST API 的行业标准(YAML/JSON)
Swagger围绕 OpenAPI 的工具生态(UI、Editor、Codegen)
SpringDocSpring Boot 3 生态的 OpenAPI 自动生成库(替代 springfox)
Swagger UI浏览器内嵌的交互式 API 文档与 Try it out
shop-spring-demo Controller + DTO 注解
              │
              ▼
      springdoc-openapi 扫描
              │
              ▼
   /v3/api-docs (JSON)  ──►  Swagger UI (/swagger-ui.html)
              │
              ▼
        前端 SDK / Postman 导入
示例域名 https://api.example.com;文档中禁止出现真实内网地址、生产密钥或公司内部服务名。

14.2 引入依赖

pom.xml

<dependency>
  <groupId>org.springdoc</groupId>
  <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
  <version>2.5.0</version>
</dependency>

启动后默认端点:

路径说明
/swagger-ui.htmlSwagger UI 入口(会重定向到 /swagger-ui/index.html
/v3/api-docsOpenAPI JSON
/v3/api-docs.yamlOpenAPI YAML(可选)

本地访问:http://127.0.0.1:8080/swagger-ui.html


14.3 全局 OpenAPI 配置

OpenApiConfig.java

package com.example.shop.config;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OpenApiConfig {

    @Bean
    public OpenAPI shopOpenAPI() {
        final String schemeName = "bearerAuth";
        return new OpenAPI()
                .info(new Info()
                        .title("shop-spring-demo API")
                        .description("虚构电商后台 REST API,教学用途")
                        .version("v1.0.0")
                        .contact(new Contact().name("Demo Team").email("api@example.com"))
                        .license(new License().name("MIT")))
                .addSecurityItem(new SecurityRequirement().addList(schemeName))
                .components(new Components()
                        .addSecuritySchemes(schemeName, new SecurityScheme()
                                .name(schemeName)
                                .type(SecurityScheme.Type.HTTP)
                                .scheme("bearer")
                                .bearerFormat("JWT")
                                .description("ch15 将接入 JWT,此处为文档占位")));
    }
}

application.yml 可选配置:

springdoc:
  api-docs:
    path: /v3/api-docs
  swagger-ui:
    path: /swagger-ui.html
    tags-sorter: alpha
    operations-sorter: alpha
  show-actuator: false

14.4 Controller 注解

@Tag(name = "商品", description = "商品 CRUD 与上下架")
@RestController
@RequestMapping("/api/products")
public class ProductController {

    @Operation(summary = "分页查询商品", description = "支持关键词搜索")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "成功",
            content = @Content(schema = @Schema(implementation = ProductPageResult.class))),
        @ApiResponse(responseCode = "401", description = "未登录")
    })
    @GetMapping
    public Result<PageResult<ProductListItemVO>> list(
            @Parameter(description = "页码,从 0 开始") @RequestParam(defaultValue = "0") int page,
            @Parameter(description = "每页条数") @RequestParam(defaultValue = "20") int size,
            @Parameter(description = "名称关键词") @RequestParam(required = false) String keyword) {
        return productService.list(page, size, keyword);
    }

    @Operation(summary = "创建商品", description = "需要 ADMIN 角色")
    @PostMapping
    @PreAuthorize("hasRole('ADMIN')")
    public Result<ProductDetailVO> create(@Valid @RequestBody ProductCreateRequest req) {
        return Result.ok(productService.create(req));
    }
}

ProductPageResult 为文档辅助类(包装泛型):

public class ProductPageResult extends Result<PageResult<ProductListItemVO>> {}

14.5 DTO/VO 上的 @Schema

ch13 的 Bean Validation 与 @Schema 互补:

@Schema(description = "创建商品请求")
public class ProductCreateRequest {

    @Schema(description = "商品名称", example = "无线鼠标", maxLength = 200)
    @NotBlank(message = "商品名称不能为空")
    private String name;

    @Schema(description = "售价(元)", example = "99.00", minimum = "0.01")
    @NotNull
    private BigDecimal price;

    @Schema(description = "库存数量", example = "100", minimum = "0")
    @NotNull
    private Integer stock;
}
@Schema(description = "商品详情视图")
public class ProductDetailVO {

    @Schema(description = "商品 ID", example = "1")
    private Long id;

    @Schema(description = "是否已上架")
    private Boolean published;

    @Schema(description = "封面 URL", example = "/media/products/cover.jpg")
    private String coverUrl;
}
注解来源文档效果
@NotNull / @NotBlankrequired: true
@Size(max=200)maxLength: 200
@Min / @DecimalMinminimum
@Schemadescriptionexample、枚举说明

14.6 统一响应 Result 的文档化

ch07 的 Result<T> 包装需在文档中说明:

@Schema(description = "统一 API 响应")
public class Result<T> {

    @Schema(description = "业务码,0 表示成功", example = "0")

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。