目录
- 前言
- 1、为什么使用Knife4j
- 2、基本使用
- 2.1 pom
- 2.2 配置Knife4j
- 2.3 拦截器放行
- 2.4 实体类
- 2.5 SpringBoot整合基础使用
- 2.5.1 基础配置
- 2.5.2 Post(实体)请求
- 2.5.3 Get(实体)请求
- 2.5.4 响应参数配置
- 1. 响应对象
- 2.响应List集合
- 2.5.5 Header参数请求
- 2.5.6 非实体参数请求
- 2.5.7 文件类型的请求
- 1. 文件上传
- 2. 文件上传带参数
- 4、接口排序
- 5、访问页面权限控制
- 6、生产环境屏蔽
- 7、多个Controller分组
- 8、对比Swagger2
- 8.1 实体类注解对比
- 8.2 分组类注解对比
- 8.3 方法注解对比
- 8.4 请求参数注解对比
- 8.5 响应参数注解对比
前言
适用于:SpringBoot 3.x版本
1、为什么使用Knife4j
在前后端分离的开发模式下,后端人员开发完接口后,需要单独出一份文档,说明每个接口的作用以及接口的传入参数与响应参数;但是项目处于快速开发阶段时,就会出现文档更新不及时的情况,久而久之在对接接口时就会出现效率下降的情况,Knife4j
提供一个可视化的UI界面,通过Knife4j
只需要注解就可以向前端暴漏出所有的接口信息,便于前端对接以及对系统的测试。页面访问方式为:ip:prot/context-path/doc.html
2、基本使用
2.1 pom
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
2.2 配置Knife4j
创建配置文件:Knife4jConfig
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("XXX系统API")
.version("1.0")
.description("Knife4j集成接口文档")
.termsOfService("http://www.lhz.com")
.license(new License().name("Apache 2.0")));
}
}
yaml
# springdoc-openapi项目配置
springdoc:
swagger-ui:
path: /swagger-ui.html
# 排序方式为首字母
tags-sorter: alpha
# 使用增强order属性进行排序,或者不设置该参数( @ApiOperationSupport(order = n)直接生效)
operations-sorter: order
api-docs:
path: /v3/api-docs
group-configs:
- group: '测试'
paths-to-match: '/**'
# controller所在包
packages-to-scan: com.lhz.demo.controller.swagger3
# knife4j的增强配置,不需要增强可以不配
knife4j:
enable: true
setting:
language: zh_cn
2.3 拦截器放行
如果项目中配置了拦截器,那么会拦截Knife4j
的请求的资源,需要进行放行处理,放行的url如下:
- “/swagger-resources/**”
- “/doc.html”
- “/swagger-ui.html”
- “/v2/**”
- “/v3/**”
- “/webjars/**”
2.4 实体类
创建一个实体类
@Data
@Schema(description = "测试实体类")
public class TestEntity {
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED)
private String name;
@Schema(description = "手机号")
private String phone;
}
2.5 SpringBoot整合基础使用
2.5.1 基础配置
通过@Tag
注解,为当前Controller
进行命名,通过@Operation
为Controller
中的方法设置名称
@Tag(name = "XX接口管理")
@RestController
public class TestController {
@Operation(summary = "测试方法", description = "测试方法")
@GetMapping("/test")
public void test() {
System.out.println("进入了test接口");
}
}
2.5.2 Post(实体)请求
和传统的Post请求写法一致参数加上@RequestBody
注解,通过@Operation
为接口命名
Controller:
@Tag(name = "XX接口管理")
@RestController
public class TestController {
@Operation(summary = "测试方法", description = "测试")
@PostMapping("/test")
public void test(@RequestBody TestEntity test) {
System.out.println("test = " + test);
}
}
文档页面:
调试页面:
2.5.3 Get(实体)请求
对于Get请求时,需要加一个由springdoc
提供的注解@ParameterObject
@Tag(name = "XX接口管理")
@RestController
public class TestController {
@Operation(summary = "测试Get请求", description = "测试")
@GetMapping("/testGet")
public void testGet(@ParameterObject TestEntity test) {
System.out.println("test = " + test);
}
}
文档页面:
调试页面:
可以看到Get请求的请求参数形式是以列表的形式进行呈现,而Post的请求参数是json形式
2.5.4 响应参数配置
对于返回对象,我们通常可以为某个具体的Object
或者List<Object>
针对这两类情况有不同的处理方式,
需要使用到swagger3
提供的@ApiResponse
注解
1. 响应对象
@Tag(name = "XX接口管理")
@RestController
public class TestController {
@Operation(summary = "测试响应对象", description = "测试")
@GetMapping("/responseObject")
@ApiResponse(content = @Content(schema = @Schema(implementation = TestEntityRes.class)))
public TestEntityRes testGet2() {
return new TestEntityRes();
}
}
文档页面:
2.响应List集合
@Tag(name = "XX接口管理")
@RestController
public class TestController {
@Operation(summary = "测试响应List集合", description = "测试")
@GetMapping("/responseList")
@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = TestEntityRes.class))))
public List<TestEntityRes> testGetList() {
return new ArrayList<>();
}
}
文档页面:
2.5.5 Header参数请求
在项目开发中,存在接口需要传入在header
中传递token
获取其他参数的情况,通过GlobalOpenApiCustomizer
进行全局的配置,此处需要进行配置类的修改,其中HttpHeaders.AUTHORIZATION
表示header的名称 该参数可以按照自己系统的header名称进行设置。
Tips:配置后所有的接口,都会在调试请求时,
RequestHeader
中都会默认加上HttpHeaders.AUTHORIZATION
配置如下:
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("XXX系统API")
.version("1.0")
.description("Knife4j集成接口文档")
.termsOfService("http://www.lhz.com")
.license(new License().name("Apache 2.0")))
.addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION))
.components(new Components().addSecuritySchemes(HttpHeaders.AUTHORIZATION, new SecurityScheme()
.name(HttpHeaders.AUTHORIZATION).type(SecurityScheme.Type.HTTP)));
}
@Bean
public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer() {
return openApi -> {
// 全局添加鉴权参数(HttpHeaders.AUTHORIZATION)
if (openApi.getPaths() != null) {
openApi.getPaths().forEach((s, pathItem) -> {
// 为所有接口添加鉴权
pathItem.readOperations().forEach(operation -> {
operation.addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION));
});
});
}
};
}
}
效果:
2.5.6 非实体参数请求
对于传入请求参数,没有进行实体类封装时,那么可以进行单独的参数配置,可能会将参数在path上进行传递,也可以提供query方式进行传递,通过@Parameters
与@Parameter
来实现
@Tag(name = "XX接口管理")
@RestController
public class TestController {
@Operation(summary = "测试响应List集合", description = "测试")
@GetMapping("/responseList")
@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = TestEntityRes.class))))
public List<TestEntityRes> testGetList() {
return new ArrayList<>();
}
}
Tips:如果只有一个请求参数的情况下,直接使用
@Parameter
注解即可
文档页面:
调试页面:
2.5.7 文件类型的请求
1. 文件上传
@Tag(name = "XX接口管理")
@RestController
public class TestController {
@Operation(summary = "单文件上传", description = "单文件上传")
@Parameter(name = "file", description = "文件", required = true, schema = @Schema(name = "file", format = "binary"))
@PostMapping("/upload")
public void upload(@RequestParam("file") MultipartFile file) {
System.out.println("file = " + file.getOriginalFilename());
}
@Operation(summary = "多文件上传", description = "多文件上传")
@Parameter(name = "files", description = "文件", required = true, schema = @Schema(name = "files", format = "binary"))
@PostMapping("/uploadBatch")
public void uploadBatch(@RequestParam("files") List<MultipartFile> files) {
for (MultipartFile file : files) {
System.out.println("file = " + file.getOriginalFilename());
}
}
}
文档页面:
2. 文件上传带参数
@Tag(name = "XX接口管理")
@RestController
public class TestController {
@Operation(summary = "文件上传带参数", description = "文件上传带参数")
@Parameters({
@Parameter(name = "id", description = "文件id", in = ParameterIn.PATH),
@Parameter(name = "file", description = "文件", required = true, schema = @Schema(name = "file", format = "binary")),
@Parameter(name = "name", description = "文件名称", in = ParameterIn.QUERY, required = true),
})
@PostMapping("/uploadParam/{id}")
public void uploadParamPath(@PathVariable("id") String id, @RequestParam("file") MultipartFile file, @RequestParam("name") String name) {
System.out.println("id = " + id);
System.out.println("file = " + file.getOriginalFilename());
System.out.println("name = " + name);
}
}
文档页面:
4、接口排序
接口排序的目的是,我们可以将一些新写的接口按照自定义的序号进行从上到下的顺序排序;
接口排序要生效,需要在yaml
配置中operations-sorter
属性需要设置为order
,并且配合ApiOperationSupport
注解使用
Yaml配置:
# springdoc-openapi项目配置
springdoc:
swagger-ui:
# 使用增强order属性进行排序,或者不设置该参数( @ApiOperationSupport(order = n)直接生效)
operations-sorter: order
注解使用:
@Tag(name = "XX接口管理")
@RestController
public class TestController {
@Operation(summary = "测试排序-一", description = "测试")
@ApiOperationSupport(order = 1)
@PostMapping("/testSort1")
public void test(@RequestBody TestEntity test) {
System.out.println("test = " + test);
}
@Operation(summary = "测试排序-二", description = "测试")
@ApiOperationSupport(order = 2)
@GetMapping("/testSort2")
public void testGet(@ParameterObject TestEntity test) {
System.out.println("test = " + test);
}
}
5、访问页面权限控制
通过开启页面权限控制
使得访问Knife4j
接口地址时需要进行账户密码验证,通过Knife4j
提供的增强功能
实现,用法如下:
yml配置:
knife4j:
# 开启增强配置
enable: true
basic:
enable: true
# Basic认证用户名
username: admin
# Basic认证密码
password: 123456
效果:
6、生产环境屏蔽
我们在开发阶段时,是可以任意访问Knife4j文档的,当项目上线以后,我们为了保证不被外部系统访问,在不大量修改代码的情况下,可以使用Knife4j提供的生产环境屏蔽
功能,用法如下:
knife4j:
# 开启增强配置
enable: true
# 开启生产环境屏蔽
production: true
效果:
7、多个Controller分组
实际开发项目中,我们可以存在多个页面模块,每个模块的controller
路径不同,那么可以在yaml
中配置,多个不同的分组,如下:
# springdoc-openapi项目配置
springdoc:
group-configs:
- group: '测试组'
paths-to-match: '/**'
packages-to-scan: com.lhz.demo.a
- group: '应用组'
paths-to-match: '/**'
packages-to-scan: com.lhz.demo.b
效果:
8、对比Swagger2
8.1 实体类注解对比
在Swagger2中通过@ApiModel
及@ApiModelProperty
两个注解进行实现,使用required = true
来表示必填标识;
@ApiModel("测试实体类")
public class TestEntity {
@ApiModelProperty(value = "名称", required = true)
private String name;
}
在Swagger3中通过一个@Schema
注解进行实现,使用requiredMode = Schema.RequiredMode.REQUIRED
来表示必填标识;
@Schema(description = "测试实体类")
public class TestEntity {
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED)
private String name;
}
8.2 分组类注解对比
在Swagger2中通过@Api
注解进行实现;
@Api(tags = "测试管理")
@RestController
@RequestMapping("test")
public class TestController {
}
在Swagger3中通过一个@Tag
注解进行实现;
@Tag(name = "测试管理")
@RestController
@RequestMapping("test")
public class TestController {
}
8.3 方法注解对比
在Swagger2中通过@Api
注解进行实现;
@Api(tags = "测试管理")
@RestController
@RequestMapping("test")
public class TestController {
@ApiOperation(value = "根据Id查询", notes = "根据Id查询")
@PostMapping("/test")
public void test() {
System.out.println("test");
}
}
在Swagger3中通过一个@Operation
注解进行实现;
@Tag(name = "测试管理")
@RestController
@RequestMapping("test")
public class TestController {
@Operation(summary = "测试方法", description = "测试")
@PostMapping("/test")
public void test() {
System.out.println("test");
}
}
8.4 请求参数注解对比
在Swagger2中通过@ApiImplicitParams
及@ApiImplicitParam
注解进行实现,并且通过dataType
指定数据类型,通过paramType
指定参数类型;
@Api(tags = "测试管理")
@RestController
@RequestMapping("test")
public class TestController {
@ApiOperation(value = "测试非实体参数请求", notes = "测试非实体参数请求"")
@GetMapping("/testParam/{id}")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "Id字段", paramType = "path", required = true, dataType = "integer"),
@ApiImplicitParam(name = "name", value = "名称", paramType = "query", required = true, dataType = "string")
})
public void test(@PathVariable Integer id, @RequestParam String name) {
System.out.println("id = " + id + ",name = " + name);
}
}
在Swagger3中通过一个@Parameters
及@Parameter
注解进行实现,并且通过schema
指定数据类型,通过in
指定参数类型;
@Tag(name = "测试管理")
@RestController
@RequestMapping("test")
public class TestController {
@Operation(summary = "测试非实体参数请求", description = "测试非实体参数请求")
@GetMapping("/testParam/{id}")
@Parameters({
@Parameter(name = "id", description = "Id字段", required = true, in = ParameterIn.PATH, schema = @Schema(type = "integer")),
@Parameter(name = "name", description = "名称", required = true, in = ParameterIn.QUERY, schema = @Schema(type = "string"))
})
public void test(@PathVariable Integer id, @RequestParam String name) {
System.out.println("id = " + id + ",name = " + name);
}
}
Tips:如果是Get请求,并且参数为实体时,需要使用
@ParameterObject
注解,比如:@Operation(summary = "测试Get请求", description = "测试") @ApiOperationSupport(order = 2) @GetMapping("/testGet") public void testGet(@ParameterObject TestEntity test) { System.out.println("test = " + test); }
8.5 响应参数注解对比
在Swagger2中通过@ApiOperation
注解的response
与responseContainer
进行实现;
@Api(tags = "测试管理")
@RestController
@RequestMapping("test")
public class TestController {
@ApiOperation(value = "返回对象", notes = "返回对象",response = TestEntityRes.class)
@GetMapping("/responseObject")
public TestEntityRes responseObject() {
return new TestEntityRes();
}
@ApiOperation(value = "返回List集合", notes = "返回List集合", response = TestEntityRes.class, responseContainer = "List")
@GetMapping("/responseList")
public List<TestEntityRes> responseList() {
return new ArrayList<>();
}
}
在Swagger3中通过一个@ApiResponse
注解进行实现,通过@Schema
注解实现返回对象,通过ArraySchema
注解实现返回List集合
@Tag(name = "测试管理")
@RestController
@RequestMapping("test")
public class TestController {
@Operation(summary = "返回对象", description = "返回对象")
@GetMapping("/responseObject")
@ApiResponse(content = @Content(schema = @Schema(implementation = TestEntityRes.class)))
public TestEntityRes responseObject() {
return new TestEntityRes();
}
@Operation(summary = "返回List集合", description = "返回List集合")
@GetMapping("/responseList")
@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = TestEntityRes.class))))
public List<TestEntityRes> responseList() {
return new ArrayList<>();
}
}