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也不是SpringDocSpring Boot 3这一刀切下来老项目的Swagger2SpringFox直接不能用了。原因很简单——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.0starter直接带好了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认证相关通过OpenAPI的components.securitySchemes和security字段配置。securitySchemes定义一个名为Bearer的方案type是httpscheme是bearerbearerFormat是JWTsecurity字段把这个方案设成全局默认这样所有接口在文档里都会显示一个锁的图标表示需要认证。配置knife4j.enabletrue开启增强功能这个属性在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.yml和application-test.yml里knife4j.enabletrueapplication-prod.yml里knife4j.enablefalse。Spring Boot 3.4的Profile激活用spring.profiles.activeprod。光配置knife4j.enablefalse还不够这个属性控制的是Knife4j的UI增强但OpenAPI的JSON接口/v3/api-docs默认还在接口元数据照样能拿到。所以还得在Spring Security或者Sa-Token的拦截器里把文档路径都拦截掉prod环境直接404或者403。我们项目里Sa-Token配置了一个SaInterceptorprod环境把/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-objecttrue配上让所有接口都通过具体分组访问避免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或者curlKnife4j的调试器对长连接支持不好这个不能强求。分组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.enablefalse不够/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文档方案。如果你也在做类似的集成希望这篇能帮你少走点弯路。