knife4j
knife4j介绍
1,Knife4j的前身是swagger-bootstrap-ui,前身swagger-bootstrap-ui是一个纯swagger-ui的ui皮肤项目
2,一开始项目初衷是为了写一个增强版本的swagger的前端ui,但是随着项目的发展,面对越来越多的个性化需求,不得不编写后端Java代码以满足新的需求,在swagger-bootstrap-ui的1.8.5~1.9.6版本之间,采用的是后端Java代码和Ui都混合在一个Jar包里面的方式提供给开发者使用.这种方式虽说对于集成swagger来说很方便,只需要引入jar包即可,但是在微服务架构下显得有些臃肿。
3,因此,项目正式更名为knife4j,取名knife4j是希望她能像一把匕首一样小巧,轻量,并且功能强悍,更名也是希望把她做成一个为Swagger接口文档服务的通用性解决方案,不仅仅只是专注于前端Ui前端.
4,swagger-bootstrap-ui的所有特性都会集中在knife4j-spring-ui包中,并且后续也会满足开发者更多的个性化需求.
5,主要的变化是,项目的相关类包路径更换为com.github.xiaoymin.knife4j前缀,开发者使用增强注解时需要替换包路径
6,后端Java代码和ui包分离为多个模块的jar包,以面对在目前微服务架构下,更加方便的使用增强文档注解(使用SpringCloud微服务项目,只需要在网关层集成UI的jar包即可,因此分离前后端)
官方网址:https://doc.xiaominfo.com/docs/quick-start
注意事项
- Spring Boot 3 只支持OpenAPI3规范
- Knife4j提供的starter已经引用springdoc-openapi的jar,开发者需注意避免jar包冲突
- JDK版本必须 >= 17
- Springboot2和SpringBoot3除了导入的依赖有些区别和配置有些区别其他的使用方式几乎差不多,但是knife4j的功能要比swggerui要多
常用注解
| 序号 | 注解名称 | 用法 | 作用 |
|---|---|---|---|
| 1 | @Tag | 修饰类 | 标记类说明信息,name属性 |
| 2 | @Operation | 修饰方法 | 设置方法的说明信息,summary属性 |
| 3 | @Schema | 修饰属性 | 设置参数属性的说明信息,description属性 |
| 4 | @Parameters | 修饰方法 | 内部使用@Parameter,为接口参数设置说明信息 |
| 5 | @Parameter | 修饰方法 | 接口参数设置说明信息 |
SpringBoot2版本
<!--添加Knife4j依赖-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
<version>4.1.0</version>
</dependency>
config
package cn.tedu.weibo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfig {//对于配置类要求可以看懂即可,不用反复去写,将来可以CV
//配置Swagger2的Docket的Bean实例
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
// apiInfo():配置 API 的一些基本信息,比如:文档标题title,文档描述description,文档版本号version
.apiInfo(apiInfo())
// select():生成 API 文档的选择器,用于指定要生成哪些 API 文档
.select()
// apis():指定要生成哪个包下的 API 文档
.apis(RequestHandlerSelectors.basePackage("com.yuan.controller"))
// paths():指定要生成哪个 URL 匹配模式下的 API 文档。这里使用 PathSelectors.any(),表示生成所有的 API 文档。
.paths(PathSelectors.any())
.build();
}
private static final String API_TILE="测试";
//文档信息配置
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
// 文档标题
.title(API_TILE)
// 文档描述信息
.description("文档")
// 文档版本号
.version("1.0")
.build();
}
}
Springboot3版本
导入依赖
dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
配置类
package com.yuan.confIg;
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 org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Knife4jConfig {
@Bean
public OpenAPI openAPI() {
return new OpenAPI()
// 配置接口文档基本信息
.info(this.getApiInfo());
}
private Info getApiInfo() {
return new Info()
// 配置文档标题
.title("SpringBoot3集成Knife4j")
// 配置文档描述
.description("SpringBoot3集成Knife4j示例文档")
// 配置作者信息
.contact(new Contact().name("yuan").url("https://www.baidu.com/").email("2121007706.com"))
// 配置License许可证信息
.license(new License().name("Apache 2.0").url("https://www.baidu.com/"))
// 概述信息
.summary("SpringBoot3集成Knife4j示例文档")
.termsOfService("https://www.baidu.com/")
// 配置版本号
.version("2.0");
}
}
controller类
package com.yuan.controller;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.yuan.pojo.Goods;
import com.yuan.service.GoodsService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/goods")
@Tag(name = "body参数")
public class GoodsController {
@Autowired
private GoodsService goodsService;
@GetMapping("/list")
@Operation(summary = " 查询数据")
@ApiOperationSupport(author = "yuan")//添加接口作者
@Parameters({
@Parameter(name = "id",description = "文件id",in = ParameterIn.PATH),
@Parameter(name = "token",description = "请求token",required = true,in = ParameterIn.HEADER),
@Parameter(name = "name",description = "文件名称",required = true,in=ParameterIn.QUERY)
})
public Object getName() {
List<Goods> list = goodsService.list();
System.out.println("返回的数据"+list);
return list;
}
}
yaml
springdoc:
swagger-ui:
path: /swagger-ui.html
tags-sorter: alpha
operations-sorter: alpha
api-docs:
path: /v3/api-docs
group-configs:
- group: 'default'
paths-to-match: '/**'
packages-to-scan: com.yuan.controller
knife4j:
enable: true
setting:
language: zh_cn
#配置用户名和密码
basic:
enable: true
username: root
password: 123456
浏览器访问页面出现一下即可:http://127.0.0.1:8080/doc.html

knife4j添加自定义文档说明
我们可以在当前项目中添加多个文件夹,文件夹中存放.md格式的markdown文件,每个.md文档代表一份自定义文档说明。
这里,我们在默认组default 下面添加接口签名认证文档说明.md和自定义文档说明.md 两个文档,结构如下

每个.md文件中,Knife4j允许一级(h1)、二级(h2)、三级(h3)标题作为最终的文档标题
比如,上面添加的自定义文档说明.md内容如下
## 效果说明
`knife4j`为了满足文档的个性化配置,添加了自定义文档功能
开发者可自定义`md`文件扩展补充整个系统的文档说明
开发者可以在当前项目中添加一个文件夹,文件夹中存放`.md`格式的markdown文件,每个`.md`文档代表一份自定义文档说明
**注意**:自定义文档说明必须以`.md`结尾的文件,其他格式文件会被忽略
配置自定义文档显示
文档添加好之后,我们在application.yml 添加如下配置信息
knife4j:
documents:
- group: default
name: 其他文档
# 某一个文件夹下所有的.md文件
locations: classpath:markdown/*
配置说明:
group: 分组的名称,这儿我们还没有配置分组,所以默认的是defaultname: 界面呈现时菜单显示locations: markdown文档路径
前端界面呈现效果
上述信息配置好之后,在浏览器访问doc.html 如下

knife4j接口排序
使用Knife4j提供的增强注解@ApiOperationSupport中的order字段可进行接口排序
HelloController 中有hello 和 getToken 两个接口,我们要实现getToken接口显示在前面,代码如下
修改application.yml
springdoc:
swagger-ui:
operations-sorter: order
② 调整@ApiOperationSupport中的order
@RestController
public class HelloController {
@ApiOperationSupport(author = "张三",order = 2)
@GetMapping("/hello")
public String hello(){
return "hello";
}
@ApiOperationSupport(author = "李四" ,order = 1)
@GetMapping("/access-appid")
public String getToken(){
return ""
}
}

knife4j接口分组
在controller包下面新建两个包,包面再建立login包和goods包,包下分别添加GoodsController和LonginController接口类,结构及代码如下

GoodsController类
package com.yuan.controller.goods;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.yuan.pojo.Goods;
import com.yuan.service.GoodsService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/goods")
//@Tag(name = "goods", description = "数据")
public class GoodsController {
@Autowired
private GoodsService goodsService;
@GetMapping("/list")
@Operation(summary = " 查询数据")
@ApiOperationSupport(author = "yuan")//添加接口作者
@Parameters({
@Parameter(name = "id",description = "文件id",in = ParameterIn.PATH),
@Parameter(name = "token",description = "请求token",required = true,in = ParameterIn.HEADER),
@Parameter(name = "name",description = "文件名称",required = true,in=ParameterIn.QUERY)
})
public Object getName() {
List<Goods> list = goodsService.list();
System.out.println("返回的数据"+list);
return list;
}
}
LonginController
package com.yuan.controller.login;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.yuan.pojo.Goods;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/login")
public class LonginController {
@GetMapping("/user")
@Operation(summary = " 查询数据")
@ApiOperationSupport(author = "yuan")//添加接口作者
public Object getName() {
return "200";
}
}
在默认情况(没有分组)的情况下,所有包下接口都显示在一一个默认组下面,如/goods/* 和/login/* 访问路径下的接口都显示在一起,如下图所示

这时,如果/goods/* 下的接口比较多,/login/* 下的接口也比较多,界面上显示就很混乱
解决办法就是添加分组信息,这里有两种配置方法
① 通过application.yml配置 goods分组和login两个分组
springdoc:
group-configs:
- group: 'goods'
paths-to-match: '/goods/**'
packages-to-scan: com.yuan.controller
- group: 'login'
paths-to-match: '/login/**'
packages-to-scan: com.yuan.controller
以上两种配置时等效的,再访问:http://localhost:8080/doc.html 显示如下显示的就是刚才设置的分组

动态请求参数
在某些特定的情况下如果后端定义的是一种Map结构,或者是参数并没有定义声明,而希望也能达到一种动态添加参数进行调试的结果,这种体验有点类似于postman
① 开启动态参数配置
knife4j:
enable: true
setting:
# 开启动态请求参数,true-开启,false-关闭
enable-dynamic-parameter: true

② 添加动态参数调试

过滤请求参数
通常我们在开发接口时,比如一个新增接口和一个修改接口,修改接口需要传递主键id、而新增接口则不需要传递此属性,但大部分情况,我们只写一个Model类,此时在新增接口时显示主键id会显得很多余.
使用自定义增强注解ApiOperationSupport中的ignoreParameters属性,可以强制忽略要显示的参数.
忽略的规则如下:
- 例如新增接口时,某实体类不需要显示Id,即可使用该属性对参数进行忽略.
ignoreParameters={"id"} - 如果存在多个层次的参数过滤,则使用名称.属性的方式,例如
ignoreParameters={"uptModel.id","uptModel.uptPo.id"},其中uptModel是实体对象参数名称,id为其属性,uptPo为实体类,作为uptModel类的属性名称 - 如果参数层级只是一级的情况下,并且参数是实体类的情况下,不需要设置参数名称,直接给定属性值名称即可
- 如果实体类属性中是通过List这种数组的方式,那么过滤规则会有所不同,在属性后面需要追加一个下标
[0],ignoreParameters={"uptModel.uptPo[0].id"}
在接口过滤时,主要有两种情况
我们在使用实体类直接作为参数时,在我们的ui界面中是不会显示参数名称的,此时可以直接使用实体的属性名称进行参数忽略,例如如下代码:
表单类型的请求是不需要添加参数名的
@ApiOperation(value = "新增Model接口1")
@ApiOperationSupport(ignoreParameters = {"id","orderDate.id"})
@PostMapping("/insertMode1l")
public Rest<UptModel> insertModel1(UptModel uptModel){
Rest<UptModel> r =new Rest<>();
r.setData(uptModel);
return r;
}
实体类UptModel.java文件代码
public class UptModel {
@ApiModelProperty(value = "主键id")
private String id;
@ApiModelProperty(value = "姓名")
private String name;
@ApiModelProperty(value = "邮箱")
private String email;
@ApiModelProperty(value = "订单信息")
private OrderDate orderDate;
}
此时,最终过过滤掉UptModel的属性id和属性orderDate类中的id属性,不在界面显示.
JSON参数
代码如下
@ApiOperation(value = "新增Model接口")
@ApiOperationSupport(ignoreParameters = {"uptModel.id","uptModel.name","uptModel.orderDate.id"})
@PostMapping("/insertModel")
public Rest<UptModel> insertModel(@RequestBody UptModel uptModel){
Rest<UptModel> r =new Rest<>();
r.setData(uptModel);
return r;
}
此时如果要过滤id的话,需要指定带上参数名称uptModel
最终忽略的值为ignoreParameters = {"uptModel.id","uptModel.name","uptModel.orderDate.id"}
关于实体类的注解升级
@Api → @Tag
@ApiSort → @ApiSupport
@ApiIgnore→@Parameter(hidden = true)或@Operation(hidden = true)或@Hidden
@ApiImplicitParam → @Parameter
@ApiImplicitParams → @Parameters
@ApiOperation(value = "foo", notes = "bar") → @Operation(summary = "foo", description = "bar")
@ApiResponse(code = 404, message = "foo") → @ApiResponse(responseCode = "404", description = "foo")
@ApiModel → @Schema
@ApiModelProperty(hidden = true) → @Schema(accessMode = READ_ONLY)
@ApiModelProperty → @Schema
@ApiParam → @Parameter