手动拼接一个swagger

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>> security;
    private ExternalDocs externalDocs;
    private Boolean deprecated;

像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#toJsonio.swagger.util.Json#pretty(java.lang.Object)这个方法格式化输出为什么会少一个键目前原因未知,可能是序列化的配置原因。

你可能感兴趣的:(手动拼接一个swagger)