fix(接口定义): 修复swagger导入一些值缺失 & 请求体导出支持json、xml格式 (#1751)

* feat(测试跟踪): 测试用例下载模版增加标签列

* fix(接口定义): 扩大请求头键长度

* fix: schedule表对旧数据name字段兼容的补充

* fix(接口定义): 修复swagger导入一些值缺失 & 请求体导出支持json、xml格式
This commit is contained in:
Coooder-X 2021-03-30 13:07:09 +08:00 committed by chenjianxing
parent fc9d040579
commit 3e97f8da6c
5 changed files with 192 additions and 15 deletions

View File

@ -26,12 +26,15 @@ import io.swagger.v3.oas.models.parameters.*;
import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses; import io.swagger.v3.oas.models.responses.ApiResponses;
import io.swagger.v3.parser.core.models.SwaggerParseResult; import io.swagger.v3.parser.core.models.SwaggerParseResult;
import net.sf.saxon.ma.json.XMLToJsonFn;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.fife.ui.rsyntaxtextarea.parser.XmlParser;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import java.io.InputStream; import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*; import java.util.*;
@ -334,6 +337,16 @@ public class Swagger3Parser extends SwaggerAbstractParser {
} else if (schema instanceof BinarySchema) { } else if (schema instanceof BinarySchema) {
return getDefaultValueByPropertyType(schema); return getDefaultValueByPropertyType(schema);
} else { } else {
if(schema.getType() != null) { // 特判属性不是对象的情况直接将基本类型赋值进去
if(StringUtils.equals(schema.getType(), "string")) {
String example = (String) schema.getExample();
return example == null ? "" : example;
} else if(StringUtils.equals(schema.getType(), "boolean")) {
return schema.getExample();
} else if(StringUtils.equals(schema.getType(), "double")) {
return schema.getExample();
}
}
Object propertiesResult = parseSchemaProperties(schema, refSet, infoMap); Object propertiesResult = parseSchemaProperties(schema, refSet, infoMap);
return propertiesResult == null ? getDefaultValueByPropertyType(schema) : propertiesResult; return propertiesResult == null ? getDefaultValueByPropertyType(schema) : propertiesResult;
} }
@ -432,7 +445,9 @@ public class Swagger3Parser extends SwaggerAbstractParser {
JSONObject requestBody = buildRequestBody(requestObject); JSONObject requestBody = buildRequestBody(requestObject);
swaggerApiInfo.setRequestBody(requestBody); swaggerApiInfo.setRequestBody(requestBody);
// 设置响应体 // 设置响应体
swaggerApiInfo.setResponses(new JSONObject()); // JSONObject reponseObject = JSON.parseObject(apiDefinition.getResponse());
// swaggerApiInfo.setResponses(buildResponseBody(reponseObject));
//.....
// 设置请求参数列表 // 设置请求参数列表
List<JSONObject> paramsList = buildParameters(requestObject); List<JSONObject> paramsList = buildParameters(requestObject);
swaggerApiInfo.setParameters(paramsList); swaggerApiInfo.setParameters(paramsList);
@ -459,6 +474,9 @@ public class Swagger3Parser extends SwaggerAbstractParser {
if(params != null) { if(params != null) {
for(int i = 0; i < params.size(); ++i) { for(int i = 0; i < params.size(); ++i) {
JSONObject param = params.getJSONObject(i); // 对于每个参数: JSONObject param = params.getJSONObject(i); // 对于每个参数:
if(param.get("name") == null || StringUtils.isEmpty(((String) param.get("name")))) {
continue;
} // 否则无参数的情况可能多出一行空行
SwaggerParams swaggerParam = new SwaggerParams(); SwaggerParams swaggerParam = new SwaggerParams();
swaggerParam.setIn(typeMap.get(type)); // 利用 map根据 request key 设置对应的参数类型 swaggerParam.setIn(typeMap.get(type)); // 利用 map根据 request key 设置对应的参数类型
swaggerParam.setDescription((String) param.get("description")); swaggerParam.setDescription((String) param.get("description"));
@ -480,9 +498,20 @@ public class Swagger3Parser extends SwaggerAbstractParser {
put("Form Data", org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE); put("Form Data", org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE);
put("WWW_FORM", org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE); put("WWW_FORM", org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE);
}}; }};
JSONObject bodyInfo = new JSONObject();
if(request.getJSONObject("body") != null && request.getJSONObject("body").containsKey("raw")) {
String bodyType = request.getJSONObject("body").getString("type");
if(bodyType.equals("JSON")) {
bodyInfo = buildRequestBodyJsonInfo(request.getJSONObject("body").getJSONObject("raw"));
} else if(bodyType.equals("XML")) {
String xmlText = request.getJSONObject("body").getString("raw");
JSONObject xmlToJson = XMLUtils.XmlToJson(xmlText);
bodyInfo = buildRequestBodyJsonInfo(xmlToJson);
}
}
String type = request.getJSONObject("body").getString("type"); String type = request.getJSONObject("body").getString("type");
JSONObject requestBody = new JSONObject(); JSONObject requestBody = new JSONObject();
JSONObject schema = new JSONObject(); JSONObject schema = bodyInfo; // 需要转换导出
JSONObject typeName = new JSONObject(); JSONObject typeName = new JSONObject();
schema.put("type", null); schema.put("type", null);
schema.put("format", null); schema.put("format", null);
@ -494,4 +523,55 @@ public class Swagger3Parser extends SwaggerAbstractParser {
requestBody.put("content", content); requestBody.put("content", content);
return requestBody; return requestBody;
} }
// 将请求体中的一个 json 对象转换成 swagger 格式的 json 对象返回
private JSONObject buildRequestBodyJsonInfo(JSONObject requestBody) {
JSONObject schema = new JSONObject();
schema.put("type", "object");
JSONObject properties = buildSchema(requestBody);
schema.put("properties", properties);
return schema;
}
// 设置一个 json 对象的属性在 swagger 格式中的类型
private JSONObject buildSchema(JSONObject requestBody) {
JSONObject schema = new JSONObject();
for(String key : requestBody.keySet()) {
Object param = requestBody.get(key);
JSONObject parsedParam = new JSONObject();
if(param instanceof java.lang.String) {
parsedParam.put("type", "string");
parsedParam.put("example", param == null? "" : param);
} else if(param instanceof java.lang.Integer) {
parsedParam.put("type", "integer");
parsedParam.put("format", "int64");
parsedParam.put("example", param);
} else if(param instanceof JSONObject) {
parsedParam = buildRequestBodyJsonInfo((JSONObject) param);
} else if(param instanceof java.lang.Boolean) {
parsedParam.put("type", "boolean");
parsedParam.put("example", param);
} else if(param instanceof java.math.BigDecimal) { // double 类型会被 fastJson 转换为 BigDecimal
parsedParam.put("type", "double");
parsedParam.put("example", param);
} else { // JSONOArray
parsedParam.put("type", "array");
JSONObject item = new JSONObject();
if(((JSONArray) param).size() > 0) {
if(((JSONArray) param).get(0) instanceof JSONObject) { ///
item = buildRequestBodyJsonInfo((JSONObject) ((JSONArray) param).get(0));
}
}
parsedParam.put("items", item);
}
schema.put(key, parsedParam);
}
return schema;
}
private JSONObject buildResponseBody(JSONObject reponse) {
JSONObject responseBody = new JSONObject();
return responseBody;
}
} }

View File

@ -2,46 +2,140 @@ package io.metersphere.commons.utils;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import io.metersphere.commons.exception.MSException;
import io.metersphere.i18n.Translator;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Map; import java.util.*;
import java.util.Set; import java.util.regex.*;
public class XMLUtils { public class XMLUtils {
private static void jsonToXmlStr(JSONObject jObj, StringBuffer buffer) { private static void jsonToXmlStr(JSONObject jObj, StringBuffer buffer, StringBuffer tab) {
Set<Map.Entry<String, Object>> se = jObj.entrySet(); Set<Map.Entry<String, Object>> se = jObj.entrySet();
StringBuffer nowTab = new StringBuffer(tab.toString());
for (Map.Entry<String, Object> en : se) { for (Map.Entry<String, Object> en : se) {
if ("com.alibaba.fastjson.JSONObject".equals(en.getValue().getClass().getName())) { if ("com.alibaba.fastjson.JSONObject".equals(en.getValue().getClass().getName())) {
buffer.append("<").append(en.getKey()).append(">"); buffer.append(tab).append("<").append(en.getKey()).append(">\n");
JSONObject jo = jObj.getJSONObject(en.getKey()); JSONObject jo = jObj.getJSONObject(en.getKey());
jsonToXmlStr(jo, buffer); jsonToXmlStr(jo, buffer, nowTab.append("\t"));
buffer.append("</").append(en.getKey()).append(">"); buffer.append(tab).append("</").append(en.getKey()).append(">\n");
} else if ("com.alibaba.fastjson.JSONArray".equals(en.getValue().getClass().getName())) { } else if ("com.alibaba.fastjson.JSONArray".equals(en.getValue().getClass().getName())) {
JSONArray jarray = jObj.getJSONArray(en.getKey()); JSONArray jarray = jObj.getJSONArray(en.getKey());
for (int i = 0; i < jarray.size(); i++) { for (int i = 0; i < jarray.size(); i++) {
buffer.append("<").append(en.getKey()).append(">"); buffer.append(tab).append("<").append(en.getKey()).append(">\n");
if (StringUtils.isNotBlank(jarray.getString(i))) { if (StringUtils.isNotBlank(jarray.getString(i))) {
JSONObject jsonobject = jarray.getJSONObject(i); JSONObject jsonobject = jarray.getJSONObject(i);
jsonToXmlStr(jsonobject, buffer); jsonToXmlStr(jsonobject, buffer, nowTab.append("\t"));
buffer.append("</").append(en.getKey()).append(">"); buffer.append(tab).append("</").append(en.getKey()).append(">\n");
} }
} }
} else if ("java.lang.String".equals(en.getValue().getClass().getName())) { } else if ("java.lang.String".equals(en.getValue().getClass().getName())) {
buffer.append("<").append(en.getKey()).append(">").append(en.getValue()); buffer.append(tab).append("<").append(en.getKey()).append(">").append(en.getValue());
buffer.append("</").append(en.getKey()).append(">"); buffer.append("</").append(en.getKey()).append(">\n");
} }
} }
} }
public static String jsonToXmlStr(JSONObject jObj) { public static String jsonToXmlStr(JSONObject jObj) {
StringBuffer buffer = new StringBuffer(); StringBuffer buffer = new StringBuffer();
buffer.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); buffer.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
try { try {
jsonToXmlStr(jObj, buffer); jsonToXmlStr(jObj, buffer, new StringBuffer(""));
} catch (Exception e) { } catch (Exception e) {
LogUtil.error(e.getMessage(), e); LogUtil.error(e.getMessage(), e);
} }
return buffer.toString(); return buffer.toString();
} }
// 传入完整的 xml 文本转换成 json 对象
public static JSONObject XmlToJson(String xml) {
JSONObject result = new JSONObject();
List<String> list = preProcessXml(xml);
try {
result = (JSONObject) XmlTagToJsonObject(list);
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
MSException.throwException(Translator.get("illegal_xml_format"));
}
return result;
}
// 预处理 xml 文本转换成 tag + data 的列表
private static List<String> preProcessXml(String xml) {
int begin = xml.indexOf("?>");
if(begin != -1) {
if(begin + 2 >= xml.length()) {
return null;
}
xml = xml.substring(begin + 2);
} // <?xml version="1.0" encoding="utf-8"?> 若存在则去除
String rgex = "\\s*";
Pattern pattern = Pattern.compile(rgex);
Matcher m = pattern.matcher(xml);
xml = m.replaceAll("");
rgex = ">";
pattern = Pattern.compile(rgex);
m = pattern.matcher(xml);
xml = m.replaceAll("> ");
rgex = "\\s*</";
pattern = Pattern.compile(rgex);
m = pattern.matcher(xml);
xml = m.replaceAll(" </");
return Arrays.asList(xml.split(" "));
}
// 传入预处理的列表返回转换成功的 json 对象
private static Object XmlTagToJsonObject(List<String> list) {
if(list == null || list.size() == 0)
return null;
Stack<String> tagStack = new Stack<>(); // tag
Stack<Object> valueStack = new Stack<>(); // 数据栈
valueStack.push(new JSONObject()); // 最终结果将存放在第一个入栈的元素中
for(String item : list) {
String beginTag = isBeginTag(item), endTag = isEndTag(item); // 判断当前 tag 是开始还是结尾
if(beginTag != null) {
tagStack.push(beginTag);
valueStack.push(new JSONObject());
} else if(endTag != null) {
if(endTag.equals(tagStack.peek())) { // 是一对 tag
Object topValue = valueStack.peek();
if(topValue instanceof String) { // 栈顶是纯数据 xml 节点
valueStack.pop();
}
valueStack.pop();
if(valueStack.peek() instanceof JSONObject) {
((JSONObject) valueStack.peek()).put(tagStack.peek(), topValue);
}
tagStack.pop();
}
} else {
valueStack.push(item);
}
}
if(valueStack.empty())
return null;
return valueStack.peek();
}
private static String isEndTag(String tagLine) {
String rgex = "</(\\w*)>";
Pattern pattern = Pattern.compile(rgex);// 匹配的模式    
Matcher m = pattern.matcher(tagLine);
if (m.find()) {
return m.group(1);
}
return null;
}
private static String isBeginTag(String tagLine) {
String rgex = "<(\\w*)>";
Pattern pattern = Pattern.compile(rgex);// 匹配的模式    
Matcher m = pattern.matcher(tagLine);
if (m.find()) {
return m.group(1);
}
return null;
}
} }

View File

@ -75,6 +75,7 @@ organization_does_not_belong_to_user=The current organization does not belong to
organization_id_is_null=Organization ID cannot be null organization_id_is_null=Organization ID cannot be null
#api #api
api_load_script_error=Load script error api_load_script_error=Load script error
illegal_xml_format=illegal XML format
api_report_is_null="Report is null, can't update" api_report_is_null="Report is null, can't update"
api_test_environment_already_exists="Api test environment already exists" api_test_environment_already_exists="Api test environment already exists"
api_test=API Test api_test=API Test

View File

@ -75,6 +75,7 @@ organization_does_not_belong_to_user=当前组织不属于当前用户
organization_id_is_null=组织 ID 不能为空 organization_id_is_null=组织 ID 不能为空
#api #api
api_load_script_error=读取脚本失败 api_load_script_error=读取脚本失败
illegal_xml_format=不合法的 XML 格式
api_report_is_null="测试报告是未生成,无法更新" api_report_is_null="测试报告是未生成,无法更新"
api_test_environment_already_exists="已存在该名称的环境配置" api_test_environment_already_exists="已存在该名称的环境配置"
api_test=接口测试 api_test=接口测试

View File

@ -75,6 +75,7 @@ organization_does_not_belong_to_user=當前組織不屬於當前用戶
organization_id_is_null=組織 ID 不能為空 organization_id_is_null=組織 ID 不能為空
#api #api
api_load_script_error=讀取腳本失敗 api_load_script_error=讀取腳本失敗
illegal_xml_format=不合法的 XML 格式
api_report_is_null="測試報告是未生成,無法更新" api_report_is_null="測試報告是未生成,無法更新"
api_test_environment_already_exists="已存在該名稱的環境配置" api_test_environment_already_exists="已存在該名稱的環境配置"
api_test=接口測試 api_test=接口測試