1. 程式人生 > >通過swagger json一鍵解析為html頁面、匯出word和excel的解析演算法分享

通過swagger json一鍵解析為html頁面、匯出word和excel的解析演算法分享

寫在前面:

完全通過Spring Boot工程 Java程式碼,將swagger json 一鍵解析為html頁面、匯出word和execel的解析演算法,不需要任何網上那些類似於“SwaggerMarkup2”等外掛來實現。

由於業務需要,準備開發一個openapi開放平臺,類似於阿里巴巴的CSB雲服務匯流排專案,用於企業內外服務能力的打通和統一開放管理,提供獨特的跨環境服務級聯機制和常見協議適配支援,實現了對api介面的對外發布和訂閱稽核,讓企業內外都能夠更方便的使用到api介面。

其中需要實現一個核心功能,服務的匯入功能,通過swagger json將我們其他專案中已經寫好的介面一鍵匯入到這個api開放平臺並生成api介面詳情頁,那麼這就需要實現一個swagger json解析的操作。

下面馬上進入正題,本文主要也是分享一下,自己解析swagger json為html、word等功能的程式碼、思路以及介面。

頁面效果展示:

將下圖這樣的swagger json解析出一個個api介面詳情頁。

解析前:

 解析後:

通過json解析完可以顯示所有的介面資訊,如圖:

 這是單個介面的api詳情資訊,如下圖:

點選按鈕匯出api詳情頁為word的效果展示,如圖:

匯出word: 

Swagger Json格式詳解:

 

程式碼部分:

我這邊實現兩種思路,一是直接解析swagger json然後直接存入實體類生成為html,還要一種是建立好實體類以及資料庫表後,將swagger json解析入庫入表做持久化,再通過表中資料渲染到頁面上。

下面我是介紹的swagger json入庫入表再渲染為html的方案。

步驟大概是:首先定義好建好表,寫好實體類後,再開始實現swagger json解析的演算法。

實體類定義:

服務資源表:

@ApiModel(value = "服務資源表", description = "服務資源表")
public class ServiceResource implements Serializable{

/**
 * 程式序列化ID
 */
private static final long serialVersionUID=1L;
        
/**
 * 服務ID
 */
    
    @ApiModelProperty(value = "服務ID")
    private String id;
        
/**
 * 租戶
 */
    
    @ApiModelProperty(value = "租戶")
    private String gmtTenant;
        
/**
 * 建立時間
 */
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "建立時間")
    private Date gmtCreate;
    public Date getGmtCreate(){
            return gmtCreate==null?null:(Date) gmtCreate.clone();
            }

    public void setGmtCreate(Date gmtCreate){
            this.gmtCreate = gmtCreate==null?null:(Date) gmtCreate.clone();
            }
        
/**
 * 建立人
 */
    
    @ApiModelProperty(value = "建立人")
    private String gmtCreator;
        
/**
 * 建立人名稱
 */
    
    @ApiModelProperty(value = "建立人名稱")
    private String gmtCrtname;
        
/**
 * 最後修改時間
 */
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "最後修改時間")
    private Date gmtModified;
    public Date getGmtModified(){
            return gmtModified==null?null:(Date) gmtModified.clone();
            }

    public void setGmtModified(Date gmtModified){
            this.gmtModified = gmtModified==null?null:(Date) gmtModified.clone();
            }
        
/**
 * 最後修改人
 */
    
    @ApiModelProperty(value = "最後修改人")
    private String gmtModifiedby;
        
/**
 * 最後修改人名稱
 */
    
    @ApiModelProperty(value = "最後修改人名稱")
    private String gmtMfyname;
        
/**
 * 服務名稱
 */
    
    @ApiModelProperty(value = "服務名稱")
    private String serviceName;
        
/**
 * 請求地址
 */
    
    @ApiModelProperty(value = "請求地址")
    private String requestUrl;
        
/**
 * 請求方法
 */
    
    @ApiModelProperty(value = "請求方法")
    private String requestMethod;
        
/**
 * 請求格式
 */
    
    @ApiModelProperty(value = "請求型別")
    private String contentType;
        
/**
 * 返回型別
 */
    
    @ApiModelProperty(value = "返回型別")
    private String callContentType;
        
/**
 * 服務描述
 */
    
    @ApiModelProperty(value = "服務描述")
    private String serviceDesc;
        
/**
 * 服務版本
 */
    
    @ApiModelProperty(value = "服務版本")
    private String serviceVersion;
        
/**
 * 是否有效
 */
    
    @ApiModelProperty(value = "是否有效")
    private Integer isValid;
        
/**
 * 是否釋出
 */
    
    @ApiModelProperty(value = "是否釋出")
    private Integer isRelease;

    /**
     * 是否釋出
     */

    @ApiModelProperty(value = "是否需要授權訪問")
    private Integer isAuthorizedAccess;

    /**
     * 操作id
     */
    @ApiModelProperty(value = "操作id")
    private String operationId;

    private Integer isDelete;

    private String routeUuid;

    private String currentCatalogId;

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getGmtTenant() {
        return gmtTenant;
    }

    public void setGmtTenant(String gmtTenant) {
        this.gmtTenant = gmtTenant;
    }

    public String getGmtCreator() {
        return gmtCreator;
    }

    public void setGmtCreator(String gmtCreator) {
        this.gmtCreator = gmtCreator;
    }

    public String getGmtCrtname() {
        return gmtCrtname;
    }

    public void setGmtCrtname(String gmtCrtname) {
        this.gmtCrtname = gmtCrtname;
    }

    public String getGmtModifiedby() {
        return gmtModifiedby;
    }

    public void setGmtModifiedby(String gmtModifiedby) {
        this.gmtModifiedby = gmtModifiedby;
    }

    public String getGmtMfyname() {
        return gmtMfyname;
    }

    public void setGmtMfyname(String gmtMfyname) {
        this.gmtMfyname = gmtMfyname;
    }

    public String getServiceName() {
        if(!StringUtils.isEmpty(serviceName)){
            return serviceName.replaceAll(" ", "");
        }
        return serviceName;
    }

    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }

    public String getRequestUrl() {
        return requestUrl;
    }

    public void setRequestUrl(String requestUrl) {
        this.requestUrl = requestUrl;
    }

    public String getRequestMethod() {
        return requestMethod;
    }

    public void setRequestMethod(String requestMethod) {
        this.requestMethod = requestMethod;
    }

    public String getContentType() {
        return contentType;
    }

    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public String getCallContentType() {
        return callContentType;
    }

    public void setCallContentType(String callContentType) {
        this.callContentType = callContentType;
    }

    public String getServiceDesc() {
        return serviceDesc;
    }

    public void setServiceDesc(String serviceDesc) {
        this.serviceDesc = serviceDesc;
    }

    public String getServiceVersion() {
        return serviceVersion;
    }

    public void setServiceVersion(String serviceVersion) {
        this.serviceVersion = serviceVersion;
    }

    public Integer getIsValid() {
        return isValid;
    }

    public void setIsValid(Integer isValid) {
        this.isValid = isValid;
    }

    public Integer getIsRelease() {
        return isRelease;
    }

    public void setIsRelease(Integer isRelease) {
        this.isRelease = isRelease;
    }

    public Integer getIsAuthorizedAccess() {
        return isAuthorizedAccess;
    }

    public void setIsAuthorizedAccess(Integer isAuthorizedAccess) {
        this.isAuthorizedAccess = isAuthorizedAccess;
    }

    public String getOperationId() {
        return operationId;
    }

    public void setOperationId(String operationId) {
        this.operationId = operationId;
    }

    public Integer getIsDelete() {
        return isDelete;
    }

    public void setIsDelete(Integer isDelete) {
        this.isDelete = isDelete;
    }

    public String getRouteUuid() {
        return routeUuid;
    }

    public void setRouteUuid(String routeUuid) {
        this.routeUuid = routeUuid;
    }

    public String getCurrentCatalogId() {
        return currentCatalogId;
    }

    public void setCurrentCatalogId(String currentCatalogId) {
        this.currentCatalogId = currentCatalogId;
    }
}
服務資源表

服務請求資訊表:

@Data
@ApiModel(value = "服務請求資訊表", description = "服務請求資訊表")
public class ServiceRequest implements Serializable{

/**
 * 程式序列化ID
 */
private static final long serialVersionUID=1L;
        
/**
 * 服務ID
 */
    
    @ApiModelProperty(value = "服務ID")
    private String id;
        
/**
 * 租戶
 */
    
    @ApiModelProperty(value = "租戶")
    private String gmtTenant;
        
/**
 * 建立時間
 */
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "建立時間")
    private Date gmtCreate;
    public Date getGmtCreate(){
            return gmtCreate==null?null:(Date) gmtCreate.clone();
            }

    public void setGmtCreate(Date gmtCreate){
            this.gmtCreate = gmtCreate==null?null:(Date) gmtCreate.clone();
            }
        
/**
 * 建立人
 */
    
    @ApiModelProperty(value = "建立人")
    private String gmtCreator;
        
/**
 * 建立人名稱
 */
    
    @ApiModelProperty(value = "建立人名稱")
    private String gmtCrtname;
        
/**
 * 最後修改時間
 */
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "最後修改時間")
    private Date gmtModified;
    public Date getGmtModified(){
            return gmtModified==null?null:(Date) gmtModified.clone();
            }

    public void setGmtModified(Date gmtModified){
            this.gmtModified = gmtModified==null?null:(Date) gmtModified.clone();
            }
        
/**
 * 最後修改人
 */
    
    @ApiModelProperty(value = "最後修改人")
    private String gmtModifiedby;
        
/**
 * 最後修改人名稱
 */
    
    @ApiModelProperty(value = "最後修改人名稱")
    private String gmtMfyname;
        
/**
 * 服務資源ID
 */
    
    @ApiModelProperty(value = "服務資源ID")
    private String serviceId;
        
/**
 * 引數名稱
 */
    
    @ApiModelProperty(value = "引數名稱")
    private String reqName;
        
/**
 * 引數描述
 */
    
    @ApiModelProperty(value = "引數描述")
    private String reqDesc;
        
/**
 * 引數型別
 */
    
    @ApiModelProperty(value = "引數型別")
    private String reqType;
        
/**
 * 引數長度
 */
    
    @ApiModelProperty(value = "引數長度")
    private Integer reqLength;
        
/**
 * 是否必填
 */
    
    @ApiModelProperty(value = "是否必填")
    private Integer isRequired;
        
/**
 * 引數來源
 */
    
    @ApiModelProperty(value = "引數來源")
    private String reqFrom;

}
View Code

服務響應資訊表:

@Data
@ApiModel(value = "服務響應資訊表", description = "服務響應資訊表")
public class ServiceResponse implements Serializable{

/**
 * 程式序列化ID
 */
private static final long serialVersionUID=1L;
        
/**
 * 服務ID
 */
    
    @ApiModelProperty(value = "服務ID")
    private String id;
        
/**
 * 租戶
 */
    
    @ApiModelProperty(value = "租戶")
    private String gmtTenant;
        
/**
 * 建立時間
 */
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "建立時間")
    private Date gmtCreate;
    public Date getGmtCreate(){
            return gmtCreate==null?null:(Date) gmtCreate.clone();
            }

    public void setGmtCreate(Date gmtCreate){
            this.gmtCreate = gmtCreate==null?null:(Date) gmtCreate.clone();
            }
        
/**
 * 建立人
 */
    
    @ApiModelProperty(value = "建立人")
    private String gmtCreator;
        
/**
 * 建立人名稱
 */
    
    @ApiModelProperty(value = "建立人名稱")
    private String gmtCrtname;
        
/**
 * 最後修改時間
 */
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "最後修改時間")
    private Date gmtModified;
    public Date getGmtModified(){
            return gmtModified==null?null:(Date) gmtModified.clone();
            }

    public void setGmtModified(Date gmtModified){
            this.gmtModified = gmtModified==null?null:(Date) gmtModified.clone();
            }
        
/**
 * 最後修改人
 */
    
    @ApiModelProperty(value = "最後修改人")
    private String gmtModifiedby;
        
/**
 * 最後修改人名稱
 */
    
    @ApiModelProperty(value = "最後修改人名稱")
    private String gmtMfyname;
        
/**
 * 服務資源ID
 */
    
    @ApiModelProperty(value = "服務資源ID")
    private String serviceId;
        
/**
 * 屬性名稱
 */
    
    @ApiModelProperty(value = "屬性名稱")
    private String propName;
        
/**
 * 屬性描述
 */
    
    @ApiModelProperty(value = "屬性描述")
    private String propDesc;
        
/**
 * 屬性型別
 */
    
    @ApiModelProperty(value = "屬性型別")
    private String propType;
        
/**
 * 屬性長度
 */
    
    @ApiModelProperty(value = "屬性長度")
    private Integer propLength;
    
}
View Code

服務響應狀態表:

@Data
@ApiModel(value = "服務響應狀態表", description = "服務響應狀態表")
public class ResponseStatus implements Serializable{

/**
 * 程式序列化ID
 */
private static final long serialVersionUID=1L;
        
/**
 * 服務ID
 */
    
    @ApiModelProperty(value = "服務ID")
    private String id;
        
/**
 * 租戶
 */
    
    @ApiModelProperty(value = "租戶")
    private String gmtTenant;
        
/**
 * 建立時間
 */
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "建立時間")
    private Date gmtCreate;
    public Date getGmtCreate(){
            return gmtCreate==null?null:(Date) gmtCreate.clone();
            }

    public void setGmtCreate(Date gmtCreate){
            this.gmtCreate = gmtCreate==null?null:(Date) gmtCreate.clone();
            }
        
/**
 * 建立人
 */
    
    @ApiModelProperty(value = "建立人")
    private String gmtCreator;
        
/**
 * 建立人名稱
 */
    
    @ApiModelProperty(value = "建立人名稱")
    private String gmtCrtname;
        
/**
 * 最後修改時間
 */
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "最後修改時間")
    private Date gmtModified;
    public Date getGmtModified(){
            return gmtModified==null?null:(Date) gmtModified.clone();
            }

    public void setGmtModified(Date gmtModified){
            this.gmtModified = gmtModified==null?null:(Date) gmtModified.clone();
            }
        
/**
 * 最後修改人
 */
    
    @ApiModelProperty(value = "最後修改人")
    private String gmtModifiedby;
        
/**
 * 最後修改人名稱
 */
    
    @ApiModelProperty(value = "最後修改人名稱")
    private String gmtMfyname;
        
/**
 * 服務資源ID
 */
    
    @ApiModelProperty(value = "服務資源ID")
    private String serviceId;
        
/**
 * 狀態碼
 */
    
    @ApiModelProperty(value = "狀態碼")
    private String statusCode;
        
/**
 * 狀態描述
 */
    
    @ApiModelProperty(value = "狀態描述")
    private String statusDesc;

    /**
     * 狀態說明
     */

    @ApiModelProperty(value = "狀態說明")
    private String statusRemark;
}
View Code

服務類別表:

@ApiModel(value = "服務類別表", description = "服務類別表")
public class ServiceCatalog implements Serializable{

/**
 * 程式序列化ID
 */
private static final long serialVersionUID=1L;
        
/**
 * 服務ID
 */
    
    @ApiModelProperty(value = "服務ID")
    private String id;
        
/**
 * 租戶
 */
    
    @ApiModelProperty(value = "租戶")
    private String gmtTenant;
        
/**
 * 建立時間
 */
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "建立時間")
    private Date gmtCreate;
    public Date getGmtCreate(){
            return gmtCreate==null?null:(Date) gmtCreate.clone();
            }

    public void setGmtCreate(Date gmtCreate){
            this.gmtCreate = gmtCreate==null?null:(Date) gmtCreate.clone();
            }
        
/**
 * 建立人
 */
    
    @ApiModelProperty(value = "建立人")
    private String gmtCreator;
        
/**
 * 建立人名稱
 */
    
    @ApiModelProperty(value = "建立人名稱")
    private String gmtCrtname;
        
/**
 * 最後修改時間
 */
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "最後修改時間")
    private Date gmtModified;
    public Date getGmtModified(){
            return gmtModified==null?null:(Date) gmtModified.clone();
            }

    public void setGmtModified(Date gmtModified){
            this.gmtModified = gmtModified==null?null:(Date) gmtModified.clone();
            }
        
/**
 * 最後修改人
 */
    
    @ApiModelProperty(value = "最後修改人")
    private String gmtModifiedby;
        
/**
 * 最後修改人名稱
 */
    
    @ApiModelProperty(value = "最後修改人名稱")
    private String gmtMfyname;
        
/**
 * 上級目錄ID
 */
    
    @ApiModelProperty(value = "上級目錄ID")
    private String pid;
        
/**
 * 目錄名稱
 */
    
    @ApiModelProperty(value = "目錄名稱")
    private String catalogName;



    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getGmtTenant() {
        return gmtTenant;
    }

    public void setGmtTenant(String gmtTenant) {
        this.gmtTenant = gmtTenant;
    }

    public String getGmtCreator() {
        return gmtCreator;
    }

    public void setGmtCreator(String gmtCreator) {
        this.gmtCreator = gmtCreator;
    }

    public String getGmtCrtname() {
        return gmtCrtname;
    }

    public void setGmtCrtname(String gmtCrtname) {
        this.gmtCrtname = gmtCrtname;
    }

    public String getGmtModifiedby() {
        return gmtModifiedby;
    }

    public void setGmtModifiedby(String gmtModifiedby) {
        this.gmtModifiedby = gmtModifiedby;
    }

    public String getGmtMfyname() {
        return gmtMfyname;
    }

    public void setGmtMfyname(String gmtMfyname) {
        this.gmtMfyname = gmtMfyname;
    }

    public String getPid() {
        return pid;
    }

    public void setPid(String pid) {
        this.pid = pid;
    }

    public String getCatalogName() {
        if(!StringUtils.isEmpty(catalogName)){
            return catalogName.replaceAll(" ", "");
        }
        return catalogName;
    }

    public void setCatalogName(String catalogName) {
        this.catalogName = catalogName;
    }
}
View Code

服務類別關係表:

@Data
@ApiModel(value = "服務類別關係表", description = "服務類別關係表")
public class ServiceCatalogRela implements Serializable{

/**
 * 程式序列化ID
 */
private static final long serialVersionUID=1L;
        
/**
 * 服務ID
 */
    
    @ApiModelProperty(value = "服務ID")
    private String id;
        
/**
 * 租戶
 */
    
    @ApiModelProperty(value = "租戶")
    private String gmtTenant;
        
/**
 * 建立時間
 */
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "建立時間")
    private Date gmtCreate;
    public Date getGmtCreate(){
            return gmtCreate==null?null:(Date) gmtCreate.clone();
            }

    public void setGmtCreate(Date gmtCreate){
            this.gmtCreate = gmtCreate==null?null:(Date) gmtCreate.clone();
            }
        
/**
 * 建立人
 */
    
    @ApiModelProperty(value = "建立人")
    private String gmtCreator;
        
/**
 * 建立人名稱
 */
    
    @ApiModelProperty(value = "建立人名稱")
    private String gmtCrtname;
        
/**
 * 最後修改時間
 */
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "最後修改時間")
    private Date gmtModified;
    public Date getGmtModified(){
            return gmtModified==null?null:(Date) gmtModified.clone();
            }

    public void setGmtModified(Date gmtModified){
            this.gmtModified = gmtModified==null?null:(Date) gmtModified.clone();
            }
        
/**
 * 最後修改人
 */
    
    @ApiModelProperty(value = "最後修改人")
    private String gmtModifiedby;
        
/**
 * 最後修改人名稱
 */
    
    @ApiModelProperty(value = "最後修改人名稱")
    private String gmtMfyname;
        
/**
 * 目錄ID
 */
    
    @ApiModelProperty(value = "目錄ID")
    private String catalogId;
        
/**
 * 服務ID
 */
    
    @ApiModelProperty(value = "服務ID")
    private String serviceId;
    
}
View Code

服務返回屬性:

@Data
public class SwaggerModelAttr implements Serializable {

    private static final long serialVersionUID = -4074067438450613643L;

    /**
     * 類名
     */
    private String className = StringUtils.EMPTY;
    /**
     * 屬性名
     */
    private String name = StringUtils.EMPTY;
    /**
     * 型別
     */
    private String type = StringUtils.EMPTY;
    /**
     * 屬性描述
     */
    private String description;
    /**
     * 巢狀屬性列表
     */
    private List<SwaggerModelAttr> properties = new ArrayList<>();
}
View Code

返回給前端的dto實體:

/**
 * @program: share-capacity-platform
 * @description: javabean轉html 傳遞給前端的dto實體類
 * @author: liumingyu
 * @date: 2020-04-14 16:35
 **/
@Data
public class SwaggerHtmlDto {

    /**
     * 大標題
     */
    private String title;

    /**
     * 小標題
     */
    private String tag;

    /**
     * 版本
     */
    private String version;

    /**
     * 封裝服務資源
     */
    private ServiceResource serviceResource;

    /**
     * 封裝請求引數list
     */
    private List<ServiceRequest> requestList;

    /**
     * 封裝響應狀態碼list
     */
    private List<ResponseStatus> responseStatusList;

    /**
     * 封裝返回屬性list
     */
    private List<ServiceResponse> responseList;
}
View Code

實體類就是以上這些,將swagger json解析後存入相應的實體類欄位中。

swagger解析程式碼:

下面開始swagger json的解析程式碼:

swagger解析service層介面:

public interface SwaggerJsonImportService {

    /**
     * swaggerJson匯入業務表
     *
     * @param jsonUrl        jsonUrl
     * @param serviceSwagger swaggerJson
     * @param isAuthorized   是否需要授權訪問
     * @return net.evecom.scplatform.common.entry.CommonResp<java.lang.String>
     * @throws IOException
     * @Author Torres Liu
     * @Description //TODO swaggerJson匯入業務表
     * @Date 2020/4/24 5:07 下午
     * @Param [jsonUrl, serviceSwagger, isAuthorized]
     **/
    CommonResp<String> swaggerJsonImport(String jsonUrl, ServiceSwagger serviceSwagger, String isAuthorized) throws IOException;

    /**
     * 匯出SwaggerJson
     *
     * @param serviceId 服務id
     * @param catalogId 目錄id
     * @return net.evecom.scplatform.common.entry.CommonResp<java.lang.String>
     * @Author Torres Liu
     * @Description //TODO 匯出SwaggerJson
     * @Date 2020/4/22 9:41 上午
     * @Param [serviceId, catalogId]
     **/
    List<SwaggerHtmlDto> swaggerJsonExport(String serviceId, String catalogId);
}
View Code

swagger解析service層介面實現類(解析的核心程式碼)

下面是一大堆枯燥的json解析,大家都是程式設計師,我就不做過多的講解程式碼,有需要學習的可以參照我程式碼中的註釋,寫的都比較詳細。

package xxxxxxxx;

import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSON;

import lombok.extern.slf4j.Slf4j;
import net.evecom.scplatform.common.entry.CommonResp;
import net.evecom.scplatform.common.entry.system.CommonEntry;
import net.evecom.scplatform.common.entry.system.UserUtil;
import net.evecom.scplatform.common.utils.text.IDUtils;
import net.evecom.scplatform.openapi.dao.*;
import net.evecom.scplatform.openapi.entity.*;
import net.evecom.scplatform.openapi.entity.dto.SwaggerHtmlDto;
import net.evecom.scplatform.openapi.service.SwaggerJsonImportService;
import net.evecom.scplatform.openapi.util.SwaggerJsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author Torres Liu
 * @description //TODO 服務匯入/匯出 業務層
 * @date 2020-04-10 14:06 下午
 **/
@SuppressWarnings({"unchecked", "rawtypes"})
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class SwaggerJsonImportServiceImpl implements SwaggerJsonImportService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ServiceCatalogDao serviceCatalogDao;

    @Autowired
    private ServiceResourceDao serviceResourceDao;

    @Autowired
    private ServiceRequestDao serviceRequestDao;

    @Autowired
    private ResponseStatusDao responseStatusDao;

    @Autowired
    private ServiceResponseDao serviceResponseDao;

    @Autowired
    private ServiceCatalogRelaDao serviceCatalogRelaDao;

    @Value("${kong.server-addr}")
    private String kongServerAddr;

    /**
     * array
     */
    private static final String ARRAY_VAL = "array";
    /**
     * $ref
     */
    private static final String REF_VAL = "$ref";
    /**
     * format
     */
    private static final String FORMAT_VAL = "format";
    /**
     * schema
     */
    private static final String SCHEMA_VAL = "schema";
    /**
     * 成功的code
     */
    private static final int SUCCESS_CODE = 200;
    /**
     * 遞迴次數
     */
    private static final int RECURSION_NUMS = 199;

    /**
     * 通過JSON或URL匯入服務
     *
     * @param jsonUrl
     * @param serviceSwagger
     * @param isAuthorized
     * @return net.evecom.scplatform.common.entry.CommonResp<java.lang.String>
     * @author Torres Liu
     * @description //TODO 通過JSON或URL匯入服務
     * @date 2020/4/24 5:46 下午
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResp<String> swaggerJsonImport(String jsonUrl, ServiceSwagger serviceSwagger, String isAuthorized) throws IOException {
        String jsonStr = "";
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        //提前生成 一級標題的id欄位 by liumingyu
        String firstTitleUuid = IDUtils.new32UUID();
        //獲取前端傳入的是否授權標識 by liumingyu
        String isAuthorizedAccessStr = StringUtils.defaultIfBlank(isAuthorized, "0");
        Integer isAuthorizedAccess = Integer.valueOf(isAuthorizedAccessStr);
        try {
            //判斷是通過url or json傳入資料 by liumingyu
            if (!StringUtils.isBlank(jsonUrl) && "".equals(serviceSwagger.getSwaggerJson())) {
                //判斷url的有效性
                boolean urlValidity = ifUrlValidity(jsonUrl);
                //判斷url是否是swagger的url
                boolean swaggerUrl = ifSwaggerUrl(jsonUrl);
                if (urlValidity && swaggerUrl) {
                    HttpGet httpGet = new HttpGet(jsonUrl);
                    CloseableHttpResponse response = httpClient.execute(httpGet);
                    if (response.getStatusLine().getStatusCode() == SUCCESS_CODE) {
                        HttpEntity entity = response.getEntity();
                        String string = EntityUtils.toString(entity, "utf-8");
                        jsonStr = string;
                    }
                    response.close();
                    httpClient.close();
                } else {
                    return CommonResp.exception("傳入的url不正確!");
                }
            } else if (serviceSwagger != null && !"".equals(serviceSwagger.getSwaggerJson())) {
                String swaggerJson = serviceSwagger.getSwaggerJson();
                //判斷字串是否為json格式
                boolean isJson = isJson(swaggerJson);
                if (isJson) {
                    JSONObject jsonObject = new JSONObject(swaggerJson);
                    Object o = JSON.toJSON(jsonObject);
                    jsonStr = com.alibaba.fastjson.JSONObject.toJSONString(o);
                } else {
                    return CommonResp.exception("傳入的json格式不正確!");
                }
            } else {
                return CommonResp.exception("服務匯入URL或JSON出錯!");
            }
            //獲取當前租戶
            String gmtTenant = UserUtil.getLoginUser().getGmtTenant();
            //獲取當前使用者id
            String userId = UserUtil.getLoginUser().getId();
            String gmtCreator = (userId != null) ? userId : "";
            //轉換 JSON string to Map by liumingyu
            Map<String, Object> map = SwaggerJsonUtils.readValue(jsonStr, HashMap.class);
            //解析info by liumingyu
            Map<String, Object> infoMap = (Map<String, Object>) map.get("info");
            //拿到一級標題 by liumingyu
            String catalogName = (String) infoMap.get("title");
            //拿到所有二級標題(類標題)的List by liumingyu
            List<Map<String, String>> tags = (List<Map<String, String>>) map.get("tags");
            //如果表中沒有該一級標題名稱,需要新增一個 by liumingyu
            if (catalogName != null) {
                //查詢庫中是否有當前登入使用者且pid為-1的根目錄
                ServiceCatalog catalogBeanByCreatorAndPid = serviceCatalogDao.findByCreatorAndPid(gmtCreator, "-1");
                //查詢庫中是否存在該一級標題名稱 by liumingyu
                ServiceCatalog catalogBean = serviceCatalogDao.findByCatalogNameAndCreator(gmtCreator, catalogName);
                //若不存在該標題名稱,新增一級目錄和二級目錄 by liumingyu
                //1.插入一級二級標題資料到服務目錄表 by liumingyu
                if (catalogBean == null && catalogBeanByCreatorAndPid != null) {
                    ServiceCatalog serviceCatalog = new ServiceCatalog();
                    serviceCatalog.setId(firstTitleUuid);
                    //將根目錄id作為一級目錄的pid
                    serviceCatalog.setPid(catalogBeanByCreatorAndPid.getId());
                    serviceCatalog.setCatalogName(catalogName);
                    serviceCatalogDao.add(serviceCatalog);
                    //新增二級標題(目錄)by liumingyu
                    addTags(tags, firstTitleUuid, gmtTenant, gmtCreator);
                } else {
                    //存在的話只要新增二級標題 by liumingyu
                    //拿到該一級目錄的id by liumingyu
                    if (catalogBean != null && catalogBean.getId() != null) {
                        String fatherId = catalogBean.getId();
                        //新增二級標題(目錄)by liumingyu
                        addTags(tags, fatherId, gmtTenant, gmtCreator);
                    }
                }
            }
            //解析model by liumingyu
            Map<String, SwaggerModelAttr> definitinMapOld = parseDefinitions(map);
            Map<String, Map<String, Object>> definitinMap = newParseDefinitions(map);
            //獲取服務版本(取得是一級info的版本號)by liumingyu
            String version = (String) infoMap.get("version");
            //解析paths by liumingyu
            Map<String, Map<String, Object>> paths = (Map<String, Map<String, Object>>) map.get("paths");
            //解析bashPath by liumingyu
            String basePath = (String) map.get("basePath");
            String[] basePathSplit = null;
            if (basePath != null && !"".equals(basePath)) {
                basePathSplit = basePath.split(",");
            }
            if (paths != null) {
                //通過entrySet()取出對映關係,iterator()迭代,存放到迭代器中 by liumingyu
                Iterator<Map.Entry<String, Map<String, Object>>> it = paths.entrySet().iterator();
                //開始遍歷paths by liumingyu
                while (it.hasNext()) {
                    //拿到單個path的資料資訊,用map的Entry物件存起來 by liumingyu
                    Map.Entry<String, Map<String, Object>> path = it.next();
                    Iterator<Map.Entry<String, Object>> it2 = path.getValue().entrySet().iterator();
                    //請求url by liumingyu
                    String requestUrl = "";
                    if (basePathSplit.length > 0 && !"/".equals(basePathSplit[0])) {
                        //拼接 bashPath + url by liumingyu
                        requestUrl = kongServerAddr + basePathSplit[0] + path.getKey();
                    } else {
                        requestUrl = kongServerAddr + path.getKey();
                    }
                    while (it2.hasNext()) {
                        Map.Entry<String, Object> it2Request = it2.next();
                        //請求方法 GET / POST 等等 by liumingyu
                        String requestMethod = it2Request.getKey().toUpperCase();
                        //拿到某個介面(服務)的具體資料 by liumingyu
                        Map<String, Object> content = (Map<String, Object>) it2Request.getValue();
                        //服務名稱 by liumingyu
                        String serviceName = String.valueOf(content.get("summary"));
                        //該服務的操作id by liumingyu
                        String operationId = String.valueOf(content.get("operationId"));
                        //請求體 by liumingyu
                        List<LinkedHashMap> parametersList = (ArrayList) content.get("parameters");
                        //響應Code體 by liumingyu
                        Map<String, Object> responsesList = (Map<String, Object>) content.get("responses");
                        //服務描述 by liumingyu
                        String serviceDesc = "";
                        String description = String.valueOf(content.get("description"));

                        if (!"".equals(description) && description != null) {
                            serviceDesc = description;
                        }
                        //請求引數格式,類似於 multipart/form-data by liumingyu
                        String contentType = "";
                        List<String> consumes = (List) content.get("consumes");
                        if (consumes != null && consumes.size() > 0) {
                            contentType = StringUtils.join(consumes, ",");
                        }
                        //返回引數格式,類似於 application/json by liumingyu
                        String callContentType = "";
                        List<String> produces = (List) content.get("produces");
                        List<String> newProduces = new ArrayList<>();
                        for (String produce : produces) {
                            String newProduce = "";
                            if ("*/*".equals(produce) || "".equals(produce)) {
                                newProduce = "application/json";
                            } else {
                                newProduce = produce;
                            }
                            newProduces.add(newProduce);
                        }
                        if (newProduces != null && newProduces.size() > 0) {
                            callContentType = StringUtils.join(newProduces, ",");
                        }
                        //服務版本預設為1.0 by liumingyu
                        String serviceVersion = "1.0";
                        serviceVersion = StringUtils.defaultIfBlank(version, serviceVersion);
                        //查詢當前庫中是否存在operationId和服務名稱,如果存在 後續所有資料不會進行新增 by liumingyu
                        List<ServiceResource> listByOperationId = serviceResourceDao.findByOperationId(operationId, serviceName, userId);
                        //若operationId不存在庫中====>才進行後續的新增操作 by liumingyu
                        if (listByOperationId.size() == 0) {
                            //封裝serviceResource表 by liumingyu
                            ServiceResource resourceTable = new ServiceResource();
                            //宣告一個uuid 作為本輪遍歷的resource表主鍵id,也是本輪遍歷其他表對應的serviceId by liumingyu
                            String thisResourceId = IDUtils.new32UUID();
                            resourceTable.setId(thisResourceId);
                            resourceTable.setServiceName(serviceName);
                            resourceTable.setServiceDesc(serviceDesc);
                            resourceTable.setRequestUrl(requestUrl);
                            resourceTable.setRequestMethod(requestMethod);
                            resourceTable.setContentType(contentType);
                            resourceTable.setCallContentType(callContentType);
                            resourceTable.setServiceVersion(serviceVersion);
                            resourceTable.setIsValid(1);
                            resourceTable.setIsRelease(0);
                            resourceTable.setIsDelete(0);
                            resourceTable.setRouteUuid(UUID.randomUUID().toString());
                            //前端傳入--->是否授權標識 by liumingyu
                            resourceTable.setIsAuthorizedAccess(isAuthorizedAccess);
                            //新增操作id by liumingyu
                            resourceTable.setOperationId(operationId);
                            //2.新增資料到serviceResource表 by liumingyu
                            serviceResourceDao.add(resourceTable);

                            //處理parametersList資料轉為ServiceRequest表List物件 by liumingyu
                            List<ServiceRequest> serviceRequestList = processRequestList(parametersList, definitinMap);
                            //3.新增資料到serviceRequest表 by liumingyu
                            addServiceRequest(serviceRequestList, thisResourceId, gmtTenant);

                            //處理responsesList資料轉為ResponseStatus表List物件 by liumingyu
                            List<ResponseStatus> responseStatusList = processResponseStatusList(responsesList, definitinMap);
                            //4.新增資料到ResponseStatus表 by liumingyu
                            addResponseStatus(responseStatusList, thisResourceId, gmtTenant);

                            //取出來狀態是200時的返回值 by liumingyu
                            Map<String, Object> responsesObj = (Map<String, Object>) responsesList.get("200");
                            if (responsesObj != null && responsesObj.get(SCHEMA_VAL) != null) {
                                //處理相應的返回值 by liumingyu
                                SwaggerModelAttr swaggerModelAttr = processResponseModelAttrs(responsesObj, definitinMapOld);
                                //拿到properties資料,這個List裡面就是需要的返回值資料 by liumingyu
                                List<SwaggerModelAttr> propertiesList = swaggerModelAttr.getProperties();
                                //5.新增資料到ServiceResponse表(傳遞propertiesList和主表的id) by liumingyu
                                addServiceResponse(propertiesList, thisResourceId, gmtTenant);
                            }

                            //操作服務類別關係表(目錄和服務關係表) by liumingyu
                            String tagsName = String.valueOf(((List) content.get("tags")).get(0));
                            //6.新增資料到目錄關係表 by liumingyu
                            addCatalogRela(tagsName, thisResourceId, gmtCreator);
                        } else {
                            log.info("迭代器當前執行到的物件operationId「" + operationId + "」已存在資料庫中,不進行插入");
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("服務匯入失敗", e);
            return CommonResp.exception("服務匯入失敗");
        }
        return CommonResp.succeed("服務匯入成功!");
    }

    /**
     * 服務匯出Json
     *
     * @param serviceId
     * @param catalogId
     * @return java.util.List<net.evecom.scplatform.openapi.entity.dto.SwaggerHtmlDto>
     * @author Torres Liu
     * @description //TODO 服務匯出Json
     * @date 2020/4/24 5:50 下午
     **/
    @Override
    public List<SwaggerHtmlDto> swaggerJsonExport(String serviceId, String catalogId) {
        String titleName = "";
        List<SwaggerHtmlDto> result = new ArrayList<>();
        try {
            if (serviceId != null && !"".equals(serviceId)) {
                SwaggerHtmlDto thisDto = new SwaggerHtmlDto();
                //根據serviceId查詢所需資料
                ServiceResource resourceTable = serviceResourceDao.findById(serviceId);
                List<ServiceRequest> requestList = serviceRequestDao.findByServiceId(serviceId);
                List<ResponseStatus> responseStatusList = responseStatusDao.findByServiceId(serviceId);
                List<ServiceResponse> serviceResponseList = serviceResponseDao.findByServiceId(serviceId);
                ServiceCatalog thisCatalogBean = serviceCatalogDao.findById(catalogId == null ? "" : catalogId);

                //將資料set到自定義封裝的dto實體中
                thisDto.setServiceResource(resourceTable);
                thisDto.setRequestList(requestList);
                thisDto.setResponseStatusList(responseStatusList);
                thisDto.setResponseList(serviceResponseList);
                //宣告一個標題名

                titleName = resourceTable.getServiceName();
                if (thisCatalogBean != null) {
                    thisDto.setTag(thisCatalogBean.getCatalogName());
                    titleName = thisCatalogBean.getCatalogName() + "-" + titleName;
                    String thisCatalogPid = thisCatalogBean.getPid();
                    ServiceCatalog pidBean = serviceCatalogDao.findById(thisCatalogPid);
                    if (pidBean != null) {
                        thisDto.setTitle(pidBean.getCatalogName());
                        titleName = pidBean.getCatalogName() + "-" + titleName;
                    }
                }
                thisDto.setVersion(resourceTable.getServiceVersion());
                //將所有資料add至result
                result.add(thisDto);
                return result;
            }
        } catch (Exception e) {
            log.error("服務匯出異常:", e);
        }
        return result;
    }


    /**
     * @param tags
     * @param pid
     * @param gmtTenant
     * @return void
     * @author Torres Liu
     * @description //TODO 將json的二級標題,新增至目錄表作為二級目錄,pid為一級目錄id
     * @date 2020/4/24 5:52 下午
     **/
    private void addTags(List<Map<String, String>> tags, String pid, String gmtTenant, String gmtCreator) {
        if (tags != null) {
            gmtTenant = (gmtTenant != null) ? gmtTenant : "";
            List<ServiceCatalog> catalogList = new ArrayList<>();
            for (Map tag : tags) {
                String name = (String) tag.get("name");
                if (name != null && !"".equals(name)) {
                    ServiceCatalog catalogBean2 = serviceCatalogDao.findByCatalogNameAndCreator(gmtCreator, name);
                    //如果沒有該二級目錄則開始新增二級目錄 by liumingyu
                    if (catalogBean2 == null && pid != null) {
                        ServiceCatalog serviceCatalogBean = new ServiceCatalog();
                        serviceCatalogBean.setPid(pid);
                        serviceCatalogBean.setCatalogName(name);
                        serviceCatalogBean.setId(IDUtils.new32UUID());
                        catalogList.add(serviceCatalogBean);
                    }
                }
            }
            if (catalogList.size() > 0) {
                //傳入List批量新增
                serviceCatalogDao.batchAdd(catalogList, new CommonEntry(), gmtTenant);
            }

        }
    }

    /**
     * @param serviceRequestList
     * @param thisResourceId
     * @param gmtTenant
     * @return void
     * @author Torres Liu
     * @description //TODO 新增資料到 服務請求表
     * @date 2020/4/24 5:52 下午
     **/
    private void addServiceRequest(List<ServiceRequest> serviceRequestList, String thisResourceId, String gmtTenant) {
        List<ServiceRequest> requestList = new ArrayList<>();
        if (serviceRequestList != null && thisResourceId != null) {
            gmtTenant = (gmtTenant != null) ? gmtTenant : "";
            for (ServiceRequest requestParameter : serviceRequestList) {
                ServiceRequest requestTable = new ServiceRequest();
                requestTable.setId(IDUtils.new32UUID());
                requestTable.setServiceId(thisResourceId);
                requestTable.setReqName(requestParameter.getReqName());
                requestTable.setReqDesc(requestParameter.getReqDesc());
                requestTable.setIsRequired(requestParameter.getIsRequired());
                requestTable.setReqType(requestParameter.getReqType());
                requestTable.setReqFrom(requestParameter.getReqFrom());
                requestList.add(requestTable);
            }
            if (requestList.size() > 0) {
                //批量新增資料
                serviceRequestDao.batchAdd(requestList, new CommonEntry(), gmtTenant);
            }
        }
    }

    /**
     * @param responseStatusList
     * @param thisResourceId
     * @param gmtTenant
     * @return void
     * @author Torres Liu
     * @description //TODO 新增資料到 響應狀態表
     * @date 2020/4/24 5:54 下午
     **/
    private void addResponseStatus(List<ResponseStatus> responseStatusList, String thisResourceId, String gmtTenant) {
        List<ResponseStatus> statusList = new ArrayList<>();
        if (responseStatusList != null && thisResourceId != null) {
            gmtTenant = (gmtTenant != null) ? gmtTenant : "";
            for (ResponseStatus response : responseStatusList) {
                ResponseStatus responseStatusTable = new ResponseStatus();
                responseStatusTable.setId(IDUtils.new32UUID());
                responseStatusTable.setServiceId(thisResourceId);
                responseStatusTable.setStatusCode(response.getStatusCode());
                responseStatusTable.setStatusDesc(response.getStatusDesc());
                responseStatusTable.setStatusRemark(response.getStatusRemark());
                statusList.add(responseStatusTable);
            }
            if (statusList.size() > 0) {
                //批量新增資料
                responseStatusDao.batchAdd(statusList, new CommonEntry(), gmtTenant);
            }
        }
    }

    /**
     * @param propertiesList
     * @param thisResourceId
     * @param gmtTenant
     * @return void
     * @author Torres Liu
     * @description //TODO 新增資料到 服務響應表
     * @date 2020/4/24 5:55 下午
     **/
    private void addServiceResponse(List<SwaggerModelAttr> propertiesList, String thisResourceId, String gmtTenant) {
        List<ServiceResponse> responseList = new ArrayList<>();
        if (propertiesList != null && thisResourceId != null) {
            gmtTenant = (gmtTenant != null) ? gmtTenant : "";
            //新增資料到serviceResponse表 by liumingyu
            for (SwaggerModelAttr p : propertiesList) {
                ServiceResponse serviceResponseTable = new ServiceResponse();
                serviceResponseTable.setId(IDUtils.new32UUID());
                //該服務id 為前面生成的serviceResource表(主表)的主鍵(資源id)by liumingyu
                serviceResponseTable.setServiceId(thisResourceId);
                serviceResponseTable.setPropName(p.getName());
                serviceResponseTable.setPropType(p.getType());
                serviceResponseTable.setPropDesc(p.getDescription());
                responseList.add(serviceResponseTable);
            }
            if (responseList.size() > 0) {
                //批量新增資料
                serviceResponseDao.batchAdd(responseList, new CommonEntry(), gmtTenant);
            }
        }
    }

    /**
     * @param tagsName
     * @param thisResourceId
     * @return void
     * @author Torres Liu
     * @description //TODO 新增資料到目錄關係表
     * @date 2020/4/24 5:55 下午
     **/
    private void addCatalogRela(String tagsName, String thisResourceId, String gmtCreator) {
        ServiceCatalogRela catalogRelaTable = new ServiceCatalogRela();
        if (tagsName != null && !"".equals(tagsName) && thisResourceId != null) {
            //通過tagsName查出目錄id by liumingyu
            ServiceCatalog catalogBean = serviceCatalogDao.findByCatalogNameAndCreator(gmtCreator, tagsName);
            if (catalogBean != null && catalogBean.getId() != null) {
                String catalogId = catalogBean.getId();
                catalogRelaTable.setId(IDUtils.new32UUID());
                //將目錄id插入關係表 by liumingyu
                catalogRelaTable.setCatalogId(catalogId);
                //將當前的服務id插入關係表 by liumingyu
                catalogRelaTable.setServiceId(thisResourceId);
                serviceCatalogRelaDao.add(catalogRelaTable);
            }
        }
    }

    /**
     * @param map
     * @return java.util.Map<java.lang.String, net.evecom.scplatform.openapi.entity.SwaggerModelAttr>
     * @author Torres Liu
     * @description //TODO 解析Definitions
     * @date 2020/4/24 5:55 下午
     **/
    private Map<String, SwaggerModelAttr> parseDefinitions(Map<String, Object> map) {
        Map<String, Map<String, Object>> definitions = (Map<String, Map<String, Object>>) map.get("definitions");
        Map<String, SwaggerModelAttr> definitinMap = new HashMap<>(256);
        if (definitions != null) {
            Iterator<String> modelNameIt = definitions.keySet().iterator();
            while (modelNameIt.hasNext()) {
                String modeName = modelNameIt.next();
                Map<String, Object> modeProperties = (Map<String, Object>) definitions.get(modeName).get("properties");
                if (modeProperties == null) {
                    continue;
                }
                Iterator<Map.Entry<String, Object>> mIt = modeProperties.entrySet().iterator();

                List<SwaggerModelAttr> attrList = new ArrayList<>();

                //解析屬性 by liumingyu
                while (mIt.hasNext()) {
                    Map.Entry<String, Object> mEntry = mIt.next();
                    Map<String, Object> attrInfoMap = (Map<String, Object>) mEntry.getValue();
                    SwaggerModelAttr modeAttr = new SwaggerModelAttr();
                    modeAttr.setName(mEntry.getKey());
                    modeAttr.setType((String) attrInfoMap.get("type"));
                    if (attrInfoMap.get(FORMAT_VAL) != null) {
                        modeAttr.setType(modeAttr.getType() + "(" + attrInfoMap.get("format") + ")");
                    }
                    modeAttr.setType(StringUtils.defaultIfBlank(modeAttr.getType(), "object"));
                    modeAttr.setDescription((String) attrInfoMap.get("description"));
                    attrList.add(modeAttr);
                }

                SwaggerModelAttr modeAttr = new SwaggerModelAttr();
                Object title = definitions.get(modeName).get("title");
                Object description = definitions.get(modeName).get("description");
                modeAttr.setClassName(title == null ? "" : title.toString());
                modeAttr.setDescription(description == null ? "" : description.toString());
                modeAttr.setProperties(attrList);
                definitinMap.put("#/definitions/" + modeName, modeAttr);
            }
        }
        return definitinMap;
    }

    /**
     * @param map
     * @return java.util.Map<java.lang.String, java.util.Map < java.lang.String, java.lang.Object>>
     * @author Torres Liu
     * @description //TODO 解析Definitions---->new
     * @date 2020/4/24 5:55 下午
     **/
    private Map<String, Map<String, Object>> newParseDefinitions(Map<String, Object> map) {
        Map<String, Map<String, Object>> definitions = (Map<String, Map<String, Object>>) map.get("definitions");
        Map<String, Map<String, Object>> definitinMap = new HashMap<>(256);
        if (definitions != null) {
            Iterator<String> modelNameIt = definitions.keySet().iterator();
            while (modelNameIt.hasNext()) {
                String modeName = modelNameIt.next();
                Map<String, Object> modeProperties = definitions.get(modeName);

                definitinMap.put("#/definitions/" + modeName, modeProperties);
            }
        }
        return definitinMap;
    }

    /**
     * @param parameters
     * @param definitionMap
     * @return java.util.List<net.evecom.scplatform.openapi.entity.ServiceRequest>
     * @author Torres Liu
     * @description //TODO 處理請求List
     * @date 2020/4/24 5:56 下午
     **/
    private List<ServiceRequest> processRequestList(List<LinkedHashMap> parameters, Map<String, Map<String, Object>> definitionMap) {
        List<ServiceRequest> requestList = new ArrayList<>();
        Map<String, Object> myHashMap = new HashMap<>(2000);
        if (!CollectionUtils.isEmpty(parameters)) {
            for (Map<String, Object> param : parameters) {
                Object in = param.get("in");
                ServiceRequest request = new ServiceRequest();
                request.setReqName(String.valueOf(param.get("name")));
                request.setReqType(param.get("type") == null ? "object" : param.get("type").toString());
                request.setReqFrom(String.valueOf(in));
                // 考慮物件引數型別 by liumingyu
                if (in != null && "body".equals(in)) {
                    Map<String, Object> schema = (Map) param.get("schema");
                    //拿到 ----> #/definitions/檔案目錄請求物件
                    Object ref = schema.get("$ref");
                    if (ref != null) {
                        Map<String, Object> mapByRefValue = definitionMap.get(ref);
                        if (mapByRefValue != null) {
                            Map<String, Object> propertiesMap = (Map<String, Object>) mapByRefValue.get("properties");
                            if (propertiesMap != null) {
                                //將properties中的值進行迭代
                                Iterator<Map.Entry<String, Object>> itProp = propertiesMap.entrySet().iterator();
                                while (itProp.hasNext()) {
                                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                    String dataFormat = simpleDateFormat.format(new Date());
                                    //取到單個值 ----> 如 endRow: {type: "integer", format: "int32"}
                                    Map.Entry<String, Object> entryIt = itProp.next();
                                    Map<String, Object> itValue = (Map<String, Object>) entryIt.getValue();
                                    String type = (String) itValue.get("type");
                                    if (!StringUtils.isBlank(type)) {
                                        switch (type) {
                                            case "string":
                                                if (itValue.get(FORMAT_VAL) != null && !"".equals(itValue.get(FORMAT_VAL))) {
                                                    String format = (String) itValue.get("format");
                                                    if ("date-time".equals(format) || "dateTime".equals(format)) {
                                                        myHashMap.put(entryIt.getKey(), dataFormat);
                                                    }
                                                } else {
                                                    myHashMap.put(entryIt.getKey(), "string");
                                                }
                                                break;
                                            case "integer":
                                                myHashMap.put(entryIt.getKey(), 0);
                                                break;
                                            case "number":
                                                myHashMap.put(entryIt.getKey(), 0.0);
                                                break;
                                            case "boolean":
                                                myHashMap.put(entryIt.getKey(), true);
                                                break;
                                            case "array":
                                                Integer initNum = 0;
                                                //開始呼叫--->遞迴演算法邏輯
                                                ifArrayRecursion(itValue, definitionMap, dataFormat, myHashMap, entryIt, initNum);
                                                break;
                                            default:
                                                myHashMap.put(entryIt.getKey(), null);
                                                break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    request.setReqDesc(JSON.toJSONString(myHashMap));
                } else {
                    request.setReqDesc((String.valueOf(param.get("description"))));
                }
                // 是否必填 by liumingyu
                request.setIsRequired(0);
                if (param.get("required") != null) {
                    Boolean required = (Boolean) param.get("required");
                    if (required == true) {
                        request.setIsRequired(1);
                    }
                }
                requestList.add(request);
            }
        }
        return requestList;
    }

    /**
     * @param responsesList
     * @param definitionMap
     * @return java.util.List<net.evecom.scplatform.openapi.entity.ResponseStatus>
     * @author Torres Liu
     * @description //TODO 處理返回狀態碼CodeList(像200、404、401...)
     * @date 2020/4/24 5:56 下午
     **/
    private List<ResponseStatus> processResponseStatusList(Map<String, Object> responsesList, Map<String, Map<String, Object>> definitionMap) {
        List<ResponseStatus> responseStatusList = new ArrayList<>();
        Iterator<Map.Entry<String, Object>> resIt = responsesList.entrySet().iterator();
        while (resIt.hasNext()) {
            Map.Entry<String, Object> entry = resIt.next();
            //宣告個響應狀態碼實體
            ResponseStatus responseStatus = new ResponseStatus();
            //開始迭代 狀態碼200 201 401 403 404 等等 by liumingyu
            responseStatus.setStatusCode(entry.getKey());
            //獲取response的value 像---> {description: "OK", schema: {$ref: "#/definitions/CommonResp«string»"}}
            LinkedHashMap<String, Object> statusCodeInfo = (LinkedHashMap) entry.getValue();
            //setDescription
            responseStatus.setStatusDesc(String.valueOf(statusCodeInfo.get("description")));
            if ("200".equals(entry.getKey())) {
                Object schema = statusCodeInfo.get("schema");
                if (schema != null && ((LinkedHashMap) schema).get("$ref") != null) {
                    //定義一個儲存definition的map
                    Map<String, Object> myHashMap = new HashMap<>(2000);
                    Map<String, Object> myHashMap2 = new HashMap<>(2000);
                    //如果schema不為null,開始解析$ref ---> $ref: "#/definitions/CommonResp«string»"
                    Object ref = ((LinkedHashMap) schema).get("$ref");
                    //將取到的ref的值放入definitionMap