OAS (OpenAPI Specification)

OAS 是 OpenAPI Specification 的简称,可以翻译为OpenAPI规范,它是定义API的一种规范,定义了一种JSON格式或者YAML格式的API文档文件格式; 它的前身是Swagger规范。在2.0版本的时候OAS还冠有 Swagger 的印记,到了3.0版本就彻底去除了该释义。

Swagger 是一个 API文档维护组织,后来成为了 Open API 标准的主要定义者。目前可以认为Swagger3就是Open API 3.0

SpringFox 是 spring 社区维护的一个项目(非官方),践行OAS的一个项目,它将Swagger融合进流行的Spring框架,根据OpenAPI规范,帮助开发者自动生成API文档。

knife4j Knife4j 是为 Java MVC 框架集成 Swagger 生成 Api 文档的增强解决方案,前身是 swagger-bootstrap-ui

in short OAS 是标准规范, 前身是Swagger, Springfox 是具体的实现;

swagger2 和 OpenAPI 3 注解

swagger 文档 Knife4j 文档 请求注解 Knife4j 文档 响应注解

注意 swagger3 注解的包路径为io.swagger.v3.oas.annotations.*

swagger2OpenAPI 3注解位置
@Api@Tag(name = “接口类描述”)Controller 类上
@ApiOperation@Operation(summary =“接口方法描述”)Controller 方法上
@ApiImplicitParams@ParametersController 方法上
@ApiImplicitParam@Parameter(description=“参数描述”)@Parameters 里
@ApiParam@Parameter(description=“参数描述”)Controller 方法的参数上
@ApiIgnore@Parameter(hidden = true) 或 @Operation(hidden = true) 或 @Hidden-
@ApiModel@Schema(description="")DTO类上
@ApiModelProperty@SchemaDTO属性上
@Hidden

Spring Boot With knife4j 生成接口文档

https://doc.xiaominfo.com/docs/quick-start

knife4j (OpenAPI 3.0)

Knife4j在后面的版本中会全面切入OpenAPI3的规范中,因此在以后的版本迭代中,只会提供给OpenAPI3规范的适配,开发者应该尽快迁移到3的规范上来。 knife4j 4.0版本针对3的规范底层迁移使用springdoc-openapi项目,放弃springfox3.0

依赖

Spring Boot 2.x

...
 
<dependency>  
	<groupId>com.github.xiaoymin</groupId>  
	<artifactId>knife4j-openapi3-spring-boot-starter</artifactId>  
	<version>4.5.0</version>  
</dependency>
</dependencies>
  
<dependencyManagement>  
	<dependencies>  
		<dependency>  
			<groupId>com.github.xiaoymin</groupId>  
			<artifactId>knife4j-dependencies</artifactId>  
			<version>4.5.0</version>  
			<type>pom</type>  
			<scope>import</scope>  
		</dependency>  
	</dependencies>  
</dependencyManagement>  
</project>

Spring Boot 3.x

<dependency>  
	<groupId>com.github.xiaoymin</groupId>
	<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId> 
	<version>4.0.0</version>
</dependency>

配置

 
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import cn.hutool.core.util.RandomUtil;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.media.StringSchema;
import io.swagger.v3.oas.models.parameters.HeaderParameter;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.beans.factory.annotation.Value;
import java.util.ArrayList;
import java.util.List;
 
/**
 * 文档页面 ./doc.html
 * @author yang
 *
 */
@Configuration
public class SwaggerConfig {
 
	public static final String TOKEN_HEADER = "Authorization";
 
	@Bean
	public OpenAPI openApi() {
		return new OpenAPI()
				.components(
						new Components().addSecuritySchemes(TOKEN_HEADER,
								// 全局参数, 这里配置 bearer 后,你的请求里会自动在 token 前加上 Bearer
								new SecurityScheme()
										.type(SecurityScheme.Type.APIKEY)
										.scheme("bearer")
										.bearerFormat("JWT")
						).addParameters(TOKEN_HEADER,
								new Parameter()
										.in("header")
										.schema(new StringSchema())
										.name(TOKEN_HEADER)
						))
				.info(
						new Info()
								.title("项目API文档")
//									.description("项目API文档")
//									 参考 Apache 2.0 许可及地址,你可以不配此项
//									.license(new License().name("Apache 2.0").url("https://www.apache.org/licenses/LICENSE-2.0.html"))
								.version("5.0")
				);
	}
 
}
 
public class SwaggerDataConfig {
    @Schema
    static class Page {
        @Schema(name = "页码 (0..N)")
        private Integer page;
 
        private Integer size;
 
        @Schema(name = "以下列格式排序标准:property[,asc | desc]。 默认排序顺序为升序。 支持多种排序条件:如:id,asc")
        private List<String> sort;
 
        public Integer getPage() {
            return page;
        }
 
        public void setPage(Integer page) {
            this.page = page;
        }
 
        public Integer getSize() {
            return size;
        }
 
        public void setSize(Integer size) {
            this.size = size;
        }
 
        public List<String> getSort() {
            return sort;
        }
 
        public void setSort(List<String> sort) {
            this.sort = sort;
        }
    }
  
}

knife4j 增强

https://doc.xiaominfo.com/docs/features/enhance

要使用Knife4j提供的增强,knife4j.enable=true必须开启

属性默认值说明值
knife4j.enablefalse是否开启Knife4j增强模式
knife4j.corsfalse是否开启一个默认的跨域配置,该功能配合自定义Host使用
knife4j.productionfalse是否开启生产环境保护策略,详情参考文档
knife4j.basic对Knife4j提供的资源提供BasicHttp校验,保护文档
knife4j.basic.enablefalse关闭BasicHttp功能
knife4j.basic.usernamebasic用户名
knife4j.basic.passwordbasic密码
knife4j.documents自定义文档集合,该属性是数组
knife4j.documents.group所属分组
knife4j.documents.name类似于接口中的tag,对于自定义文档的分组
knife4j.documents.locationsmarkdown文件路径,可以是一个文件夹(classpath:markdowns/*),也可以是单个文件(classpath:md/sign.md)
knife4j.setting前端Ui的个性化配置属性
knife4j.setting.enable-after-scripttrue调试Tab是否显示AfterScript功能,默认开启
knife4j.setting.languagezh-CNUi默认显示语言,目前主要有两种:中文(zh-CN)、英文(en-US)
knife4j.setting.enable-swagger-modelstrue是否显示界面中SwaggerModel功能
knife4j.setting.swagger-model-nameSwagger Models重命名SwaggerModel名称,默认
knife4j.setting.enable-document-managetrue是否显示界面中”文档管理”功能
knife4j.setting.enable-reload-cache-parameterfalse是否在每个Debug调试栏后显示刷新变量按钮,默认不显示
knife4j.setting.enable-versionfalse是否开启界面中对某接口的版本控制,如果开启,后端变化后Ui界面会存在小蓝点
knife4j.setting.enable-request-cachetrue是否开启请求参数缓存
knife4j.setting.enable-filter-multipart-apisfalse针对RequestMapping的接口请求类型,在不指定参数类型的情况下,如果不过滤,默认会显示7个类型的接口地址参数,如果开启此配置,默认展示一个Post类型的接口地址
knife4j.setting.enable-filter-multipart-api-method-typePOST具体接口的过滤类型
knife4j.setting.enable-hostfalse是否启用Host
knife4j.setting.enable-host-textfalseHOST地址
knife4j.setting.enable-home-customfalse是否开启自定义主页内容
knife4j.setting.home-custom-path主页内容Markdown文件路径
knife4j.setting.enable-searchfalse是否禁用Ui界面中的搜索框
knife4j.setting.enable-footertrue是否显示Footer
knife4j.setting.enable-footer-customfalse是否开启自定义Footer
knife4j.setting.footer-custom-contentfalse自定义Footer内容
knife4j.setting.enable-dynamic-parameterfalse是否开启动态参数调试功能
knife4j.setting.enable-debugtrue启用调试
knife4j.setting.enable-open-apitrue显示OpenAPI规范
knife4j.setting.enable-grouptrue显示服务分组

排序

分组排序 (Controller)

https://doc.xiaominfo.com/docs/features/tagSort

Controller之间的排序主要有两种方式,排序的规则是倒序,但是排序的最小值必须大于0

建议优先级是:@ApiSupport>@ApiSort>@Api

对于最高级别的值,可以从999开始 @ApiSupport注解自2.0.3版本引入

第一种,使用@ApiSupport注解中的属性order,代码示例如下:

@Api(tags = "2.0.3版本-20200312")
@ApiSupport(order = 284)
@RestController
@RequestMapping("/api/nxew203")
public class Api203Constroller {
    
}

第二种情况,使用knife4j提供的增强注解@ApiSort,代码示例如下:

@Api(tags = "2.0.2版本-20200226")
@ApiSort(286)
@RestController
@RequestMapping("/api/nxew202")
public class Api202Controller {
    
    

第三种,使用注解@Api中的属性position(需要注意的是该属性以及过时,建议开发者使用第一种),代码示例如下:

@Api(tags = "2.0.2版本-20200226",position = 286)
@RestController
@RequestMapping("/api/nxew202")
public class Api202Controller {
    
    
}

Knife4j也是通过Spring Plugin插件化的方式,扫描接口注解,最终通过扩展OpenAPI的扩展属性 tags[0].x-order进行赋值,最终在Ui界面中解析,然后再进行排序后渲染组件

  1. 但是 只有当Controller上的@Tag注解同时填写namedescription字段时,这个分组才会进入到tags字段中
  2. 自Knife4j 4.0版本,开发者必须使用knife4j-openapi2-spring-boot-starter组件才生效

接口排序 (RequestMapping)

Controller下的具体接口,排序规则是使用Knife4j提供的增强注解@ApiOperationSupport中的order字段,代码示例如下:

 
@ApiOperationSupport(order = 33)
@ApiOperation(value = "忽略参数值-Form类型")
@PostMapping("/ex")
public Rest<LongUser> findAll(LongUser longUser) {
    Rest<LongUser> r=new Rest<>();
    r.setData(longUser);
    return r;
}

Knife4j通过Spring Plugin插件体系,对每个接口进行扫描,最终将扫描的@ApiOperationSupport注解获取的order值通过OpenAPI的扩展属性规范进行赋值

最终在OpenAPI的规范中,接口的path节点下,通过x-order属性得到接口的排序,最终前端根据排序值进行排序

分组

/**
 * GroupedOpenApi 是对接口文档分组,类似于 swagger 的 Docket
 */
@Bean
public GroupedOpenApi A_ProjectApi() {
	return GroupedOpenApi.builder()
			// 组名
			.group("项目接口")
			// 扫描的路径,支持通配符
			.pathsToMatch("/api/**")
			// 扫描的包
			.packagesToScan("cn.simae.cloud.tny")
			.build();
}
 
 
@Bean
public GroupedOpenApi B_AuthApi() {
	return GroupedOpenApi.builder()
			// 组名
			.group("登陆接口")
			// 扫描的包
			.packagesToScan("cn.simae.cloud.admin.modules.security.rest")
			.build();
}
 
@Bean
public GroupedOpenApi C_SysApi() {
	return GroupedOpenApi.builder()
			.group("框架接口")
			.pathsToMatch("/api/**")
			.packagesToScan("cn.simae.cloud.admin.modules")
			.packagesToExclude("cn.simae.cloud.admin.modules.security.rest")
			// 添加自定义配置,这里添加了一个用户认证的 header,否则 knife4j 里会没有 header
			.addOperationCustomizer((operation, handlerMethod) -> operation.security(
					Collections.singletonList(new SecurityRequirement().addList(TOKEN_HEADER)))
			)
			.build();
}

配置

# 接口文档
knife4j:
  enable: true
  setting:
    enable-debug: true
springdoc:
  swagger-ui:
    path: /swagger-ui.html
# 分组下的接口排序, 不配置 使用 Knife4j
#    tags-sorter: alpha
#    operations-sorter: alpha
#    show-extensions: true
  api-docs:
    path: /v3/api-docs
    enabled: true

生产环境屏蔽

https://doc.xiaominfo.com/docs/features/accessControl

目前Springfox-Swagger以及Knife4j提供的资源接口包括如下:

资源说明
/doc.htmlKnife4j提供的文档访问地址
/v2/api-docs-extKnife4j提供的增强接口地址,自2.0.6版本后删除
/swagger-resourcesSpringfox-Swagger提供的分组接口
/v2/api-docsSpringfox-Swagger提供的分组实例详情接口
/swagger-ui.htmlSpringfox-Swagger提供的文档访问地址
/swagger-resources/configuration/uiSpringfox-Swagger提供
/swagger-resources/configuration/securitySpringfox-Swagger提供

springdoc以及Knife4j提供的资源接口包括如下:

资源说明
/doc.htmlKnife4j提供的文档访问地址
/v3/api-docsspringdoc提供的实例接口
/v3/api-docs/swagger-configspringdoc提供的分组接口
/v3/api-docs/**分组
/swagger-ui/index.htmlspringdoc提供的文档访问地址

当我们部署系统到生产系统,为了接口安全,需要屏蔽所有Swagger的相关资源

如果使用SpringBoot框架,只需在application.properties或者application.yml配置文件中配置

knife4j:
  # 开启增强配置 
  enable: true
 # 开启生产环境屏蔽
  production: true

配置此属性后,所有资源都会屏蔽输出.