目录
1、为什么使用Knife4j
在前后端分离的开发模式下,后端人员开发完接口后,需要单独出一份文档,说明每个接口的作用以及接口的传入参数与响应参数;但是项目处于快速开发阶段时,就会出现文档更新不及时的情况,久而久之在对接接口时就会出现效率下降的情况,Knife4j
提供一个可视化的UI界面,通过Knife4j
只需要注解就可以向前端暴漏出所有的接口信息,便于前端对接以及对系统的测试。页面访问方式为:ip:prot/context-path/doc.html
2、基本使用
2.1 pom
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.9</version>
</dependency>
2.2 配置Knife4j分组
创建配置文件:Knife4jConfig
@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfig {
/**
* 创建一个Docket实例,指定controller包路径
*
* @return
*/
@Bean(value = "test")
public Docket test() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(this.apiInfo())
//分组名称
.groupName("系统管理")
.select()
//这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("com.project.test.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("API")
.description("接口详细文档")
.contact(new Contact("开发者名称", null, "开发者邮箱"))
.version("1.0")
.build();
}
}
2.3 拦截器放行
如果项目中配置了拦截器,那个会拦截Knife4j
的请求的资源,需要进行放行处理,比如:
@Configuration
public class WebMvcRegistrationsConfig extends WebMvcConfigurationSupport {
@Resource
private AuthenticationHandlerInterceptor authenticationHandlerInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 无需拦截的接口集合
List<String> ignorePath = new ArrayList<>();
// knife4j(swagger)
ignorePath.add("/swagger-resources/**");
ignorePath.add("/doc.html");
ignorePath.add("/v2/**");
ignorePath.add("/webjars/**");
ignorePath.add("/static/**");
ignorePath.add("/templates/**");
ignorePath.add("/error");
//先拦截认证
registry.addInterceptor(authenticationHandlerInterceptor).addPathPatterns("/**").excludePathPatterns(ignorePath);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
2.4 实体类
创建一个实体类,通过knife4j提供的ApiModelProperty
对字段添加描述
public class User{
@ApiModelProperty("主键")
private String id;
@ApiModelProperty("名称")
private String name;
@ApiModelProperty("手机邮箱")
private String mail;
@ApiModelProperty("用户性别(0男 1女 2未知)")
private Integer gender;
@ApiModelProperty("头像")
private String avatar;
@ApiModelProperty("部门Id")
private String deptId;
}
2.5 SpringBoot整合基础使用
2.5.1 基础配置
通过@Api
注解,为当前Controller
进行命名,通过@ApiOperation
为Controller
中的方法设置名称
@Api(tags = "用户管理")
@RestController
public class UserController {
@ApiOperation(value = "基础测试", notes = "基础测试")
@GetMapping("/test")
public void test() {
System.out.println("进入了test接口");
}
}
访问测试:
访问地址为格式ip:prot/context-path/doc.html
,比如:http://127.0.0.1:10008/demo/doc.html
调试测试:
在点击相应的接口名称后,就可以进入到调试页面,通过发送按钮
发起接口请求;
2.5.2 Post(实体)请求
和传统的Post请求写法一致参数加上@RequestBody
注解,通过@ApiOperation
为接口命名
Controller:
@Api(tags = "用户管理")
@RestController
public class UserController {
@ApiOperation(value = "新增数据", notes = "新增数据")
@PostMapping("/add")
public void insert(@RequestBody User user) {
System.out.println("新增用户:" + user);
}
}
文档页面:
调试页面:
结果:
2.5.3 Get(实体)请求与响应参数
对于Get请求时,我们可能会存在返回一个对象也可能是一个集合的情况,可以提供@ApiOperation
注解的response
方法设置响应参数,通过responseContainer=List
设置返回的类型为集合,具体实现如下:
@Api(tags = "用户管理")
@ApiSort(10)
@RestController
@RequestMapping("user")
public class UserController {
@ApiOperation(value = "查询列表", notes = "查询列表", response = UserParam.class, responseContainer = "List")
@ApiOperationSupport(order = 1)
@GetMapping
public List<UserParam> listUser(BaseQueryParam param) {
return new ArrayList<>();
}
@ApiOperation(value = "根据Id查询查询", notes = "根据Id查询", response = UserParam.class)
@ApiOperationSupport(order = 2)
@GetMapping("/{userId}")
public UserParam getUserRole(@PathVariable("userId") String userId) {
return new UserParam();
}
}
文档说明文档:
调试页面:
可以看到Get请求的请求参数形式是以列表的形式进行呈现,而Post的请求参数是json形式
2.5.4 Header参数请求
在项目开发中,存在接口需要传入在header
中传递token
获取其他参数的情况,通过@ApiImplicitParam
注解设置paramType = "header"
,用法如下:
@Api(tags = "用户管理")
@RestController
@RequestMapping("user")
public class UserController {
@ApiOperation(value = "根据Id查询", notes = "根据Id查询", response = UserParam.class)
@ApiImplicitParam(name = "token", value = "token令牌", paramType = "header", required = true, dataType = "String")
@GetMapping
public UserParam getUserRole(HttpServletRequest request) {
System.out.println("获取Header:" + request.getHeader("token"));
return new UserParam();
}
}
效果:
2.5.5 非实体参数请求
对于传入请求参数,如果参数不对,可能不会进行实体类的封装,那么可以进行单独的参数配置,通过@ApiImplicitParam
设置paramType = "path"
,如果是多个@ApiImplicitParam
需要在外面加一个@ApiImplicitParams
注解,并且可以同时设置请求参数与header参数,如下:
@Api(tags = "用户管理")
@RestController
@RequestMapping("user")
public class UserController {
@ApiOperation(value = "根据Id查询", notes = "根据Id查询", response = UserParam.class)
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "数据id", paramType = "path", dataType = "int", required = true),
@ApiImplicitParam(name = "name", value = "数据名称", paramType = "path", dataType = "String", required = true),
@ApiImplicitParam(name = "token", value = "token令牌", paramType = "header", required = true, dataType = "String")
})
@GetMapping
// @RequestParam接收的参数的类型要与与dataType的类型一致
public UserParam getUserRole(@RequestParam int id, @RequestParam String name) {
System.out.println("id:" + id);
System.out.println("name:" + name);
return new UserParam();
}
}
效果:
2.5.6 全局参数配置
通过在Knife4j
的UI界面,设置全局参数
,参数分为header
与query
两种类型,设置全局参数
以后,在接口的调试页面,配置的全局参数
会自动进行参数的填充,配置后需要重新刷新页面;
自动填充:
3、分组排序
分组排序的目的是,我们可以按照自定义的序号将接口类进行从上到下的顺序排序;
未开启排序前:
在下图中可以看到在未开启分组排序
前Controller
中的顺序是登录管理->用户管理
,而UI页面
的顺序是用户管理->登录管理
,看起来顺序是乱的,如果接口多了以后顺序就会更加会乱。
开启排序后:
Knife4j
为了解决排序提供了增强功能
与@ApiSort(num)
注解用于自定义排序,其中num
越大排序越靠后,用法如下:
yml配置:
在Knife4j-2.0.6
版本后将@EnableKnife4j
注解的方式修改为了使用yaml
配置
knife4j:
enable: true
注解使用:
@Api(tags = "登陆管理")
@ApiSort(1)
@RestController
@RequestMapping("/login")
public class LoginController {
......
......
}
@Api(tags = "用户管理")
@ApiSort(2)
@RestController
@RequestMapping("user")
public class UserController {
......
......
}
效果:
4、接口排序
接口排序的目的是,我们可以将一些新写的接口按照自定义的序号进行从上到下的顺序排序;
未开启排序前:
在下图中可以看到在未开启接口排序
前Controller
中的顺序是基础测试->新增数据
,而UI页面
的顺序是新增数据->基础测试
,看起来顺序是乱的,如果接口多了以后顺序就会更加会乱。
开启排序后:
Knife4j
为了解决排序提供了增强功能
与@ApiOperationSupport(order = num)
注解用于自定义排序,其中num
越大排序越靠后,用法如下:
yml配置:
在Knife4j-2.0.6
版本后将@EnableKnife4j
注解的方式修改为了使用yaml
配置
knife4j:
enable: true
注解使用:
@Api(tags = "用户管理")
@RestController
public class UserController {
@ApiOperation(value = "基础测试", notes = "基础测试")
// 排序注解
@ApiOperationSupport(order = 1)
@GetMapping("/test")
public void test() {
System.out.println("进入了test接口");
}
@ApiOperation(value = "新增数据", notes = "新增数据")
// 排序注解
@ApiOperationSupport(order = 2)
@PostMapping("/add")
public void insert(@RequestBody UserParam param) {
System.out.println("新增用户:" + param);
}
}
效果:
5、访问页面权限控制
通过开启页面权限控制
使得访问Knife4j
接口地址时需要进行账户密码验证,通过Knife4j
提供的增强功能
实现,用法如下:
yml配置:
在Knife4j-2.0.6
版本后将@EnableKnife4j
注解的方式修改为了使用yaml
配置
knife4j:
# 开启增强配置
enable: true
basic:
enable: true
# Basic认证用户名
username: admin
# Basic认证密码
password: 123456
效果:
6、生产环境屏蔽
我们在开发阶段时,是可以任意访问Knife4j文档的,当项目上线以后,我们为了保证不被外部系统访问,在不大量修改代码的情况下,可以使用Knife4j提供的生产环境屏蔽
功能,用法如下:
yml配置:
在Knife4j-2.0.6
版本后将@EnableKnife4j
注解的方式修改为了使用yaml
配置
knife4j:
# 开启增强配置
enable: true
# 开启生产环境屏蔽
production: true
效果:
7、多个Controller分组
实际开发项目中,我们可以存在多个页面模块,每个模块的controller
路径不同,那么可以在Knife4jConfig
中配置,多个不同的分组,如下:
@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfig {
/**
* 创建一个Docket实例,指定controller包路径
*
* @return
*/
@Bean(value = "system")
public Docket system() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(this.apiInfo())
//分组名称
.groupName("系统管理")
.select()
//这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("com.project.system.controller"))
.paths(PathSelectors.any())
.build();
}
@Bean(value = "wage")
public Docket wage() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(this.apiInfo())
//分组名称
.groupName("工资管理")
.select()
//这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("com.project.wage.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("API")
.description("接口详细文档")
.contact(new Contact("开发者名称", null, "开发者邮箱"))
.version("1.0")
.build();
}
}
效果: