文章目录
一、Swagger简介与核心概念
1.1 什么是Swagger?
Swagger是一套围绕OpenAPI规范构建的开源工具,它可以帮助我们设计、构建、记录和使用RESTful API。简单来说,Swagger就像是你API的"说明书"和"测试工具"合二为一。
日常生活化比喻:想象你去一家餐厅,菜单就是API文档。传统方式是你需要手动写一份纸质菜单(Word文档),而Swagger则是一个电子菜单屏,不仅能展示菜品(API接口),还能直接下单测试(调用接口),并且当菜品更新时菜单会自动同步(与代码同步更新)。
1.2 Swagger核心组件
组件名称 | 功能描述 | 类比日常生活 |
---|---|---|
Swagger UI | 可视化API文档界面 | 餐厅的电子点菜屏 |
Swagger Editor | API设计编辑器 | 菜单设计师的工作台 |
Swagger Codegen | 代码生成工具 | 根据设计图自动做菜的机器人厨师 |
Swagger Hub | 云端API协作平台 | 连锁餐厅的中央厨房管理系统 |
1.3 Swagger2 vs Swagger3
特性 | Swagger2 | Swagger3 (OpenAPI 3.0) |
---|---|---|
规范基础 | Swagger规范 | OpenAPI 3.0规范 |
依赖 | springfox-swagger2 | springdoc-openapi-ui |
注解包 | io.swagger.annotations | io.swagger.v3.oas.annotations |
安全性 | 有限支持 | 更强大的安全方案支持 |
性能 | 较低 | 更高 |
社区支持 | 维护中 | 活跃开发 |
组件复用 | 有限 | 更好的组件复用支持 |
文件上传 | 简单支持 | 多部分请求更好支持 |
为什么选择Swagger3:
- 遵循最新的OpenAPI 3.0规范
- 更好的性能
- 更活跃的社区支持
- 更丰富的功能特性
二、SpringBoot集成Swagger3
2.1 基础环境搭建
2.1.1 添加Maven依赖
<!-- SpringDoc OpenAPI (Swagger3) -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.14</version>
</dependency>
<!-- 如果使用WebFlux -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webflux-ui</artifactId>
<version>1.6.14</version>
</dependency>
2.1.2 基础配置类
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("电商平台API文档")
.version("1.0")
.description("这是一个电商平台的后端API文档")
.termsOfService("http://swagger.io/terms/")
.license(new License().name("Apache 2.0").url("http://springdoc.org")));
}
}
配置项解析:
title
: API文档标题,相当于书的封面标题version
: API版本号,像书的版次description
: API描述,相当于书的简介termsOfService
: 服务条款URLlicense
: 许可证信息
2.2 访问Swagger UI
启动应用后,可以通过以下URL访问:
- Swagger UI界面:
http://localhost:8080/swagger-ui.html
- OpenAPI JSON描述:
http://localhost:8080/v3/api-docs
界面解读:
- 顶部:API文档标题和版本
- 左侧:API分组列表(控制器列表)
- 右侧:API详细信息区域
- 顶部搜索框:可以快速搜索API
- "Try it out"按钮:可以直接测试API
三、Swagger3注解详解
3.1 常用注解概览
注解 | 作用范围 | 功能描述 | 类比日常生活 |
---|---|---|---|
@Tag | Controller类 | 对API进行分组 | 书的章节标题 |
@Operation | 方法 | 描述API操作 | 章节中的小节标题 |
@Parameter | 参数 | 描述单个参数 | 菜谱中的食材清单 |
@Schema | 模型属性 | 描述模型属性 | 产品说明书中的规格参数 |
@ApiResponse | 方法 | 描述响应状态码 | 家电的故障代码说明 |
@Hidden | 类/方法/字段 | 隐藏API或属性 | 商业秘密,不对外公开 |
3.2 控制器层注解
3.2.1 @Tag - 控制器分组
@RestController
@RequestMapping("/api/products")
@Tag(name = "产品管理", description = "产品相关的API,包括CRUD操作")
public class ProductController {
// 控制器方法...
}
参数说明:
name
: 必填,分组名称description
: 可选,分组描述
3.2.2 @Operation - 方法描述
@GetMapping("/{id}")
@Operation(
summary = "获取产品详情",
description = "根据ID获取单个产品的详细信息",
tags = { "产品管理" },
parameters = {
@Parameter(name = "id", description = "产品ID", required = true)
}
)
public ResponseEntity<Product> getProductById(@PathVariable Long id) {
// 方法实现...
}
参数说明:
summary
: 简短描述,显示在方法列表description
: 详细描述tags
: 所属标签(与@Tag的name对应)parameters
: 参数描述
3.2.3 @Parameter - 参数描述
@GetMapping("/search")
@Operation(summary = "搜索产品")
public List<Product> searchProducts(
@Parameter(description = "产品名称关键字", example = "手机")
@RequestParam String keyword,
@Parameter(description = "最低价格", example = "1000")
@RequestParam(required = false) Double minPrice,
@Parameter(description = "最高价格", example = "5000")
@RequestParam(required = false) Double maxPrice) {
// 方法实现...
}
参数说明:
description
: 参数描述required
: 是否必填example
: 示例值hidden
: 是否隐藏
3.3 模型层注解
3.3.1 @Schema - 模型属性描述
public class Product {
@Schema(description = "产品ID", example = "1")
private Long id;
@Schema(description = "产品名称", example = "智能手机", required = true)
private String name;
@Schema(description = "产品价格", example = "2999.99")
private BigDecimal price;
@Schema(description = "库存数量", example = "100")
private Integer stock;
@Schema(description = "上架状态", example = "true")
private Boolean onSale;
@Schema(description = "创建时间", example = "2023-01-01 10:00:00")
private LocalDateTime createTime;
// getters and setters...
}
参数说明:
description
: 属性描述example
: 示例值required
: 是否必填hidden
: 是否隐藏allowableValues
: 允许的值范围
3.3.2 枚举类型描述
public enum OrderStatus {
@Schema(description = "待支付")
PENDING,
@Schema(description = "已支付")
PAID,
@Schema(description = "已发货")
SHIPPED,
@Schema(description = "已完成")
COMPLETED,
@Schema(description = "已取消")
CANCELLED
}
3.4 响应注解
3.4.1 @ApiResponse - 响应状态描述
@PostMapping
@Operation(summary = "创建新产品")
@ApiResponses({
@ApiResponse(responseCode = "201", description = "产品创建成功"),
@ApiResponse(responseCode = "400", description = "无效的输入参数"),
@ApiResponse(responseCode = "500", description = "服务器内部错误")
})
public ResponseEntity<Product> createProduct(@RequestBody Product product) {
// 方法实现...
return ResponseEntity.status(HttpStatus.CREATED).body(savedProduct);
}
参数说明:
responseCode
: HTTP状态码description
: 状态描述content
: 响应内容描述(复杂响应时使用)
3.4.2 响应内容描述
@GetMapping("/{id}")
@Operation(summary = "获取产品详情")
@ApiResponse(responseCode = "200", description = "成功获取产品详情",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = Product.class)))
public Product getProductById(@PathVariable Long id) {
// 方法实现...
}
四、Swagger3高级配置
4.1 全局参数配置
4.1.1 添加全局请求头
/**
* 该方法创建一个名为 customOpenAPI 的 Spring Bean,用于生成自定义的 OpenAPI 规范对象。
* OpenAPI 规范可以描述 RESTful API 的结构和使用方式,方便开发者生成 API 文档、测试代码等。
*
* @return 自定义配置的 OpenAPI 对象
*/
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
// 设置 OpenAPI 文档的基本信息
.info(new Info()
// 设置 API 文档的标题
.title("API文档")
// 设置 API 文档的版本号
.version("1.0"))
// 添加安全需求,表明此 API 需要进行安全认证
.addSecurityItem(new SecurityRequirement()
// 添加一个名为 "Authorization" 的安全方案列表,意味着所有 API 操作都需要使用该安全方案进行认证
.addList("Authorization"))
// 设置 OpenAPI 文档的组件,组件可包含安全方案、响应模式等
.components(new Components()
// 添加一个名为 "Authorization" 的安全方案
.addSecuritySchemes("Authorization",
new SecurityScheme()
// 设置安全方案的类型为 HTTP 认证
.type(SecurityScheme.Type.HTTP)
// 设置 HTTP 认证的方案为 bearer token 认证
.scheme("bearer")
// 指定 bearer token 的格式为 JWT(JSON Web Token)
.bearerFormat("JWT")));
}
4.1.2 全局参数
/**
* 此方法定义了一个名为 customOpenAPI 的 Spring Bean,用于创建自定义的 OpenAPI 规范对象。
* OpenAPI 规范可用于详细描述 RESTful API 的结构、请求参数、响应格式等信息,方便开发者生成 API 文档和进行接口测试。
*
* @return 自定义配置的 OpenAPI 对象
*/
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
// 设置 OpenAPI 文档的基本信息
.info(new Info()
// 为 API 文档设置标题
.title("API文档")
// 指定 API 文档的版本号
.version("1.0"))
// 配置 OpenAPI 文档的组件,这里主要用于添加参数等信息
.components(new Components()
// 添加一个名为 "pageNumber" 的参数
.addParameters("pageNumber",
new Parameter()
// 指定该参数位于查询字符串中
.in("query")
// 定义参数的名称为 "pageNumber"
.name("pageNumber")
// 对参数进行描述,表明该参数代表页码
.description("页码")
// 设置该参数为非必需参数
.required(false)
// 定义参数的模式,这里指定参数类型为整数,并设置默认值为 1
.schema(new Schema().type("integer").defaultValue(1)))
// 添加一个名为 "pageSize" 的参数
.addParameters("pageSize",
new Parameter()
// 指定该参数位于查询字符串中
.in("query")
// 定义参数的名称为 "pageSize"
.name("pageSize")
// 对参数进行描述,表明该参数代表每页显示的数量
.description("每页数量")
// 设置该参数为非必需参数
.required(false)
// 定义参数的模式,这里指定参数类型为整数,并设置默认值为 10
.schema(new Schema().type("integer").defaultValue(10))));
}
4.2 分组配置
@Bean
@Primary
public GroupedOpenApi publicApi() {
return GroupedOpenApi.builder()
.group("public")
.pathsToMatch("/api/public/**")
.build();
}
@Bean
public GroupedOpenApi adminApi() {
return GroupedOpenApi.builder()
.group("admin")
.pathsToMatch("/api/admin/**")
.addOpenApiMethodFilter(method -> method.isAnnotationPresent(PreAuthorize.class))
.build();
}
访问不同分组:
- public组:
http://localhost:8080/swagger-ui.html?group=public
- admin组:
http://localhost:8080/swagger-ui.html?group=admin
4.3 安全配置
4.3.1 JWT认证配置
/**
* 定义一个名为 customOpenAPI 的 Spring Bean,用于创建自定义的 OpenAPI 规范对象。
* OpenAPI 规范是用于描述 RESTful API 的标准,可用于生成 API 文档、客户端代码等。
*
* @return 自定义的 OpenAPI 规范对象
*/
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
// 设置 OpenAPI 文档的基本信息
.info(new Info()
// 设置 API 文档的标题
.title("API文档")
// 设置 API 文档的版本号
.version("1.0"))
// 添加安全需求,表明该 API 需要使用 JWT 进行身份验证
.addSecurityItem(new SecurityRequirement()
// 添加一个名为 "JWT" 的安全方案列表
.addList("JWT"))
// 设置 OpenAPI 文档的组件,包括安全方案等
.components(new Components()
// 添加一个名为 "JWT" 的安全方案
.addSecuritySchemes("JWT",
new SecurityScheme()
// 设置安全方案的类型为 HTTP
.type(SecurityScheme.Type.HTTP)
// 设置 HTTP 认证方案为 bearer token
.scheme("bearer")
// 指定 bearer token 的格式为 JWT
.bearerFormat("JWT")
// 指定 token 所在的位置为请求头
.in(SecurityScheme.In.HEADER)
// 指定请求头中携带 token 的字段名为 "Authorization"
.name("Authorization")));
}
4.3.2 OAuth2配置
/**
* 此方法会创建一个 Spring Bean,用于生成自定义的 OpenAPI 对象。
* OpenAPI 规范可用于描述 RESTful API,有助于生成 API 文档、客户端代码等。
*
* @return 自定义的 OpenAPI 规范对象
*/
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
// 配置 OpenAPI 文档的基本信息
.info(new Info()
// 设置 API 文档的标题
.title("API文档")
// 设置 API 文档的版本号
.version("1.0"))
// 配置 OpenAPI 文档的组件,像安全方案等内容都可在此配置
.components(new Components()
// 添加一个名为 "oauth2" 的安全方案
.addSecuritySchemes("oauth2",
new SecurityScheme()
// 设置安全方案的类型为 OAuth 2.0
.type(SecurityScheme.Type.OAUTH2)
// 配置 OAuth 2.0 的授权流程
.flows(new OAuthFlows()
// 采用隐式授权流程
.implicit(new OAuthFlow()
// 设置授权请求的 URL,客户端会重定向到该 URL 以获取授权码
.authorizationUrl("https://example.com/oauth2/authorize")
// 配置授权范围
.scopes(new Scopes()
// 添加一个名为 "read" 的授权范围,描述为 "读取权限"
.addString("read", "读取权限")
// 添加一个名为 "write" 的授权范围,描述为 "写入权限"
.addString("write", "写入权限"))))));
}
}
4.4 自定义UI配置
# application.properties
springdoc.swagger-ui.path=/api-docs
springdoc.swagger-ui.tagsSorter=alpha
springdoc.swagger-ui.operationsSorter=alpha
springdoc.swagger-ui.docExpansion=none
springdoc.swagger-ui.filter=true
springdoc.swagger-ui.persistAuthorization=true
springdoc.swagger-ui.display-request-duration=true
常用配置项:
path
: Swagger UI路径tagsSorter
: 标签排序方式(alpha/method)operationsSorter
: 操作排序方式(alpha/method)docExpansion
: 文档展开方式(none/list/full)filter
: 是否显示搜索框persistAuthorization
: 是否保持授权信息display-request-duration
: 是否显示请求持续时间
五、实战案例:电商系统API文档
5.1 产品管理模块
@RestController
@RequestMapping("/api/products")
@Tag(name = "产品管理", description = "产品相关的CRUD操作")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping
@Operation(summary = "获取产品列表", description = "分页获取所有产品")
@Parameters({
@Parameter(name = "page", description = "页码", example = "1"),
@Parameter(name = "size", description = "每页数量", example = "10")
})
public Page<Product> getProducts(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
return productService.getProducts(page, size);
}
@GetMapping("/{id}")
@Operation(summary = "获取产品详情", description = "根据ID获取单个产品")
@ApiResponse(responseCode = "200", description = "成功获取产品")
@ApiResponse(responseCode = "404", description = "产品不存在")
public Product getProductById(
@Parameter(description = "产品ID", required = true, example = "1")
@PathVariable Long id) {
return productService.getProductById(id);
}
@PostMapping
@Operation(summary = "创建产品", description = "创建新产品")
@ApiResponse(responseCode = "201", description = "产品创建成功")
@ApiResponse(responseCode = "400", description = "无效的输入")
public ResponseEntity<Product> createProduct(
@io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "产品信息",
required = true,
content = @Content(
schema = @Schema(implementation = Product.class),
examples = @ExampleObject(
value = "{\"name\": \"智能手机\", \"price\": 2999.99, \"stock\": 100}"
)
)
)
@Valid @RequestBody Product product) {
Product savedProduct = productService.createProduct(product);
return ResponseEntity.status(HttpStatus.CREATED).body(savedProduct);
}
@PutMapping("/{id}")
@Operation(summary = "更新产品", description = "更新现有产品信息")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "产品更新成功"),
@ApiResponse(responseCode = "400", description = "无效的输入"),
@ApiResponse(responseCode = "404", description = "产品不存在")
})
public Product updateProduct(
@Parameter(description = "产品ID", required = true, example = "1")
@PathVariable Long id,
@Valid @RequestBody Product product) {
return productService.updateProduct(id, product);
}
@DeleteMapping("/{id}")
@Operation(summary = "删除产品", description = "删除指定产品")
@ApiResponse(responseCode = "204", description = "产品删除成功")
@ApiResponse(responseCode = "404", description = "产品不存在")
public ResponseEntity<Void> deleteProduct(
@Parameter(description = "产品ID", required = true, example = "1")
@PathVariable Long id) {
productService.deleteProduct(id);
return ResponseEntity.noContent().build();
}
}
5.2 订单管理模块
@RestController
@RequestMapping("/api/orders")
@Tag(name = "订单管理", description = "订单相关的操作")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping
@Operation(summary = "创建订单", description = "根据购物车创建新订单")
@ApiResponse(responseCode = "201", description = "订单创建成功")
@ApiResponse(responseCode = "400", description = "无效的输入")
public ResponseEntity<Order> createOrder(
@io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "订单信息",
required = true,
content = @Content(
schema = @Schema(implementation = OrderRequest.class),
examples = @ExampleObject(
value = "{\"userId\": 1, \"items\": [{\"productId\": 1, \"quantity\": 2}]}"
)
)
)
@Valid @RequestBody OrderRequest orderRequest) {
Order order = orderService.createOrder(orderRequest);
return ResponseEntity.status(HttpStatus.CREATED).body(order);
}
@GetMapping("/{orderId}")
@Operation(summary = "获取订单详情", description = "根据订单ID获取订单详情")
@ApiResponse(responseCode = "200", description = "成功获取订单")
@ApiResponse(responseCode = "404", description = "订单不存在")
public Order getOrder(
@Parameter(description = "订单ID", required = true, example = "ORD-123456")
@PathVariable String orderId) {
return orderService.getOrder(orderId);
}
@GetMapping("/user/{userId}")
@Operation(summary = "获取用户订单", description = "获取指定用户的所有订单")
@Parameters({
@Parameter(name = "page", description = "页码", example = "1"),
@Parameter(name = "size", description = "每页数量", example = "10")
})
public Page<Order> getUserOrders(
@Parameter(description = "用户ID", required = true, example = "1")
@PathVariable Long userId,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
return orderService.getUserOrders(userId, page, size);
}
@PatchMapping("/{orderId}/status")
@Operation(summary = "更新订单状态", description = "更新订单状态")
@ApiResponse(responseCode = "200", description = "状态更新成功")
@ApiResponse(responseCode = "400", description = "无效的状态")
@ApiResponse(responseCode = "404", description = "订单不存在")
public Order updateOrderStatus(
@Parameter(description = "订单ID", required = true, example = "ORD-123456")
@PathVariable String orderId,
@Parameter(description = "新状态", required = true,
schema = @Schema(implementation = OrderStatus.class))
@RequestParam OrderStatus status) {
return orderService.updateOrderStatus(orderId, status);
}
}
六、Swagger3最佳实践
6.1 文档规范建议
-
命名一致性:
- 使用一致的命名规范(如全部小写,单词用连字符连接)
- 保持路径结构一致(如
/api/{resource}
)
-
版本控制:
- 在路径中包含版本号(如
/api/v1/products
) - 使用
@Tag
标注API版本
- 在路径中包含版本号(如
-
响应标准化:
- 使用统一响应格式
- 包含标准错误码和消息
6.2 性能优化
-
按需加载:
- 使用分组功能只加载必要的API
- 生产环境可以禁用Swagger UI
-
缓存配置:
springdoc.cache.disabled=false
-
生产环境配置:
# 生产环境禁用Swagger UI springdoc.swagger-ui.enabled=false # 但保留API文档端点(可选) springdoc.api-docs.enabled=true
6.3 安全性建议
-
访问控制:
@Profile({"dev", "test"}) // 只在开发和测试环境启用 @Configuration public class SwaggerConfig { // 配置内容... }
-
敏感信息保护:
- 使用
@Hidden
隐藏敏感API - 避免在文档中暴露敏感字段
- 使用
-
HTTPS:
- 确保Swagger UI通过HTTPS访问
- 配置正确的服务器URL:
@Bean public OpenAPI customOpenAPI() { return new OpenAPI() .servers(List.of(new Server().url("https://api.example.com"))); }
七、常见问题与解决方案
7.1 常见问题排查表
问题现象 | 可能原因 | 解决方案 |
---|---|---|
404访问不到Swagger UI | 路径配置错误/依赖缺失 | 检查springdoc.swagger-ui.path 配置 |
模型显示不正确 | 未使用@Schema注解 | 为模型添加@Schema注解 |
参数描述不显示 | 未使用@Parameter | 为参数添加@Parameter注解 |
分组不生效 | 分组配置错误 | 检查GroupedOpenApi配置 |
授权无效 | 安全配置不正确 | 检查SecurityScheme配置 |
7.2 与Spring Security集成
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/swagger-ui/**").permitAll()
.antMatchers("/v3/api-docs/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().disable()
.csrf().disable();
}
}
7.3 自定义文档处理器
@Bean
public OpenApiCustomiser openApiCustomiser() {
return openApi -> {
// 添加服务器信息
openApi.addServersItem(new Server().url("http://localhost:8080").description("本地环境"));
openApi.addServersItem(new Server().url("https://dev.example.com").description("开发环境"));
// 添加扩展信息
openApi.addExtension("x-api-version", "1.0.0");
// 修改默认响应
openApi.getPaths().values().forEach(pathItem -> {
pathItem.readOperations().forEach(operation -> {
operation.getResponses().addApiResponse("500",
new ApiResponse().description("服务器内部错误"));
});
});
};
}
八、Swagger3扩展与进阶
8.1 多语言支持
@Bean
public OpenAPI customOpenAPI(MessageSource messageSource) {
return new OpenAPI()
.info(new Info()
.title(messageSource.getMessage("swagger.title", null, LocaleContextHolder.getLocale()))
.description(messageSource.getMessage("swagger.description", null, LocaleContextHolder.getLocale()))
.version("1.0"));
}
8.2 动态文档生成
@RestController
@RequestMapping("/api/dynamic")
@Tag(name = "动态API", description = "动态生成的API")
public class DynamicApiController {
@GetMapping("/{resource}")
@Operation(summary = "获取动态资源")
@Parameter(name = "resource", description = "资源类型", example = "users")
public ResponseEntity<?> getDynamicResource(
@PathVariable String resource,
@RequestParam Map<String, String> allParams) {
// 根据resource和参数动态处理
return ResponseEntity.ok().build();
}
@Bean
public OpenApiCustomiser dynamicApiCustomiser() {
return openApi -> {
PathItem pathItem = new PathItem()
.get(new Operation()
.addTagsItem("动态API")
.summary("动态资源操作")
.addParametersItem(new Parameter()
.name("resource")
.in("path")
.description("资源类型")
.required(true)
.schema(new StringSchema())))
.post(new Operation()
.addTagsItem("动态API")
.summary("创建动态资源"));
openApi.path("/api/dynamic/{resource}", pathItem);
};
}
}
8.3 自定义UI主题
- 添加自定义CSS文件到
resources/static/swagger-ui/
目录 - 配置自定义CSS路径:
springdoc.swagger-ui.config-url=/swagger-ui/swagger-config.yml springdoc.swagger-ui.css-url=/swagger-ui/custom.css
示例custom.css
:
.swagger-ui .topbar {
background-color: #2c3e50;
}
.swagger-ui .info .title {
color: #27ae60;
}
.opblock-tag {
background-color: #f8f9fa;
border-left: 4px solid #3498db;
}
九、总结与资源推荐
9.1 关键点回顾
-
Swagger3优势:
- 遵循OpenAPI 3.0规范
- 更好的性能和扩展性
- 更丰富的注解支持
-
核心注解:
@Tag
- API分组@Operation
- 方法描述@Parameter
- 参数描述@Schema
- 模型描述
-
最佳实践:
- 合理分组API
- 生产环境安全控制
- 统一的文档规范
关注不关注,你自己决定(但正确的决定只有一个)。
喜欢的点个关注,想了解更多的可以关注微信公众号 “Eric的技术杂货库” ,提供更多的干货以及资料下载保存!