你以为“写接口文档”很麻烦?那为什么别人能让它自动生成还带权限分组?

举报
bug菌 发表于 2026/01/13 16:42:07 2026/01/13
【摘要】 🏆本文收录于《滚雪球学SpringBoot 3》:https://blog.csdn.net/weixin_43970743/category_12795608.html,专门攻坚指数提升,本年度国内最系统+最专业+最详细(永久更新)。  本专栏致力打造最硬核 SpringBoot3 从零基础到进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。...

🏆本文收录于《滚雪球学SpringBoot 3》:https://blog.csdn.net/weixin_43970743/category_12795608.html,专门攻坚指数提升,本年度国内最系统+最专业+最详细(永久更新)。
  
本专栏致力打造最硬核 SpringBoot3 从零基础到进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。 如果想快速定位学习,可以看这篇【SpringBoot3教程导航帖】https://blog.csdn.net/weixin_43970743/article/details/151115907,你想学习的都被收集在内,快速投入学习!!两不误。
  
若还想学习更多,可直接前往《滚雪球学SpringBoot(全版本合集)》:https://blog.csdn.net/weixin_43970743/category_11599389.html,涵盖SpringBoot所有版本教学文章。

演示环境说明:

  • 开发工具:IDEA 2021.3
  • JDK版本: JDK 17(推荐使用 JDK 17 或更高版本,因为 Spring Boot 3.x 系列要求 Java 17,Spring Boot 3.5.4 基于 Spring Framework 6.x 和 Jakarta EE 9,它们都要求至少 JDK 17。)
  • Spring Boot版本:3.5.4(于25年7月24日发布)
  • Maven版本:3.8.2 (或更高)
  • Gradle:(如果使用 Gradle 构建工具的话):推荐使用 Gradle 7.5 或更高版本,确保与 JDK 17 兼容。
  • 操作系统:Windows 11

前言:别把 Swagger 当成“写文档工具”,它更像“接口契约打印机”

OpenAPI 的核心意思很朴素:用一种标准、语言无关的方式描述 HTTP API,让人和机器都能读懂。这不是玄学,是规范——OpenAPI Specification(OAS)就是这么定义自己的:语言无关、可让消费者在不看源码的情况下理解并交互接口。
  而 SpringDoc 的价值更现实:它在运行时检查 Spring 项目(Controller、注解、参数、校验等),自动推断 API 语义并生成 OpenAPI 3 文档
  换句话说:你只要把“接口该是什么样”写在代码里(注解/模型/校验),它就帮你把契约打印出来,还顺手给你一个 Swagger UI 页面用来测试。

好,铺垫结束。下面进入正题:用 SpringDoc 替代 SpringFox,并把你给的大纲扩写成“能直接抄进项目”的版本(放心,我不会让你抄一堆没用的配置然后祈祷它能跑😅)。

1. 集成 SpringDoc:替代 SpringFox 的“正经姿势”

1.1 为什么不建议再用 SpringFox?

我不打算在这儿拉踩谁——但工程选型讲究一个“能持续维护”。SpringDoc 这条线的目标非常明确:紧跟 OpenAPI 3,并且对 Spring Boot 的适配更自然(尤其是 Spring Boot 3 / Spring Framework 6 / Jakarta 命名空间之后)。SpringDoc 官方也明确自己是为了自动生成 OpenAPI 3 文档而存在。
  所以“替代 SpringFox”的动机,本质上不是“新潮”,而是:减少不可控的兼容成本

1.2 依赖怎么加(Spring Boot 3 推荐)

下面以 Spring Boot 3.x + Spring Web MVC 为例(WebFlux 依赖名不同,但思路一样)。

Maven

<dependency>
  <groupId>org.springdoc</groupId>
  <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
  <version><!-- 以你项目锁定版本为准 --></version>
</dependency>

SpringDoc 官方站点提供整体能力说明与配置入口。

关键访问路径(默认)

一般你会用到两类端点:

  • OpenAPI JSON:/v3/api-docs(可改路径)
  • Swagger UI:/swagger-ui/index.html(可改路径)

友情吐槽一句:很多人遇到“能访问 /v3/api-docs,但 UI 404”,然后开始怀疑人生。别慌,八成是 Security/拦截器把静态资源挡了,后面我们会专门讲。

1.3 application.yml 常用配置(少而精)

SpringDoc 的配置项属于“标准 Spring 配置属性”,官方列得很全。
我这里挑最常用的:

springdoc:
  api-docs:
    enabled: true
    path: /v3/api-docs
  swagger-ui:
    enabled: true
    path: /swagger-ui.html   # 会重定向到 /swagger-ui/index.html

小建议:生产环境要不要开 UI?看你们团队规范。至少别默认对公网裸奔(你不尴尬,安全同事会帮你尴尬🙂)。

2. @Tag、@Operation、@Schema:把“自动生成”从能用变成好用

SpringDoc 会自动扫 Controller 和模型生成文档,但“自动”通常只保证“有”,不保证“清晰”。想让接口文档看起来像个正经产品(而不是像一坨接口列表),你得靠注解把信息补齐。

接下来我们用一个很典型的业务:用户登录 + 订单查询 做例子。

2.1 @Tag:给接口分组起名字(不然全堆一起很灾难)

Swagger-Core 的 @Tag 注解可以用在类或方法上,用来给单个 operation 或整个类的 operations 打标签。

import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;

@Tag(name = "User", description = "用户相关接口:注册、登录、个人信息")
@RestController
@RequestMapping("/api/users")
public class UserController {

    @PostMapping("/login")
    public String login() {
        return "ok";
    }
}

我的真实感受

  • 没有 @Tag 的文档像“超市仓库”——东西都有,但你找不到。
  • 有了 @Tag 至少像“货架”——分类清楚,骂人都更有理有据。

2.2 @Operation:给每个接口补上“人类语言的说明书”

@Operation 用于定义一个 OpenAPI Operation,或者补充 operation 的额外属性(summary、description、responses 等)。

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import org.springframework.web.bind.annotation.*;

@Operation(
    summary = "用户登录",
    description = "使用邮箱+密码登录,成功后返回 accessToken。注意:密码不会在任何响应中回传(别想了😄)"
)
@PostMapping("/login")
public LoginResponse login(
        @Parameter(description = "登录请求体") @RequestBody LoginRequest req
) {
    // ...省略鉴权逻辑
    return new LoginResponse("token");
}

实战建议(有点“老工程师碎碎念”):

  • summary 写短一点:列表里一眼扫过去要能懂
  • description 写清楚边界:成功/失败、幂等性、是否缓存、是否需要权限
  • 重要字段别靠口口相传:写在 description 里,未来能救命

2.3 @Schema:模型字段不写清楚,前端同学就会用“意念”对接

@Schema 用于定义 OpenAPI 规范中的 Schema(可以标在类、字段、参数、方法等),并补充描述、示例、是否必填等信息。

2.3.1 请求/响应模型示例

import io.swagger.v3.oas.annotations.media.Schema;

@Schema(name = "LoginRequest", description = "登录请求体")
public class LoginRequest {

    @Schema(description = "邮箱", example = "dev@example.com", requiredMode = Schema.RequiredMode.REQUIRED)
    private String email;

    @Schema(description = "密码(明文传输需走 HTTPS)", example = "P@ssw0rd!", requiredMode = Schema.RequiredMode.REQUIRED)
    private String password;

    // getter/setter ...
}

@Schema(name = "LoginResponse", description = "登录响应体")
public class LoginResponse {

    @Schema(description = "访问令牌(JWT)", example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
    private String accessToken;

    public LoginResponse(String accessToken) { this.accessToken = accessToken; }

    // getter/setter ...
}

2.3.2 常见“坑点”与写法建议

  • example 别瞎写:写一个真实形态的值,Swagger UI 里测试会更顺滑
  • requiredMode 建议明确:否则团队里会出现“你以为必填、我以为选填”的经典误会
  • 对枚举字段最好写 description 说明含义(比如 0/1/2 到底代表啥)

我见过最离谱的一次:状态字段叫 status,值是 1/2/3/9。没人写注释。
三个月后连作者本人都说:“9 是啥来着?”
——所以别省这点字,真的。

3. 配合 Spring Security:Swagger UI 到底该放行还是该加锁?

这个问题通常没有“唯一正确答案”,只有“适合你们团队的答案”。但不管你选哪条路,Spring Security 的授权配置一定得搞明白:哪些路径需要 permitAll,哪些需要 authenticated/hasRole。

Spring Security 官方文档里对 Servlet 环境下的请求授权(authorizeHttpRequests 等)讲得很清楚。

下面我给你两套常用策略:开发环境全放行 vs 生产环境受控访问

3.1 策略 A:开发环境放行 Swagger(最常见)

适用场景:内网开发、联调频繁、UI 仅在 dev/test 开。

import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
      .csrf(csrf -> csrf.disable())
      .authorizeHttpRequests(auth -> auth
          // 放行 OpenAPI 文档与 Swagger UI 静态资源
          .requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
          // 其余接口走认证
          .anyRequest().authenticated()
      );

    return http.build();
}

为什么要放行这么多?
因为 Swagger UI 本质是一堆静态资源 + 它会请求 OpenAPI JSON(/v3/api-docs)。你只放行一个路径,另外的资源还是会被拦,页面照样“白给”。(这就是前面我说的“能访问 JSON 但 UI 404”的高发原因。)

3.2 策略 B:生产环境只允许特定角色访问 Swagger

适用场景:生产可查文档,但只给运维/后端/支持人员。

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
      .csrf(csrf -> csrf.disable())
      .authorizeHttpRequests(auth -> auth
          // 文档与 UI 只允许 ADMIN 或 DOCS 角色
          .requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html")
              .hasAnyRole("ADMIN", "DOCS")
          .anyRequest().authenticated()
      )
      .httpBasic(basic -> {}); // 你也可以换成 JWT/OAuth2 等方式

    return http.build();
}

小提醒:

  • 如果你用的是 JWT 方案,也可以给 Swagger UI 配一个“登录入口”或在网关层做访问控制。
  • 别把文档端点对公网完全开放(除非你们是公开 API 且有明确的安全策略)。
  • Spring Security 6 的授权写法建议以官方 reference 为准(authorizeHttpRequests/requestMatchers 等)。

3.3 进阶:只在特定 Profile 启用 Swagger(更稳)

“我不想在生产暴露 UI,但测试环境要用”——这需求太常见了,常见到我都不想吐槽🙂。

做法:给配置类加 @Profile("dev") 或者用配置开关控制 springdoc.swagger-ui.enabled

SpringDoc 官方属性里明确支持通过 springdoc.api-docs.enabled 来禁用端点。

# application-prod.yml
springdoc:
  api-docs:
    enabled: false
  swagger-ui:
    enabled: false

4. 多分组文档:Mobile API vs Web API(终于到“看起来很高级”的部分了)

当你的系统开始同时服务移动端和 Web 端,接口就会出现两种典型分裂:

  • 同一个资源,但 Mobile 只要“轻量字段”,Web 要“全量字段”
  • Mobile 走 /api/m/**,Web 走 /api/web/**
  • 或者按包分:controller.mobile vs controller.web

这时候如果你还把所有接口堆在一个文档里……嗯,怎么说呢,体验大概等于:在 400 页 PDF 里找你想要的 2 行字📄。

SpringDoc 支持基于路径、包扫描等方式对 OpenAPI 文档分组;官方也提供了属性配置入口。
GroupedOpenApi.Builder 的能力(pathsToMatch/packagesToScan/pathsToExclude 等)在其 Javadoc 里也列得很清楚。

下面给两种方式:代码式分组(更灵活)配置式分组(更省事)

4.1 方式一:代码式分组(推荐,适合复杂筛选)

4.1.1 Mobile / Web 基于路径分组

import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OpenApiGroupConfig {

    @Bean
    public GroupedOpenApi mobileApi() {
        return GroupedOpenApi.builder()
                .group("Mobile API")
                .pathsToMatch("/api/m/**")
                .build();
    }

    @Bean
    public GroupedOpenApi webApi() {
        return GroupedOpenApi.builder()
                .group("Web API")
                .pathsToMatch("/api/web/**")
                .build();
    }
}

这里的 pathsToMatch 是 GroupedOpenApi builder 的核心能力之一。

4.1.2 基于包扫描分组(更适合团队协作)

@Bean
public GroupedOpenApi mobileApi() {
    return GroupedOpenApi.builder()
            .group("Mobile API")
            .packagesToScan("com.example.demo.controller.mobile")
            .build();
}

@Bean
public GroupedOpenApi webApi() {
    return GroupedOpenApi.builder()
            .group("Web API")
            .packagesToScan("com.example.demo.controller.web")
            .build();
}

同理,packagesToScan 也是 builder 提供的能力。

4.2 方式二:配置式分组(简单项目更省心)

SpringDoc 的 properties 文档里列出了可用配置项,并明确它依赖标准 Spring 配置文件。

典型写法(示意):

springdoc:
  group-configs:
    - group: Mobile API
      paths-to-match: /api/m/**
    - group: Web API
      paths-to-match: /api/web/**

什么时候用配置式?

  • 分组规则非常简单:按路径/包分就行
  • 你不想写一堆 @Bean
    什么时候用代码式?
  • 你需要更复杂的过滤:比如“只展示标注了 @Operation 的接口”、或者按 header/produces/consumes 分组(builder 支持这些维度)。

5. 把四个点串起来:一个“能跑、能看、能控权限、能分组”的最小完整示例

下面给你一个相对完整的骨架(你可以直接复制到项目里改包名):

5.1 Controller 示例(Mobile & Web)

@Tag(name = "Order", description = "订单接口")
@RestController
@RequestMapping("/api/m/orders")
public class MobileOrderController {

    @Operation(summary = "移动端订单列表", description = "返回轻量字段:id、状态、总价")
    @GetMapping
    public List<MobileOrderDto> list() { return List.of(); }
}

@Tag(name = "Order", description = "订单接口")
@RestController
@RequestMapping("/api/web/orders")
public class WebOrderController {

    @Operation(summary = "Web端订单列表", description = "返回全量字段:包含用户、明细、优惠信息")
    @GetMapping
    public List<WebOrderDto> list() { return List.of(); }
}

@Schema(description = "移动端订单 DTO(轻量)")
class MobileOrderDto {
    @Schema(description = "订单ID", example = "10001")
    public Long id;

    @Schema(description = "订单状态", example = "PAID")
    public String status;

    @Schema(description = "总价(单位:分)", example = "19900")
    public Integer totalFee;
}

@Schema(description = "Web端订单 DTO(全量)")
class WebOrderDto extends MobileOrderDto {
    @Schema(description = "用户邮箱", example = "dev@example.com")
    public String userEmail;

    @Schema(description = "优惠金额(分)", example = "1000")
    public Integer discountFee;
}
  • @Tag:类/方法级标签
  • @Operation:接口说明
  • @Schema:模型说明

5.2 分组配置(Mobile vs Web)

@Configuration
public class OpenApiGroupConfig {

    @Bean
    public GroupedOpenApi mobileApi() {
        return GroupedOpenApi.builder()
                .group("Mobile API")
                .pathsToMatch("/api/m/**")
                .build();
    }

    @Bean
    public GroupedOpenApi webApi() {
        return GroupedOpenApi.builder()
                .group("Web API")
                .pathsToMatch("/api/web/**")
                .build();
    }
}

GroupedOpenApi builder 的 pathsToMatch 等能力可参考其 Javadoc。

5.3 Spring Security 放行/管控 Swagger

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
      .csrf(csrf -> csrf.disable())
      .authorizeHttpRequests(auth -> auth
          .requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
          .anyRequest().authenticated()
      );
    return http.build();
}

授权配置写法与机制参考 Spring Security Reference。

6. 一些“写了就少掉头发”的实战建议(不写你也会踩)

6.1 文档内容“过度自动化”的副作用:信息不对称

自动生成会让人误以为“文档一定正确”。但实际上:

  • Controller 参数没写校验/没写描述 → 文档就含糊
  • DTO 字段含义没写 → 使用方靠猜
  • 接口行为(幂等、分页、排序规则)没写 → 联调靠吵

所以我的原则是:

能自动的交给 SpringDoc;不能自动的(语义、边界、约束)必须由人补齐。
这也是 springdoc FAQ 强调的方向:让文档尽可能贴近代码、尽量少改动,但允许用注解补充。

6.2 Swagger UI 是“测试入口”,别把它当成“生产调试神器”

UI 在 dev/test 很香,但在 prod:

  • 权限要控
  • 日志要留
  • 最好配合网关/内网/堡垒机
    别最后变成“谁都能点两下试试”的公开按钮。你以为是方便,安全同事看了想把你电脑电源拔了😅。

6.3 多分组不是为了炫技,是为了减少沟通成本

Mobile 和 Web 的接口混在一起,最常见的后果是:

  • 前端同学点错接口调试
  • 测试同学写错用例
  • 新人接手以为“为什么同名接口返回字段不一样”

分组这件事一次做对,后面每天都省时间。

结语:你真正想要的不是“文档页面”,而是“接口契约能长期可信”

我见过太多“文档工具上了、页面也能打开”,但团队仍然天天扯皮的项目。问题不在工具,而在:接口契约没有被当成契约
  SpringDoc 能把“生成”这件事变得很省力;而 @Tag/@Operation/@Schema 能把“可读性”拉起来;Spring Security 决定它是“开发利器”还是“生产隐患”;多分组则决定团队协作效率是“丝滑”还是“互相瞪眼”。
  把这四件事串起来,你的文档就不再是“摆设”,而是工程的一部分——很朴素,但很顶用。

🧧福利赠与你🧧

  无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」,bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。

最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。

同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G PDF编程电子书、简历模板、技术文章Markdown文档等海量资料。

ps:本文涉及所有源代码,均已上传至Gitee:https://gitee.com/bugjun01/SpringBoot-demo 开源,供同学们一对一参考 Gitee传送门https://gitee.com/bugjun01/SpringBoot-demo,同时,原创开源不易,欢迎给个star🌟,想体验下被🌟的感jio,非常感谢❗

🫵 Who am I?

我是 bug菌:

  • 热活跃于 CSDN:https://blog.csdn.net/weixin_43970743 | 掘金:https://juejin.cn/user/695333581765240 | InfoQ:https://www.infoq.cn/profile/4F581734D60B28/publish | 51CTO:https://blog.51cto.com/u_15700751 | 华为云:https://bbs.huaweicloud.com/community/usersnew/id_1582617489455371 | 阿里云:https://developer.aliyun.com/profile/uolxikq5k3gke | 腾讯云:https://cloud.tencent.com/developer/user/10216480/articles 等技术社区;
  • CSDN 博客之星 Top30、华为云多年度十佳博主&卓越贡献奖、掘金多年度人气作者 Top40;
  • 掘金、InfoQ、51CTO 等平台签约及优质作者;
  • 全网粉丝累计 30w+

更多高质量技术内容及成长资料,可查看这个合集入口 👉 点击查看:https://bbs.csdn.net/topics/612438251 👈️
硬核技术公众号 「猿圈奇妙屋」https://bbs.csdn.net/topics/612438251 期待你的加入,一起进阶、一起打怪升级。

- End -

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。