chore: sync local latest state and repository cleanup
This commit is contained in:
893
docs/reports/architecture/OPENAPI_CONFIG.md
Normal file
893
docs/reports/architecture/OPENAPI_CONFIG.md
Normal file
@@ -0,0 +1,893 @@
|
||||
# 🦟 蚊子项目 - OpenAPI 3.0 文档配置
|
||||
|
||||
## 📋 概述
|
||||
|
||||
蚊子项目使用SpringDoc OpenAPI生成OpenAPI 3.0规范的API文档,支持自动生成和实时更新。
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 1. 添加依赖
|
||||
|
||||
```xml
|
||||
<!-- pom.xml -->
|
||||
<properties>
|
||||
<springdoc.version>2.3.0</springdoc.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- SpringDoc OpenAPI -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>${springdoc.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Kubernetes支持(可选) -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-common</artifactId>
|
||||
<version>${springdoc.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
|
||||
### 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<SecurityReference> 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<ApiResponse<Activity>> 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<ApiResponse<Activity>> 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<ApiResponse<Activity>> 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<Void> 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<ApiResponse<LeaderboardResponse>> 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*
|
||||
Reference in New Issue
Block a user