Swagger3(OpenAPI 3.0)作为 API 文档生成工具,能帮助开发者快速构建清晰、可交互的 API 文档,减少前后端协作沟通成本。本文基于 springdoc-openapi 实现,详细介绍 Swagger3 在 Spring Boot 项目中的基本使用方法、核心配置、常用注解及进阶优化方案。
一、项目环境与依赖配置
1. 环境要求
- Spring Boot 版本:2.7.x 及以上(兼容 Spring Boot 3.x)
- JDK 版本:1.8 及以上
2. 添加核心依赖
在项目 pom.xml 中引入 Swagger3 核心依赖(springdoc-openapi 实现)和 Knife4j 增强 UI 依赖(提供更友好的交互体验):
xml
<!-- Swagger3 核心依赖(SpringDoc 实现) -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.5.0</version> <!-- 稳定版本,与 Spring Boot 版本兼容 -->
</dependency>
<!-- Knife4j 增强 UI(推荐,提供更友好的交互) -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.5.0</version>
</dependency>
说明:若使用 Spring Boot 3.x,需确保依赖的
jakarta版本兼容,Knife4j 4.5.0+ 已适配 Spring Boot 3.x。
二、Swagger3 核心配置
1. 配置类编写
创建 Swagger 配置类,定义 API 基本信息、安全方案、服务器环境等核心配置:
java
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
// 1. API 基本信息配置
.info(new Info()
.title("Spring Boot Swagger3 Demo API") // 文档标题
.version("1.0.0") // 接口版本
.description("这是一个 Spring Boot Swagger3 示例项目,展示了 Swagger3 的核心特性(注解使用、认证配置、多环境适配等)") // 文档描述
.contact(new Contact() // 联系人信息
.name("Example Team")
.email("contact@example.com")
.url("http://example.com")
)
.license(new License() // 许可证信息
.name("Apache 2.0")
.url("http://springdoc.org")
)
)
// 2. 安全方案配置(JWT Bearer 认证)
.addSecurityItem(new SecurityRequirement().addList("bearerAuth"))
.components(new io.swagger.v3.oas.models.Components()
.addSecuritySchemes("bearerAuth", new SecurityScheme()
.name("bearerAuth")
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")
)
)
// 3. 服务器环境配置(本地/测试/生产)
.servers(Arrays.asList(
new Server().url("http://localhost:8080").description("本地开发环境"),
new Server().url("https://staging.example.com").description("测试环境"),
new Server().url("https://production.example.com").description("生产环境")
));
}
}
2. 多环境配置(application-{profile}.properties)
通过配置文件控制不同环境是否启用 Swagger(生产环境建议禁用,避免接口暴露):
开发环境(application-dev.properties)
properties
# 启用 Swagger3 文档
springdoc.swagger-ui.enabled=true
springdoc.api-docs.enabled=true
springdoc.openapi.enabled=true
# Swagger UI 优化配置
springdoc.swagger-ui.operations-sorter=alpha # 接口按字母排序(alpha=字母序,method=请求方法序)
springdoc.swagger-ui.tags-sorter=alpha # 分组按字母排序
springdoc.swagger-ui.default-model-expand-depth=2 # 默认展开模型层级(2级)
springdoc.swagger-ui.default-models-expand-depth=2 # 默认展开所有模型
springdoc.swagger-ui.path=/swagger-ui.html # 原生 Swagger UI 访问路径
knife4j.enable=true # 启用 Knife4j 增强 UI
生产环境(application-prod.properties)
properties
# 生产环境禁用 Swagger(安全考虑)
springdoc.swagger-ui.enabled=false
springdoc.api-docs.enabled=false
springdoc.openapi.enabled=false
knife4j.enable=false # 禁用 Knife4j UI
三、常用注解与实战示例
Swagger3 通过注解描述 API 接口、参数、响应和数据模型,以下是核心注解的实战用法(基于控制器和实体类):
1. 接口分组:@Tag
用于标记控制器或接口组,方便文档分类展示,支持关联外部文档:
java
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.externalDocs.ExternalDocumentation;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/users")
@Tag(
name = "用户管理", // 分组名称(文档中显示的分组标签)
description = "用户相关核心接口,包含用户查询、创建、更新、删除等 CRUD 操作", // 分组描述
externalDocs = @ExternalDocumentation( // 外部文档链接(可选)
url = "http://example.com/docs/user-api",
description = "用户管理 API 详细设计文档"
)
)
public class UserController {
// 接口实现...
}
2. 接口描述:@Operation
用于描述具体接口的功能、用途,支持指定接口排序:
java
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Operation(
summary = "分页查询所有用户", // 接口简要说明(文档列表页显示)
description = "支持按页码和每页大小分页,返回用户列表及分页信息(总条数、总页数)", // 详细描述
tags = {"用户管理"}, // 所属分组(与 @Tag 名称一致)
position = 1 // 接口排序权重(数值越小越靠前)
)
@GetMapping
public ResponseEntity<PageResponse> getAllUsers(
@RequestParam(defaultValue = "1") Integer page, // 页码(默认1)
@RequestParam(defaultValue = "10") Integer size // 每页大小(默认10)
) {
// 业务逻辑:查询分页用户数据
Page<User> userPage = userService.listUsers(page - 1, size); // page 从 0 开始
PageResponse pageResponse = new PageResponse<>(
userPage.getContent(),
userPage.getTotalElements(),
userPage.getTotalPages(),
page,
size
);
return ResponseEntity.ok(ApiResponse.success(pageResponse));
}
3. 请求参数描述:@Parameter
用于描述请求参数(路径参数、查询参数、请求头),明确参数含义、示例值和约束:
java
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.models.enums.ParameterIn;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@Operation(summary = "根据 ID 查询用户", description = "通过用户唯一 ID 获取用户详情", position = 2)
@GetMapping("/{id}")
public ResponseEntity<ApiResponse> getUserById(
@Parameter(
description = "用户唯一 ID", // 参数说明
example = "1001", // 示例值(文档中可直接使用)
in = ParameterIn.PATH, // 参数位置:PATH/QUERY/HEADER
required = true, // 是否必填(默认 false)
name = "id" // 参数名称(与 @PathVariable 一致)
)
@PathVariable Long id
) {
User user = userService.getUserById(id);
if (user == null) {
return ResponseEntity.ok(ApiResponse.fail("用户不存在"));
}
return ResponseEntity.ok(ApiResponse.success(user));
}
4. 响应说明:@ApiResponses + @ApiResponse
定义接口可能的响应状态码、描述和响应格式,帮助前端理解返回逻辑:
java
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@Operation(summary = "创建用户", description = "新增用户信息,用户名不可重复", position = 3)
@ApiResponses({
@ApiResponse(
responseCode = "201", // 响应状态码(创建成功)
description = "用户创建成功",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ApiResponse.class) // 响应数据模型
)
),
@ApiResponse(responseCode = "400", description = "请求参数错误(如用户名长度不足、邮箱格式错误)"),
@ApiResponse(responseCode = "409", description = "用户名已存在(冲突)"),
@ApiResponse(responseCode = "500", description = "服务器内部错误")
})
@PostMapping
public ResponseEntity<ApiResponse> createUser(
@RequestBody User user // 请求体(下文详细描述)
) {
boolean success = userService.createUser(user);
if (success) {
return ResponseEntity.status(201).body(ApiResponse.success(user));
}
return ResponseEntity.ok(ApiResponse.fail("创建失败"));
}
5. 请求体描述:@RequestBody
用于描述 POST/PUT 等请求的请求体,明确请求格式、示例值和必填项:
java
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.media.ExampleObject;
@PostMapping
public ResponseEntity<ApiResponse> createUser(
@RequestBody(
description = "用户创建请求参数",
required = true, // 是否必填
content = @Content(
mediaType = "application/json",
examples = @ExampleObject( // 请求体示例(文档中可直接复制使用)
name = "创建用户示例",
value = "{\"username\": \"test_user\", \"password\": \"123456a\", \"email\": \"test@example.com\", \"age\": 25, \"active\": true}"
),
schema = @Schema(implementation = User.class) // 请求体数据模型
)
)
@org.springframework.web.bind.annotation.RequestBody User user
) {
// 业务逻辑...
}
6. 数据模型描述:@Schema
用于描述实体类及其字段,明确字段含义、示例值、数据格式和约束:
java
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "用户实体类(存储用户核心信息)")
public class User {
@Schema(
description = "用户唯一 ID",
example = "1001",
accessMode = Schema.AccessMode.READ_ONLY // 只读字段(创建时无需传入)
)
private Long id;
@Schema(
description = "用户名(登录账号)",
example = "admin",
requiredMode = Schema.RequiredMode.REQUIRED, // 必填字段
minLength = 3, // 最小长度
maxLength = 20, // 最大长度
pattern = "^[a-zA-Z0-9_]+$" // 正则表达式(仅允许字母、数字、下划线)
)
private String username;
@Schema(
description = "用户邮箱",
example = "admin@example.com",
format = "email", // 数据格式(邮箱格式校验)
requiredMode = Schema.RequiredMode.REQUIRED
)
private String email;
@Schema(
description = "用户年龄",
example = "28",
minimum = "1", // 最小值
maximum = "120", // 最大值
requiredMode = Schema.RequiredMode.NOT_REQUIRED // 非必填
)
private Integer age;
@Schema(
description = "账号状态(true=启用,false=禁用)",
example = "true",
defaultValue = "true" // 默认值
)
private Boolean active;
}
四、进阶功能配置
1. 全局参数配置
若项目中所有接口都需要携带固定参数(如 X-Request-Id 请求头),可在 SwaggerConfig 中添加全局参数:
java
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.media.Schema;
import java.util.Collections;
@Bean
public OpenAPI customOpenAPI() {
// 全局请求头参数:X-Request-Id(用于链路追踪)
Parameter globalRequestId = new Parameter()
.name("X-Request-Id")
.description("请求唯一标识(用于链路追踪)")
.in(ParameterIn.HEADER)
.required(false)
.schema(new Schema().example("req-20240520123456"));
return new OpenAPI()
.info(...) // 原有信息配置
.addSecurityItem(...) // 原有安全配置
.components(...) // 原有组件配置
.servers(...) // 原有服务器配置
.addParametersItem(globalRequestId); // 添加全局参数
}
2. 分组排序优化
通过 extensions 配置分组排序,让文档分组更符合业务逻辑:
java
import java.util.Arrays;
import java.util.HashMap;
import java.util.Collections;
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(...)
.addSecurityItem(...)
.components(...)
.servers(...)
// 分组排序配置
.extensions(Collections.singletonMap(
"x-tagGroups",
Arrays.asList(
new HashMap<String, Object>() {{
put("name", "核心业务");
put("tags", Arrays.asList("用户管理", "订单管理"));
put("order", 1); // 分组排序权重(数值越小越靠前)
}},
new HashMap<String, Object>() {{
put("name", "基础功能");
put("tags", Arrays.asList("产品管理", "系统配置"));
put("order", 2);
}}
)
));
}
3. 忽略指定接口、参数
- 忽略接口:使用
@Hidden注解(该接口不会显示在文档中)
java
import io.swagger.v3.oas.annotations.Hidden;
@Hidden
@GetMapping("/internal") // 内部接口,不对外暴露
public ResponseEntity() {
return ResponseEntity.ok("内部接口返回");
}
- 忽略参数:在
@Parameter中设置hidden = true
java
@GetMapping("/info")
public ResponseEntity<ApiResponse>(
@Parameter(hidden = true) // 隐藏该参数(不显示在文档中)
@RequestParam String secretKey // 内部校验参数,无需前端关注
) {
// 业务逻辑...
}
4. 自定义响应示例(续)
java
@ApiResponses({
@ApiResponse(
responseCode = "200",
description = "操作成功",
content = @Content(
mediaType = "application/json",
examples = @ExampleObject(
name = "成功示例",
value = "{\"code\": 200, \"message\": \"操作成功\", \"data\": {\"id\": 1001, \"username\": \"admin\", \"email\": \"admin@example.com\"}}"
)
)
),
@ApiResponse(
responseCode = "400",
description = "参数错误",
content = @Content(
mediaType = "application/json",
examples = @ExampleObject(
name = "参数错误示例",
value = "{\"code\": 400, \"message\": \"用户名长度不能小于3位\", \"data\": null}"
)
)
)
})
@PostMapping
public ResponseEntity<ApiResponse> createUser(@RequestBody User user) {
// 业务逻辑...
}
5. 集成 Spring Security 权限控制
若项目使用 Spring Security 进行权限管理,可通过 Swagger 配置实现认证联动,让文档支持携带令牌访问受保护接口:
java
import io.swagger.v3.oas.models.security.OAuthFlow;
import io.swagger.v3.oas.models.security.OAuthFlows;
import io.swagger.v3.oas.models.security.Scopes;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(...) // 原有信息配置
// 配置 OAuth2 认证(密码模式)
.addSecurityItem(new SecurityRequirement().addList("oauth2"))
.components(new io.swagger.v3.oas.models.Components()
.addSecuritySchemes("oauth2", new SecurityScheme()
.type(SecurityScheme.Type.OAUTH2)
.flows(new OAuthFlows()
.password(new OAuthFlow()
.tokenUrl("http://localhost:8080/oauth2/token") // 令牌获取地址
.scopes(new Scopes()
.addString("read", "读取权限")
.addString("write", "写入权限")
)
)
)
)
)
.servers(...); // 原有服务器配置
}
}
补充:需在 Spring Security 配置中放行 Swagger 相关路径,避免被拦截:
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
// 放行 Swagger 相关路径
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/knife4j/**").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
}
五、文档访问与调试
1. 访问地址
配置完成后,启动项目,通过以下地址访问 Swagger 文档:
- 原生 Swagger UI:
http://localhost:8080/swagger-ui.html - Knife4j 增强 UI(推荐):
http://localhost:8080/doc.html - OpenAPI 规范 JSON:
http://localhost:8080/v3/api-docs
2. 在线调试流程
- 打开 Knife4j UI 地址,在文档顶部选择对应的服务器环境(如本地开发环境);
- 若配置了认证(JWT/OAuth2),点击页面右上角「授权」按钮,输入令牌或完成认证流程;
- 选择目标接口,点击「调试」按钮,填写请求参数(路径参数 / 查询参数 / 请求体);
- 点击「发送」按钮,查看响应结果(状态码、响应体、响应头)。
六、常见问题排查
1. 文档页面无法访问
- 检查
springdoc.swagger-ui.enabled和knife4j.enable配置是否为true(开发环境); - 确认依赖版本与 Spring Boot 版本兼容(如 Spring Boot 3.x 需使用 Knife4j 4.5.0+);
- 排查 Spring Security 或拦截器是否拦截了 Swagger 相关路径,需手动放行。
2. 接口未显示在文档中
- 检查控制器是否添加
@RestController注解,接口是否添加 HTTP 注解(@GetMapping/@PostMapping等); - 确认接口方法是否为
public权限(非public方法不会被扫描); - 检查是否误加
@Hidden注解,或是否配置了接口扫描范围限制。
3. 注解不生效
- 确认导入的是
io.swagger.v3.oas.annotations包下的注解(而非 Swagger2 的io.swagger.annotations); - 检查依赖是否完整(核心依赖
springdoc-openapi-starter-webmvc-ui不可缺失)。
七、总结
Swagger3(OpenAPI 3.0)通过 springdoc-openapi 与 Spring Boot 项目无缝集成,仅需简单配置和注解,即可生成规范、可交互的 API 文档,大幅降低前后端协作成本。
核心优势
- 实时同步:接口变更时,文档自动更新,避免「文档与代码不一致」问题;
- 在线调试:支持直接在文档页面发送请求,无需依赖 Postman 等第三方工具;
- 灵活扩展:支持 JWT/OAuth2 认证、全局参数、分组排序等高级功能;
- 友好交互:Knife4j 增强 UI 提供更直观的操作体验,支持文档导出(PDF/Markdown)。
最佳实践
- 开发环境启用 Swagger,生产环境强制禁用(避免接口暴露风险);
- 接口注解需完整(
@Tag+@Operation+@ApiResponses),参数和模型添加@Parameter/@Schema说明; - 结合 Spring Security 配置权限控制,保障文档访问安全;
- 定期更新依赖版本,确保兼容性和安全性。
通过本文的配置和示例,开发者可快速上手 Swagger3,并根据项目需求灵活扩展功能,让 API 文档成为前后端协作的「桥梁」而非「负担」。