当前位置: 首页 > news >正文

Knife4j 4.4 + Spring Boot 3:OpenAPI3文档配置与Bearer认证集成

做后端的,谁没被前端同事追着问过"这个接口返回字段啥意思""这个参数必填吗""有没有示例值"。最早期我们项目API文档是写在Confluence上的,Word风格那种,接口一改文档忘改,半个月后文档和代码完全对不上,前端照着文档调接口全是400,最后还是得抓着后端口对口确认。

后来上线了Knife4j,文档直接从代码注解生成,接口变了注解也得改,至少改完文档跟着变。我们Spring Boot 3.4.3的项目里用的是Knife4j 4.4.0,基于OpenAPI3规范,整套配置和踩坑过程整理一下分享出来。

一、为什么必须要API文档

不是矫情,是真能省事。

前后端联调。前端拿到一份能在线点开、能直接发请求试的文档,效率比看Markdown高一个数量级。我们前端Vue那边的同学,基本是开着Knife4j页面对着调,请求参数点"调试"按钮直接发,看到响应示例再决定字段怎么处理。比口头交流或者翻聊天记录靠谱太多。

新人理解接口。新人入职第一周不可能把所有Controller读完,但有了文档可以按模块快速浏览,知道系统有哪些接口、各自负责什么。我们项目11个模块的Controller,新人靠Knife4j两天就能摸清接口地图。

接口自测。后端自己开发完一个接口,在Knife4j里点调试、传参数、看响应,比开Postman新建集合省事。尤其配合Bearer认证配置好之后,登录拿token填一次,后续所有接口都自动带,调试链路特别顺。

文档这件事,要么代码即文档,要么文档即负债。Word文档这条路走过的人都懂,最后一定变成"文档没人维护、内容全是过期信息"的死局。

二、技术选型:为什么是Knife4j 4.4,不是Swagger2也不是SpringDoc

Spring Boot 3这一刀切下来,老项目的Swagger2(SpringFox)直接不能用了。原因很简单——Spring Boot 3把javax.*全换成了jakarta.*,SpringFox依赖的还是javax.servlet,依赖一拉进来就报ClassNotFound。SpringFox官方也基本停止维护了,社区里只能找到一些fork版本,谁敢往生产上引。

剩下两条路:SpringDoc和Knife4j。

SpringDoc是OpenAPI3的原生实现,维护活跃,Spring Boot 3支持得很好。但它的UI就是OpenAPI标准的Swagger UI,能用,但功能比较朴素——没有接口搜索、没有全局参数配置记忆、没有离线文档导出、调试体验也一般。

Knife4j 4.x底层就是基于springdoc-openapi做的,注解和API规范完全沿用OpenAPI3,但前端UI重写了一套,明显更顺手:左侧支持接口搜索、可以记忆上次填的参数、文档导出支持Markdown和HTML、还有请求参数缓存。对国内开发者更友好的是UI默认中文。

我们选的是knife4j-openapi3-jakarta-spring-boot-starter版本4.4.0,starter直接带好了SpringDoc依赖,不需要单独再引springdoc-openapi-webmvc-core,避免版本冲突。jakarta这个后缀很关键,对应Spring Boot 3的jakarta包名,老的非jakarta版本拉进来还是会被javax卡死。

三、Knife4jConfig配置类:三个核心Bean

整套配置就一个Knife4jConfig类,里面三个核心部分。

第一是OpenAPIBean,定义文档的全局元信息:title、version、description、contact(姓名、邮箱、url)。这些信息会显示在文档首页。Contact建议写真邮箱,方便外部对接的人联系到维护者。

第二是GroupedOpenApi,按模块分组。这块下面专门讲,11个模块就是11个GroupedOpenApi Bean。

第三是Bearer认证相关,通过OpenAPIcomponents.securitySchemessecurity字段配置。securitySchemes定义一个名为Bearer的方案,type是http,scheme是bearer,bearerFormat是JWTsecurity字段把这个方案设成全局默认,这样所有接口在文档里都会显示一个锁的图标,表示需要认证。

配置knife4j.enable=true开启增强功能,这个属性在application.yml里。增强功能开了之后,UI才有接口搜索、文档导出这些能力。

四、注解使用:四个层级

OpenAPI3的注解体系比Swagger2清爽,io.swagger.v3.oas.annotations包下,按层级分四类。

Controller级的@Tag。每个Controller类上加@Tag(name = "用户管理", description = "用户的增删改查"),name会作为左侧菜单的分组名,description是补充说明。name不能重复,重复的话UI上会合并到一起,很难看。我们一开始有个同事图省事都写"管理",结果11个模块全挤在一个分组下,后来强制约定name要带模块前缀。

接口级的@Operation。方法上加@Operation(summary = "分页查询用户", description = "支持按用户名、手机号、状态过滤")。summary是接口列表里那行短标题,要简洁;description是详情页的长说明。这里有个坑下面专门讲——description里换行用\n在UI里不生效,得用<br>

DTO级的@Schema。实体类字段上加@Schema(description = "用户ID", example = "1001", requiredMode = REQUIRED)。description是字段说明,example是示例值,requiredMode控制是否必填。example这个属性一定要填,前端看文档最希望看到的就是真实示例值,光有描述不够直观。

参数级的@Parameter。方法参数上加@Parameter(description = "页码", required = true, example = "1"),主要给路径参数和查询参数补充说明。@RequestParam这种简单参数其实用@Parameter就够了,但复杂对象入参用@Schema标注DTO更合适。

还有一个@Hidden注解,加在方法上可以让接口从文档里隐藏。内部接口、调试接口、不希望对外暴露的,用这个屏蔽掉,比单独写配置过滤方便。

五、Bearer认证集成:让Knife4j带上Sa-Token的JWT

我们项目用Sa-Token做认证,登录后返回JWT token,前端把token放在Authorization头里,格式是Bearer {token}。Knife4j默认是不会带这个头的,调试接口会直接401。要让Knife4j自动带上token,核心是配置SecurityScheme

OpenAPIBean里,components.addSecuritySchemes("Bearer", new SecurityScheme().type(Type.HTTP).scheme("bearer").bearerFormat("JWT").in(In.HEADER).name("Authorization")),定义一个名为Bearer的方案,类型是HTTP Bearer,放在请求头的Authorization字段。

然后openApi.addSecurityItem(new SecurityRequirement().addList("Bearer")),把Bearer方案加到全局SecurityRequirement里。这一行是关键——加上之后所有接口默认都关联这个认证方案,UI上每个接口旁边都会有个锁的图标。

实际使用的时候,用户点页面右上角的"文档管理"→"Authorize",弹出框里把登录拿到的JWT token粘进去(不要带Bearer前缀,Knife4j会自动加),点确认。之后调试任何接口,Knife4j都会自动在请求头里带上Authorization: Bearer {token}

这里有个小细节要注意:token要填纯token值,不要手贱带Bearer前缀。我刚开始配置完测试,token前面加了Bearer,结果请求头变成Authorization: Bearer Bearer xxxxx,后端解析失败401,排查了好几分钟才发现是重复了。

六、生产环境安全:必须关闭文档

API文档这东西,开发环境是利器,生产环境是漏洞。

为什么生产必须关?两个原因。第一是接口暴露——所有接口的路径、参数、返回结构对任何能访问到文档URL的人都是透明的,相当于把系统结构白送人。第二是参数泄露——example里填的示例值如果是真实业务数据(比如真实手机号、订单号),生产环境就泄露了。

我们用Profile控制:application-dev.ymlapplication-test.ymlknife4j.enable=trueapplication-prod.ymlknife4j.enable=false。Spring Boot 3.4的Profile激活用spring.profiles.active=prod

光配置knife4j.enable=false还不够,这个属性控制的是Knife4j的UI增强,但OpenAPI的JSON接口/v3/api-docs默认还在,接口元数据照样能拿到。所以还得在Spring Security或者Sa-Token的拦截器里把文档路径都拦截掉,prod环境直接404或者403。我们项目里Sa-Token配置了一个SaInterceptor,prod环境把/doc.html/swagger-ui/**/v3/api-docs/**/webjars/**/favicon.ico这些路径全部拦截。

还有一个常见疏漏:网关层。如果项目前面有Nginx反代,prod环境的Nginx配置里也要把这些路径deny掉,否则应用层关了网关层没关,等于没关。

七、11个模块的分组展示

我们项目11个模块:系统管理(用户/角色/菜单/部门)、AI供应商、AI模型、AI对话、AI知识库、代码生成器、文件管理、定时任务、系统监控、操作日志、字典管理。

每个模块一个GroupedOpenApi,关键配置是packagesToScan。比如系统管理模块:

GroupedOpenApi.builder().group("01-系统管理").packagesToScan("com.xxx.system.controller").build()

group名前面加数字前缀是为了控制UI上的显示顺序,Knife4j默认按字母序排,01开头的系统管理会排在最上面。如果不加前缀,"AI模块"会排在"系统管理"前面,看着别扭。

packagesToScan要写Controller所在的全限定包路径,不能写错。我们一开始有人把controller写成Controller(大写C),结果分组里有这个模块但接口数为0,排查半天才发现是包路径大小写问题——Java包名是大小写敏感的。

跨模块的Controller,比如有个公共的文件上传Controller被多个模块引用,可以单独建一个"00-公共接口"分组,packagesToScan指向公共包。这样既不污染业务模块的分组,又能在文档里展示出来。

OpenAPI主文档(group为default的那个)我们不展示,直接把springdoc.default-flat-param-object=true配上,让所有接口都通过具体分组访问,避免default分组和模块分组重复显示接口。

八、踩坑记录

jakarta包名导致的依赖冲突。这个最坑。一开始引的是knife4j-openapi3-spring-boot-starter(没有jakarta后缀),4.4.0版本,结果启动直接报ClassNotFoundException: javax.servlet.http.HttpServletRequest。Spring Boot 3的servlet包是jakarta,老starter还是javax。解决方案是换成knife4j-openapi3-jakarta-spring-boot-starter,只差一个词,但能差死人。Maven依赖这种东西,少个词、多 个词,表现就是天差地别。

@Operation的description换行不生效。description里写"第一行\n第二行",UI渲染出来还是一行,\n直接显示成字面字符。换成System.lineSeparator()也不行。最后发现Knife4j的description渲染走的是HTML,要用<br>标签才能换行。"第一行<br>第二行"就正常了。这个反直觉的地方不知道坑了多少人。

SSE接口在文档里显示异常。AI对话的流式接口,返回类型是text/event-stream,一开始@Operation没特别配置,文档里把响应类型识别成application/json,调试的时候一直转圈不出结果——因为Knife4j的调试器在等JSON响应结束,SSE是流式的一直不发完。后来给SSE接口加produces = MediaType.TEXT_EVENT_STREAM_VALUE,再配合@ApiResponse显式声明响应类型,文档显示就正常了。调试SSE接口还是得用浏览器原生EventSource或者curl,Knife4j的调试器对长连接支持不好,这个不能强求。

分组packagesToScan写错。前面提过,包名大小写敏感。还有一个坑是逗号分隔的多个包路径,packagesToScan接受的是可变参数,不是逗号分隔字符串。一开始有人写成packagesToScan("com.xxx.a.controller,com.xxx.b.controller")——一个字符串当成一个包名,结果两个包都没扫到。正确写法是packagesToScan("com.xxx.a.controller", "com.xxx.b.controller"),两个字符串参数。

Knife4j的basic认证弹窗。Knife4j有个knife4j.basic.enable配置,开启后访问/doc.html会弹basic认证框。一开始我以为这个开了之后Bearer token就不用单独配了,其实是两码事——basic认证是访问文档站点本身的,Bearer是接口业务层的认证。两个都要配,不能省。

生产环境漏关OpenAPI端点。前面提到的,光配knife4j.enable=false不够,/v3/api-docs还能访问。我们一开始上线就漏了这个,幸亏安全扫描发现了,赶紧把Sa-Token拦截规则补上。这个坑很多人都踩过,原因是knife4j.enable这个名字有迷惑性,让人以为关了它就万事大吉。

写在最后

Knife4j这套东西不算复杂,但真要在Spring Boot 3项目里用顺,从依赖选型到配置到注解到生产关闭,每一步都有坑。我们这套配置在11个模块的项目里跑了挺久,文档体验比早期Word时代好太多,前后端联调的扯皮次数明显减少。

几个心得:一是Spring Boot 3的jakarta变更影响面比想象大,凡是依赖servlet API的库都要核对jakarta版本;二是生产环境关闭文档要彻底,UI、JSON端点、网关层一个都不能漏;三是注解要写就写完整,summary、description、example、requiredMode都填上,半残的文档比没文档更坑人——前端看到没example的字段会按自己的理解填,调试出问题又得回来问。

OpenAPI3规范加上Knife4j的UI,在Spring Boot 3项目里是目前最顺手的API文档方案。如果你也在做类似的集成,希望这篇能帮你少走点弯路。

http://www.jsqmd.com/news/1140193/

相关文章:

  • 炉石传说HsMod插件:5个技巧让你的游戏体验提升300%
  • 如何用小说下载器一键保存全网小说:新手完整指南
  • 练拳击之后,我发现“代码耦合”和“动作僵硬”是同一件事
  • 图像归一化实战:5种方法在ResNet-50图像分类任务中的性能影响分析
  • 如何快速解锁惠普游戏本性能:OmenSuperHub终极控制指南
  • Seedance2.5本地AI生图与视频生成工具全面评测
  • Python 后端基础(十八):Nginx 怎么用,反向代理、静态资源、HTTPS 和负载均衡讲清楚
  • VTube Studio API架构:虚拟主播系统的WebSocket通信与事件驱动设计
  • vLLM与SGLang推理框架性能横评的技术文章大纲
  • 于react19+vite8+arco+zustand搭建后台管理模板【基础框架】
  • 基于SpringBoot+Vue高校社团平台
  • 【Bug已解决】OpenClaw 升级后报错 Invalid configuration key: legacy_path 解决方案
  • CLIP ViT-B/32 零样本图像分类实战:CIFAR-100 数据集 Top-5 准确率 65.31%
  • 阿里云天池森林火灾数据集分析:3步完成数据预处理与特征工程
  • ChanlunX缠论分析插件:从手工绘图到算法识别的技术跃迁
  • 抖音动态监控助手:5分钟部署,实时追踪博主更新与直播提醒
  • Awards | 百奥几何唐建博士获 WWW 2026 Test of Time Award
  • Web安全入门实战:从零搭建合法靶场与核心漏洞手动测试指南
  • TensorFlow 2.x 石头剪刀布数据集实战:ImageDataGenerator 5种数据增强效果对比
  • RT-DETR升级:CVPR2026 FourierSR+RepC3|全局频域建模+重参数化融合,轻量高精实时检测
  • hw-buaa-lab项目路线图:未来技术发展与学习规划展望
  • 终极指南:3步实现塞尔达传说Switch与WiiU存档自由互通
  • 计算机毕业设计之jsp农作物生长监测系统的设计与实现
  • 软件测试实战指南:从接口自动化到性能压测的完整落地方案
  • 搞懂 Linux 内核容器技术,才算真正吃透 Linux 内核底层
  • 降重降AI工具哪家强?多款AI降重平台实测对比
  • 大学生必备7款AI论文写作工具,一站式搞定选题初稿与降AI率
  • AI技术助力SEO关键词优化的有效 Strategies
  • Notepad--跨平台文本编辑器:国产软件的终极替代方案
  • 螺柱焊技术介绍:从原理到应用的全景解析