mcpField
S
springdoc-openapi

springdoc-openapi

github.com/claude-dev-suite开发4656 次安装2 天前更新
代码仓库

关于 springdoc-openapi

面向 Spring Boot Java 项目的技能指南,介绍使用 springdoc-openapi 为 API 生成并配置 OpenAPI 文档与 Swagger UI。涵盖端点、模型、安全要求和 API 分组等文档实践。

主要功能

  1. 01配置 API 文档与 Swagger UI
  2. 02用注解描述端点和模型
  3. 03记录安全方案与响应
  4. 04按标签或路径分组 API
  5. 05隐藏内部端点
  6. 06排查常见配置问题

适用场景

  1. 01为 Spring Boot API 添加 OpenAPI 文档
  2. 02补充 DTO 字段和枚举说明
  3. 03整理公开与内部端点
  4. 04检查 Swagger UI 或模式生成问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill springdoc-openapi

安装后在 Claude Code 中输入/springdoc-openapi确认已加载。

详细介绍

Springdoc OpenAPI(Swagger)

深入了解:使用技术为 springdoc-openapi 的 mcp__documentation__fetch_docs 获取全面文档。

Maven 配置

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

应用配置

springdoc:
  api-docs:
    path: /v3/api-docs
    enabled: true
  swagger-ui:
    path: /swagger-ui.html
    enabled: true
    operationsSorter: method
    tagsSorter: alpha
    displayRequestDuration: true
    filter: true
  packages-to-scan: com.example.controller
  paths-to-match: /api/**

OpenAPI 配置

@Configuration
public class OpenApiConfig {

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
            .info(new Info()
                .title("My API")
                .version("1.0.0")
                .description("REST API Documentation")
                .contact(new Contact()
                    .name("API Support")
                    .email("[email protected]"))
                .license(new License()
                    .name("MIT")
                    .url("https://opensource.org/licenses/MIT")))
            .externalDocs(new ExternalDocumentation()
                .description("Wiki Documentation")
                .url("https://wiki.example.com"))
            .addSecurityItem(new SecurityRequirement().addList("bearerAuth"))
            .components(new Components()
                .addSecuritySchemes("bearerAuth",
                    new SecurityScheme()
                        .type(SecurityScheme.Type.HTTP)
                        .scheme("bearer")
                        .bearerFormat("JWT")
                        .description("JWT token authentication")));
    }
}

控制器文档

@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
@Tag(name = "Users", description = "User management endpoints")
public class UserController {

    private final UserService userService;

    @Operation(
        summary = "Get all users",
        description = "Returns a paginated list of all users"
    )
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "Success",
            content = @Content(schema = @Schema(implementation = PageUserResponse.class))),
        @ApiResponse(responseCode = "401", description = "Unauthorized",
            content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    @GetMapping
    public ResponseEntity<Page<UserResponse>> findAll(
            @Parameter(description = "Page number (0-indexed)")
            @RequestParam(defaultValue = "0") int page,
            @Parameter(description = "Page size")
            @RequestParam(defaultValue = "10") int size) {
        return ResponseEntity.ok(userService.findAll(page, size));
    }

    @Operation(summary = "Get user by ID")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "User found"),
        @ApiResponse(responseCode = "404", description = "User not found")
    })
    @GetMapping("/{id}")
    public ResponseEntity<UserResponse> findById(
            @Parameter(description = "User ID", required = true, example = "1")
            @PathVariable Long id) {
        return ResponseEntity.ok(userService.findById(id));
    }

    @Operation(summary = "Create new user")
    @ApiResponses({
        @ApiResponse(responseCode = "201", description = "User created"),
        @ApiResponse(responseCode = "400", description = "Invalid input")
    })
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public ResponseEntity<UserResponse> create(
            @io.swagger.v3.oas.annotations.parameters.RequestBody(
                description = "User creation data",
                required = true,
                content = @Content(schema = @Schema(implementation = CreateUserRequest.class)))
            @Valid @RequestBody CreateUserRequest dto) {
        return ResponseEntity.status(HttpStatus.CREATED)
            .body(userService.create(dto));
    }
}

Schema 文档

@Data
@Schema(description = "User creation request")
public class CreateUserRequest {

    @Schema(
        description = "User's full name",
        example = "John Doe",
        minLength = 2,
        maxLength = 100,
        requiredMode = Schema.RequiredMode.REQUIRED
    )
    @NotBlank
    @Size(min = 2, max = 100)
    private String name;

    @Schema(
        description = "User's email address",
        example = "[email protected]",
        format = "email",
        requiredMode = Schema.RequiredMode.REQUIRED
    )
    @NotBlank
    @Email
    private String email;

    @Schema(
        description = "User's password",
        example = "SecurePass123!",
        minLength = 8,
        requiredMode = Schema.RequiredMode.REQUIRED,
        accessMode = Schema.AccessMode.WRITE_ONLY
    )
    @NotBlank
    @Size(min = 8)
    private String password;

    @Schema(
        description = "User's role",
        example = "USER",
        defaultValue = "USER",
        allowableValues = {"ADMIN", "MANAGER", "USER"}
    )
    private UserRole role;
}

@Data
@Builder
@Schema(description = "User response")
public class UserResponse {

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

    @Schema(description = "User's name", example = "John Doe")
    private String name;

    @Schema(description = "User's email", example = "[email protected]")
    private String email;

    @Schema(description = "User's role", example = "USER")
    private UserRole role;

    @Schema(description = "Account status", example = "ACTIVE")
    private UserStatus status;

    @Schema(description = "Creation timestamp", example = "2024-01-15T10:30:00")
    private LocalDateTime createdAt;
}

枚举文档

@Schema(description = "User roles")
public enum UserRole {
    @Schema(description = "System administrator with full access")
    ADMIN,

    @Schema(description = "Department manager")
    MANAGER,

    @Schema(description = "Regular user")
    USER
}

安全文档

// Mark endpoint as public (no auth required)
@Operation(summary = "Login", security = {})
@PostMapping("/auth/login")
public ResponseEntity<AuthResponse> login(@RequestBody LoginRequest request) {
    return ResponseEntity.ok(authService.login(request));
}

// Require specific roles in documentation
@Operation(
    summary = "Delete user",
    security = @SecurityRequirement(name = "bearerAuth")
)
@PreAuthorize("hasRole('ADMIN')")
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
    userService.delete(id);
    return ResponseEntity.noContent().build();
}

按标签对 API 分组

@Configuration
public class OpenApiConfig {

    @Bean
    public GroupedOpenApi publicApi() {
        return GroupedOpenApi.builder()
            .group("public")
            .pathsToMatch("/api/v1/public/**")
            .build();
    }

    @Bean
    public GroupedOpenApi adminApi() {
        return GroupedOpenApi.builder()
            .group("admin")
            .pathsToMatch("/api/v1/admin/**")
            .build();
    }
}

隐藏端点

@Hidden  // Hide entire controller
@RestController
public class InternalController { }

// Hide specific endpoint
@Operation(hidden = true)
@GetMapping("/internal")
public void internal() { }

关键注解

注解用途
@Tag对端点分组
@Operation描述端点
@Parameter记录路径/查询参数
@Schema记录模型/字段
@ApiResponse记录响应
@Hidden在文档中隐藏
@SecurityRequirement安全方案

不适合使用此技能的情况

  • 编写通用 OpenAPI 规范(使用 openapi 技能)
  • 编写 GraphQL API 文档(使用 graphql 技能)
  • 非 Spring Boot Java 项目
  • 生成前端 OpenAPI 客户端(使用 openapi-codegen 技能)
  • Node.js/TypeScript API(使用 openapi 或特定框架的技能)

反模式

反模式不良影响解决方案
端点缺少 @Operation文档质量差,缺少描述为所有端点添加 @Operation
@Schema 中没有示例API 难以理解为所有 Schema 添加示例值
DTO 未使用 @Schema缺少字段说明使用 @Schema 记录所有 DTO 字段
未隐藏内部端点暴露实现细节使用 @Hidden 隐藏内部端点
缺少安全要求身份验证要求不明确在需要时添加 @SecurityRequirement
缺少错误响应文档API 合约不完整记录所有 4xx/5xx 响应
将实体类用作 API 模型泄露数据库结构创建独立的 DTO 类
在代码中硬编码 API 信息配置未外置使用 application.yml 配置 API 元数据
@Parameter 缺少说明API 可用性差记录所有路径/查询参数

快速故障排查

问题可能原因解决方案
Swagger UI 未加载springdoc 配置不正确检查 application.yml 中的 springdoc.swagger-ui.path
未显示端点控制器不在扫描路径中检查 springdoc.packages-to-scan
Schema 缺少字段字段为 private 且没有 getter添加 getter,或在字段上使用 @Schema
UI 中的安全功能不起作用未配置安全方案在配置中添加 @SecurityScheme
UI 中的基础路径错误未配置服务器 URL在 OpenAPI 配置中设置 servers
生成的 Schema 中存在类型错误不支持 DTO 字段类型使用 @Schema 指定格式
循环引用错误DTO 自引用使用 @Schema(ref = "#/components/schemas/X")
缺少枚举值未记录枚举在枚举字段上添加 @Schema
/v3/api-docs 返回 404未启用 springdoc添加 springdoc 依赖,并检查 api-docs.enabled

参考文档

评论

支持 Markdown