Spring Boot Swagger3 使用指南

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. 在线调试流程

  1. 打开 Knife4j UI 地址,在文档顶部选择对应的服务器环境(如本地开发环境);
  2. 若配置了认证(JWT/OAuth2),点击页面右上角「授权」按钮,输入令牌或完成认证流程;
  3. 选择目标接口,点击「调试」按钮,填写请求参数(路径参数 / 查询参数 / 请求体);
  4. 点击「发送」按钮,查看响应结果(状态码、响应体、响应头)。

六、常见问题排查

1. 文档页面无法访问

  • 检查 springdoc.swagger-ui.enabledknife4j.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 文档,大幅降低前后端协作成本。

核心优势

  1. 实时同步:接口变更时,文档自动更新,避免「文档与代码不一致」问题;
  2. 在线调试:支持直接在文档页面发送请求,无需依赖 Postman 等第三方工具;
  3. 灵活扩展:支持 JWT/OAuth2 认证、全局参数、分组排序等高级功能;
  4. 友好交互:Knife4j 增强 UI 提供更直观的操作体验,支持文档导出(PDF/Markdown)。

最佳实践

  1. 开发环境启用 Swagger,生产环境强制禁用(避免接口暴露风险);
  2. 接口注解需完整(@Tag+@Operation+@ApiResponses),参数和模型添加 @Parameter/@Schema 说明;
  3. 结合 Spring Security 配置权限控制,保障文档访问安全;
  4. 定期更新依赖版本,确保兼容性和安全性。
    通过本文的配置和示例,开发者可快速上手 Swagger3,并根据项目需求灵活扩展功能,让 API 文档成为前后端协作的「桥梁」而非「负担」。
相关推荐
骑着bug的coder3 小时前
第5讲:事务——数据一致性的保护伞
后端·mysql
Java天梯之路3 小时前
Spring Boot 钩子全集实战(一):构造与配置阶段
java·spring boot·面试
Java编程爱好者3 小时前
咱们聊聊Spring循环依赖那点事儿:从“死锁”到“三级缓存”的奇妙之旅
后端
月明长歌3 小时前
【码道初阶】LeetCode 622:设计循环队列:警惕 Rear() 方法中的“幽灵数据”陷阱
java·算法·leetcode·职场和发展
程序员根根3 小时前
SpringBoot Web 入门核心知识点(快速开发案例 + 分层解耦实战)
java·spring boot
Dylan的码园3 小时前
链表与LinkedList
java·数据结构·链表
【非典型Coder】3 小时前
JVM 垃圾收集器中的记忆集与读写屏障
java·开发语言·jvm
小橙编码日志3 小时前
Java事务常见的失效场景总结
后端·面试
马卡巴卡3 小时前
Java关键字解析之abstract:抽象的本质、规范定义与多态基石
后端