写在前面:
完全通过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接口详情页。
解析前:
![](https://img2020.cnblogs.com/blog/1581071/202005/1581071-20200526144522854-409402545.png)
解析后:
通过json解析完可以显示所有的接口信息,如图:
![](https://img2020.cnblogs.com/blog/1581071/202011/1581071-20201126142635007-1959736839.png)
导入后即可现实相应的接口信息:
![](https://img2020.cnblogs.com/blog/1581071/202011/1581071-20201126142757795-1812699969.png)
这是单个接口的api详情信息,如下图:
![](https://img2020.cnblogs.com/blog/1581071/202005/1581071-20200526145019390-410146189.png)
点击按钮导出api详情页为word的效果展示,如图:
![](https://img2020.cnblogs.com/blog/1581071/202005/1581071-20200526163551832-2084378594.png)
导出word:
![](https://img2020.cnblogs.com/blog/1581071/202005/1581071-20200526163403036-2016605327.png)
Swagger Json格式详解:
![](https://img2020.cnblogs.com/blog/1581071/202005/1581071-20200526145441458-1271051422.png)
代码部分:
我这边实现两种思路,一是直接解析swagger json然后直接存入实体类生成为html,还要一种是建立好实体类以及数据库表后,将swagger json解析入库入表做持久化,再通过表中数据渲染到页面上。
下面我是介绍的swagger json入库入表再渲染为html的方案。
步骤大概是:首先定义好建好表,写好实体类后,再开始实现swagger json解析的算法。
实体类定义:
服务资源表:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@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;
}
}
服务资源表
服务请求信息表:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@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
服务响应信息表:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@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
服务响应状态表:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@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
服务类别表:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@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
服务类别关系表:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@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
服务返回属性:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@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 properties = new ArrayList();
}
View Code
返回给前端的dto实体:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/**
* @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 requestList;
/**
* 封装响应状态码list
*/
private List responseStatusList;
/**
* 封装返回属性list
*/
private List responseList;
}
View Code
实体类就是以上这些,将swagger json解析后存入相应的实体类字段中。
swagger解析代码:
下面开始swagger json的解析代码:
swagger解析service层接口:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public interface SwaggerJsonImportService {
/**
* swaggerJson导入业务表
*
* @param jsonUrl jsonUrl
* @param serviceSwagger swaggerJson
* @param isAuthorized 是否需要授权访问
* @return net.evecom.scplatform.common.entry.CommonResp
* @throws IOException
* @Author Torres Liu
* @Description //TODO swaggerJson导入业务表
* @Date 2020/4/24 5:07 下午
* @Param [jsonUrl, serviceSwagger, isAuthorized]
**/
CommonResp swaggerJsonImport(String jsonUrl, ServiceSwagger serviceSwagger, String isAuthorized) throws IOException;
/**
* 导出SwaggerJson
*
* @param serviceId 服务id
* @param catalogId 目录id
* @return net.evecom.scplatform.common.entry.CommonResp
* @Author Torres Liu
* @Description //TODO 导出SwaggerJson
* @Date 2020/4/22 9:41 上午
* @Param [serviceId, catalogId]
**/
List swaggerJsonExport(String serviceId, String catalogId);
}
View Code
swagger解析service层接口实现类(解析的核心代码)
下面是一大堆枯燥的json解析,大家都是程序员,我就不做过多的讲解代码,有需要学习的可以参照我代码中的注释,写的都比较详细。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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.clienthods.CloseableHttpResponse;
import org.apache.http.clienthods.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
* @author Torres Liu
* @description //TODO 通过JSON或URL导入服务
* @date 2020/4/24 5:46 下午
**/
@Override
@Transactional(rollbackFor = Exception.class)
public CommonResp 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 map = SwaggerJsonUtils.readValue(jsonStr, HashMap.class);
//解析info by liumingyu
Map infoMap = (Map) map.get("info");
//拿到一级标题 by liumingyu
String catalogName = (String) infoMap.get("title");
//拿到所有二级标题(类标题)的List by liumingyu
List tags = (List) 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 definitinMapOld = parseDefinitions(map);
Map definitinMap = newParseDefinitions(map);
//获取服务版本(取得是一级info的版本号)by liumingyu
String version = (String) infoMap.get("version");
//解析paths by liumingyu
Map paths = (Map) 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 it = paths.entrySet().iterator();
//开始遍历paths by liumingyu
while (it.hasNext()) {
//拿到单个path的数据信息,用map的Entry对象存起来 by liumingyu
Map.Entry path = it.next();
Iterator 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 it2Request = it2.next();
//请求方法 GET / POST 等等 by liumingyu
String requestMethod = it2Request.getKey().toUpperCase();
//拿到某个接口(服务)的具体数据 by liumingyu
Map content = (Map) it2Request.getValue();
//服务名称 by liumingyu
String serviceName = String.valueOf(content.get("summary"));
//该服务的操作id by liumingyu
String operationId = String.valueOf(content.get("operationId"));
//请求体 by liumingyu
List parametersList = (ArrayList) content.get("parameters");
//响应Code体 by liumingyu
Map responsesList = (Map) 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 consumes = (List) content.get("consumes");
if (consumes != null && consumes.size() > 0) {
contentType = StringUtils.join(consumes, ",");
}
//返回参数格式,类似于 application/json by liumingyu
String callContentType = "";
List produces = (List) content.get("produces");
List 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 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 serviceRequestList = processRequestList(parametersList, definitinMap);
//3.添加数据到serviceRequest表 by liumingyu
addServiceRequest(serviceRequestList, thisResourceId, gmtTenant);
//处理responsesList数据转为ResponseStatus表List对象 by liumingyu
List responseStatusList = processResponseStatusList(responsesList, definitinMap);
//4.添加数据到ResponseStatus表 by liumingyu
addResponseStatus(responseStatusList, thisResourceId, gmtTenant);
//取出来状态是200时的返回值 by liumingyu
Map responsesObj = (Map) responsesList.get("200");
if (responsesObj != null && responsesObj.get(SCHEMA_VAL) != null) {
//处理相应的返回值 by liumingyu
SwaggerModelAttr swaggerModelAttr = processResponseModelAttrs(responsesObj, definitinMapOld);
//拿到properties数据,这个List里面就是需要的返回值数据 by liumingyu
List 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
* @author Torres Liu
* @description //TODO 服务导出Json
* @date 2020/4/24 5:50 下午
**/
@Override
public List swaggerJsonExport(String serviceId, String catalogId) {
String titleName = "";
List result = new ArrayList();
try {
if (serviceId != null && !"".equals(serviceId)) {
SwaggerHtmlDto thisDto = new SwaggerHtmlDto();
//根据serviceId查询所需数据
ServiceResource resourceTable = serviceResourceDao.findById(serviceId);
List requestList = serviceRequestDao.findByServiceId(serviceId);
List responseStatusList = responseStatusDao.findByServiceId(serviceId);
List 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 tags, String pid, String gmtTenant, String gmtCreator) {
if (tags != null) {
gmtTenant = (gmtTenant != null) ? gmtTenant : "";
List 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 serviceRequestList, String thisResourceId, String gmtTenant) {
List 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 responseStatusList, String thisResourceId, String gmtTenant) {
List 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 propertiesList, String thisResourceId, String gmtTenant) {
List 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
* @author Torres Liu
* @description //TODO 解析Definitions
* @date 2020/4/24 5:55 下午
**/
private Map parseDefinitions(Map map) {
Map definitions = (Map) map.get("definitions");
Map definitinMap = new HashMap(256);
if (definitions != null) {
Iterator modelNameIt = definitions.keySet().iterator();
while (modelNameIt.hasNext()) {
String modeName = modelNameIt.next();
Map modeProperties = (Map) definitions.get(modeName).get("properties");
if (modeProperties == null) {
continue;
}
Iterator mIt = modeProperties.entrySet().iterator();
List attrList = new ArrayList();
//解析属性 by liumingyu
while (mIt.hasNext()) {
Map.Entry mEntry = mIt.next();
Map attrInfoMap = (Map) 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>
* @author Torres Liu
* @description //TODO 解析Definitions---->new
* @date 2020/4/24 5:55 下午
**/
private Map newParseDefinitions(Map map) {
Map definitions = (Map) map.get("definitions");
Map definitinMap = new HashMap(256);
if (definitions != null) {
Iterator modelNameIt = definitions.keySet().iterator();
while (modelNameIt.hasNext()) {
String modeName = modelNameIt.next();
Map modeProperties = definitions.get(modeName);
definitinMap.put("#/definitions/" + modeName, modeProperties);
}
}
return definitinMap;
}
/**
* @param parameters
* @param definitionMap
* @return java.util.List
* @author Torres Liu
* @description //TODO 处理请求List
* @date 2020/4/24 5:56 下午
**/
private List processRequestList(List parameters, Map definitionMap) {
List requestList = new ArrayList();
Map myHashMap = new HashMap(2000);
if (!CollectionUtils.isEmpty(parameters)) {
for (Map 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 schema = (Map) param.get("schema");
//拿到 ----> #/definitions/文件目录请求对象
Object ref = schema.get("$ref");
if (ref != null) {
Map mapByRefValue = definitionMap.get(ref);
if (mapByRefValue != null) {
Map propertiesMap = (Map) mapByRefValue.get("properties");
if (propertiesMap != null) {
//将properties中的值进行迭代
Iterator 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 entryIt = itProp.next();
Map itValue = (Map) 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
* @author Torres Liu
* @description //TODO 处理返回状态码CodeList(像200、404、401...)
* @date 2020/4/24 5:56 下午
**/
private List processResponseStatusList(Map responsesList, Map definitionMap) {
List responseStatusList = new ArrayList();
Iterator resIt = responsesList.entrySet().iterator();
while (resIt.hasNext()) {
Map.Entry 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 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 myHashMap = new HashMap(2000);
Map myHashMap2 = new HashMap(2000);
//如果schema不为null,开始解析$ref ---> $ref: "#/definitions/CommonResp«string»"
Object ref = ((LinkedHashMap) schema).get("$ref");
//将取到的ref的值放入definitionMap作为key去查询该definitions的具体内容
Map mapByRef1 = definitionMap.get(ref);
//获取到该definitions中的properties字段内容(里面是code、data、msg)
Map properties = (Map) mapByRef1.get("properties");
//将properties拿来迭代,继续后续逻辑...
Iterator itProperties = properties.entrySet().iterator();
while (itProperties.hasNext()) {
//拿到entry对象,其中entryProp的key 是 code、data、msg
Map.Entry entryProp = itProperties.next();
//取到entryProp的value
Map valueMap = (Map) entryProp.getValue();
//其中如果是data,那可能里面还存在$ref
if (valueMap.get("$ref") != null || valueMap.get("items") != null) {
//如果存在 继续取出$ref的值 ---> 如 #/definitions/PageInfo«ScFile对象»
Object refValue = valueMap.get("$ref");
Map thisItems = (Map) valueMap.get("items");
Object refValues = (refValue != null) ? refValue : thisItems.get("$ref");
//继续将refValue作为key通过definitionMap来获取definitions
Map mapByRefValue = definitionMap.get(refValues);
if (mapByRefValue != null) {
//继续获取该definitions中的properties的值
Map propertiesMap = (Map) mapByRefValue.get("properties");
if (propertiesMap != null) {
//将properties中的值进行迭代
Iterator 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 entryIt = itProp.next();
// entryIt.getKey()= endRow ; entryIt.getValue() = {type: "integer", format: "int32"}
Map itValue = (Map) 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)) {
myHashMap2.put(entryIt.getKey(), dataFormat);
}
} else {
myHashMap2.put(entryIt.getKey(), "string");
}
break;
case "integer":
myHashMap2.put(entryIt.getKey(), 0);
break;
case "number":
myHashMap2.put(entryIt.getKey(), 0.0);
break;
case "boolean":
myHashMap2.put(entryIt.getKey(), true);
break;
case "array":
Integer initNum = 0;
//开始调用--->递归算法逻辑
ifArrayRecursion(itValue, definitionMap, dataFormat, myHashMap2, entryIt, initNum);
break;
default:
myHashMap2.put(entryIt.getKey(), null);
break;
}
}
}
}
}
//将myHashMap2存入data
myHashMap.put(entryProp.getKey(), myHashMap2);
} else {
//不存在ref的直接存入map中
if (valueMap.get("type") != null) {
//拿到type的值
String type = (String) valueMap.get("type");
switch (type) {
case "string":
myHashMap.put(entryProp.getKey(), "string");
break;
case "integer":
myHashMap.put(entryProp.getKey(), 0);
break;
case "number":
myHashMap.put(entryProp.getKey(), 0.0);
break;
case "boolean":
myHashMap.put(entryProp.getKey(), true);
break;
default:
myHashMap.put(entryProp.getKey(), new Object());
break;
}
}
}
}
responseStatus.setStatusRemark(JSON.toJSONString(myHashMap));
}
}
responseStatusList.add(responseStatus);
}
return responseStatusList;
}
/**
* @return net.evecom.scplatform.openapi.entity.SwaggerModelAttr
* @Author liumingyu
* @Description //TODO 处理返回属性列表
* @Date 2020/4/8 6:56 下午
* @Param [responseObj, definitinMap]
**/
private SwaggerModelAttr processResponseModelAttrs(Map responseObj, Map definitinMap) {
Map schema = (Map) responseObj.get("schema");
String type = (String) schema.get("type");
String ref = null;
//数组 by liumingyu
if (ARRAY_VAL.equals(type)) {
Map items = (Map) schema.get("items");
if (items != null && items.get(REF_VAL) != null) {
ref = (String) items.get(REF_VAL);
}
}
//对象 by liumingyu
if (schema.get(REF_VAL) != null) {
ref = (String) schema.get(REF_VAL);
}
//其他类型 by liumingyu
SwaggerModelAttr modelAttr = new SwaggerModelAttr();
modelAttr.setType(StringUtils.defaultIfBlank(type, StringUtils.EMPTY));
if (StringUtils.isNotBlank(ref) && definitinMap.get(ref) != null) {
modelAttr = definitinMap.get(ref);
}
return modelAttr;
}
/**
* @param itValue
* @param definitionMap
* @param dataFormat
* @param myHashMapPre
* @param entryPreIt
* @param initNums
* @return void
* @author Torres Liu
* @description //TODO ifArray递归算法 [如果参数存在type=array,开始执行该递归逻辑,该递归是为了解析json中多层嵌套array的数据]
* @date 2020/4/24 5:56 下午
**/
private void ifArrayRecursion(Map itValue, Map definitionMap,
String dataFormat, Map myHashMapPre,
Map.Entry entryPreIt, Integer initNums) {
if (initNums 通过serviceId获取相应javabean转为html
* @date 2020/4/24 6:01 下午
**/
@Override
public Map getBeanToHtml(String serviceId, String catalogId) {
//String jsonStr = "";
Map resultMap = new HashMap(50);
List result = new ArrayList();
try {
if (serviceId != null && !"".equals(serviceId)) {
SwaggerHtmlDto thisDto = new SwaggerHtmlDto();
//根据serviceId查询所需数据
ServiceResource resourceTable = serviceResourceDao.findById(serviceId);
List requestList = serviceRequestDao.findByServiceId(serviceId);
List responseStatusList = responseStatusDao.findByServiceId(serviceId);
List 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);
if (thisCatalogBean != null) {
thisDto.setTag(thisCatalogBean.getCatalogName());
String thisCatalogPid = thisCatalogBean.getPid();
if (!MAX_CATALOG_PID.equals(thisCatalogPid)) {
ServiceCatalog pidBean = serviceCatalogDao.findById(thisCatalogPid);
if (pidBean != null) {
thisDto.setTitle(pidBean.getCatalogName());
}
} else {
thisDto.setTitle(thisCatalogBean.getCatalogName());
}
}
thisDto.setVersion(resourceTable.getServiceVersion());
//将所有数据add至result
result.add(thisDto);
Map tableMap = new HashMap(50);
if (catalogId != null && thisCatalogBean != null) {
tableMap = result.stream().parallel().collect(Collectors.groupingBy(SwaggerHtmlDto::getTitle));
} else {
tableMap = result.stream().parallel().collect(Collectors.groupingBy(SwaggerHtmlDto::getVersion));
}
resultMap.put("tableMap", new TreeMap(tableMap));
}
} catch (Exception e) {
log.error("Javabean Convert Swagger Json Error", e);
}
return resultMap;
}
}
View Code
Swagger解析工具类:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/**
* @Author Torres Liu
* @Description //TODO Swagger格式解析Json工具类
* @Date 2020/4/8 4:32 下午
* @Param
* @return
**/
public class SwaggerJsonUtils {
private static ObjectMapper objectMapper = new ObjectMapper();
static {
objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
}
public static T readValue(String jsonStr, Class clazz) throws IOException {
return objectMapper.readValue(jsonStr, clazz);
}
public static List readListValue(String jsonStr, Class clazz) throws IOException {
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, clazz);
return objectMapper.readValue(jsonStr, javaType);
}
public static ArrayNode readArray(String jsonStr) throws IOException {
JsonNode node = objectMapper.readTree(jsonStr);
if (node.isArray()) {
return (ArrayNode) node;
}
return null;
}
public static JsonNode readNode(String jsonStr) throws IOException {
return objectMapper.readTree(jsonStr);
}
public static String writeJsonStr(Object obj) throws JsonProcessingException {
return objectMapper.writeValueAsString(obj);
}
public static ObjectNode createObjectNode() {
return objectMapper.createObjectNode();
}
public static ArrayNode createArrayNode() {
return objectMapper.createArrayNode();
}
}
View Code
获取各种IP地址工具类:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package xxxxxxxx
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.clienthods.CloseableHttpResponse;
import org.apache.http.clienthods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
public class WebToolUtils {
/**
* UNKNOWN
*/
private final static String UNKNOWN = "unknown";
/**
* 获取本地IP地址
*
* @throws SocketException
*/
public static String getLocalIp() throws UnknownHostException, SocketException {
if (isWindowsOs()) {
return InetAddress.getLocalHost().getHostAddress();
} else {
return getLinuxLocalIp();
}
}
/**
* 判断操作系统是否是Windows
*
* @return
*/
public static boolean isWindowsOs() {
String windowsSys = "windows";
boolean isWindowsOs = false;
String osName = System.getProperty("os.name");
if (osName.toLowerCase().indexOf(windowsSys) > -1) {
isWindowsOs = true;
}
return isWindowsOs;
}
/**
* 获取本地Host名称
*/
public static String getLocalHostName() throws UnknownHostException {
return InetAddress.getLocalHost().getHostName();
}
/**
* 获取Linux下的IP地址
*
* @return IP地址
* @throws SocketException
*/
private static String getLinuxLocalIp() throws SocketException {
String ip = "";
try {
for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface intf = en.nextElement();
String name = intf.getName();
if (!name.contains("docker") && !name.contains("lo")) {
for (Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress()) {
String ipaddress = inetAddress.getHostAddress().toString();
if (!ipaddress.contains("::") &&
!ipaddress.contains("0:0:") &&
!ipaddress.contains("fe80")) {
ip = ipaddress;
System.out.println(ipaddress);
}
}
}
}
}
} catch (SocketException ex) {
System.out.println("获取ip地址异常");
ip = "127.0.0.1";
ex.printStackTrace();
}
System.out.println("IP:" + ip);
return ip;
}
/**
* 获取用户真实IP地址,不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址,
*
* 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值,究竟哪个才是真正的用户端的真实IP呢?
* 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。
*
* 如:X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130,
* 192.168.1.100
*
* 用户真实IP为: 192.168.1.110
*
* @param request
* @return
*/
public static String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
/**
* 向指定URL发送GET方法的请求
*
* @param url 发送请求的URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return URL 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param) {
StringBuffer result = new StringBuffer();
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
URL realUrl = new URL(urlNameString);
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 建立实际的连接
connection.connect();
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new
InputStreamReader(connection.getInputStream(),"UTF-8"));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result.toString();
}
/**
* 向指定 URL 发送POST方法的请求
* @param pathUrl
* @param name
* @param pwd
* @param phone
* @param content
*/
public static void sendPost(String pathUrl, String name, String pwd, String phone, String content) {
try {
// 建立连接
URL url = new URL(pathUrl);
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
// //设置连接属性
// 使用 URL 连接进行输出
httpConn.setDoOutput(true);
// 使用 URL 连接进行输入
httpConn.setDoInput(true);
// 忽略缓存
httpConn.setUseCaches(false);
// 设置URL请求方法
httpConn.setRequestMethod("POST");
String requestString = "客服端要以以流方式发送到服务端的数据...";
// 设置请求属性
// 获得数据字节数据,请求数据流的编码,必须和下面服务器端处理请求流的编码一致
byte[] requestStringBytes = requestString.getBytes("utf-8");
httpConn.setRequestProperty("Content-length", "" + requestStringBytes.length);
httpConn.setRequestProperty("Content-Type", " application/x-www-form-urlencoded");
// 维持长连接
httpConn.setRequestProperty("Connection", "Keep-Alive");
httpConn.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
httpConn.setRequestProperty("Accept-Encoding", "gzip, deflate");
httpConn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
httpConn.setRequestProperty("User-Agent",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0");
httpConn.setRequestProperty("Upgrade-Insecure-Requests", "1");
httpConn.setRequestProperty("account", name);
httpConn.setRequestProperty("passwd", pwd);
httpConn.setRequestProperty("phone", phone);
httpConn.setRequestProperty("content", content);
// 建立输出流,并写入数据
OutputStream outputStream = httpConn.getOutputStream();
outputStream.write(requestStringBytes);
outputStream.close();
// 获得响应状态
int responseCode = httpConn.getResponseCode();
// 连接成功
if (HttpURLConnection.HTTP_OK == responseCode) {
// 当正确响应时处理数据
StringBuffer sb = new StringBuffer();
String readLine;
BufferedReader responseReader;
// 处理响应流,必须与服务器响应流输出的编码一致
responseReader = new BufferedReader(new InputStreamReader(httpConn.getInputStream(), "utf-8"));
while ((readLine = responseReader.readLine()) != null) {
sb.append(readLine).append("\n");
}
responseReader.close();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* 执行一个HTTP POST请求,返回请求响应的HTML
* @param url
* @param name
* @param pwd
* @param phone
* @param content
*/
public static void doPost(String url, String name, String pwd, String phone, String content) {
// 创建默认的httpClient实例.
CloseableHttpClient httpclient = HttpClients.createDefault();
// 创建httppost
HttpPost httppost = new HttpPost(url);
// 创建参数队列
List formparams = new ArrayList();
formparams.add(new BasicNameValuePair("account", name));
formparams.add(new BasicNameValuePair("passwd", pwd));
formparams.add(new BasicNameValuePair("phone", phone));
formparams.add(new BasicNameValuePair("content", content));
UrlEncodedFormEntity uefEntity;
try {
uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
httppost.setEntity(uefEntity);
System.out.println("executing request " + httppost.getURI());
CloseableHttpResponse response = httpclient.execute(httppost);
try {
HttpEntity entity = response.getEntity();
if (entity != null) {
System.out.println("--------------------------------------");
System.out.println("Response content: " + EntityUtils.toString(entity, "UTF-8"));
System.out.println("--------------------------------------");
}
} finally {
response.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接,释放资源
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
View Code
以上便是后端解析的代码(dao接口和mapper.xml的sql我这边忽略了,可以根据自己实际业务去写),最后附上前端代码:
前端api详情页代码:
前端这边使用了thymeleaf模板引擎。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
DOCTYPE html>
.swaggerApi {
border-radius: 15px;
}
.swaggerApi .bg {
color: #000000;
/*background-color: #69b869;*/
}
.swaggerApi .trBgA {
color: #000000;
background-color: #d9edf7;
}
.swaggerApi .trBgA:hover {
background-color: #d9edf7;
}
.swaggerApi .trBgB {
color: #000000;
background-color: #fcf8e3;
}
.swaggerApi .trBgB:hover {
background-color: #fcf8e3;
}
.swaggerApi .titleTagA {
color: #337ab7;
background-color: #d9edf7;
font-size: 18px;
font-weight: 600;
}
.swaggerApi .titleTagB {
color: #aa7408;
background-color: #fcf8e3;
font-size: 18px;
font-weight: 600;
}
.swaggerApi .titleTagC {
color: #5cb85c;
background-color: #dff0d8;
font-size: 18px;
font-weight: 600;
}
.swaggerApi table {
padding: 10px;
border: 1px solid #dbe3e4;
table-layout: fixed;
color: #333333;
background-color: #ffffff;
}
.swaggerApi tr {
height: 36px;
font-size: 16px;
}
.swaggerApi tr:hover{
background-color: #f5f5f5;
}
.swaggerApi td {
padding: 8px;
border: 1px solid #ddd;
height: 36px;
overflow: hidden;
word-break: break-all;
word-wrap: break-word;
font-size: 16px;
font-family: 宋体;
}
.swaggerApi .first_title {
/*color: #eee;*/
height: 60px;
line-height: 60px;
margin: 0;
font-weight: bold;
font-size: 20px;
font-family: 宋体;
}
.swaggerApi .second_title {
/*color: #eee;*/
height: 40px;
line-height: 40px;
margin: 0;
font-size: 16px;
font-family: 宋体;
}
.swaggerApi .doc_title {
color: #eee;
font-size: 24px;
text-align: center;
font-weight: bold;
border-bottom: 1px solid #eee;
padding-bottom: 9px;
margin: 34px 0 20px;
font-family: 宋体;
}
.swaggerApi .download_btn_def {
float: right;
margin-left: 10px;
display: inline-block;
height: 38px;
line-height: 38px;
padding: 0 18px;
background-color: #009688;
color: #fff;
white-space: nowrap;
text-align: center;
font-size: 14px;
border: none;
border-radius: 2px;
cursor: pointer;
}
.swaggerApi .download_btn_def:hover {
opacity: 0.8;
}
.swaggerApi .download_btn_blue {
float: right;
margin-left: 10px;
display: inline-block;
height: 38px;
line-height: 38px;
padding: 0 18px;
background-color: #1E9FFF;
color: #fff;
white-space: nowrap;
text-align: center;
font-size: 14px;
border: none;
border-radius: 2px;
cursor: pointer;
}
.swaggerApi .download_btn_blue:hover {
opacity: 0.8;
}
.swaggerApi .alert {
padding: 15px;
margin-bottom: 5px;
border: 1px solid transparent;
border-radius: 4px;
}
.swaggerApi .alert-warning {
color: #8a6d3b;
background-color: #fcf8e3;
border-color: #faebcc;
}
下载(excel)
下载(doc)
提示:调用时需在请求头添加凭证,格式如下
Request Headers:
Authorization : Basic Base64(ak:sk)
ServiceInfo
服务名称
服务描述
请求地址
请求方法
请求类型
返回类型
Parameters
参数名称
参数类型
参数来源
是否必填
说明
Responses
响应状态码
描述
返回说明
/**/
/**
* json美化
* jsonFormat2(json)这样为格式化代码。
* jsonFormat2(json,true)为开启压缩模式
* @param txt
* @param compress
* @returns {string}
*/
function jsonFormat(txt,compress){
debugger;
txt = JSON.stringify(txt);
//alert(txt);
var indentChar = ' ';
if(/^\s*$/.test(txt)){
alert('数据为空,无法格式化! ');
return;
}
try{var data=eval('('+txt+')');}
catch(e){
alert('数据源语法错误,格式化失败! 错误信息: '+e.description,'err');
return;
};
var draw=[],last=false,This=this,line=compress?'':'\n',nodeCount=0,maxDepth=0;
var notify=function(name,value,isLast,indent/*缩进*/,formObj){
nodeCount++;/*节点计数*/
for (var i=0,tab='';i*/
View Code
使用思路:
首先通过swagger json解析为实体类并存入数据库中(对应上面的swagger解析代码),在通过调用javabean转html的接口来实现将存入的数据转为html页面(对应上面的javabean转为html渲染页面代码)。
结尾:
总结:
其实也可以直接通过swagger json解析然后存入实体类直接渲染给页面。就是不入库直接将swaggerjson生成出html,这种方案我也实现了,但是在这篇文章中不做过多介绍,如果有需要以后我也会写篇文章做一下记录。
其实都是一样的思路啦,写代码讲究的是思路。
参考资料:
https://www.cnblogs.com/jmcui/p/8298823.html
https://github.com/JMCuixy/swagger2word
https://www.aliyun.com/product/csb?spm=5176.10695662.784136.1.57b794ceX78G27
|