# 🦟 蚊子项目 - OpenAPI 3.0 文档配置 ## 📋 概述 蚊子项目使用SpringDoc OpenAPI生成OpenAPI 3.0规范的API文档,支持自动生成和实时更新。 ## 🚀 快速开始 ### 1. 添加依赖 ```xml 2.3.0 org.springdoc springdoc-openapi-starter-webmvc-ui ${springdoc.version} org.springdoc springdoc-openapi-starter-common ${springdoc.version} ``` ### 2. 基础配置 ```yaml # application-prod.yml springdoc: api-docs: enabled: true path: /api-docs groups: enabled: true swagger-ui: enabled: true path: /swagger-ui.html display-operation-id: true display-request-duration: true show-extensions: true show-common-extensions: true default-models-expand-depth: 2 default-model-expand-depth: 2 try-it-out-enabled: true persist-authorization: true tags-sorter: alpha operations-sorter: alpha group-configs: - group: public display-name: Public APIs paths-to-match: /api/v1/** - group: internal display-name: Internal APIs paths-to-match: /api/v1/internal/** - group: admin display-name: Admin APIs paths-to-match: /api/v1/admin/** ``` ### 3. OpenAPI配置类 ```java package com.mosquito.project.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 io.swagger.v3.oas.models.servers.Server; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import java.util.List; /** * OpenAPI配置类 */ @Configuration @Profile("prod") public class OpenApiConfig { @Value("${spring.application.name}") private String applicationName; @Value("${spring.application.version}") private String applicationVersion; @Value("${springdoc.api-docs.server.url}") private String serverUrl; @Bean public OpenAPI mosquitoOpenAPI() { // 安全方案定义 SecurityScheme apiKeyScheme = new SecurityScheme() .type(SecurityScheme.Type.APIKEY) .in(SecurityScheme.In.HEADER) .name("X-API-Key") .description("API密钥认证"); SecurityScheme bearerAuthScheme = new SecurityScheme() .type(SecurityScheme.Type.HTTP) .scheme("bearer") .bearerFormat("JWT") .description("JWT Token认证"); // 安全要求 SecurityRequirement apiKeyRequirement = new SecurityRequirement() .addList("API Key"); SecurityRequirement bearerAuthRequirement = new SecurityRequirement() .addList("Bearer Auth"); // 服务器配置 Server server = new Server() .url(serverUrl) .description("生产环境服务器"); // 组件配置 Components components = new Components() .addSecuritySchemes("API Key", apiKeyScheme) .addSecuritySchemes("Bearer Auth", bearerAuthScheme); return new OpenAPI() .info(new Info() .title("蚊子项目 API文档") .description("蚊子项目推广活动管理系统的API接口文档") .version(applicationVersion) .contact(new Contact() .name("蚊子项目团队") .email("support@mosquito.com") .url("https://mosquito.com")) .license(new License() .name("MIT License") .url("https://opensource.org/licenses/MIT"))) .servers(List.of(server)) .components(components) .addSecurityItem(apiKeyRequirement) .addSecurityItem(bearerAuthRequirement); } } ``` ### 4. 开发环境配置 ```java package com.mosquito.project.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.oas.annotations.EnableOpenApi; import springfox.documentation.service.*; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spi.service.contexts.SecurityContext; import springfox.documentation.spring.web.plugins.Docket; import java.util.Collections; import java.util.List; /** * Swagger配置(开发环境) */ @Configuration @EnableOpenApi @Profile("dev") public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.OAS_30) .apiInfo(apiInfo()) .securitySchemes(Collections.singletonList(apiKey())) .securityContexts(Collections.singletonList(securityContext())) .select() .apis(RequestHandlerSelectors.basePackage("com.mosquito.project.controller")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("蚊子项目 API文档") .description("蚊子项目推广活动管理系统的API接口文档") .version("2.0.0") .contact(new Contact( "蚊子项目团队", "https://mosquito.com", "support@mosquito.com")) .license("MIT License") .licenseUrl("https://opensource.org/licenses/MIT") .build(); } private ApiKey apiKey() { return new ApiKey("API Key", "X-API-Key", "header"); } private SecurityContext securityContext() { return SecurityContext.builder() .securityReferences(defaultAuth()) .operationSelector(operationContext -> true) .build(); } private List defaultAuth() { AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); return Collections.singletonList( new SecurityReference("API Key", new AuthorizationScope[]{authorizationScope}) ); } } ``` ## 📖 API注解示例 ### 1. Controller注解 ```java package com.mosquito.project.controller; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/v1/activities") @Tag(name = "活动管理", description = "活动相关的API接口") @SecurityRequirement(name = "API Key") public class ActivityController { /** * 创建活动 */ @PostMapping @Operation( summary = "创建新活动", description = "创建一个新的推广活动,返回活动ID", tags = {"活动管理"}, operationId = "createActivity" ) @ApiResponses(value = { @ApiResponse( responseCode = "201", description = "活动创建成功", content = @Content( mediaType = "application/json", schema = @Schema(implementation = Activity.class) ) ), @ApiResponse( responseCode = "400", description = "请求参数错误", content = @Content( mediaType = "application/json", schema = @Schema(implementation = ApiResponse.class) ) ), @ApiResponse( responseCode = "401", description = "API密钥无效", content = @Content( mediaType = "application/json", schema = @Schema(implementation = ApiResponse.class) ) ) }) public ResponseEntity> createActivity( @Parameter( name = "request", description = "活动创建请求", required = true, schema = @Schema(implementation = CreateActivityRequest.class) ) @RequestBody CreateActivityRequest request) { // 实现逻辑 } /** * 获取活动详情 */ @GetMapping("/{id}") @Operation( summary = "获取活动详情", description = "根据活动ID获取活动的详细信息", tags = {"活动管理"}, operationId = "getActivityById" ) @ApiResponses(value = { @ApiResponse( responseCode = "200", description = "活动详情", content = @Content( mediaType = "application/json", schema = @Schema(implementation = Activity.class) ) ), @ApiResponse( responseCode = "404", description = "活动不存在", content = @Content( mediaType = "application/json", schema = @Schema(implementation = ApiResponse.class) ) ) }) public ResponseEntity> getActivity( @Parameter( name = "id", description = "活动ID", required = true, example = "1" ) @PathVariable Long id) { // 实现逻辑 } /** * 更新活动 */ @PutMapping("/{id}") @Operation( summary = "更新活动信息", description = "更新指定活动的信息", tags = {"活动管理"}, operationId = "updateActivity" ) @ApiResponses(value = { @ApiResponse( responseCode = "200", description = "更新成功", content = @Content( mediaType = "application/json", schema = @Schema(implementation = Activity.class) ) ), @ApiResponse( responseCode = "404", description = "活动不存在" ) }) public ResponseEntity> updateActivity( @PathVariable Long id, @RequestBody UpdateActivityRequest request) { // 实现逻辑 } /** * 删除活动 */ @DeleteMapping("/{id}") @Operation( summary = "删除活动", description = "删除指定的活动", tags = {"活动管理"}, operationId = "deleteActivity" ) @ApiResponses(value = { @ApiResponse( responseCode = "204", description = "删除成功" ), @ApiResponse( responseCode = "404", description = "活动不存在" ) }) public ResponseEntity deleteActivity(@PathVariable Long id) { // 实现逻辑 } /** * 获取排行榜 */ @GetMapping("/{id}/leaderboard") @Operation( summary = "获取活动排行榜", description = "获取指定活动的排行榜数据,支持分页", tags = {"活动管理"}, operationId = "getLeaderboard" ) @Parameters({ @Parameter( name = "id", description = "活动ID", required = true ), @Parameter( name = "page", description = "页码,从0开始", required = false, schema = @Schema(type = "integer", defaultValue = "0") ), @Parameter( name = "size", description = "每页大小", required = false, schema = @Schema(type = "integer", defaultValue = "20", maximum = "100") ), @Parameter( name = "topN", description = "只显示前N名,如果设置则忽略分页", required = false, schema = @Schema(type = "integer") ) }) @ApiResponses(value = { @ApiResponse( responseCode = "200", description = "排行榜数据", content = @Content( mediaType = "application/json", schema = @Schema(implementation = LeaderboardResponse.class) ) ) }) public ResponseEntity> getLeaderboard( @PathVariable Long id, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size, @RequestParam(required = false) Integer topN) { // 实现逻辑 } } ``` ### 2. 模型注解 ```java package com.mosquito.project.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import java.time.LocalDateTime; /** * 活动创建请求 */ @Data @Schema(description = "活动创建请求") public class CreateActivityRequest { @Schema( description = "活动名称", example = "新年推广活动", required = true ) @NotBlank(message = "活动名称不能为空") @Size(min = 2, max = 100, message = "活动名称长度必须在2-100个字符之间") private String name; @Schema( description = "活动开始时间", example = "2024-01-01T10:00:00", required = true ) @NotNull(message = "开始时间不能为空") private LocalDateTime startTime; @Schema( description = "活动结束时间", example = "2024-01-31T23:59:59", required = true ) @NotNull(message = "结束时间不能为空") private LocalDateTime endTime; @Schema( description = "活动描述", example = "新年期间的用户推广活动" ) private String description; @Schema( description = "活动状态", example = "draft", allowableValues = {"draft", "active", "completed", "cancelled"} ) private String status; } ``` ```java package com.mosquito.project.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.time.LocalDateTime; import java.util.List; /** * 活动响应 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor @Schema(description = "活动响应") public class Activity { @Schema(description = "活动ID", example = "1") private Long id; @Schema(description = "活动名称", example = "新年推广活动") private String name; @Schema(description = "活动开始时间", example = "2024-01-01T10:00:00") private LocalDateTime startTime; @Schema(description = "活动结束时间", example = "2024-01-31T23:59:59") private LocalDateTime endTime; @Schema(description = "活动状态", example = "active") private String status; @Schema(description = "活动描述") private String description; @Schema(description = "创建时间", example = "2024-01-01T08:00:00") private LocalDateTime createdAt; @Schema(description = "更新时间", example = "2024-01-01T08:00:00") private LocalDateTime updatedAt; } ``` ### 3. 枚举注解 ```java package com.mosquito.project.domain; import io.swagger.v3.oas.annotations.media.Schema; /** * 活动状态枚举 */ @Schema(description = "活动状态") public enum ActivityStatus { @Schema(description = "草稿状态") DRAFT("draft", "草稿"), @Schema(description = "进行中") ACTIVE("active", "进行中"), @Schema(description = "已完成") COMPLETED("completed", "已完成"), @Schema(description = "已取消") CANCELLED("cancelled", "已取消"); private final String code; private final String description; ActivityStatus(String code, String description) { this.code = code; this.description = description; } public String getCode() { return code; } public String getDescription() { return description; } } ``` ## 🌐 访问API文档 ### Swagger UI ``` 开发环境: http://localhost:8080/swagger-ui.html 测试环境: https://test-api.mosquito.com/swagger-ui.html 生产环境: https://api.mosquito.com/swagger-ui.html ``` ### OpenAPI JSON ``` http://localhost:8080/api-docs https://api.mosquito.com/api-docs ``` ### OpenAPI YAML ``` http://localhost:8080/api-docs.yaml https://api.mosquito.com/api-docs.yaml ``` ## 🔒 安全配置 ### 1. API密钥认证 ```java @SecurityRequirement(name = "API Key") @Operation(summary = "需要API密钥的接口") public ResponseEntity securedEndpoint() { // 实现逻辑 } ``` ### 2. JWT认证 ```java @SecurityRequirement(name = "Bearer Auth") @Operation(summary = "需要JWT Token的接口") public ResponseEntity jwtSecuredEndpoint() { // 实现逻辑 } ``` ### 3. 多重安全要求 ```java @Operation( summary = "多种认证方式", security = { @SecurityRequirement(name = "API Key"), @SecurityRequirement(name = "Bearer Auth") } ) public ResponseEntity multipleAuthEndpoint() { // 实现逻辑 } ``` ## 📚 导出API文档 ### 1. 导出JSON格式 ```bash curl -o openapi.json http://localhost:8080/api-docs ``` ### 2. 导出YAML格式 ```bash curl -o openapi.yaml http://localhost:8080/api-docs.yaml ``` ### 3. 使用OpenAPI Generator生成客户端 ```bash # 生成TypeScript客户端 openapi-generator-cli generate \ -i openapi.json \ -g typescript-axios \ -o ./client/typescript # 生成Java客户端 openapi-generator-cli generate \ -i openapi.json \ -g java \ -o ./client/java # 生成Python客户端 openapi-generator-cli generate \ -i openapi.json \ -g python \ -o ./client/python ``` ## 🧪 测试API文档 ### 1. 使用Swagger UI测试 ```typescript // 在浏览器中访问Swagger UI // 1. 点击 "Authorize" 按钮 // 2. 输入API密钥: "your-api-key" // 3. 点击 "Authorize" // 4. 现在可以使用 "Try it out" 功能测试API ``` ### 2. 使用Postman测试 ```javascript // Postman Pre-request Script pm.request.headers.add({ key: 'X-API-Key', value: 'your-api-key' }); // 导入OpenAPI到Postman // 1. 打开Postman // 2. File -> Import // 3. 选择 openapi.json 文件 // 4. Postman会自动创建Collection ``` ## 🔧 自定义配置 ### 1. 自定义响应示例 ```java @Operation( summary = "创建活动", responses = { @ApiResponse( responseCode = "201", description = "活动创建成功", content = @Content( mediaType = "application/json", schema = @Schema(implementation = Activity.class), examples = @ExampleObject( name = "示例响应", value = "{\"id\":1,\"name\":\"新年推广活动\",\"status\":\"active\"}" ) ) ) } ) ``` ### 2. 自定义请求示例 ```java @Operation( summary = "创建活动", requestBody = @RequestBody( description = "活动创建请求", content = @Content( mediaType = "application/json", schema = @Schema(implementation = CreateActivityRequest.class), examples = { @ExampleObject( name = "标准请求", value = "{\"name\":\"新年推广活动\",\"startTime\":\"2024-01-01T10:00:00\",\"endTime\":\"2024-01-31T23:59:59\"}" ) } ) ) ) ``` ### 3. 自定义错误响应 ```java @Operation( summary = "创建活动", responses = { @ApiResponse( responseCode = "400", description = "请求参数错误", content = @Content( mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class), examples = @ExampleObject( name = "参数错误示例", value = "{\"code\":\"VALIDATION_ERROR\",\"message\":\"活动名称不能为空\",\"details\":{\"name\":\"活动名称不能为空\"}}" ) ) ) } ) ``` ## 📊 API文档最佳实践 ### 1. 分组组织 ```java @Tag(name = "活动管理", description = "活动相关的API接口") @Tag(name = "用户管理", description = "用户相关的API接口") @Tag(name = "分享功能", description = "分享相关的API接口") ``` ### 2. 清晰的描述 ```java @Operation( summary = "创建新活动", // 简短的标题 description = """ 创建一个新的推广活动。 **注意事项:** - 活动名称不能为空 - 开始时间必须早于结束时间 - 活动时长不能超过90天 """ // 详细的描述 ) ``` ### 3. 错误处理 ```java @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "操作成功"), @ApiResponse(responseCode = "400", description = "请求参数错误"), @ApiResponse(responseCode = "401", description = "API密钥无效"), @ApiResponse(responseCode = "403", description = "权限不足"), @ApiResponse(responseCode = "404", description = "资源不存在"), @ApiResponse(responseCode = "429", description = "请求过于频繁"), @ApiResponse(responseCode = "500", description = "服务器内部错误") }) ``` ## 🔄 自动化文档更新 ### 1. CI/CD集成 ```yaml # .github/workflows/docs.yml name: Update API Documentation on: push: branches: [main] jobs: update-docs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Generate OpenAPI Spec run: | curl -o openapi.json http://localhost:8080/api-docs curl -o openapi.yaml http://localhost:8080/api-docs.yaml - name: Commit Documentation run: | git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git add openapi.json openapi.yaml git commit -m "Update API documentation" git push ``` ### 2. 自动生成客户端SDK ```bash #!/bin/bash # generate-client-sdks.sh # 生成TypeScript客户端 echo "Generating TypeScript client..." openapi-generator-cli generate \ -i openapi.json \ -g typescript-axios \ -o ./client/typescript # 生成Java客户端 echo "Generating Java client..." openapi-generator-cli generate \ -i openapi.json \ -g java \ -o ./client/java echo "Client SDKs generated successfully!" ``` --- *OpenAPI文档配置版本: v2.0.0* *最后更新: 2026-01-22* *维护团队: API Team*