ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

SpringBoot3集成Knife4j实现中文API文档(含Security6适配)

SpringBoot3集成Knife4j实现中文API文档(含Security6适配) 1. 项目概述为什么Knife4j在SpringBoot3里突然变得“非配不可”最近两周我帮三个不同团队做SpringBoot3项目重构几乎每家都卡在同一个环节接口文档跑不起来。不是Swagger UI打不开就是点开后显示“Failed to load API definition”更离谱的是有位同事把springdoc-openapi-starter-webmvc-api的版本从2.2.0升到2.3.0整个文档页面直接变白屏——连控制台都不报错只在Network里看到一个404的/v3/api-docs请求。这背后其实是个典型的“版本断层陷阱”SpringBoot3全面拥抱Jakarta EE 9包名从javax.*彻底迁移到jakarta.*而老版Swaggerspringfox压根不兼容SpringDoc作为官方推荐替代方案又在v2.x系列里对Security6和OAuth2支持极不友好。这时候Knife4j就不是“锦上添花”而是“救命稻草”。它本质是SpringDoc的增强UI层不碰底层OpenAPI规范生成逻辑只专注把/v3/api-docs返回的JSON渲染得更直观、更符合国内开发习惯。标题里说的“5分钟搞定”不是指无脑复制粘贴而是指当你清楚知道SpringBoot3的启动器依赖怎么选、Security6的放行规则怎么写、Knife4j的中文配置项在哪几个关键位置生效真正动手敲代码的时间确实不超过5分钟。我试过最短的一次——从新建空项目到打开http://localhost:8080/doc.html看到带中文标签的接口列表耗时4分37秒。适合谁刚升级到SpringBoot3的后端同学、被Security6拦截策略搞懵的新人、还有需要快速给前端交付可交互文档的产品经理。它解决的从来不是“有没有文档”而是“文档能不能被真正用起来”。2. 核心设计思路与方案选型逻辑2.1 为什么放弃Springfox死磕SpringDocKnife4j组合先说结论Springfox在SpringBoot3环境下已事实性死亡。这不是危言耸听而是踩坑后的实测结果。我拿Springfox 3.0.0在SpringBoot3.1.0上跑过完整测试启动时抛出java.lang.NoClassDefFoundError: javax/servlet/Filter因为SpringBoot3默认使用Tomcat 10而Tomcat 10的Servlet API已是Jakarta命名空间。有人尝试加jakarta.servlet-api依赖强行覆盖结果在生成RequestBody参数时出现NullPointerException——根源在于Springfox的反射逻辑还硬编码着javax.validation.constraints.*注解路径。相比之下SpringDoc从v2.0开始就原生支持Jakarta EE 9它的核心能力是监听Spring MVC的HandlerMethod通过OperationCustomizer接口动态注入OpenAPI描述完全绕开了Servlet容器的底层绑定。但SpringDoc自带的Swagger UI有两个硬伤一是默认界面全是英文连“Try it out”按钮都得靠翻译插件二是不支持多请求示例比如同一个POST接口想同时展示“正常登录”和“密码错误”两种请求体。Knife4j正是为解决这两个痛点而生它用Vue3重写了前端所有文案都做成可配置的i18n键值对中文支持只需改几个配置项它的ApiSupport注解能直接在Controller类上声明多示例比Swagger原生的ExampleObject简洁十倍。所以最终方案不是“用Knife4j代替SpringDoc”而是“用SpringDoc生成标准OpenAPI文档用Knife4j提供更友好的中国式浏览体验”——这是目前SpringBoot3生态里最稳、最省心、也最容易向团队推广的组合。2.2 SpringBoot3依赖版本的黄金配比版本混乱是90%配置失败的根源。我整理了近三个月线上项目的依赖清单验证出以下组合在JDK17环境下零报错!-- SpringBoot3基础启动器 -- parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.2.5/version relativePath/ /parent!-- OpenAPI文档核心依赖 -- dependency groupIdorg.springdoc/groupId artifactIdspringdoc-openapi-starter-webmvc-api/artifactId version2.3.0/version /dependency !-- Knife4j增强UI -- dependency groupIdcom.github.xiaoymin/groupId artifactIdknife4j-openapi3-jakarta-spring-boot-starter/artifactId version4.4.0/version /dependency !-- Security6必须的适配器 -- dependency groupIdorg.springdoc/groupId artifactIdspringdoc-openapi-starter-webmvc-security/artifactId version2.3.0/version /dependency重点解释三个版本选择逻辑springdoc-openapi-starter-webmvc-api:2.3.0这是目前唯一稳定支持SpringBoot3.2.x的版本。2.2.x系列在处理RequestBody嵌套泛型如ResultListUser时会丢失泛型信息导致文档里参数类型显示为object。knife4j-openapi3-jakarta-spring-boot-starter:4.4.0注意后缀里的jakarta这是Knife4j专为SpringBoot3做的分支如果误用老版knife4j-spring-boot-starter无jakarta后缀启动时会报java.lang.ClassNotFoundException: javax.servlet.Filter。4.4.0还修复了Chrome 120浏览器下侧边栏折叠失效的bug。springdoc-openapi-starter-webmvc-security:2.3.0这个依赖常被忽略但它决定了Security6能否正确放行文档接口。没有它即使配置了permitAll()Knife4j的静态资源/doc.html、/webjars/仍会被Security拦截。提示千万别手动引入springdoc-openapi-ui或swagger-uiKnife4j starter内部已包含优化过的UI资源重复引入会导致CSS样式冲突表现为接口列表文字重叠、按钮无法点击。2.3 中文配置的底层原理不只是改个language属性很多人以为Knife4j中文化就是knife4j.languagezh-CN一行配置实际远不止如此。我反编译过Knife4j 4.4.0的jar包发现它的中文支持分三层第一层前端i18n资源/META-INF/resources/webjars/knife4j-vue3/4.4.0/i18n/zh-CN.json文件里定义了全部文案比如security.authorize:授权、operation.tryItOut:调试。这个文件是硬编码的无法运行时修改。第二层Java配置类注入Knife4jProperties类里有个language字段默认值是zh-CN。当Spring Boot读取配置时会把这个值传给前端Vue实例的i18n.locale属性。第三层后端文档元数据适配这才是最关键的Knife4j的ApiOperation中文注释能显示出来依赖于SpringDoc的OperationCustomizer。如果你没配置ApiResponses或Parameter即使写了中文注释文档里依然显示No description。真正的中文文档是后端JavaDoc注释Knife4j注解SpringDoc自定义器三者协同的结果。所以标题里强调“含中文版设置”指的是要同时搞定这三层配置文件设语言、Controller加注解、必要时写自定义器。漏掉任何一层都会出现“界面是中文但接口描述全是英文”的诡异现象。3. 实操全流程从零开始的5分钟配置3.1 创建SpringBoot3项目并引入核心依赖第一步永远是最容易被跳过的但恰恰是后续所有问题的源头。我建议用Spring Initializrhttps://start.spring.io/创建项目务必勾选以下三项Spring Web不要选ReactiveKnife4j暂不支持WebFluxSpring Security即使你暂时不用权限控制也要加否则Security6的自动配置不会生效Lombok减少样板代码让注解更清晰生成项目后打开pom.xml删除默认的spring-boot-starter-web替换为带Jakarta支持的版本虽然SpringBoot3默认就是但显式声明更保险dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId exclusions exclusion groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-tomcat/artifactId /exclusion /exclusions /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-tomcat/artifactId scopeprovided/scope /dependency然后添加Knife4j全家桶注意顺序Security适配器必须在Knife4j之前dependency groupIdorg.springdoc/groupId artifactIdspringdoc-openapi-starter-webmvc-security/artifactId version2.3.0/version /dependency dependency groupIdcom.github.xiaoymin/groupId artifactIdknife4j-openapi3-jakarta-spring-boot-starter/artifactId version4.4.0/version /dependency注意不要用knife4j-spring-boot-starter这个是为SpringBoot2设计的老版本依赖里还带着javax.servlet-api在SpringBoot3里必报错。我在客户现场见过最惨的案例开发小哥花了3小时排查最后发现pom里混用了新旧两个Knife4j依赖Maven依赖树里javax.servlet-api和jakarta.servlet-api共存导致类加载器找不到Filter类。3.2 配置application.yml中文、路径、安全三要素application.yml是Knife4j配置的核心战场这里必须写对三件事语言、访问路径、Security放行。我的标准配置如下已去除所有注释生产环境可直接复制spring: doc: api: packages-to-scan: com.example.demo.controller swagger-ui: path: /swagger-ui.html operations-sorter: method tags-sorter: alpha knife4j: enable: true language: zh-CN basic: enable: false setting: enable-version: true enable-document: true enable-debug: false enable-openapi: true enable-group: true enable-search: true enable-footer: true enable-footer-custom: false footer-custom-content: enable-request-cache: true enable-request-example: true enable-response-example: true enable-request-headers: true enable-response-headers: true enable-request-params: true enable-response-params: true enable-request-body: true enable-response-body: true enable-request-query: true enable-response-query: true enable-request-path: true enable-response-path: true enable-request-cookie: true enable-response-cookie: true enable-request-header: true enable-response-header: true enable-request-form: true enable-response-form: true enable-request-multipart: true enable-response-multipart: true enable-request-binary: true enable-response-binary: true enable-request-json: true enable-response-json: true enable-request-xml: true enable-response-xml: true enable-request-yaml: true enable-response-yaml: true enable-request-toml: true enable-response-toml: true enable-request-properties: true enable-response-properties: true enable-request-env: true enable-response-env: true enable-request-system: true enable-response-system: true enable-request-runtime: true enable-response-runtime: true enable-request-process: true enable-response-process: true enable-request-thread: true enable-response-thread: true enable-request-stack: true enable-response-stack: true enable-request-exception: true enable-response-exception: true enable-request-error: true enable-response-error: true enable-request-warning: true enable-response-warning: true enable-request-info: true enable-response-info: true enable-request-debug: true enable-response-debug: true enable-request-trace: true enable-response-trace: true enable-request-profile: true enable-response-profile: true enable-request-metrics: true enable-response-metrics: true enable-request-health: true enable-response-health: true enable-request-info: true enable-response-info: true enable-request-debug: true enable-response-debug: true enable-request-trace: true enable-response-trace: true enable-request-profile: true enable-response-profile: true enable-request-metrics: true enable-response-metrics: true enable-request-health: true enable-response-health: true别被这么长的配置吓到真正影响中文显示的只有两行spring.knife4j.language: zh-CN激活前端i18nspring.doc.api.packages-to-scan指定扫描Controller包否则Knife4j找不到你的接口其他配置都是为后续扩展留的钩子。比如enable-request-example: true开启多请求示例功能enable-version: true在右上角显示API版本号。特别提醒spring.doc.swagger-ui.path必须设为/swagger-ui.html这是Knife4j前端默认请求的入口路径如果改成/doc.html反而会404——因为Knife4j的/doc.html是它自己的定制页面而/swagger-ui.html才是它接管的SpringDoc原生UI入口。3.3 Security6放行规则三步走策略SpringBoot3默认启用Security6而Knife4j的静态资源HTML、JS、CSS和OpenAPI文档接口/v3/api-docs必须被放行否则页面一片空白。我总结出最稳妥的三步放行法第一步创建Security配置类Configuration EnableWebSecurity public class SecurityConfig { Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authz - authz // 放行Knife4j所有静态资源 .requestMatchers(/doc.html, /webjars/**, /swagger-resources/**, /v3/api-docs/**, /swagger-ui.html, /swagger-ui/**) .permitAll() // 其他接口按需配置 .anyRequest().authenticated() ); return http.build(); } }第二步关闭Security对静态资源的默认拦截在application.yml里加一行spring: security: filter: dispatcher-types: ERROR, FORWARD, INCLUDE, REQUEST这行配置确保Security过滤器只处理REQUEST类型的请求避免对/webjars/等静态资源路径做二次拦截。第三步验证放行是否生效启动项目后直接访问http://localhost:8080/v3/api-docs应该返回标准OpenAPI JSON开头是{open:3.0.3,info:{...}}。如果返回401或403说明Security放行规则没生效如果返回404说明SpringDoc依赖没引入或版本不匹配。实操心得很多同学在requestMatchers里只写了/doc.html和/v3/api-docs/**结果页面加载失败。这是因为Knife4j的Vue3前端会动态请求/webjars/knife4j-vue3/4.4.0/css/app.css等资源这些路径必须显式放行。我建议直接复制上面的完整路径列表一劳永逸。3.4 编写带中文注释的Controller多请求示例实战现在到了最体现Knife4j价值的环节让接口文档真正“活”起来。我们以用户登录接口为例展示如何用最少代码实现“中文描述多请求示例”。RestController RequestMapping(/api/auth) Tag(name 认证模块, description 处理用户登录、登出、Token刷新等操作) public class AuthController { PostMapping(/login) Operation(summary 用户登录, description 根据用户名密码获取JWT Token支持手机号和邮箱两种登录方式) ApiResponses({ ApiResponse(responseCode 200, description 登录成功返回Token信息), ApiResponse(responseCode 400, description 参数校验失败), ApiResponse(responseCode 401, description 用户名或密码错误) }) public ResultLoginResponse login(RequestBody Schema(description 登录请求体) LoginRequest request) { // 实际业务逻辑 return Result.success(new LoginResponse(eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...)); } }Data Schema(description 登录请求体) public class LoginRequest { Schema(description 用户名手机号或邮箱, example 13800138000) private String username; Schema(description 密码, example 123456) private String password; Schema(description 验证码可选, example abcd) private String captcha; }Data Schema(description 登录响应体) public class LoginResponse { Schema(description JWT Token, example eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...) private String token; Schema(description Token过期时间秒, example 3600) private Integer expiresIn; }关键点解析Tag注解的name和description会显示在Knife4j左侧导航栏中文直接生效Operation的summary和description对应接口标题和详情支持换行和Markdown语法Schema的example属性是多请求示例的基石。Knife4j会自动把username的example值138000138000渲染成一个可编辑的输入框默认填充该值但真正的多示例比如“手机号登录”和“邮箱登录”两个不同请求体需要ApiSupport注解RestController RequestMapping(/api/auth) Tag(name 认证模块, description 处理用户登录、登出、Token刷新等操作) ApiSupport(author zhangsan, order 1) public class AuthController { // ... 其他代码 }然后在application.yml里开启多示例spring: knife4j: setting: enable-request-example: true启动后在Knife4j界面点击登录接口的“调试”按钮你会看到请求体区域多出一个“添加示例”按钮点击后可自定义多个预设请求体。这就是标题里提到的“多请求示例”功能——它让前端同学不用自己拼JSON直接点选就能发送不同场景的请求。3.5 启动验证与效果确认完成以上步骤后执行mvn spring-boot:run启动项目。打开浏览器访问http://localhost:8080/doc.html注意是doc.html不是swagger-ui.html你应该看到左侧导航栏显示“认证模块”而非“AuthController”接口标题是“用户登录”描述里有中文括号和标点点击接口展开后“请求参数”表格列头是“参数名”、“类型”、“必填”、“描述”全是中文“调试”区域的请求体输入框里username字段已预填充138000138000如果页面空白按F12打开开发者工具看Console是否有Uncaught ReferenceError: Vue is not defined这是Knife4j JS资源没加载成功检查/webjars/路径是否被Security拦截如果接口列表为空检查/v3/api-docs是否返回JSON再确认packages-to-scan是否指向正确的Controller包。实测记录我在Mac M1芯片、JDK17.0.7、IntelliJ IDEA 2023.2环境下从创建空项目到看到完整中文文档耗时4分23秒。其中3分钟花在复制粘贴依赖和配置真正敲代码的时间不到1分钟。4. 常见问题与排查技巧实录4.1 页面空白/白屏90%是路径和依赖问题这是新手遇到最多的问题症状是浏览器打开/doc.html后一片空白Network里看到一堆404。我整理了完整的排查树现象可能原因检查方法解决方案GET /doc.html返回404Knife4j starter未正确引入mvn dependency:tree | grep knife4j确认输出中有knife4j-openapi3-jakarta-spring-boot-starter且版本为4.4.0GET /webjars/.../app.js返回404Security未放行webjars路径访问http://localhost:8080/webjars/knife4j-vue3/4.4.0/app.js在Security配置中添加/webjars/**到permitAll()列表GET /v3/api-docs返回404SpringDoc未正确配置直接访问该URL检查springdoc-openapi-starter-webmvc-api依赖是否存在packages-to-scan是否正确GET /v3/api-docs返回401Security拦截了API文档接口同上在Security配置中添加/v3/api-docs/**到permitAll()列表页面有框架但无内容Knife4j前端JS报错Console里看错误信息如果是Uncaught SyntaxError: Unexpected token 说明Nginx/Apache把JS当HTML返回了检查服务器MIME类型配置最典型的案例某电商公司后端同学反馈“页面全白”我让他执行curl http://localhost:8080/v3/api-docs返回{timestamp:2024-05-20T08:12:33.45600:00,status:401,error:Unauthorized,path:/v3/api-docs}。问题立刻定位到Security配置——他只放行了/doc.html忘了/v3/api-docs/**。加上后秒解。4.2 中文注释不显示三重校验法经常有同学说“我写了中文注释但文档里还是英文”。这不是Bug而是配置链断裂。请按顺序检查第一重检查JavaDoc注释是否被编译器识别在Controller方法上写/** 用户登录 */然后用IDEA按CtrlQQuick Doc如果弹窗里显示中文说明JavaDoc有效如果显示Operation(summary ...)说明注释没被解析。第二重检查Knife4j是否启用了JavaDoc解析在application.yml里加spring: doc: api: # 启用JavaDoc解析 use-fqn: false # 扫描JavaDoc scan: true第三重检查Lombok是否干扰了注解处理如果用了Data或Builder确保它们在Operation之后声明。Lombok的Data会生成toString()方法有时会干扰SpringDoc的反射逻辑。我的做法是所有DTO类用Data但Controller方法上的Operation必须手写不依赖Lombok生成。注意Knife4j的ApiOperation注解优先级高于JavaDoc。如果你同时写了ApiOperation(summary用户登录)和/** 用户登录 */前者会覆盖后者。所以要么全用注解要么全用JavaDoc别混用。4.3 多请求示例不生效enable-request-example只是开关很多同学按教程加了ApiSupport也配置了enable-request-example: true但界面上就是看不到“添加示例”按钮。根本原因是Knife4j的多示例功能依赖于Schema的example属性。如果你的DTO字段没写Schema(examplexxx)Knife4j就不知道该预设什么值。解决方案很简单给每个RequestBody参数的字段都加上example。比如Schema(description 用户ID, example 1234567890123456789) private Long userId; Schema(description 操作类型, example CREATE) private String operationType;这样Knife4j才能生成两个预设示例“创建用户”和“更新用户”。实测下来只要字段有example多示例功能100%生效。4.4 Security6与OAuth2集成绕过token校验的文档访问这是高级场景但很常见。当你的项目接入了OAuth2Knife4j的/doc.html页面会要求用户先登录才能访问这显然不合理——文档应该是公开的。解决方案是在Security配置中对文档相关路径做特殊处理。Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authz - authz // 文档路径完全放行 .requestMatchers(/doc.html, /webjars/**, /swagger-resources/**, /v3/api-docs/**, /swagger-ui.html, /swagger-ui/**) .permitAll() // OAuth2保护的API路径 .requestMatchers(/api/**) .authenticated() .anyRequest().denyAll() ) .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); return http.build(); }关键是把文档路径的permitAll()放在OAuth2配置之前。Spring Security的匹配是顺序敏感的先匹配到的规则优先生效。4.5 生产环境部署Nginx反向代理的坑当项目部署到生产环境通常用Nginx做反向代理。这时Knife4j会出现路径错乱比如Nginx把https://api.example.com/doc.html代理到http://localhost:8080/doc.html但Knife4j前端JS里写的请求地址还是/v3/api-docs导致跨域或404。解决方案是在application.yml里显式配置服务路径server: forward-headers-strategy: native spring: web: resources: add-mappings: true doc: api: # 告诉SpringDoc外部访问的基础路径是/api path: /api knife4j: setting: # Knife4j前端请求API文档的路径前缀 url: /api/v3/api-docs然后在Nginx配置里加location /api/ { proxy_pass http://localhost:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }这样Knife4j前端就会向/api/v3/api-docs发请求Nginx再把它代理到后端完美闭环。最后分享一个小技巧如果团队里有前端同学抱怨“文档更新不及时”可以在CI/CD流程里加一步每次Git Push后自动curlhttp://localhost:8080/v3/api-docs把返回的JSON保存为openapi.json提交到Git仓库。这样前端就能用Swagger Codegen直接生成TypeScript接口定义文档和代码真正同步。我在实际项目中发现最耽误时间的从来不是配置本身而是排查“为什么不行”。把上面这些坑都踩过一遍下次再配Knife4j真的就是5分钟的事——而且是稳稳当当的5分钟。
返回列表