swagger是一个文档,openapi是一个规范,一般是根据openapi的规范,生成swagger实体类,即api文档。
现在流行的springboot,一般我们生成swagger,都是在controller中利用swagger提供的注解自动生成文档。
如果我们要自己手动构造一个swagger,该怎么做呢。
动手实践
引入依赖
首先引入swagger的依赖,版本是1.6.2
io.swagger
swagger-core
1.6.2
构造swagger
先看一下Swagger类中的一些变量
protected String swagger = "2.0";
protected Info info;
protected String host;
protected String basePath;
protected List tags;
protected List schemes;
protected List consumes;
protected List produces;
protected List security;
protected Map paths;
protected Map securityDefinitions;
protected Map definitions;
protected Map parameters;
protected Map responses;
protected ExternalDocs externalDocs;
protected Map vendorExtensions;
有这几个成员变量,一般我们需要展示的是info,host,basepath,tags,paths,definitions这几个属性。
另外parameters和responses是paths的子属性,consumes和produces是parameters的子属性。
Swagger为我们提供了一些方法来构建这些标签,方法返回的是this
Swagger swagger = new Swagger();
swagger.info()
.host()
.basePath()
.tags()
.paths();
swagger.setDefinitions();
如上几行代码就可以构建一个Swagger对象了,definitions需要调用set方法。
重点需要关注tags,paths,definitions这3个。
tags
先看一个tags示例
import io.swagger.models.Swagger;
import io.swagger.models.Tag;
import io.swagger.util.Json;
import java.util.ArrayList;
import java.util.List;
public static void main(String[] args) {
Swagger swagger = new Swagger();
List tags = new ArrayList<>();
Tag tag = new Tag();
tag.setName("basic-error-controller");
tag.setDescription("Basic Error Controller");
tags.add(tag);
swagger.tags(tags);
System.out.println(Json.pretty(swagger));
}
得到的swagger格式如下
{
"swagger" : "2.0",
"tags" : [ {
"name" : "basic-error-controller",
"description" : "Basic Error Controller"
} ]
}
Basic Error Controller是springmvc默认的异常处理器,如果写个springboot的demo,然后生成在线文档,会有这么个tag.
paths
paths是一个重要的属性,请求,响应的定义都会在这个属性里定义。
paths在Swagger中是用一个map来定义的,Map
其他的属性都在Path类中定义了,看一下path的成员变量
private Map vendorExtensions = new LinkedHashMap();
private Operation get;
private Operation put;
private Operation post;
private Operation head;
private Operation delete;
private Operation patch;
private Operation options;
private List parameters;
将http请求的method,get/post之类的定义成了Operation,我们来看一下Operation的成员变量
private Map vendorExtensions = new LinkedHashMap();
private List tags;
private String summary;
private String description;
private String operationId;
private List schemes;
private List consumes;
private List produces;
private List parameters = new ArrayList();
private Map responses;
private List
像tags,summary,description,operationId之类的都是一些描述信息。入参封装成了Parameter,响应封装成了Response.
Parameter是一个接口,根据不同的行为有不同的实现类,看一下Parameter的实现
- BodyParameter
- CookieParameter
- FormParameter
- HeaderParameter
- PathParameter
- QueryParameter
- RefParameter
定义了所有的参数位置,比如in query 参数是以query的形式传递,in path是以路径的方式传递,in body是放在request body里,in header是放在http header里。
Parameter和Response里都有一个schema的概念,这里的约束代表实体类的Model。
Model一共有4种类型
- ArrayModel 数组类型,参数是数组形式
- ComposedModel 组合类型
- ModelImpl 通用类型,一般是对象
- RefModel 引用类型,引用了别的实体类
然后有一个Property概念,是具体的属性类型,看一下具体的使用
io.swagger.models.Response#schema
@Deprecated
public Response schema(Property property) {
this.setSchema(property);
return this;
}
io.swagger.models.ArrayModel#items
public ArrayModel items(Property items) {
this.setItems(items);
return this;
}
Response对象的schema是需要传入Property的,ArrayModel的items入参也是Property。
以ArrayModel举例,传入的Property代表Array的属性,比如String,io.swagger.models.ArrayModel#items则代表了String[]。
Property有大概22种具体类型
- ArrayProperty
- BaseIntegerProperty
- BinaryProperty
- BooleanProperty
- ByteArrayProperty
- ComposedProperty
- DateProperty
- DateTimeProperty
- DecimalProperty
- DoubleProperty
- EmailProperty
- FileProperty
- FloatProperty
- IntegerProperty
- LongProperty
- MapProperty
- ObjectProperty
- PasswordProperty
- RefProperty
- StringProperty
- UUIDProperty
- UntypedProperty
Model和Property构成完整约束,Parameter代表参数,Response代表响应,一个完整的Operation对象就可以构建出来了。
看一个小例子
public static void main(String[] args) {
Map paths = new HashMap<>();
Path path = new Path();
paths.put("/abc",path);
Operation operation = new Operation();
Response response = new Response();
ModelImpl model = new ModelImpl();
model.additionalProperties(new RefProperty("Person"));
response.setResponseSchema(model);
MapProperty mapProperty = new MapProperty();
mapProperty.additionalProperties(new RefProperty("Person"));
response.setSchema(mapProperty);
operation.addResponse("200",response);
path.set("post",operation);
Swagger swagger = new Swagger();
swagger.paths(paths);
System.out.println(Json.pretty(swagger));
}
swagger输出如下
{
"swagger" : "2.0",
"paths" : {
"/abc" : {
"post" : {
"parameters" : [ ],
"responses" : {
"200" : {
"schema" : {
"type" : "object",
"additionalProperties" : {
"$ref" : "#/definitions/Person"
}
}
}
}
}
}
}
}
definitions
definitions代表实体类的定义,比如传入一个对象Person,Person对象会创建一个definitions。
definitions是个map
io.swagger.models.Swagger#setDefinitions
public void setDefinitions(Map definitions) {
this.definitions = definitions;
}
可以看出value是个Model类型,我们看一个小例子
public static void main(String[] args) {
Swagger swagger = new Swagger();
HashMap modelMap = new HashMap<>(16);
HashMap propertyMap1 = new HashMap<>(16);
ModelImpl model1 = new ModelImpl();
RefProperty refProperty = new RefProperty("User");
propertyMap1.put("user",refProperty);
propertyMap1.put("id",new StringProperty());
model1.setProperties(propertyMap1);
modelMap.put("General",model1);
ModelImpl model2 = new ModelImpl();
HashMap propertyMap2 = new HashMap<>(16);
propertyMap2.put("name",new StringProperty());
model2.setProperties(propertyMap2);
modelMap.put("User",model2);
swagger.setDefinitions(modelMap);
System.out.println(Json.pretty(swagger));
}
swagger格式化输出如下
{
"swagger" : "2.0",
"definitions" : {
"User" : {
"properties" : {
"name" : {
"type" : "string"
}
}
},
"General" : {
"properties" : {
"id" : {
"type" : "string"
},
"user" : {
"$ref" : "#/definitions/User"
}
}
}
}
}
格式化输出
格式化输出比较简单的就是使用swagger的工具类
io.swagger.util.Json#pretty(java.lang.Object)
Json.pretty(new Swagger);
不过这样会有一些问题
我们使用path的demo来试一下
public static void main(String[] args) {
Map paths = new HashMap<>(16);
Path path = new Path();
paths.put("/abc",path);
Operation operation = new Operation();
Response response = new Response();
RefModel model = new RefModel("User");
RefProperty refProperty = new RefProperty("User");
response.setResponseSchema(model);
response.setSchema(refProperty);
operation.addResponse("200",response);
path.set("post",operation);
Swagger swagger = new Swagger();
swagger.paths(paths);
System.out.println(Json.pretty(swagger));
}
swagger格式化输出
{
"swagger" : "2.0",
"paths" : {
"/abc" : {
"post" : {
"parameters" : [ ],
"responses" : {
"200" : {
"schema" : {
"$ref" : "#/definitions/User"
}
}
}
}
}
}
}
现在改成另一种格式化输出组件
public static void main(String[] args) {
Map paths = new HashMap<>(16);
Path path = new Path();
paths.put("/abc",path);
Operation operation = new Operation();
Response response = new Response();
RefModel model = new RefModel("User");
RefProperty refProperty = new RefProperty("User");
response.setResponseSchema(model);
response.setSchema(refProperty);
operation.addResponse("200",response);
path.set("post",operation);
Swagger swagger = new Swagger();
swagger.paths(paths);
//System.out.println(Json.pretty(swagger));
List modules = new ArrayList<>();
modules.add(new Swagger2JacksonModule());
JsonSerializer jsonSerializer = new JsonSerializer(modules);
System.out.println(JSON.toJSONString( jsonSerializer.toJson(swagger)));
}
swagger格式化输出如下
{
"swagger": "2.0",
"paths": {
"/abc": {
"post": {
"responses": {
"200": {
"schema": {
"$ref": "#/definitions/User",
"originalRef": "User"
},
"responseSchema": {
"$ref": "#/definitions/User",
"originalRef": "User"
}
}
}
}
}
}
}
2个输出对比的话,会发现io.swagger.util.Json#pretty(java.lang.Object)
这个方法的输出会少一个键:responseSchema
。
而springfox.documentation.spring.web.json.JsonSerializer#toJson
输出则会打印responseSchema
我们通常在springboot中集成swagger,最后输出就是用的springfox.documentation.spring.web.json.JsonSerializer#toJson
,io.swagger.util.Json#pretty(java.lang.Object)
这个方法格式化输出为什么会少一个键目前原因未知,可能是序列化的配置原因。