背景
新需求中需要实现动态生成API及文档的功能,生成API不说,但动态生成Restful风格的API一般没接触过,以往都是直接代码扫描产生文档的,这次需要进行研究
设计思想
首先在熟悉完整个OpenAPI设计规范及Swagger-UI后,设计起来没那么困难了,主要需要抓住两个关键点:
- 开源的Swagger-UI项目,是可以传入不同的json/yaml来展现不同的API文档的,这个网上挺多的,不展开
- 实现动态文档,就需要依托数据库进行存取,合理的拆解Swagger结构并存储会将问题简单化,例如将单独的json结构存放在MongoDB中
具体设计
主要POM
由于项目使用Spring Boot,所以主要有springfox-swagger2及swagger官方包组成
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.swagger/swagger-core -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-core</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.6.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
模型设计
这个其实在swagger-models包已经做好定义了,我们要做的只是new一个并使用,当然直接使用json也不是不可以,这里将Swagger拆分为(真正只有json字段部分有效):
- 主体:
{
"id": "aaa",
"name": "代码生成json",
"json": {
"swagger": "2.0",
"info": {
"contact": {
"name": "Wilson Support",
"url": "http://www.baidu.com",
"email": "support@wilson.com"
},
"description": "代码生成json",
"title": "我的Swagger REST API",
"version": "0.0.1"
},
"basePath": "/v1",
"host": "127.0.0.1:8080",
"schemes": ["http"]
}
}
- 标签:
{
"id": "1",
"swaggerId": "aaa",
"json": {"name": "tag1", "description": "test"}
}
- 具体API:
{
"id": "1",
"swaggerId": "aaa",
"json": {
"/users": {
"get": {
"summary": "查询用户",
"tags": ["tag1"],
"produces": ["application/json"],
"consumes": ["application/json],
"description": "。。。。。",
"responses": {
"200": {"description": "Success"},
"400": {"description": "Bad request"},
"401": {"description": "Unauthorized"},
"500": {"description": "Internal Server Error"},
"403": {"description": "Forbidden"},
"404": {"description": "Not found"}
},
"parameters": [{
"in": "query",
"name": "userName",
"description": "用户名称",
"type": "string",
"required": true
}]
}
}
}
}
- 模型描述:
{
"id": "1",
"swaggerId": "aaa",
"name": "返回结果",
"json": {
"resultDto": {
"properties": {
"msg": {
"default": "成功",
"type": "string"
},
"code": {
"default": "000000",
"type": "string"
},
"data": {
"type": "object"
}
}
}
}
}
拼接设计
拼接Swagger=主体+n标签+nAPI+n*模型,用swaggerId外键字段来匹配相应部分,这样,可以动态新增非主体部分
多源展示代码
demo使用的是springfox的ui,其实只是利用了springfox的SwaggerResourcesProvider,它能指定API文档的来源(你也可以直接用swagger-ui前端项目),下面是代码
/**
* Swagger多源配置
* <li>目标:保证启动后swagger-ui.html能展示来自不同类型的文档</li>
* <li>使用方式:配置后自动生效,一定要配置允许跨域</li>
* <li>现有bug:无</li>
* @author Wilson 2020/02/06
* @version 0.0.1
* @since 0.0.1
* @see SwaggerResource
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig extends WebMvcConfigurationSupport {
/**
* Swagger多源,体现在swagger-ui可列表选择不同swagger文档
* @param defaultResourcesProvider
* @return swagger资源生产者
*/
@Bean
@Primary
public SwaggerResourcesProvider swaggerResourcesProvider(InMemorySwaggerResourcesProvider defaultResourcesProvider) {
return () -> {
List<SwaggerResource> resourcesList = new ArrayList<>();
// 静态文件,存于resources文件夹下
SwaggerResource resource1 = new SwaggerResource();
resource1.setName("静态YML");
resource1.setSwaggerVersion("2.0");
resource1.setLocation("/swagger-api.yml");
resourcesList.add(resource1);
// 模拟数据库获取拼接的文档,请求见SwaggerController
SwaggerResource resource2 = new SwaggerResource();
resource2.setName("动态API");
resource2.setSwaggerVersion("2.0");
resource2.setLocation("/json");
resourcesList.add(resource2);
// 自身代码扫描生成的文档,默认路径http://localhost:8080/v2/api-docs
SwaggerResource resource3 = new SwaggerResource();
resource3.setName("自身");
resource3.setSwaggerVersion("2.0");
resource3.setLocation("/v2/api-docs");
resourcesList.add(resource3);
return resourcesList;
};
}
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.wilson.demo.swagger.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("springboot利用swagger构建api文档")
.description("简单优雅的restful风格")
.version("0.1")
.build();
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("/","classpath:/");
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
.maxAge(3600)
.allowCredentials(true);
}
}
代码Demo
- Github:https://github.com/wilsonyy/multi-swagger-demo
- Gitee:https://gitee.com/wilsonyan/multi-swagger-demo