随着前后端的分离,作为后端的开发多以接口的方式暴露给前端使用,一方面需要对接口进行版本管理,另一方面需要对接口进行文档说明的管理,这里对knife4j进行了简单的使用,借以说明如何通过knife4j在springboot项目中自动生成接口说明文档以及进行接口版本管理。
knife4j需要引入的包
对于新的knife4j使用比较简单,需要在springboot项目引入以下两个包即可,如下
com.github.xiaoymin knife4j-spring-boot-starter 2.0.2javax.validation validation-api 2.0.1.Final
然后就是对接口自动生成的相关配置,这里对一个接口做了两个版本,分别进行配置,对于相同接口的不同版本配置也可以放在一个配置类中,这个看个人喜好,这里假定有一个关于用户的接口,一共有两个版本,分别配置如下
接口版本V1.0.0配置
package or.noka.nokabar.config;import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Import;import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import springfox.documentation.swagger2.annotations.EnableSwagger2;/** ---------------------------------------------------------- * 接口文档生成配置 * 接口版本 V 1.0.0 * @author xiefangjian@163.com * @version 1.0.0 **--------------------------------------------------------**/@Configuration@EnableSwagger2@EnableKnife4j@Import(BeanValidatorPluginsConfiguration.class)public class SwaggerConfigV1_0_0 { /** --------------------------------------------------- * 接口版本 API_VERSIONS_V_1_0_0 * @return 接口配置信息 ** ------------------------------------------------**/ @Bean(ConstVarConfig.API_VERSIONS_V_1_0_0) public Docket docket() { Docket docket=new Docket(DocumentationType.SWAGGER_2) .apiInfo(appinfo())//接说明信息 .groupName(ConstVarConfig.API_VERSIONS_V_1_0_0)//接口版本号 .select() .apis(RequestHandlerSelectors.basePackage("or.noka.nokabar.controller"))//这里指定Controller扫描包路径 .paths((s) -> { if(s.indexOf("/"+ConstVarConfig.API_VERSIONS_V_1_0_0)!=-1) {//只显示对应版本的接口 return true; } return false; }) .build(); return docket; } /** ---------------------------------------------- * 接口说明信息 * @return 接口说明信息 ** -------------------------------------------**/ private ApiInfo appinfo(){ return new ApiInfoBuilder() .title("接口服务")//设置文档的标题 .description("
API 接口文档
" + "
这里存放接口说明" + "
接口说明") // 设置文档的描述 .version(ConstVarConfig.API_VERSIONS_V_1_0_0) //设置文档的版本信息-> 1.0.0 .build(); }}
接口版本V1.0.01配置
package or.noka.nokabar.config;import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Import;import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import springfox.documentation.swagger2.annotations.EnableSwagger2;/** ---------------------------------------------------------- * 接口文档生成配置 * 接口版本 V 1.0.1 * @author xiefangjian@163.com * @version 1.0.0 **--------------------------------------------------------**/@Configuration@EnableSwagger2@EnableKnife4j@Import(BeanValidatorPluginsConfiguration.class)public class SwaggerConfigV1_0_1 { /** ---------------------------------------------------- * 接口版本 API_VERSIONS_V_1_0_1 * @return 接口配置信息 ** -------------------------------------------------**/ @Bean(ConstVarConfig.API_VERSIONS_V_1_0_1) public Docket docket() { Docket docket=new Docket(DocumentationType.SWAGGER_2) .apiInfo(appinfo())//接说明 .groupName(ConstVarConfig.API_VERSIONS_V_1_0_1)//接口版本 .select() .apis(RequestHandlerSelectors.basePackage("or.noka.nokabar.controller"))//这里指定Controller扫描包路径 .paths((s) -> { if(s.indexOf("/"+ConstVarConfig.API_VERSIONS_V_1_0_1)!=-1) {//只显示对应版本的接口 return true; } return false; }) .build(); return docket; } /** --------------------------------------------------- * 接口说明信息 * @return 接口说明信息 ** ------------------------------------------------**/ private ApiInfo appinfo(){ return new ApiInfoBuilder() .title("接口服务")//设置文档的标题 .description("
API 接口文档
" + "
这里存放接口说明" + "
接口说明") // 设置文档的描述 .version(ConstVarConfig.API_VERSIONS_V_1_0_1) //设置文档的版本信息-> 1.0.1 .build(); }}
以上配置了两个版本的接口分别为V1.0.0和V1.0.0.1,这两个版本的定义放在了ConstVarConfig类中,该类中只是对这两个版本做了常量定义,以便在接口实现中使用该版本定义,实现如下
package or.noka.nokabar.config;/** ----------------------------------------------- * 配置常量 * @author xiefangjian@163.com * @version 1.0.0 ** --------------------------------------------**/public class ConstVarConfig { public static final String API_VERSIONS_V_1_0_0 = "V1.0.0";//接口版本号 public static final String API_VERSIONS_V_1_0_1 = "V1.0.1";//接口版本号}
接口实现及接口说明文档编写
接口实现和普通的springboot中的Controller实现完全相同,只需要加上接口说明自动生成需要的一些说明即可
package or.noka.nokabar.controller;import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;import com.github.xiaoymin.knife4j.annotations.ApiSort;import io.swagger.annotations.Api;import io.swagger.annotations.ApiImplicitParam;import io.swagger.annotations.ApiImplicitParams;import io.swagger.annotations.ApiOperation;import or.noka.nokabar.config.ConstVarConfig;import or.noka.nokabar.vo.UserApiVo;import org.springframework.stereotype.Component;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;/** -------------------------------------------------------------- * 用户相关接口 * @author xiefangjian@163.com * @version 1.0.0 ** -----------------------------------------------------------**/@Controller@Component@Api(tags = "1 用户接口") //接口名称,该内容将做为接口说明界面中的第一级菜单名称@ApiSort(1) //该接口文档在接口界面中菜单的排序,该排序只针对第一级菜单的顺序@RequestMapping("/user")//接口根地址,该地址与后面的方法访问地址共同组成接口访问的完整地址public class UserAPIController { /**---------------------------------------------------------- * 用户登陆接口 * 接口版本 API_VERSIONS_V_1_0_0 * @param id 传入参数 id **------------------------------------------------------**/ @GetMapping({"/login/"+ConstVarConfig.API_VERSIONS_V_1_0_0+"/{id}"})//接口调用地址 @ApiOperationSupport(order = 1)//接口排序,只针对二级菜单的顺序,序号越小,排序越靠前 @ResponseBody //返回JSON @ApiOperation(value = "1.1 用户登陆接口",notes = "用户登陆接口",produces = "application/json") @ApiImplicitParam(name = "id",value = "用户id",dataType = "Long",paramType = "Long",required = true) public UserApiVo loginV1_0_0(@PathVariable("id") String id){ return new UserApiVo("SUCCESS","login success"); } /**---------------------------------------------------------- * 用户登陆接口 * 接口版本 API_VERSIONS_V_1_0_1 * @param id 传入参数 id * @param password 传入参数 密码 **------------------------------------------------------**/ @GetMapping({"/login/"+ConstVarConfig.API_VERSIONS_V_1_0_1+"/{id}/{password}"})//接口调用地址 @ApiOperationSupport(order = 1)//接口排序,只针对二级菜单的顺序,序号越小,排序越靠前 @ResponseBody //返回JSON @ApiOperation(value = "1.1 用户登陆接口",notes = "用户登陆接口",produces = "application/json") //接口名称以及接口说明 @ApiImplicitParam(name = "id",value = "用户id",dataType = "Long",paramType = "Long",required = true) @ApiImplicitParams({ @ApiImplicitParam(name = "id",value = "用户id",dataType = "Long",paramType = "Long",required = true), @ApiImplicitParam(name = "password",value = "用户密码",dataType = "String",paramType = "Long",required = true) }) public UserApiVo loginV1_0_1(@PathVariable("id") String id,@PathVariable("password") String password){ return new UserApiVo("SUCCESS","login success"); }}
以上配置中,分别对接口的名称,参数类型,参数是否为必须的进行了说明,具体参数含义如下
- ApiOperationSupport
order:接口排序,序号越小,排序越靠前,该功能需要在接口界面中开启增强功能才会有效果
- ApiOperation
value:接口名称,显示在二级菜单中的名称
notes:接口描述,显示在接口描述信息中的内容
produces:接口返回的数据类型,这里返回的是JSON字符串
- ApiImplicitParam
name:参数名字,与方法里的参数同名
value:参数描述
dataType:参数的数据类型
required:该参数是否为必须项
如上所示,多个参数需要用ApiImplicitParams进行配置
配置完成以后,在接口中可以看到该接口说明,并且可以直接进行接口测试
接口说明界面
接口在线测试界面
以上接口返回的是一个名为UserApiVo的对象,该对象被定义成了一个消息的实体对象,可以在该消息实体对象中对参数进行说明,如下
package or.noka.nokabar.vo;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import java.io.Serializable;/** ------------------------------------------------- * 用户接口返回对象 * @author xiefangjian@163.com * @version V1.0.0 */@Data //这里使用了lombok封装实体类@AllArgsConstructor //全参数构造方法@NoArgsConstructor //无参数构造方法@ApiModel("用户操作返回信息")//定义用户操作接口返回对象说明public class UserApiVo implements Serializable { @ApiModelProperty(value = "返回代码,{SUCCESS|操作成功,FAIL|操作失败}",required = true) private String code=null; @ApiModelProperty(value = "返回信息",required = true) private String msg=null;}
以上配置完成以后,就可以启动项目访问接口说明文档了,接口说明文档的访问路径为/doc.html,默认是没有密码的,可以直接访问,为了安全可以配置一个访问账户和密码
knife4j访问参数配置
## 是否关闭接口文档,默认是false,在生产环境中可以设为true,以关闭接口说明#knife4j.production=true## 开启Swagger的Basic认证功能,默认是falseknife4j.basic.enable=true## Basic认证用户名knife4j.basic.username=admin## Basic认证密码knife4j.basic.password=admin123
至此,knife4j所有配置完成,这里的版本控制被放置在了接口访问路径里的最后一级,这只是个人喜好,没有特别意义,版本号的标识可以放在访问路径中的任何地方,另外如果接口需要做版本控制,那么最好从一开始就要规划好多版本共存的问题,以及是否需要不同版本接口向下兼容等问题。