一、前言
昨天收到一条评论,让我觉得有些小事应该坚持做下去。
SpringBoot前后端分离项目中,一般会借助Swagger生成API文档,相信在日常的开发中,同学们已经应用的比较熟练。但是,在使用过程中,肯定也会发现Swagger中有很多的不方便之处,这些缺点一直饱受诟病,于是在17年,knife4j横空出世。当然一开始它也只是一个swagger的UI皮肤,随着时间的推移,knife4j已经迭代了很多的版本,支持者也不断增加。如果你的项目仍然在使用swagger,那么就跟随笔者的这篇博文,一起领略下knife4j的强大之处吧。官网:knife4j
本文基于上一篇,SpringBoot整合新版本Mybatis-Plus代码生成器所生成的项目进行测试演示。
二、正文
1. 基础环境
- SpringBoot版本:>= 2.2.x
- knife4j:2.0.7
特别注意
1、目前已经发行的Knife4j版本,Knife4j本身已经引入了springfox,开发者在使用时不用再单独引入Springfox的具体版本,否额会导致版本冲突。另外在网关层聚合(例如gateway)时,必须禁用Knife4j的增强模式
2、使用Knife4j2.0.6及以上的版本,Spring Boot的版本必须大于等于2.2.x
再啰嗦一句,我翻了翻官网,官网说:需要注意的是,目前Knife4j的主版本依然是沿用2.x的版本号,也就是从2.0.6版本开始逐步升级,迭代发布时版本会随之升级,但同时3.x版本也会同步更新发布,主要是满足开发者对于springfox3以及OpenAPI3规范的使用。
因此,本文依然以2.0.6之后的版本进行各配置演示。
2. 引入依赖
<!--knife4j-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.7</version>
</dependency>
3. 配置类—Knife4jConfig类
package com.ieslab.knife4j.demo.config;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
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.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
/**
* @Author: zongshaofeng
* @Description:
* @Date:Create:in 2021/11/05 10:30
* @Modified By:
*/
@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfig {
/**
* 创建API应用
* apiInfo() 增加API相关信息
* 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
* 本例采用指定扫描的包路径来定义指定要建立API的目录。
*
* @return
*/
@Bean(value = "defaultApi2")
public Docket defaultApi2() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.title("演示Knife4j接口文档")
.description("@是小宗啊?")
.termsOfServiceUrl("http://localhost:8088/api/*")
.contact(new Contact("小宗","www.xxx.com","xxx@qq.com"))
.version("1.0")
.build()
)
.groupName("1.0版本")
.select()
// 这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("com.ieslab.knife4j.demo"))
.paths(PathSelectors.any())
.build();
}
}
4. 各配置项分别演示
本部分会分别对官网部分常用配置,采用配置加效果截图的形式做演示,如果需要直接拿到完整的配置,请直接到第5小节自取。
所有的增强配置,前提是需要在application.yml中开启增强模式。
knife4j:
# 开启增强配置 可不必再增加@EnableKnife4j注解
enable: true
- 接口添加作者及配置接口顺序
- 生产环境屏蔽资源
# Knife4j配置
knife4j:
# 开启增强配置 可不必再增加@EnableKnife4j注解
enable: true
# 开启生产环境屏蔽
production: true
3. 访问页面加权控制
# Knife4j配置
knife4j:
# 开启增强配置 可不必再增加@EnableKnife4j注解
enable: true
# 开启生产环境屏蔽
production: false
# 开启Swagger的Basic认证功能,允许开发者在配置文件中配置一个静态的用户名和密码,
# 当对接者访问Swagger页面时,输入此配置的用户名和密码后才能访问Swagger文档页面
basic:
enable: true
# Basic认证用户名
username: test
# Basic认证密码
password: 123
4. 过滤请求参数
通常我们在开发接口时,比如一个新增接口和一个修改接口,修改接口需要传递主键id、而新增接口则不需要传递此属性,但大部分情况,我们只写一个Model类,此时在新增接口时显示主键id会显得很多余.
使用自定义增强注解ApiOperationSupport中的ignoreParameters属性,可以强制忽略要显示的参数.
过滤的规则需要明确:
- 例如新增接口时,某实体类不需要显示Id,即可使用该属性对参数进行忽略.ignoreParameters={“id”}
- 如果存在多个层次的参数过滤,则使用名称.属性的方式,例如 ignoreParameters={“uptModel.id”,“uptModel.uptPo.id”},其中uptModel是实体对象参数名称,id为其属性,uptPo为实体类,作为uptModel类的属性名称
- 如果参数层级只是一级的情况下,并且参数是实体类的情况下,不需要设置参数名称,直接给定属性值名称即可,但是如果是JSON参数,需要指定带上参数名称uptModel,最终忽略的值为ignoreParameters = {“uptModel.id”,“uptModel.name”,“uptModel.orderDate.id”}
- 如果实体类属性中是通过List这种数组的方式,那么过滤规则会有所不同,在属性后面需要追加一个下标[0],ignoreParameters={“uptModel.uptPo[0].id”}
如果说的不太明白,可以直接去官网文档,比较详细。过滤请求参数
- 包含请求参数
很好理解,正是过滤请求参数的反面,要忽略的太多,那么就配置需要包含的,省心省力。 - 其他的暂时用不到,还有就是Swagger的一些注解的使用了,也不再过多介绍,再下一小节会贴出所有的代码。
5. 完整代码
- yml配置文件:
# Knife4j配置
knife4j:
# 开启增强配置 可不必再增加@EnableKnife4j注解
enable: true
# 开启生产环境屏蔽
production: false
# 开启Swagger的Basic认证功能,允许开发者在配置文件中配置一个静态的用户名和密码,
# 当对接者访问Swagger页面时,输入此配置的用户名和密码后才能访问Swagger文档页面
basic:
enable: true
# Basic认证用户名
username: test
# Basic认证密码
password: 123
- User实体类:
package com.ieslab.knife4j.demo.module.student.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
*
* </p>
*
* @author zongshaofeng
* @since 2021-11-04 16:45:41
*/
@Getter
@Setter
@TableName("user")
@ApiModel(value = "User对象", description = "")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "用户ID" ,example = "1")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "时间" ,example = "2021-11-05 12:04:00")
@TableField("time")
private LocalDateTime time;
@ApiModelProperty(value = "用户名称" ,example = "小宗")
@TableField("name")
private String name;
@ApiModelProperty(value = "用户内容" ,example = "这里是用户内容。")
@TableField("content")
private String content;
}
- UserController类:
package com.ieslab.knife4j.demo.module.student.controller;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.ieslab.knife4j.demo.module.student.entity.User;
import com.ieslab.knife4j.demo.module.student.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* <p>
* 前端控制器
* </p>
*
* @author zongshaofeng
* @since 2021-11-04 16:45:41
*/
@Api(tags = "用户管理")// 配置Controller标题
@ApiSupport(author = "zongshaofeng",order = 1)// 配置作者和顺序,越小越靠前不能小于0
@RestController
@RequestMapping("/student/user")
public class UserController {
@Resource
private UserService userService;
@ApiOperation(value = "查询全部用户信息")// 配置各个方法的标题
@ApiOperationSupport(author = "zongshaofeng",order = 1)// 配置作者和顺序,越小越靠前不能小于0,方法上的会覆盖类上的配置
@GetMapping("/list")
public ResponseEntity<List<User>> listUser() {
List<User> users = userService.list();
return ResponseEntity.ok(users);
}
@ApiOperation(value = "根据用户Id,查询用户信息")
@ApiOperationSupport(author = "zongshaofeng",order = 2)
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable("id") Integer userId) {
User user = userService.getById(userId);
return ResponseEntity.ok(user);
}
@ApiOperation(value = "保存用户信息")
@ApiOperationSupport(author = "zongshaofeng",order = 3,ignoreParameters = {"id"})
@PostMapping("/saveUser")
public ResponseEntity saveUser(User user) {
boolean save = userService.save(user);
return ResponseEntity.ok(save);
}
}
-Knife4jConfig类:
package com.ieslab.knife4j.demo.config;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
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.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
/**
* @Author: zongshaofeng
* @Description:
* @Date:Create:in 2021/11/05 10:30
* @Modified By:
*/
@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfig {
/**
* 创建API应用
* apiInfo() 增加API相关信息
* 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
* 本例采用指定扫描的包路径来定义指定要建立API的目录。
*
* @return
*/
@Bean(value = "defaultApi2")
public Docket defaultApi2() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.title("演示Knife4j接口文档")
.description("@是小宗啊?")
.termsOfServiceUrl("http://localhost:8088/api/*")
.contact(new Contact("小宗","www.xxx.com","xxx@qq.com"))
.version("1.0")
.build()
)
.groupName("1.0版本")
.select()
// 这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("com.ieslab.knife4j.demo"))
.paths(PathSelectors.any())
.build();
}
}
三、总结
其实还有很多的比较复杂的内容都没有涉及到,到目前为止,一般的使用场景应该是足够应付的,如果有新的需求,可进一步去官网进行学习。总之,问题不大。
下周见。