Knife4j是一款基于Swagger的增强工具(所以,该集成方式同样适用于swagger),拥有更强的功能以及更符合大众审美观的UI。
Knife4j官网:https://doc.xiaominfo.com/knife4j/ (学习以及获取更多的功能用法、资讯一定要习惯去官网获取)
借用官网一个友情提示
1、目前已经发行的Knife4j版本,Knife4j本身已经引入了springfox,开发者在使用时不用再单独引入Springfox的具体版本,否额会导致版本冲突。另外在网关层聚合(例如gateway)时,必须禁用Knife4j的增强模式;
2、使用Knife4j2.0.6及以上的版本,Spring Boot的版本必须大于等于2.2.x;
com.github.xiaoymin
knife4j-spring-boot-starter
1.9.6
@Configuration
//knife4j依赖swagger:该注解也可直接加载启动类上
@EnableSwagger2
//支持knife4j的ui:该注解也可直接加载启动类上
@EnableSwaggerBootstrapUi
public class Knife4jConfig {
@Bean
public Docket initDocket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(createApiInfo()).select()
// 扫描包:只扫描某个路径下带有Swagger注解的类,然后将其加入API文档
// .apis(RequestHandlerSelectors.basePackage("com.zepal.rest.controller"))
// 只扫描带有api注解的类
// .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
// 只扫描带有ApiOperation注解的方法
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
// 对指定路径监控
.paths(PathSelectors.any())
.build();
}
private ApiInfo createApiInfo() {
return new ApiInfoBuilder()
// api文档的标题属性:会在api文档中相应显示
.title("knife4j演示 V1.0")
// api文档描述属性:会在api文档中相应显示
.description("我是描述")
// 服务url属性:会在api文档中相应显示
.termsOfServiceUrl("http://localhost:9000/")
// 自定义版本号属性:会在api文档中相应显示
.version("1.0")
.build();
}
}
如果项目中配置了拦截器,需要在注册拦截器时,将Knife4j相关的资源放行
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 不拦截的请求
List patterns = new ArrayList();
patterns.add("/swagger-resources/**");
patterns.add("/webjars/**");
patterns.add("/v2/**");
patterns.add("/swagger-ui.html/**");
patterns.add("/doc.html/**");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// swagger页面
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
// knife4j页面
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
访问本项目地址:localhos:port/doc.html出现如下界面:
避坑
避坑1:在使用相关注解时,所有注解的属性值不要出现英文点("."),否则会导致无法识别,在api文档中也就不会出现相应接口信息。
心得
心得1:在为所有接口进行命名的时候,建议遵循该规则:模块:功能:细分功能,以冒号分隔开,"模块:功能"注解到Controller类上,"细分功能"注解到具体的接口上,命名具体划分几级,则根据项目具体情况而定。比如:购物车:商品管理:新增商品。这样在api文档中显示的接口信息比较直观。
@Api注解
该注解一般用于控制层的类名上,即Controller的类名上。该注解常用属性tags(如果用value属性,不会被解析),用于说明该Controller的功能。
@ApiOperation
该注解一般用于具体的api接口上。该注解常用属性value,用于说明该api接口的功能,属性consumes,用于描述该接口接收的参数媒体类型。比如:application/json,application/xml,multipart/form-date,applictaion/x-www-form-urlencoded。consumes属性默认属性是"application/json",所以,如果接口支持的请求参数媒体类型不是"application/json",建议将该属性添加上,免得接口调用方传参不知道用什么媒体类型。
@ApiImplicitParam
该注解一般用于具体的api接口上,用于描述请求参数。属性name描述参数名,属性value描述参数说明,属性required描述参数是否必须,属性dataType描述参数类型。多个参数用@ApiImplicitParams嵌套,它支持@ApiImplicitParam数组。
一个完整的示例:
@Api(tags = "knife4j演示:")
@Controller
public class Knif4jController {
@PostMapping("/knife4j_A")
@ResponseBody
@ApiOperation(value = "演示接口A", consumes = "applictaion/x-www-form-urlencoded,application/json")
@ApiImplicitParams({
@ApiImplicitParam(name = "username", value = "用户名", required = true, dataType = "string"),
@ApiImplicitParam(name = "password", value = "密码", required = true, dataType = "string")
})
public String methodA(String username, String password) {
// applictaion/x-www-form-urlencoded
return "success";
}
}
重启项目后,可以在localhost:port/doc.html 文档页面中,看到接口信息,如下:
说明:示例没有定义响应对象,只是返回了一个String字符串,所以在api文档中看不到响应参数。
响应参数注解,以及使用自定对象封装请求参数
@ApiModel注解:注解到响应对象或请求对象类上,value属性用于描述该对象的名称
@ApiModelProperty注解:注解到请求对象或响应对象的属性上。value属性用于描述参数说明,dataType属性用于描述数据类型。required属性用于描述参数是否必须,一般用于请求对象,响应对象没有意义。
一个完整的示例:
@ApiModel(value = "测试请求对象")
public class TestVO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "用户名", dataType = "string", required = true)
private String username;
@ApiModelProperty(value = "密码", dataType = "string", required = true)
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}