1. 程式人生 > >使用Swagger生成JAVA Mock Server(Springboot)程式碼

使用Swagger生成JAVA Mock Server(Springboot)程式碼

Swagger為我們提供了非常多的工具,其中最強的還要算這個程式碼的生成工具。在前後端分離的大環境下,前後端之間訂立的介面顯得尤為重要,介面在訂立之後變動的可能性已經很小,這就要求我們提前去設計介面,也就是我們為前端提供的API。

但是我們發現,在開發過程中訂立的介面壽命其實很短,這是一件非常嚴重的事情。因此Swagger為我們提供了另外一種比較優雅的方式:就是你先訂立介面,然後再去生成介面;也就是使用介面文件去生成程式碼,這是非常好的一種實踐方式。


Mock Server為我們解決下面的問題:
1、我們設計了API,但後臺還沒有開發完成;
2、因為網路等原因,導致直接呼叫真實的後臺API會很不穩定或者很耗時。

前期準備

先看下面文章,如何生成API文件,拿到文件後,我們才能生成Mock Server Code
SpringBoot中使用Swagger生成RESTful規範API文件
http://blog.csdn.net/a78270528/article/details/78506338

實現步驟:
1、訪問:http://localhost:8090/v2/api-docs,會返回介面的JSON資料,複製(文章最後有完整JSON程式碼)。



2、再開啟Swagger Editor(https://editor.swagger.io),也可以下載程式碼,在本地部署訪問。我們這裡使用線上方式,貼上剛剛複製的JSON,提示轉成YAML:



3、點選Generate Server,選擇spring,直接彈出下載程式碼。

4、解壓後,就是一個完整的Spring Boot工程,Import(Projects from Folder or Achive)到我們的MyEclipse:


5、這時候我們可以正常啟動專案,Swagger2SpringBoot,右鍵Run as..

6、這裡面推薦一個工具Postman,最好使用Chrome下的外掛方式安裝,單獨的Postman不支援中文。在Postman中訪問我們之前編寫的介面:


7、我們按照介面要求填寫了介面,傳送後返回HTTP請求415錯誤 – 不支援的媒體型別(Unsupported media type)


8、解決方法是去除Swagger生成介面的Consumes,讓其不限制請求型別:


9、修改後重啟專案,再次傳送請求,這回不是415了,變成了406錯誤(HTTP 406 Not acceptable,翻譯過來是“不能接收”),因為Swagger生成的程式碼介面,必須指定Accept:



10、所以們在傳送請求時在Headers中加入Accept: application/json,再次傳送請求,這回返回提200,終於成功了:


11、,但卻發現並沒有返回內容,BODY是空,原因是Swagger生成的Mock Server只能判斷介面是否呼叫成功,並不能返回需要的資料,如果需要返回一些假資料給前端進行測試,需要手動增加程式碼,我們在第4步時紅色框起來的兩個JAVA類,UserApi是對應的介面,UserApiController是介面實現,我們需要修改UserApiController中對應的介面實現,以返回資料:



12、這時我們再次傳送介面,返回如下:



到此,我們整個Mock Server的程式碼已經調通,部署並可以正常使用了。

為什麼406會報錯,又要我們指定Accept: application/json,這是Swagger的問題,我們需要整合Swagger的原始碼,修改swagger.js如下:
if (this.type === "POST" || this.type === "GET" || this.type === "PATCH") {
    if (this.opts.responseContentType) {
      responseContentType = this.opts.responseContentType;
    } else {
      responseContentType = "application/json";
    }
}

再在swagger-ui.js中替換這一行:
opts.responseContentType = $("div select[name=responseContentType]", $(this.el)).val();

替換成:

if($("div select[name=responseContentType]", $(this.el)).val() === undefined) { 
    opts.responseContentType = opts.parent.model.produces[0];
}
else {
    opts.responseContentType = $("div select[name=responseContentType]", $(this.el)).val();
}

這樣就從根本敢406報錯的問題,再請求時就不用加上Accept: application/json了。

下面附上介面的JSON檔案,僅供測試使用。

{
    "swagger": "2.0",
    "info": {
        "description": "2017.11.9上線版本",
        "version": "1.0",
        "title": "實戰指揮平臺--基礎資料API說明文件",
        "contact": {
            "name": "智慧消防研發部"
        }
    },
    "host": "127.0.0.1:8090",
    "basePath": "/",
    "tags": [
        {
            "name": "validator-controller",
            "description": "Validator Controller"
        },
        {
            "name": "user-controller",
            "description": "測試UserController"
        }
    ],
    "paths": {
        "/user": {
            "get": {
                "tags": [
                    "user-controller"
                ],
                "summary": "查詢個人資訊介面",
                "description": "查詢個人資訊介面",
                "operationId": "queryUsingGET",
                "consumes": [
                    "application/json"
                ],
                "produces": [
                    "*/*"
                ],
                "parameters": [
                    {
                        "name": "page",
                        "in": "query",
                        "description": "page",
                        "required": true,
                        "type": "integer",
                        "format": "int32"
                    },
                    {
                        "name": "count",
                        "in": "query",
                        "description": "count",
                        "required": true,
                        "type": "integer",
                        "format": "int32"
                    },
                    {
                        "name": "token",
                        "in": "header",
                        "description": "訪問憑證",
                        "required": true,
                        "type": "string"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/Demo"
                            }
                        }
                    },
                    "401": {
                        "description": "Unauthorized"
                    },
                    "403": {
                        "description": "Forbidden"
                    },
                    "404": {
                        "description": "Not Found"
                    }
                }
            },
            "post": {
                "tags": [
                    "user-controller"
                ],
                "summary": "增加個人資訊介面",
                "description": "增加個人資訊介面",
                "operationId": "insertUsingPOST",
                "consumes": [
                    "application/json"
                ],
                "produces": [
                    "*/*"
                ],
                "parameters": [
                    {
                        "in": "body",
                        "name": "name",
                        "description": "name",
                        "required": false,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    },
                    "201": {
                        "description": "Created"
                    },
                    "401": {
                        "description": "Unauthorized"
                    },
                    "403": {
                        "description": "Forbidden"
                    },
                    "404": {
                        "description": "Not Found"
                    }
                }
            }
        },
        "/validator/query": {
            "get": {
                "tags": [
                    "validator-controller"
                ],
                "summary": "query",
                "operationId": "queryUsingGET_1",
                "consumes": [
                    "application/json"
                ],
                "produces": [
                    "*/*"
                ],
                "parameters": [
                    {
                        "in": "body",
                        "name": "page",
                        "description": "page",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "format": "int32"
                        }
                    },
                    {
                        "name": "count",
                        "in": "query",
                        "description": "count",
                        "required": true,
                        "type": "integer",
                        "format": "int32"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/Demo"
                            }
                        }
                    },
                    "401": {
                        "description": "Unauthorized"
                    },
                    "403": {
                        "description": "Forbidden"
                    },
                    "404": {
                        "description": "Not Found"
                    }
                }
            }
        }
    },
    "definitions": {
        "Demo": {
            "type": "object",
            "properties": {
                "age": {
                    "type": "string"
                },
                "id": {
                    "type": "string"
                },
                "name": {
                    "type": "string"
                }
            }
        }
    }
}

API詳細說明:

作用範圍 API 使用位置
物件屬性 @ApiModelProperty 用在出入引數物件的欄位上
協議集描述 @Api 用於controller類上
協議描述 @ApiOperation 用在controller的方法上
Response集 @ApiResponses 用在controller的方法上
Response @ApiResponse 用在 @ApiResponses裡邊
非物件引數集 @ApiImplicitParams 用在controller的方法上
非物件引數描述 @ApiImplicitParam 用在@ApiImplicitParams的方法裡邊
描述返回物件的意義 @ApiModel 用在返回物件類上

@ApiImplicitParam

屬性 取值 作用
paramType 查詢引數型別
path 以地址的形式提交資料
query 直接跟引數完成自動對映賦值
body 以流的形式提交 僅支援POST
header 引數在request headers 裡邊提交
form 以form表單的形式提交 僅支援POST
dataType 引數的資料型別 只作為標誌說明,並沒有實際驗證
Long
String
name 接收引數名
value 接收引數的意義描述
required 引數是否必填
true 必填
false 非必填
defaultValue 預設值

以上就是使用Swagger搭建RESTful風格測試Mock Server,生成Springboot程式碼的全部過程,整個開發過程其實很簡單,但網路上的資料太少,經過不斷的踩坑,終於除錯成功。