做项目经常要写的,不只是代码,也不是寂寞,而是文档。项目文档,设计文档,接口文档等等。那接口文档怎么写,大家都知道用Swagger。但一说到Swagger,就不得不提一下OpenAPI。简单来说,OpenAPI简称OAS,即OpenAPI Specification,是一个用于定义和描述API的语言规范,可以通过这套规范,在向第三方的开发者提供对外暴露的接口服务时,大家达成统一的标准。
Swagger是套工具,Swagger2.0团队将其API规范捐献给OpenAPI的组织,再经过组织的发展与完善之后,OpenAPI3.0发布。Swagger3.0在2017年发布,支持OpenAPI3.0,提供了可以使用JSON,YAML编写API文档的功能,并能更好的支持restful接口。项目中要支持OpenAPI3.0我们常用的组件有两个,一个是springfox,还有一个则是springdoc。有什么区别呢?我们以前使用swagger都用的是springfox2.0,而springfox3.0是将原来的Swagger2.0升级到Swagger3.0来支持OpenAPI3.0,也就是说我们原先使用的springfox只要升级下版本号,就可以支持OpenAPI3.0的协议了。springdoc是全新的基于Swagger的一个组件,更早支持OpenAPI3.0的标准,并兼容spring框架。在Swagger2.0的时候,为了支持OpenAPI3.0,很多项目都采用了这个组件,到目前为止也更为流行,下面简单的写下基础的配置。
1.springfox
添加springfox依赖:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
增加配置类:
@Configuration
@EnableOpenApi
@ConditionalOnProperty(value = "springfox.documentation.enabled", havingValue = "true", matchIfMissing = true)
public class Swagger3Config {
@Bean
public Docket createBizApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.st.storyadmin.controller.biz"))
.paths(PathSelectors.regex("/biz.*"))
.build()
.globalRequestParameters(this.getGlobalRequestParameters())
.globalResponses(HttpMethod.GET, getGlobalResonseMessage())
.globalResponses(HttpMethod.POST, getGlobalResonseMessage())
.groupName("业务处理");
}
@Bean
public Docket createBaseInfoApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.st.storyadmin.controller.baseinfo"))
.paths(PathSelectors.regex("/baseinfo.*"))
.build()
.globalRequestParameters(this.getGlobalRequestParameters())
.globalResponses(HttpMethod.GET, getGlobalResonseMessage())
.globalResponses(HttpMethod.POST, getGlobalResonseMessage())
.groupName("基础配置");
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Story-Admin系统后台服务API接口文档")
.description("Story-Admin系统后台API接口")
.version("1.0")
.build();
}
//生成全局通用参数
private List<RequestParameter> getGlobalRequestParameters() {
List<RequestParameter> parameters = new ArrayList<>();
parameters.add(new RequestParameterBuilder()
.name("appid").description("AppId")
.required(true).in(ParameterType.QUERY)
.query(q -> q.model(m -> m.scalarModel(ScalarType.STRING)))
.required(false).build());
return parameters;
}
//生成通用响应信息
private List<Response> getGlobalResonseMessage() {
List<Response> responseList = new ArrayList<>();
responseList.add(new ResponseBuilder()
.code("404")
.description("找不到资源").build());
return responseList;
}
}
好吧就这么简单,最终的效果放在后面了。
2.springdoc
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.5.10</version>
</dependency>
这里我们将所有的API接口按照包或者请求路径分为三个组,可以通过定义三个 GroupedOpenApi实现:
@Configuration
public class OpenApiConfig {
@Bean
public GroupedOpenApi createBaseApi() {
return GroupedOpenApi.builder()
.group("基础配置")
.packagesToScan("com.st.storyadmin.controller.baseinfo")
//.pathsToMatch("/baseinfo/**")
.build();
}
@Bean
public GroupedOpenApi createBizApi() {
return GroupedOpenApi.builder()
.group("业务处理")
.packagesToScan("com.st.storyadmin.controller.biz")
//.pathsToMatch("/biz/**")
.build();
}
@Bean
public GroupedOpenApi createPublicApi() {
return GroupedOpenApi.builder()
.group("公共模块")
.packagesToScan("com.st.storyadmin.controller.pub")
//.pathsToMatch("/public/**")
.build();
}
@Bean
public OpenAPI springShopOpenAPI() {
return new OpenAPI()
.info(new Info().title("Story-Admin系统后台服务API接口文档")
.description("Story-Admin系统后台服务API接口文档")
.version("v0.0.1")
.license(new License().name("Apache 2.0").url("http://springdoc.org")))
.externalDocs(new ExternalDocumentation()
.description("Story-Admin Documentation")
.url("https://story-admin.wiki.github.org/docs"));
}
}
当然也可以按照注释中的代码,根据URI来进行匹配分组,那么我们访问接口的默认地址就是 http://localhost:8080/swagger-ui.html。
如果想要修改上面的API文档地址,可以通过下面的配置轻松实现。
#OpenApi
springdoc:
api-docs:
path: /api/data
swagger-ui:
path: /api/index.html
这时,我们的文档地址可就变成了 http://localhost:8080/api/index.html 。
那么我们Controller上的注解要怎么写?
引用下springdoc官网的话:
将swagger 2注解替换为swagger 3注解(它已经包含在springdoc openapi ui依赖项中)。swagger 3注释的包是io.swagger.v3.oas.annotations。
简单来说Swagger2的注解已经被新的注解替换了,举个最简单的例子:
@RestController
@Tag(name = "查询方案配置接口")
@RequestMapping(value = "/baseinfo/scheme")
public class BaseQuerySchemeController {
@GetMapping(value = "/getAllModules")
@Operation(summary = "获取所有模块标识")
public Result<Set<String>> getAllModules() {
//...
}
}
@Schema(title = "查询方案中条件Vo")
public class GeneralFilterVo {
@Schema(title="模块")
String module;
@Schema(title="属性描述")
String propLabel;
//...
}
下面则是从官网拿过来的,全部注解的变更:
@Api → @Tag
@ApiIgnore → @Parameter(hidden = true) or @Operation(hidden = true) or @Hidden
@ApiImplicitParam → @Parameter
@ApiImplicitParams → @Parameters
@ApiModel → @Schema
@ApiModelProperty(hidden = true) → @Schema(accessMode = READ_ONLY)
@ApiModelProperty → @Schema
@ApiOperation(value = "foo", notes = "bar") → @Operation(summary = "foo", description = "bar")
@ApiParam → @Parameter
@ApiResponse(code = 404, message = "foo") → @ApiResponse(responseCode = "404", description = "foo")
好了,关于springfox和springdoc引用后最终的效果如下:
3.Knife4j
有的人会觉得Swagger的页面比较难看,那么可以试试Knife4j,它是基于swagger2.0的版本,重写了Swagger的UI,因此目前还不支持OpenApi3.0的标准。
首先添加依赖:
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>
增加配置类
@Configuration
@EnableSwagger2
@EnableKnife4j
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
List<Parameter> aParameters = Lists.newArrayList();
return new Docket(DocumentationType.SWAGGER_2)
.globalOperationParameters(aParameters)
.apiInfo(apiInfo())
.groupName("业务处理")
.select()
.apis(RequestHandlerSelectors.basePackage("com.st.storyadmin"))
.paths(PathSelectors.any())
.build()
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
/**
* 登陆验证配置
* @return
*/
private List<ApiKey> securitySchemes() {
List<ApiKey> apiKeys = new ArrayList();
ApiKey apiKey = new ApiKey("Authorization", SecurityConsts.REQUEST_AUTH_HEADER, "header");
apiKeys.add(apiKey);
return apiKeys;
}
/**
* 登陆验证配置
* @return
*/
private List<SecurityContext> securityContexts() {
List<SecurityContext> securityContextList = new ArrayList();
SecurityContext securityContext = SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.any())
.build();
securityContextList.add(securityContext);
return securityContextList;
}
/**
* 登陆验证配置
* @return
*/
public List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
List<SecurityReference> securityReferenceList = new ArrayList<>();
securityReferenceList.add(new SecurityReference("Authorization", authorizationScopes));
return securityReferenceList;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Story-Admin系统RESTful APIs文档说明")
.description("相关接口构建RESTful APIs")
.termsOfServiceUrl("")
.version("1.0")
.build();
}
}
到这里就结束了,当然配置起来还是相对简单的,效果如下: