swagger 是一个 api 文档维护组织,后来成为了 Open API 标准的主要定义者;
对于开发者来说,swagger是帮助后端开发人员在开发/测试环境下生成接口测试页面功能的注解;
大多数项目用的是swagger2标准OpenApi2的规范,最新的规范是swagger3的OpenApi3规范;
提到swagger,那么SpringFox和SpringDoc作为实现swagger规范的佼佼者,自然被广大后端人员大量使用,目前SpringFox已经支持swagger3的注解(swagger2也可使用),而SpringDoc已经进化成仅支持swagger3的注解了。
但是对于国人来说SpringFox和SpringDoc实现的ui界面并没有多友好,用到极致也不过是个懒得写测试用例的框架罢了,前端人员看这个ui界面可以说很抓狂,后端人员也很苦恼,我这swagger都维护好了,怎么前端就看不懂了,怎么项目经理还要我再写个接口文档?
主要原因是:英文烂、ui界面没有区分度、无法生成静态的接口文档
那么国人应该用什么框架来解决这些烦恼呢?knife4j
Knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案,前身是swagger-bootstrap-ui,取名kni4j是希望她能像一把匕首一样小巧,轻量,并且功能强悍!
简单来说,Knife4j是遵循swagger2规范,集成springFox并增强的前后端一体化框架
开源地址:https://gitee.com/xiaoym/knife4j
文档地址:https://doc.xiaominfo.com/knife4j/documentation/
截一张图展示一下:
本教程使用的注解全部为swagger2的注解,也就是Api开头的注解,比如@ApiOperation("注册")
、@Api(tags = "登陆控制")
,如果已存在的项目用的是swagger3的注解,请继续使用SpringDoc哈。
仅介绍最通用的使用教程,最常用的swagger实现框架,大概就是SpringFox了,而knife4j是包含SpringFox的,需要用knife4j就要更换掉原SpringFox依赖。
1.依赖:
<dependency>
<groupId>com.github.xiaoymingroupId>
<artifactId>knife4j-spring-boot-starterartifactId>
<version>3.0.3version>
dependency>
2.通用springboot-swagger2配置文件:
import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
import org.springframework.beans.factory.annotation.Autowired;
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.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
/**
* swagger2配置
*
* @author huang cheng
* 2021/8/13
*/
@Configuration
@EnableSwagger2
public class Swagger2Config {
/*引入Knife4j提供的扩展类*/
private final OpenApiExtensionResolver openApiExtensionResolver;
@Autowired
public Swagger2Config(OpenApiExtensionResolver openApiExtensionResolver) {
this.openApiExtensionResolver = openApiExtensionResolver;
}
private final static String groupName = "cheng";//组群名称
private final static String headerName = "Authorization";//需要swagger每次调接口前携带的头信息的key
//private final static String headerName2 = "test";//如果要多个请求头信息,自行解放注释
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())//文档信息
.groupName(groupName)//组群名称
.select()
.apis(RequestHandlerSelectors.basePackage("com.cheng.authonlytoken.controller"))//需要扫描的api所在目录
.paths(PathSelectors.any())//匹配全部地址路径
.build()
.securitySchemes(securitySchemes())//配置安全方案
.securityContexts(securityContexts())//配置安全方案所实现的上下文
.extensions(openApiExtensionResolver.buildExtensions(groupName))//赋予插件体系
;
}
private List<SecurityScheme> securitySchemes() {
List<SecurityScheme> apiKeyList = new ArrayList<>();
//配置header头1
ApiKey token_access = new ApiKey(headerName, headerName, "header");
apiKeyList.add(token_access);
//配置header头2
//ApiKey token_access2 = new ApiKey( headerName2, headerName2, "header");
//apiKeyList.add(token_access2);
return apiKeyList;
}
private List<SecurityContext> securityContexts() {
List<SecurityContext> securityContextList = new ArrayList<>();
List<SecurityReference> securityReferenceList = new ArrayList<>();
//为每个api添加请求头
securityReferenceList.add(new SecurityReference(headerName, scopes()));
//以此类推
//securityReferenceList.add(new SecurityReference(headerName2, scopes()));
securityContextList.add(SecurityContext
.builder()
.securityReferences(securityReferenceList)
.forPaths(PathSelectors.any())
.build()
);
return securityContextList;
}
private AuthorizationScope[] scopes() {
return new AuthorizationScope[]{new AuthorizationScope("global", "accessAnything")};//作用域为全局
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("swagger2文档")
.description("更多精彩博客请关注:https://blog.csdn.net/qq_42495847?spm=1000.2115.3001.5343")
.termsOfServiceUrl("https://blog.csdn.net/qq_42495847?spm=1000.2115.3001.5343")
.contact(new Contact("cheng", "https://blog.csdn.net/qq_42495847?spm=1000.2115.3001.5343", "[email protected]"))
.version("1.0")
.build();
}
}
Authorization
,并让所有扫描到的api携带这个header3.如果有拦截器,请放行以下地址:
/**
* 放行Swagger
*/
public static final String[] SWAGGER_WHITELIST = {
"/swagger-ui.html/**",
"/swagger-ui/**",
"/swagger-resources/**",
"/v2/api-docs",
"/v3/api-docs",
"/v3/api-docs/swagger-config",
"/webjars/**",
"/doc.html",
};
最后在生成环境yml配置文件中加上配置:
knife4j:
# 开启增强配置
enable: true
# 开启生产环境屏蔽
production: true
4.配置每个接口的swagger注解信息
swagger2常用注解:
常用注解
swagger2 | swagger3 | 注解位置 |
---|---|---|
@Api(tags = “接口类描述”) | @Tag(tags = “接口类描述”) | Controller 类上 |
@ApiOperation(“接口方法描述”) | @Operation(summary =“接口方法描述”) | Controller 方法上 |
@ApiImplicitParams | @Parameters | Controller 方法上 |
@ApiImplicitParam | @Parameter(description=“参数描述”) | Controller 方法上 @Parameters 里 |
@ApiParam(“参数描述”) | @Parameter(description=“参数描述”) | Controller 方法的参数上 |
@ApiIgnore | @Parameter(hidden = true) 或 @Operation(hidden = true) 或 @Hidden | - |
@ApiModel(description = “dto类描述”) | @Schema(description = “dto类描述”) | DTO类上 |
@ApiModelProperty(“属性描述”) | @Schema(description = “属性描述”) | DTO属性上 |
还是从前swagger2的味道,示例如下:
controller:
/**
* 用户登录控制
* @author huang cheng
* 2021/8/11
*/
@Api(tags = "登陆控制")
@RestController
@RequestMapping("/auth")
public class LoginController {
@Resource
private LoginService loginService;
@ApiOperation("注册")
@PostMapping("/register")
public CResponse<TokenVo> register(@RequestBody @Valid RegisterDto registerDto){
return loginService.register(registerDto);
}
/**
* 微信授权成功后调用该方法 获取token
* @param loginDto 传入该用户可获取到的用户信息
* @return token 放到Header中的Authorization作为值
*/
@ApiOperation("得到token")
@PostMapping("/getToken")
public CResponse<TokenVo> getToken(@RequestBody @Valid LoginDto loginDto){
return loginService.getToken(loginDto);
}
/**
* 得到当前token中包含的用户信息
* @return 用户信息
*/
@ApiOperation("得到当前token中包含的用户信息")
@PostMapping("/getUserInfo")
public CResponse<UserInfo> getUserInfo(HttpServletRequest request){
String token = request.getHeader("Authorization");
if (StringUtils.isBlank(token)){
throw new CommonException("token为空");
}
return loginService.getUserInfo(token);
}
}
pojo:
/**
* 登陆参数
* @author huang cheng
* 2021/8/11
*/
@ApiModel("登陆参数")
@Data
public class LoginDto {
@ApiModelProperty("登录类型")
@NotBlank(message = "登录类型不能为空")
private String identityType;
@ApiModelProperty("标识-账号")
@NotBlank(message = "账号不能为空")
private String identifier;
@ApiModelProperty("密码凭证")
@NotBlank(message = "密码凭证不能为空")
private String credential;
}
5.配置完成后访问 域名/{contextPath}/doc.html
比如我访问localhost:8080/doc.html,即可进入好看的knife4j的ui界面了
6.配置统一的认证请求头
一般接口都至少戴个token来证明自己是安全的请求,通用的配置文件中已经配置了请求头Authorization,可以在Authorize界面看到
配置后api的调试界面自动带上该请求头的key和value
7.离线文档功能
在文档管理-离线文档中,可下载四种格式的接口文档:markdown、HTML、word、openapi
示例:
已经比自己写的接口文档还要好看和详细了
如果是多人合作项目,不想生成其他人的api信息,使用复制文档功能:
前往官方文档查看:
文档地址:https://doc.xiaominfo.com/knife4j/documentation/