springboot 整合knife4j(绝对可用)1.9.6版~2.0.8版
1.情景展示
开发接口供别人调用或者前后端分离后,前端调后端请求需要提供什么参数,会返回什么样的结果。如果一对一沟通的话,费时费力,写接口文档的话也比较麻烦。
2.效果展示
现在使用knife4j就可以实现以下效果:
点击调试按钮,就可以直接配置请求参数,发送请求啦
3 1.9.6版本配置
这是1.9最后一个版本,要想实现这种效果,实现步骤如下:
1.引入jar包
只需要引入这一个jar包就可以了,无需其它jar包。
2.创建一个配置类,比如:Knife4jConfig
3.导包
4.添加注解
以上是三个注解,一个都不能少,在这里需要注意的一点就是:
启用knif4j使用的注解是:@EnableSwaggerBootstrapUi,而不是@EnableKnife4j
5.创建Docket对象,并注入到spring容器当中
6.设置主页文档内容
在配置文件类Knife4jConfig中添加以上两个方法即可。
4 2.0.4版本配置
导包
< code > < dependency > < groupId >com.github.xiaoymin < artifactId >knife4j-spring-boot-starter < version >2.0.4
说明:2.0.2版本的,只需要把上面jar包的版本号改成2.0.2即可,下面的配置一模一样。
只需要引入这一个jar包就可以了,无需其它jar包。
创建一个配置类
比如:Knife4jConfig(配置文件类最好创建一个config/conf包,方便统一管理)
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import io.swagger.annotations.ApiOperation;
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.EnableSwagger2;
/**
* 项目接口文档配置(swagger)
* @description: 使用knife4j需要一个swagger的配置类
* @author: Marydon
* @date: 2020年08月11日 0011 9:22
*/
@Configuration
// 必须启用swagger
@EnableSwagger2
@EnableKnife4j
// swagger文档配置只在指定环境可访问(该注解的值对应的是application.yml文件中的spring.profiles.active的值)
// 支持使用!,比如:!prod表示非生产环境
// @Profile({"dev","test","jc"})
public class Knife4jConfig {
/*
* 创建连接的包信息
* @param: 方法名称随便起,虽然它的名字会被作为Bean对象的名字注入spring容器
* @date: 2020年08月11日 0011 9:51
* @param:
* @return: springfox.documentation.spring.web.plugins.Docket 返回创建状况
*/
@Bean
public Docket defaultApi2() {
return new Docket(DocumentationType.SWAGGER_2) // 选择swagger2版本
.useDefaultResponseMessages( false )
// 接口文档的基本信息
.apiInfo(apiInfo())
.select()
// 这里指定Controller扫描包路径(项目路径也行)
// 方式一:配置扫描:所有想要在swagger界面统一管理的接口,都必须在此包下
// .apis(RequestHandlerSelectors.basePackage("com.company.project.web.controller.entrance"))
// 方式二:只有当方法上有@ApiOperation注解时,才能生成对应的接口文档
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation. class ))
// 路径使用any风格(指定所有路径)
.paths(PathSelectors.any())
.build();
}
/*
* 设置文档信息主页的内容说明
* @date: 2020年08月11日 0011 9:52
* @param:
* @return: springfox.documentation.service.ApiInfo 文档信息
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title( "接口项目 后台服务API接口文档" )
.description( "服务相关接口(knife4j)" )
// 服务Url(网站地址)
.termsOfServiceUrl( "http://localhost:8080/" )
.contact( new Contact( "Marydon" , null , "marydon20170307@163.com" ))
.version( "1.0" )
.build();
}
}
启动项目,访问:http://IP:端口号/程序名称/doc.html即可,显示主页。
5.注解基本用法
@Api()
用于类的说明,准确的来说用于controller,表示这个类是一个swagger资源
对应的是:一个Controller
注意:tags属性必须显式声明,否者无法修改小组的显示名称
举例:
实际效果:
未生效(因为没有声明:tags=)
@ApiOperation()
用于方法的说明,表示这是一个HTTP请求
对应的是controller里的方法
2020-12-16
这里需要注意的是:
@PostMapping对应的post请求,反映到API上就是post请求;
@GetMapping对应的get请求,反映到API上就是get请求;
@RequestMapping如果没有指定具体请求方式
API文档如下:
它会给你生出7种不同的请求方式,API本身没错
实际上,我们使用@RequestMapping的真实目的,也许是:想让该接口既支持get请求,也支持post请求,那我们可以做出限定。
这样,就OK啦
2023年9月28日15:17:04
设置请求数据类型(只是为了knife4j文档识别)
在SpringMVC和SpringBoot框架当中,控制层的参数格式,有两种经常使用的数据格式(也是前后端数据交互常用格式)。
一种是x-www-form-urlencoded(form表单),一种是application/json(JSON)。
有且只有,当入参被@RequestParam注解修饰时,才会被Knife4j文档识别成:form表单格式。
否则,会被Knife4j统一当中JSON格式的请求参数。
当然,我们不设置@RequestParam注解,后台也是能正常解析出前端发起的form表单数据的。
当入参被@RequestBody注解修饰时,会被Knife4j文档识别成:JSON格式。
设置响应数据类型(只是为了knife4j文档识别)
声明:无论是使用的SpringMVC还是SpringBoot框架,最终,响应数据的格式,默认使用的都是JSON格式。
有一个奇怪的地方就是:
knife4j生成的所有接口方法,所对应的响应数据类型都是:*/*,当我在Mapping注解里指定可接受的数据类型后,API上却成了响应数据类型的值。
请求的数据类型是不会受到影响的,knife4j是根据方法入参来自动判断请求的数据类型的,举个栗子:
上面我们用的是@RequestBody,那knife4j就知道请求数据类型为:application/json;
当我们改用@RequestParam时,它会识别为:application/x-www-form-urlencoded。
等等,上面两种是我实际测试出来的,其它的识别方式就不得而知了。
2020-12-17
今天,发现:knife4j会将header和produces的值都塞到响应数据类型里面。比如:
@RequestMapping (value = "clear" , method = {RequestMethod.GET, RequestMethod.POST}, headers = { "Accept=text/pain" }, produces = "text/html;charset=UTF-8" )
所以,当我们想要这里展示出具体的响应数据类型的话,在Mapping注解添加produces属性并设值即可。
2023年9月28日15:17:22
@GetMapping(value = "/getPipelineOne", produces = {"application/json;charset=UTF-8"})
@ApiOperationSupport()
(knife4j增加特性)用于接口方法排序,作者信息描述等
@ApiImplicitParams()
参数列表说明
如果不是用实体类接收入参的话,存在多个入参可以用该注解说明
@ApiParam()
对单个参数的说明
如果不是用实体类接收入参的话,存在一个或者多个入参也可以用该注解进行逐个说明
2023年9月28日16:29:39
错误用法
对应的接口说明
接口的入参变成了汉字。
对参数的解释说明,应该使用@ApiParam的value属性。
一般情况下,是不需要声明@ApiParam的name属性的。因为name的默认值就是请求参数的参数名称。
示例:
@ApiParam(name = "数据来源表名(区分大小写)", required = true, example = "table1")
String tablenameSource
参数名就是:tablenameSource。
正确用法
@ApiOperation(value = "查询表字段映射列表", notes = "查询表字段映射列表", httpMethod = "GET")
@GetMapping(value = "/getFlinkDataFieldList", produces = {"application/json;charset=UTF-8"})
public List<FlinkDataField> getFieldList(@ApiParam(value = "任务主键ID", required = true, example = "1")
@Pattern(regexp = "^[1-9]\\d*$", message = "任务主键ID必须为正整数")
@RequestParam String pipelineid,
@ApiParam(value = "数据来源库ID", required = true, example = "1")
@Pattern(regexp = "^[1-9]\\d*$", message = "数据来源库ID必须为正整数")
@RequestParam String databaseidSource,
@ApiParam(value = "数据来源表名(区分大小写)", required = true, example = "table1")
@NotBlank(message = "数据来源表名不能为空")
@RequestParam String tablenameSource){
FlinkDataField dataField = FlinkDataField.builder().build()
.setPipelineid(Long.parseLong(pipelineid))
.setDatabaseidSource(Long.parseLong(databaseidSource))
.setTablenameSource(tablenameSource)
;
return fieldService.getFlinkDataField(dataField);
}
@ApiModel()
用于描述一个数据模型的信息,即我们常用的实体、VO类、DTO类等描述
在接口入参用实体类接收时,通常用该注解对实体类进行说明,一般与@ApiModelProperty结合使用,与上面两个参数注解达到的效果是一样的。
说明:该注解里面的汉字不能重复!!!每一个实体类对应的汉字说明必须具有唯一性!!!
否则,knife4j展示的接口文档所需的请求参数或响应参数与实际不符!!!
@ApiModelProperty()
用于描述数据模型的属性信息
对应的是方法名的请求入参
@ApiIgnore
自动生成接口说明时忽略,可用于类、方法、方法入参
@ApiResponses
响应状态描述(在控制类下方,首个方法名上方)
对应到文档上是:
小结
6 2.0.6以后的版本
使用该版本,必须使用@EnableSwagger2WebMvc这一个注解。
该配置类里的两个方法
就可以合并成一个方法啦
@Bean (value = "defaultApi2" )
public Docket defaultApi2() {
Docket docket = new Docket(DocumentationType.SWAGGER_2) // 选择swagger2版本
// 接口文档的基本信息
.apiInfo( new ApiInfoBuilder()
.title( "接口项目 后台服务API接口文档" )
.description( "服务相关接口(knife4j)" )
// 服务Url(网站地址)
.termsOfServiceUrl( "http://127.0.0.1:8080/" )
.contact( new Contact( "Marydon" , null , "marydon20170307@163.com" ))
.version( "1.0" )
.build())
//分组名称,不配置的话,默认值为:default
.groupName( "2.X版本" )
.select()
// 这里指定Controller扫描包路径(项目路径也行)
// 方式一:配置扫描:所有想要在swagger界面统一管理的接口,都必须在此包下
// .apis(RequestHandlerSelectors.basePackage("com.baidu.zhidao.web.controller.entrance"))
// 方式二:只有当方法上有@ApiOperation注解时,才能生成对应的接口文档
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation. class ))
// 路径使用any风格(指定所有路径)
.paths(PathSelectors.any())
.build();
return docket;
}
PS:不合并也是可以哒。
说明:
使用Knife4j2.0.6及以上的版本,Spring Boot的版本必须大于等于2.2.x
需要注意的是:
当knife4j<=1.9.6时,它是knife4j的前身,叫做:swagger-bootstrap-ui,必须用注解@EnableSwaggerBootstrapUi+@EnableSwagger2;
不仅支持swagger-bootstrap-ui,原始的swagger-ui还是可以使用的,访问地址:
http://${host}:${port}/swagger-ui.html
当2.0.0<=knife4j<=2.0.5时,必须用注解@EnableKnife4j+@EnableSwagger2;
当2.0.6<=knife4j<=2.0.8时,必须使用注解@EnableSwagger2WebMvc。
当knife4j>1.9.6时,已经不支持swagger-ui了。
7.文档设置访问权限控制
一般情况下,我们在正式环境下是要屏蔽接口文档的,只有在非生产环境(比如:开发环境、测试环境)下才允许访问,如何实现?
可在application.properties/application.yml文件中添加以下配置。
禁用文档
properties文件:knife4j.production=true
yml文件如下:
重启服务,此时,再次访问doc.html,将是这个样子:
启用文档:将值改为false即可(表示的含义是:非生产环境)
这样一来,在打包的时候,如果允许访问,就将其值改成false;否则,就改成true。
这种方式不够智能,打包的时候,我们还需要记得改值,太麻烦了,还有更简单的一种。
通过注解@Profile来实现
可以配置多个访问环境,中间使用逗号隔开;
也可以使用!,!prod,就表示只要profile的值不等于prod,就可以访问得到文档;
@profile里的值对应的是主配置文件application.yml中spring.profiles.active的值,如下图所示:
spring.profiles.active的值的值其实是很随意的,跟开发环境、生产环境、预演环境、生产环境等没有半毛钱关系,只不过是大家习惯于这样使用,方便区分罢了。
按照这种方式,基本上就已经满足普通开发者的需求了,也相当于实现了动态配置。
说明:
如果采取这种方式,下面的值必须是false或者直接删掉该配置。
然而这种方式对于我来说还是太傻了,随着公司产品的推广,一个地方会添加一个配置文件,每个地方又都有正式和测试之分;
这样的话,每个地方测试的时候,我得改下配置启用;在正式上线的时候再禁用,太麻烦!怎么办,有没有一劳永逸的办法?
通过在pom.xml中配置多个profile实现
在properties标签添加自定义属性isProduction,名称随意,值是固定的:true/false
在主配置文件application引入该标签的值即可
说明:yml文件引入pom.xml的值使用@标签名@,properties文件引入pom.xml的值使用${标签名}
这样,我在打包的时候,就不需要手动去修改production的值,而是通过切换环境通过maven插件,将对应的值塞到主配置文件中。
说明:
这种方式,适用于大量配置文件,且需要来回切换环境的需求;
通过这种配置方式,就无需再配置@Profile注解了,否则就有点画蛇添足了。
8.文档通过密码访问
通过上面,我们只能控制环境来间接控制文档是否可访问,只要你能访问该接口文档,那么别人也一样可以访问得到,还不够安全。
如果有更高的安全需求,我们还可以为文档添加访问密码。
这样,当我们再次访问该文档时,就需要输入用户名和密码才能访问啦。
9.自定义Footer
修改这个显示内容
前提:knife4j>=2.0.8
第一步:必须开启增强功能
第二步:设置Footer
第三步:修改knife4j的配置类,比如:我上面叫做Knife4jConfig.java
注入对象:OpenApiExtensionResolver
// 自定义footer需要用到
@Resource
private OpenApiExtensionResolver openApiExtensionResolver;
Docket增加扩展方法
new Docket(DocumentationType.SWAGGER_2)
// 扩展属性(footer)
.extensions(openApiExtensionResolver.buildSettingExtensions());
效果展示:
10.分组管理
2023年9月26日09:06:55
这个分组是真正意义上的分组,不同于下面的分组排序功能。
在swagger当中,我们可以配置多个分组,对接口进行管理。
如果需要的话,操作步骤如下:
1.创建不同的Docket,对组进行管理(一个Docket相当于一个组);
2.设置groupName,添加组名;
3.设置api,指定该组管理的作用域。
11.分组排序(对多个Controller进行排序)
2020-12-16
文档上,每一项对应的是一个Controller,每一个controller相当于一个小组,有时候我们会想给它们排排顺序,怎么搞?
要想实现这个个性化的需求,需要满足三个条件:
第一,knife4j>=2.0.8;
第二,使用注解@ApiSupport;
说明:每个控制层的order值,必须大于0,且最好间隔10以上。
第三,开启增强功能。
增强功能需要通过配置yml配置文件开启:
knife4j:
enable: true
12.接口排序(对同一个Controller当中的接口排序)
每个控制器可能会对外公开多个接口,多个接口如何自定义排序呢?
使用注解@ApiOperationSupport;
其它两个条件,同上,缺一不可。
13.不拦截swagger请求
2022年1月20日15:55:15
当我们配置springMVC拦截器后,swagger的请求也会被误拦;
所以,需要我们将其访问路径排除拦截之外。
*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*,/v2/api-docs,/swagger-resources,/doc.html,/
或
/swagger-ui/index.html,/doc.html,/swagger-resources/**,/webjars/**, /static/**
具体实现方式,见文末推荐。
14.全局参数配置
2023年9月26日10:47:16
对于接口的访问,我们一般都有用户权限控制。
这该怎么调试接口呢?
比方说,我们可以设置全局参数,以token为例。
说明:配置好全局参数后,需要刷新页面,才会生效!
这样在调接口的时候,会自动添加到接口的请求头当中。
请求头部内容展示
2023年9月27日19:16:34
15.遇到一个奇葩问题
通常情况下,我们是遇不到的,但是,一旦遇到就会很抓狂。
table对象里面嵌套了columns数组。
正确的数据结构,应该是:
然鹅,table对象当中,却包含了其它对象的属性。
另一个实体类,长这样。
无论怎样尝试,都搞不定。
最终,同事发现,这两个对像的@ApiModel的备注一模一样。
这样就让swagger误以为:它俩是一体的!!!
实际上,在前端调用的时候,我们后台解析这次入参的数据结构时,并不受影响。
只不过,是swagger展示的数据结构,让我误以为,提供的数据结构不对。
这也算是给自己长了一个教训。
2023年9月28日10:34:48
16.knife4j注解+请求入参校验 用法示例
form表单格式请求(application/x-www-form-urlencoded)
form表单请求或者get请求,需要使用@RequestParam来标注入参。
@ApiOperation(value = "获取来源表名的字段信息", notes = "获取来源表名的字段信息", httpMethod = "GET")
@GetMapping(value = "/getSourceTableFieldList")
public List<TableFieldVo> getSourceTableFieldList(@ApiParam(value = "数据库ID", required = true, example = "1")
@Pattern(regexp = "^[1-9]\\d*$", message = "数据库ID必须为正整数")
@RequestParam String sourceDatabaseId,
@ApiParam(value = "表名(区分大小写)", required = true, example = "table1")
@NotBlank(message = "表名不能为空")
@RequestParam String sourceTableName,
@ApiParam(value = "目标表状态(0:不存在表;1:已存在表)", required = true, example = "1")
@Min(value = 0, message = "targetTableStatus:[0,1]")
@Max(value = 1, message = "targetTableStatus:[0,1]")
@RequestParam String targetTableStatus){
// 根据数据库ID和表名查询所有字段信息
return pipelineService.getSourceTableFieldList(sourceDatabaseId, sourceTableName, targetTableStatus);
}
另外,如果是非必传项,被@RequestParam注解修饰时,需要声明required属性值为false。
@RequestParam(required = false)
因为该注解的默认值是:必传项。
@ApiOperation(value = "分页查询管道列表", notes = "分页查询管道列表", httpMethod = "GET")
@GetMapping(value = "/getPipelineList")
public PageList<FlinkDataPipeline> getPipelineList(@ApiParam(value = "管道名称", required = false, example = "管道1")
@RequestParam(required = false) String pipelinename){
FlinkDataPipelineVo pipelineVo = FlinkDataPipelineVo.builder().build()
.setPipelinename(pipelinename)
;
return pipelineService.getPageList(pipelineVo);
}
json格式请求(application/json)
@ApiOperation(value = "添加管道信息", notes = "添加管道信息", httpMethod = "POST")
@PostMapping("/add")
public Boolean addPipelineAndField(@RequestBody @Valid PipelineFieldVo pipelineFieldVo){
return pipelineService.addPipelineAndField(pipelineFieldVo);
}
被@RequestBody注解修饰的,接收入参的实体类,如果想要参数校验生效的话,除了需要在实体类对应的属性上增加校验之外,
还要在该实体类上增加@Valid注解,只有这样,对请求入参的校验才会生效。
说明:
要想使用校验规则生效,除了需要引入hibernate-validator.jar包外,还需要在控制器类名上增加@Validated注解。
更详细的用法,见文末推荐。
写在最后
哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!
相关推荐:
本文来自博客园,作者:Marydon,转载请注明原文链接:https://www.cnblogs.com/Marydon20170307/p/14082450.html