fix(接口定义): 修复swagger导入一些值缺失 & 请求体导出支持json、xml格式 (#1751)
* feat(测试跟踪): 测试用例下载模版增加标签列 * fix(接口定义): 扩大请求头键长度 * fix: schedule表对旧数据name字段兼容的补充 * fix(接口定义): 修复swagger导入一些值缺失 & 请求体导出支持json、xml格式
This commit is contained in:
parent
b67a6fafe2
commit
138f1e3874
|
@ -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.ApiResponses;
|
||||
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.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.fife.ui.rsyntaxtextarea.parser.XmlParser;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
|
@ -334,6 +337,16 @@ public class Swagger3Parser extends SwaggerAbstractParser {
|
|||
} else if (schema instanceof BinarySchema) {
|
||||
return getDefaultValueByPropertyType(schema);
|
||||
} 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);
|
||||
return propertiesResult == null ? getDefaultValueByPropertyType(schema) : propertiesResult;
|
||||
}
|
||||
|
@ -432,7 +445,9 @@ public class Swagger3Parser extends SwaggerAbstractParser {
|
|||
JSONObject requestBody = buildRequestBody(requestObject);
|
||||
swaggerApiInfo.setRequestBody(requestBody);
|
||||
// 设置响应体
|
||||
swaggerApiInfo.setResponses(new JSONObject());
|
||||
// JSONObject reponseObject = JSON.parseObject(apiDefinition.getResponse());
|
||||
// swaggerApiInfo.setResponses(buildResponseBody(reponseObject));
|
||||
//.....
|
||||
// 设置请求参数列表
|
||||
List<JSONObject> paramsList = buildParameters(requestObject);
|
||||
swaggerApiInfo.setParameters(paramsList);
|
||||
|
@ -459,6 +474,9 @@ public class Swagger3Parser extends SwaggerAbstractParser {
|
|||
if(params != null) {
|
||||
for(int i = 0; i < params.size(); ++i) {
|
||||
JSONObject param = params.getJSONObject(i); // 对于每个参数:
|
||||
if(param.get("name") == null || StringUtils.isEmpty(((String) param.get("name")))) {
|
||||
continue;
|
||||
} // 否则无参数的情况,可能多出一行空行
|
||||
SwaggerParams swaggerParam = new SwaggerParams();
|
||||
swaggerParam.setIn(typeMap.get(type)); // 利用 map,根据 request 的 key 设置对应的参数类型
|
||||
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("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");
|
||||
JSONObject requestBody = new JSONObject();
|
||||
JSONObject schema = new JSONObject();
|
||||
JSONObject schema = bodyInfo; // 需要转换导出
|
||||
JSONObject typeName = new JSONObject();
|
||||
schema.put("type", null);
|
||||
schema.put("format", null);
|
||||
|
@ -494,4 +523,55 @@ public class Swagger3Parser extends SwaggerAbstractParser {
|
|||
requestBody.put("content", content);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,46 +2,140 @@ package io.metersphere.commons.utils;
|
|||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.regex.*;
|
||||
|
||||
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();
|
||||
StringBuffer nowTab = new StringBuffer(tab.toString());
|
||||
for (Map.Entry<String, Object> en : se) {
|
||||
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());
|
||||
jsonToXmlStr(jo, buffer);
|
||||
buffer.append("</").append(en.getKey()).append(">");
|
||||
jsonToXmlStr(jo, buffer, nowTab.append("\t"));
|
||||
buffer.append(tab).append("</").append(en.getKey()).append(">\n");
|
||||
} else if ("com.alibaba.fastjson.JSONArray".equals(en.getValue().getClass().getName())) {
|
||||
JSONArray jarray = jObj.getJSONArray(en.getKey());
|
||||
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))) {
|
||||
JSONObject jsonobject = jarray.getJSONObject(i);
|
||||
jsonToXmlStr(jsonobject, buffer);
|
||||
buffer.append("</").append(en.getKey()).append(">");
|
||||
jsonToXmlStr(jsonobject, buffer, nowTab.append("\t"));
|
||||
buffer.append(tab).append("</").append(en.getKey()).append(">\n");
|
||||
}
|
||||
}
|
||||
} else if ("java.lang.String".equals(en.getValue().getClass().getName())) {
|
||||
buffer.append("<").append(en.getKey()).append(">").append(en.getValue());
|
||||
buffer.append("</").append(en.getKey()).append(">");
|
||||
buffer.append(tab).append("<").append(en.getKey()).append(">").append(en.getValue());
|
||||
buffer.append("</").append(en.getKey()).append(">\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String jsonToXmlStr(JSONObject jObj) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||
buffer.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
|
||||
try {
|
||||
jsonToXmlStr(jObj, buffer);
|
||||
jsonToXmlStr(jObj, buffer, new StringBuffer(""));
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
#api
|
||||
api_load_script_error=Load script error
|
||||
illegal_xml_format=illegal XML format
|
||||
api_report_is_null="Report is null, can't update"
|
||||
api_test_environment_already_exists="Api test environment already exists"
|
||||
api_test=API Test
|
||||
|
|
|
@ -75,6 +75,7 @@ organization_does_not_belong_to_user=当前组织不属于当前用户
|
|||
organization_id_is_null=组织 ID 不能为空
|
||||
#api
|
||||
api_load_script_error=读取脚本失败
|
||||
illegal_xml_format=不合法的 XML 格式
|
||||
api_report_is_null="测试报告是未生成,无法更新"
|
||||
api_test_environment_already_exists="已存在该名称的环境配置"
|
||||
api_test=接口测试
|
||||
|
|
|
@ -75,6 +75,7 @@ organization_does_not_belong_to_user=當前組織不屬於當前用戶
|
|||
organization_id_is_null=組織 ID 不能為空
|
||||
#api
|
||||
api_load_script_error=讀取腳本失敗
|
||||
illegal_xml_format=不合法的 XML 格式
|
||||
api_report_is_null="測試報告是未生成,無法更新"
|
||||
api_test_environment_already_exists="已存在該名稱的環境配置"
|
||||
api_test=接口測試
|
||||
|
|
Loading…
Reference in New Issue