From 036d5a5551ce4161dfcb6c12f1868c62e5078b13 Mon Sep 17 00:00:00 2001 From: chenjianxing Date: Mon, 7 Dec 2020 20:17:25 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat(=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95):?= =?UTF-8?q?=20=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89=20postman=20=E5=AF=BC?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../definition/parse/ApiDefinitionImport.java | 2 - .../dto/parse/postman/PostmanKeyValue.java | 2 + .../api/dto/scenario/KeyValue.java | 15 +- .../api/parse/ApiImportAbstractParser.java | 48 +++++ .../api/parse/ApiImportParser.java | 5 +- .../io/metersphere/api/parse/MsParser.java | 70 +++---- .../metersphere/api/parse/PostmanParser.java | 189 +++++++----------- .../metersphere/api/parse/Swagger2Parser.java | 77 +++---- .../api/service/ApiDefinitionService.java | 30 +-- .../api/service/ApiModuleService.java | 34 ++-- .../db/migration/V46__api_definition.sql | 2 +- .../request/http/ApiHttpRequestForm.vue | 2 +- 12 files changed, 219 insertions(+), 257 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImport.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImport.java index 572deba927..f4475d097f 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImport.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImport.java @@ -3,7 +3,6 @@ package io.metersphere.api.dto.definition.parse; import io.metersphere.api.dto.definition.ApiDefinitionResult; import lombok.Data; -import java.util.HashMap; import java.util.List; @Data @@ -11,5 +10,4 @@ public class ApiDefinitionImport { private String projectName; private String protocol; private List data; - private HashMap> resultMap; } diff --git a/backend/src/main/java/io/metersphere/api/dto/parse/postman/PostmanKeyValue.java b/backend/src/main/java/io/metersphere/api/dto/parse/postman/PostmanKeyValue.java index c68e4fc114..8fbe9ec1e0 100644 --- a/backend/src/main/java/io/metersphere/api/dto/parse/postman/PostmanKeyValue.java +++ b/backend/src/main/java/io/metersphere/api/dto/parse/postman/PostmanKeyValue.java @@ -7,6 +7,8 @@ public class PostmanKeyValue { private String key; private String value; private String type; + private String description; + private String contentType; public PostmanKeyValue() { } diff --git a/backend/src/main/java/io/metersphere/api/dto/scenario/KeyValue.java b/backend/src/main/java/io/metersphere/api/dto/scenario/KeyValue.java index d141ddaa01..25a9e982a1 100644 --- a/backend/src/main/java/io/metersphere/api/dto/scenario/KeyValue.java +++ b/backend/src/main/java/io/metersphere/api/dto/scenario/KeyValue.java @@ -20,22 +20,23 @@ public class KeyValue { private boolean required; public KeyValue() { - this.enable = true; - this.required = true; + this(null, null); } public KeyValue(String name, String value) { - this.name = name; - this.value = value; - this.enable = true; - this.required = true; + this(name, value, null); } public KeyValue(String name, String value, String description) { + this(name, value, description, null); + } + + public KeyValue(String name, String value, String description, String contentType) { this.name = name; this.value = value; - this.enable = true; this.description = description; + this.contentType = contentType; + this.enable = true; this.required = true; } diff --git a/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java b/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java index f8f19bc121..b1e20d8260 100644 --- a/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java @@ -1,11 +1,19 @@ package io.metersphere.api.parse; import io.metersphere.api.dto.ApiTestImportRequest; +import io.metersphere.api.dto.definition.ApiDefinitionResult; +import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; +import io.metersphere.api.dto.scenario.Body; import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.dto.scenario.Scenario; import io.metersphere.api.dto.scenario.request.HttpRequest; +import io.metersphere.api.dto.scenario.request.RequestType; +import io.metersphere.api.service.ApiModuleService; +import io.metersphere.base.domain.ApiModule; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.LogUtil; +import io.metersphere.commons.utils.SessionUtils; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import java.io.BufferedReader; @@ -16,9 +24,13 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.UUID; public abstract class ApiImportAbstractParser implements ApiImportParser { + protected String projectId; + protected ApiModuleService apiModuleService; + protected String getApiTestStr(InputStream source) { StringBuilder testStr = null; try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(source, StandardCharsets.UTF_8))) { @@ -47,6 +59,42 @@ public abstract class ApiImportAbstractParser implements ApiImportParser { } } + protected void createModule(ApiModule module) { + module.setProtocol(RequestType.HTTP); + List apiModules = apiModuleService.selectSameModule(module); + if (CollectionUtils.isEmpty(apiModules)) { + apiModuleService.addNode(module); + } else { + module.setId(apiModules.get(0).getId()); + } + } + + protected ApiDefinitionResult buildApiDefinition(String id, String name, String path, String method) { + ApiDefinitionResult apiDefinition = new ApiDefinitionResult(); + apiDefinition.setName(name); + apiDefinition.setPath(path); + apiDefinition.setProtocol(RequestType.HTTP); + apiDefinition.setMethod(method); + apiDefinition.setId(id); + apiDefinition.setProjectId(this.projectId); + apiDefinition.setUserId(SessionUtils.getUserId()); + return apiDefinition; + } + + protected MsHTTPSamplerProxy buildRequest(String name, String path, String method) { + MsHTTPSamplerProxy request = new MsHTTPSamplerProxy(); + request.setName(name); + request.setPath(path); + request.setMethod(method); + request.setProtocol(RequestType.HTTP); + request.setId(UUID.randomUUID().toString()); + request.setHeaders(new ArrayList<>()); + request.setArguments(new ArrayList<>()); + request.setRest(new ArrayList<>()); + request.setBody(new Body()); + return request; + } + protected void addContentType(HttpRequest request, String contentType) { // addHeader(request, "Content-Type", contentType); } diff --git a/backend/src/main/java/io/metersphere/api/parse/ApiImportParser.java b/backend/src/main/java/io/metersphere/api/parse/ApiImportParser.java index 6173f71c77..ee308cd82a 100644 --- a/backend/src/main/java/io/metersphere/api/parse/ApiImportParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/ApiImportParser.java @@ -2,12 +2,9 @@ package io.metersphere.api.parse; import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; -import io.metersphere.api.dto.parse.ApiImport; import java.io.InputStream; public interface ApiImportParser { - ApiImport parse(InputStream source, ApiTestImportRequest request); - ApiDefinitionImport parseApi(InputStream source, ApiTestImportRequest request); - + ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request); } diff --git a/backend/src/main/java/io/metersphere/api/parse/MsParser.java b/backend/src/main/java/io/metersphere/api/parse/MsParser.java index c9d165e247..676f8b224a 100644 --- a/backend/src/main/java/io/metersphere/api/parse/MsParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/MsParser.java @@ -6,7 +6,6 @@ import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.parser.Feature; import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; -import io.metersphere.api.dto.parse.ApiImport; import io.metersphere.api.dto.scenario.request.RequestType; import io.metersphere.commons.constants.MsRequestBodyType; import org.apache.commons.lang3.StringUtils; @@ -16,52 +15,43 @@ import java.io.InputStream; public class MsParser extends ApiImportAbstractParser { @Override - public ApiImport parse(InputStream source, ApiTestImportRequest request) { - String testStr = getApiTestStr(source); - ApiImport apiImport = JSON.parseObject(parsePluginFormat(testStr), ApiImport.class); - apiImport.getScenarios().forEach(scenario -> setScenarioByRequest(scenario, request)); - return apiImport; - } - - @Override - public ApiDefinitionImport parseApi(InputStream source, ApiTestImportRequest request) { + public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) { String testStr = getApiTestStr(source); + JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField); + if (testObject.get("projectName") == null) { + testStr = parsePluginFormat(testObject); + } ApiDefinitionImport apiImport = JSON.parseObject(testStr, ApiDefinitionImport.class); return apiImport; } - private String parsePluginFormat(String testStr) { - JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField); - if (testObject.get("scenarios") != null) { - return testStr; - } else { - //插件格式 - JSONArray scenarios = new JSONArray(); - testObject.keySet().forEach(scenarioName -> { - JSONObject scenario = new JSONObject(); - scenario.put("name", scenarioName); - JSONArray requestsObjects = new JSONArray(); - JSONObject requestsObject = testObject.getJSONObject(scenarioName); - requestsObject.keySet().forEach(requestName -> { - JSONObject requestObject = new JSONObject(true); - JSONObject requestTmpObject = requestsObject.getJSONObject(requestName); - //排序,确保type在第一个,否则转换失败 - if (StringUtils.isBlank(requestTmpObject.getString("type"))) { - requestObject.put("type", RequestType.HTTP); - } + private String parsePluginFormat( JSONObject testObject) { + //插件格式 + JSONArray scenarios = new JSONArray(); + testObject.keySet().forEach(scenarioName -> { + JSONObject scenario = new JSONObject(); + scenario.put("name", scenarioName); + JSONArray requestsObjects = new JSONArray(); + JSONObject requestsObject = testObject.getJSONObject(scenarioName); + requestsObject.keySet().forEach(requestName -> { + JSONObject requestObject = new JSONObject(true); + JSONObject requestTmpObject = requestsObject.getJSONObject(requestName); + //排序,确保type在第一个,否则转换失败 + if (StringUtils.isBlank(requestTmpObject.getString("type"))) { + requestObject.put("type", RequestType.HTTP); + } - requestTmpObject.keySet().forEach(key -> requestObject.put(key, requestTmpObject.get(key))); - requestObject.put("name", requestName); - parseBody(requestObject); - requestsObjects.add(requestObject); - }); - scenario.put("requests", requestsObjects); - scenarios.add(scenario); + requestTmpObject.keySet().forEach(key -> requestObject.put(key, requestTmpObject.get(key))); + requestObject.put("name", requestName); + parseBody(requestObject); + requestsObjects.add(requestObject); }); - JSONObject result = new JSONObject(); - result.put("scenarios", scenarios); - return result.toJSONString(); - } + scenario.put("requests", requestsObjects); + scenarios.add(scenario); + }); + JSONObject result = new JSONObject(); + result.put("scenarios", scenarios); + return result.toJSONString(); } private void parseBody(JSONObject requestObject) { diff --git a/backend/src/main/java/io/metersphere/api/parse/PostmanParser.java b/backend/src/main/java/io/metersphere/api/parse/PostmanParser.java index e8eed52279..ec5f63a386 100644 --- a/backend/src/main/java/io/metersphere/api/parse/PostmanParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/PostmanParser.java @@ -5,180 +5,135 @@ import com.alibaba.fastjson.JSONObject; import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.definition.ApiDefinitionResult; import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; -import io.metersphere.api.dto.definition.request.MsTestElement; -import io.metersphere.api.dto.definition.request.configurations.MsHeaderManager; import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; -import io.metersphere.api.dto.parse.ApiImport; import io.metersphere.api.dto.parse.postman.*; import io.metersphere.api.dto.scenario.Body; import io.metersphere.api.dto.scenario.KeyValue; -import io.metersphere.api.dto.scenario.Scenario; -import io.metersphere.api.dto.scenario.request.HttpRequest; -import io.metersphere.api.dto.scenario.request.Request; -import io.metersphere.api.dto.scenario.request.RequestType; +import io.metersphere.api.service.ApiModuleService; +import io.metersphere.base.domain.ApiModule; import io.metersphere.commons.constants.MsRequestBodyType; import io.metersphere.commons.constants.PostmanRequestBodyMode; +import io.metersphere.commons.utils.CommonBeanFactory; import org.apache.commons.lang3.StringUtils; -import org.apache.jorphan.collections.HashTree; import java.io.InputStream; import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; -import java.util.UUID; public class PostmanParser extends ApiImportAbstractParser { @Override - public ApiImport parse(InputStream source, ApiTestImportRequest request) { - - String testStr = getApiTestStr(source); - PostmanCollection postmanCollection = JSON.parseObject(testStr, PostmanCollection.class); - PostmanCollectionInfo info = postmanCollection.getInfo(); - List variables = postmanCollection.getVariable(); - ApiImport apiImport = new ApiImport(); - List scenarios = new ArrayList<>(); - - Scenario scenario = new Scenario(); - scenario.setName(info.getName()); - setScenarioByRequest(scenario, request); - parseItem(postmanCollection.getItem(), scenario, variables, scenarios); - apiImport.setScenarios(scenarios); - - return apiImport; - } - - @Override - public ApiDefinitionImport parseApi(InputStream source, ApiTestImportRequest request) { + public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) { String testStr = getApiTestStr(source); + this.projectId = request.getProjectId(); PostmanCollection postmanCollection = JSON.parseObject(testStr, PostmanCollection.class); List variables = postmanCollection.getVariable(); ApiDefinitionImport apiImport = new ApiDefinitionImport(); - List requests = new ArrayList<>(); - - parseItem(postmanCollection.getItem(), variables, requests); - apiImport.setData(requests); + List results = new ArrayList<>(); + parseItem(postmanCollection.getItem(), variables, results, buildModule(postmanCollection.getInfo().getName(), null)); + apiImport.setData(results); return apiImport; } - private void parseItem(List items, List variables, List scenarios) { + private void parseItem(List items, List variables, List results, ApiModule parentModule) { for (PostmanItem item : items) { List childItems = item.getItem(); if (childItems != null) { - parseItem(childItems, variables, scenarios); + ApiModule module = buildModule(item.getName(), parentModule); + parseItem(childItems, variables, results, module); } else { ApiDefinitionResult request = parsePostman(item); if (request != null) { - scenarios.add(request); + results.add(request); + } + if (parentModule != null) { + request.setModuleId(parentModule.getId()); } } } } + private ApiModule buildModule(String name, ApiModule parentModule) { + apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class); + ApiModule module; + if (parentModule != null) { + module = apiModuleService.getNewModule(name, this.projectId, parentModule.getLevel() + 1); + module.setParentId(parentModule.getId()); + } else { + module = apiModuleService.getNewModule(name, this.projectId, 1); + } + createModule(module); + return module; + } + private ApiDefinitionResult parsePostman(PostmanItem requestItem) { PostmanRequest requestDesc = requestItem.getRequest(); if (requestDesc == null) { return null; } + requestDesc.getAuth(); // todo 认证方式等待优化 PostmanUrl url = requestDesc.getUrl(); - ApiDefinitionResult request = new ApiDefinitionResult(); - request.setName(requestItem.getName()); - request.setPath(url.getRaw()); - request.setMethod(requestDesc.getMethod()); - request.setProtocol(RequestType.HTTP); - MsHTTPSamplerProxy requestElement = new MsHTTPSamplerProxy(); - requestElement.setName(requestItem.getName() + "Postman MHTTPSamplerProxy"); - requestElement.setBody(parseBody(requestDesc)); - requestElement.setArguments(parseKeyValue(url.getQuery())); - requestElement.setProtocol(RequestType.HTTP); - requestElement.setPath(url.getRaw()); - requestElement.setMethod(requestDesc.getMethod()); - requestElement.setId(UUID.randomUUID().toString()); - requestElement.setRest(new ArrayList()); - MsHeaderManager headerManager = new MsHeaderManager(); - headerManager.setId(UUID.randomUUID().toString()); - headerManager.setName(requestItem.getName() + "Postman MsHeaderManager"); - headerManager.setHeaders(parseKeyValue(requestDesc.getHeader())); - HashTree tree = new HashTree(); - tree.add(headerManager); - LinkedList list = new LinkedList<>(); - list.add(headerManager); - requestElement.setHashTree(list); - request.setRequest(JSON.toJSONString(requestElement)); - return request; + MsHTTPSamplerProxy request = buildRequest(requestItem.getName(), url.getRaw(), requestDesc.getMethod()); + ApiDefinitionResult apiDefinition = + buildApiDefinition(request.getId(), requestItem.getName(), url.getRaw(), requestDesc.getMethod()); + parseBody(request.getBody(), requestDesc); + request.setArguments(parseKeyValue(url.getQuery())); + request.setHeaders(parseKeyValue(requestDesc.getHeader())); + apiDefinition.setRequest(JSON.toJSONString(request)); + return apiDefinition; } - private List parseKeyValue(List postmanKeyValues) { if (postmanKeyValues == null) { return null; } List keyValues = new ArrayList<>(); - postmanKeyValues.forEach(item -> keyValues.add(new KeyValue(item.getKey(), item.getValue()))); + postmanKeyValues.forEach(item -> keyValues.add(new KeyValue(item.getKey(), item.getValue(), item.getDescription(), item.getContentType()))); return keyValues; } - private void parseItem(List items, Scenario scenario, List variables, List scenarios) { - List requests = new ArrayList<>(); - for (PostmanItem item : items) { - List childItems = item.getItem(); - if (childItems != null) { - Scenario subScenario = new Scenario(); - subScenario.setName(item.getName()); - subScenario.setEnvironmentId(scenario.getEnvironmentId()); - parseItem(childItems, subScenario, variables, scenarios); - } else { - Request request = parseRequest(item); - if (request != null) { - requests.add(request); - } - } - } - scenario.setVariables(parseKeyValue(variables)); - scenario.setRequests(requests); - scenarios.add(scenario); - } - - private Request parseRequest(PostmanItem requestItem) { - HttpRequest request = new HttpRequest(); - PostmanRequest requestDesc = requestItem.getRequest(); - if (requestDesc == null) { - return null; - } - PostmanUrl url = requestDesc.getUrl(); - request.setName(requestItem.getName()); - request.setUrl(url.getRaw()); - request.setUseEnvironment(false); - request.setMethod(requestDesc.getMethod()); - request.setHeaders(parseKeyValue(requestDesc.getHeader())); - request.setParameters(parseKeyValue(url.getQuery())); - request.setBody(parseBody(requestDesc)); - return request; - } - - private Body parseBody(PostmanRequest requestDesc) { - Body body = new Body(); + private void parseBody(Body body, PostmanRequest requestDesc) { JSONObject postmanBody = requestDesc.getBody(); if (postmanBody == null) { - return null; + return; } String bodyMode = postmanBody.getString("mode"); if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.RAW.value())) { - body.setRaw(postmanBody.getString(bodyMode)); - body.setType(MsRequestBodyType.RAW.value()); - JSONObject options = postmanBody.getJSONObject("options"); - if (options != null) { - JSONObject raw = options.getJSONObject(PostmanRequestBodyMode.RAW.value()); - if (raw != null) { - body.setFormat(raw.getString("language")); - } - } - } else if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.FORM_DATA.value()) || StringUtils.equals(bodyMode, PostmanRequestBodyMode.URLENCODED.value())) { + parseRawBody(body, postmanBody, bodyMode); + } else if (StringUtils.equalsAny(bodyMode, PostmanRequestBodyMode.FORM_DATA.value(), PostmanRequestBodyMode.URLENCODED.value())) { List postmanKeyValues = JSON.parseArray(postmanBody.getString(bodyMode), PostmanKeyValue.class); - body.setType(MsRequestBodyType.KV.value()); body.setKvs(parseKeyValue(postmanKeyValues)); + if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.FORM_DATA.value())) { + body.setType(Body.FORM_DATA); + } else if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.URLENCODED.value())) { + body.setType(Body.WWW_FROM); + } + } else if (StringUtils.equals(bodyMode, PostmanRequestBodyMode.FILE.value())) { + body.setType(Body.BINARY); + body.setKvs(new ArrayList<>()); } - return body; } + private void parseRawBody(Body body, JSONObject postmanBody, String bodyMode) { + body.setRaw(postmanBody.getString(bodyMode)); + body.setType(MsRequestBodyType.RAW.value()); + JSONObject options = postmanBody.getJSONObject("options"); + if (options != null) { + JSONObject raw = options.getJSONObject(PostmanRequestBodyMode.RAW.value()); + if (raw != null) { + String bodyType = ""; + switch (raw.getString("language")) { + case "json": + bodyType = Body.JSON; + break; + case "xml": + bodyType = Body.XML; + break; + default: + bodyType = Body.RAW; + } + body.setType(bodyType); + } + } + } } diff --git a/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java b/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java index a886ee77d2..112067cd4a 100644 --- a/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java +++ b/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java @@ -8,11 +8,13 @@ import io.metersphere.api.dto.definition.ApiDefinitionResult; import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; import io.metersphere.api.dto.definition.response.HttpResponse; -import io.metersphere.api.dto.parse.ApiImport; import io.metersphere.api.dto.scenario.Body; import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.dto.scenario.request.RequestType; +import io.metersphere.api.service.ApiModuleService; +import io.metersphere.base.domain.ApiModule; import io.metersphere.commons.constants.SwaggerParameterType; +import io.metersphere.commons.utils.CommonBeanFactory; import io.swagger.models.*; import io.swagger.models.parameters.*; import io.swagger.models.properties.*; @@ -28,7 +30,7 @@ public class Swagger2Parser extends ApiImportAbstractParser { private Map definitions = null; @Override - public ApiDefinitionImport parseApi(InputStream source, ApiTestImportRequest request) { + public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) { Swagger swagger; if (StringUtils.isNotBlank(request.getSwaggerUrl())) { swagger = new SwaggerParser().read(request.getSwaggerUrl()); @@ -36,22 +38,18 @@ public class Swagger2Parser extends ApiImportAbstractParser { swagger = new SwaggerParser().readWithInfo(getApiTestStr(source)).getSwagger(); } ApiDefinitionImport definitionImport = new ApiDefinitionImport(); - definitionImport.setResultMap(parseRequests(swagger)); + this.projectId = request.getProjectId(); + definitionImport.setData(parseRequests(swagger)); return definitionImport; } - @Override - public ApiImport parse(InputStream source, ApiTestImportRequest request) { - return null; - } - - private HashMap> parseRequests(Swagger swagger) { + private List parseRequests(Swagger swagger) { Map paths = swagger.getPaths(); Set pathNames = paths.keySet(); this.definitions = swagger.getDefinitions(); - HashMap> moduleMap = new HashMap<>(); + List results = new ArrayList<>(); for (String pathName : pathNames) { Path path = paths.get(pathName); @@ -59,76 +57,55 @@ public class Swagger2Parser extends ApiImportAbstractParser { Set httpMethods = operationMap.keySet(); for (HttpMethod method : httpMethods) { Operation operation = operationMap.get(method); - - ApiDefinitionResult apiDefinition = buildApiDefinition(operation, pathName, method.name()); MsHTTPSamplerProxy request = buildRequest(operation, pathName, method.name()); + ApiDefinitionResult apiDefinition = buildApiDefinition(request.getId(), operation, pathName, method.name()); parseParameters(operation, request); apiDefinition.setRequest(JSON.toJSONString(request)); - apiDefinition.setId(request.getId()); apiDefinition.setResponse(JSON.toJSONString(parseResponse(operation.getResponses()))); - buildResultMap(moduleMap, apiDefinition, operation); + buildModule(apiDefinition, operation); + results.add(apiDefinition); } } this.definitions = null; - return moduleMap; + return results; } - private void buildResultMap(HashMap> moduleMap, - ApiDefinitionResult apiDefinition, Operation operation) { + private void buildModule(ApiDefinitionResult apiDefinition, Operation operation) { List tags = operation.getTags(); if (tags != null) { tags.forEach(tag -> { - List list = moduleMap.get(tag); - if (list == null) { - list = new ArrayList<>(); - moduleMap.put(tag, list); - } - list.add(apiDefinition); + apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class); + ApiModule module = apiModuleService.getNewModule(tag, this.projectId, 1); + createModule(module); + apiDefinition.setModuleId(module.getId()); }); - } else { - List list = moduleMap.get("#default"); - if (list == null) { - list = new ArrayList<>(); - moduleMap.put("#default", list); - } - list.add(apiDefinition); } } - private ApiDefinitionResult buildApiDefinition(Operation operation, String path, String method) { - ApiDefinitionResult apiDefinition = new ApiDefinitionResult(); + private ApiDefinitionResult buildApiDefinition(String id, Operation operation, String path, String method) { + String name = ""; if (StringUtils.isNotBlank(operation.getSummary())) { - apiDefinition.setName(operation.getSummary()); + name = operation.getSummary(); } else { - apiDefinition.setName(operation.getOperationId()); + name = operation.getOperationId(); } - apiDefinition.setPath(path); - apiDefinition.setProtocol(RequestType.HTTP); - apiDefinition.setMethod(method); - return apiDefinition; + return buildApiDefinition(id, name, path, method); } + private MsHTTPSamplerProxy buildRequest(Operation operation, String path, String method) { - MsHTTPSamplerProxy request = new MsHTTPSamplerProxy(); + String name = ""; if (StringUtils.isNotBlank(operation.getSummary())) { - request.setName(operation.getSummary()); + name = operation.getSummary(); } else { - request.setName(operation.getOperationId()); + name = operation.getOperationId(); } - request.setPath(path); - request.setMethod(method); - request.setProtocol(RequestType.HTTP); - return request; + return buildRequest(name, path, method); } private void parseParameters(Operation operation, MsHTTPSamplerProxy request) { List parameters = operation.getParameters(); - request.setId(UUID.randomUUID().toString()); - request.setHeaders(new ArrayList<>()); - request.setArguments(new ArrayList<>()); - request.setRest(new ArrayList<>()); - request.setBody(new Body()); request.getBody().setType(getBodyType(operation)); // todo 路径变量 {xxx} 是否要转换 diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java index 5edcd6d7c3..fef7732035 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -323,7 +323,7 @@ public class ApiDefinitionService { ApiImportParser apiImportParser = ApiImportParserFactory.getApiImportParser(request.getPlatform()); ApiDefinitionImport apiImport = null; try { - apiImport = Objects.requireNonNull(apiImportParser).parseApi(file == null ? null : file.getInputStream(), request); + apiImport = Objects.requireNonNull(apiImportParser).parse(file == null ? null : file.getInputStream(), request); } catch (Exception e) { LogUtil.error(e.getMessage(), e); MSException.throwException(Translator.get("parse_data_error")); @@ -335,30 +335,16 @@ public class ApiDefinitionService { private void importApiTest(ApiTestImportRequest importRequest, ApiDefinitionImport apiImport) { SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); ApiDefinitionMapper batchMapper = sqlSession.getMapper(ApiDefinitionMapper.class); - HashMap> resultMap = apiImport.getResultMap(); - Integer batchNum = 1; - for (String key : resultMap.keySet()) { - List apiDefinitions = resultMap.get(key); - ApiModule newModule = apiModuleService.getNewModule(key, importRequest.getProjectId(), 1); - newModule.setProtocol(RequestType.HTTP); - if (!StringUtils.equals(key, "#default")) { - apiModuleService.addNode(newModule); + List data = apiImport.getData(); + for (int i = 0; i < data.size(); i++) { + ApiDefinitionResult item = data.get(i); + if (item.getName().length() > 255) { + item.setName(item.getName().substring(0, 255)); } - - apiDefinitions.forEach(item -> { - item.setProjectId(importRequest.getProjectId()); - if (!StringUtils.equals(key, "#default")) { - item.setModuleId(newModule.getId()); - } - item.setModulePath(importRequest.getModulePath()); - item.setEnvironmentId(importRequest.getEnvironmentId()); - item.setUserId(SessionUtils.getUserId()); - createTest(item, batchMapper); - }); - if (batchNum % 300 == 0) { + createTest(item, batchMapper); + if (i % 300 == 0) { sqlSession.flushStatements(); } - batchNum++; } sqlSession.flushStatements(); } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiModuleService.java b/backend/src/main/java/io/metersphere/api/service/ApiModuleService.java index 1edffcb1a5..db748be12b 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiModuleService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiModuleService.java @@ -98,6 +98,10 @@ public class ApiModuleService { public String addNode(ApiModule node) { validateNode(node); + return addNodeWithoutValidate(node); + } + + public String addNodeWithoutValidate(ApiModule node) { node.setCreateTime(System.currentTimeMillis()); node.setUpdateTime(System.currentTimeMillis()); node.setId(UUID.randomUUID().toString()); @@ -126,24 +130,28 @@ public class ApiModuleService { private void checkApiModuleExist(ApiModule node) { if (node.getName() != null) { - ApiModuleExample example = new ApiModuleExample(); - ApiModuleExample.Criteria criteria = example.createCriteria(); - criteria.andNameEqualTo(node.getName()) - .andProjectIdEqualTo(node.getProjectId()); - if (StringUtils.isNotBlank(node.getParentId())) { - criteria.andParentIdEqualTo(node.getParentId()); - } else { - criteria.andParentIdIsNull(); - } - if (StringUtils.isNotBlank(node.getId())) { - criteria.andIdNotEqualTo(node.getId()); - } - if (apiModuleMapper.selectByExample(example).size() > 0) { + if (selectSameModule(node).size() > 0) { MSException.throwException(Translator.get("test_case_module_already_exists") + ": " + node.getName()); } } } + public List selectSameModule(ApiModule node) { + ApiModuleExample example = new ApiModuleExample(); + ApiModuleExample.Criteria criteria = example.createCriteria(); + criteria.andNameEqualTo(node.getName()) + .andProjectIdEqualTo(node.getProjectId()); + if (StringUtils.isNotBlank(node.getParentId())) { + criteria.andParentIdEqualTo(node.getParentId()); + } else { + criteria.andParentIdIsNull(); + } + if (StringUtils.isNotBlank(node.getId())) { + criteria.andIdNotEqualTo(node.getId()); + } + return apiModuleMapper.selectByExample(example); + } + private List queryByModuleIds(List nodeIds) { ApiDefinitionRequest apiDefinitionRequest = new ApiDefinitionRequest(); apiDefinitionRequest.setModuleIds(nodeIds); diff --git a/backend/src/main/resources/db/migration/V46__api_definition.sql b/backend/src/main/resources/db/migration/V46__api_definition.sql index 91049386b7..3509a1a023 100644 --- a/backend/src/main/resources/db/migration/V46__api_definition.sql +++ b/backend/src/main/resources/db/migration/V46__api_definition.sql @@ -18,7 +18,7 @@ CREATE TABLE IF NOT EXISTS `api_definition` ( `name` varchar(255) NOT NULL COMMENT 'Test name', `method` varchar(64) NOT NULL COMMENT 'method', `protocol` varchar(255) NOT NULL COMMENT 'request protocol', - `path` varchar(255) DEFAULT NULL COMMENT 'request path', + `path` varchar(1000) DEFAULT NULL COMMENT 'request path', `module_path` varchar(1000) COMMENT 'module path', `description` varchar(255) DEFAULT NULL COMMENT 'Test description', `environment_id` varchar(50) DEFAULT NULL COMMENT 'environment id', diff --git a/frontend/src/business/components/api/definition/components/request/http/ApiHttpRequestForm.vue b/frontend/src/business/components/api/definition/components/request/http/ApiHttpRequestForm.vue index 2aeba0e768..b7b0f6735c 100644 --- a/frontend/src/business/components/api/definition/components/request/http/ApiHttpRequestForm.vue +++ b/frontend/src/business/components/api/definition/components/request/http/ApiHttpRequestForm.vue @@ -18,7 +18,7 @@ - + {{$t('api_test.definition.request.query_param')}}
From 91d37ccafe01f53e1b9c62291940492aec0a473c Mon Sep 17 00:00:00 2001 From: chenjianxing Date: Tue, 8 Dec 2020 11:28:23 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat(=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95):?= =?UTF-8?q?=20=20=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/metersphere/api/parse/MsParser.java | 123 +++++++++++------- .../metersphere/api/parse/Swagger2Parser.java | 8 +- frontend/src/business/components/xpack | 2 +- 3 files changed, 81 insertions(+), 52 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/parse/MsParser.java b/backend/src/main/java/io/metersphere/api/parse/MsParser.java index 676f8b224a..78effbfff9 100644 --- a/backend/src/main/java/io/metersphere/api/parse/MsParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/MsParser.java @@ -5,12 +5,21 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.parser.Feature; import io.metersphere.api.dto.ApiTestImportRequest; +import io.metersphere.api.dto.definition.ApiDefinitionResult; import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; +import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; +import io.metersphere.api.dto.scenario.Body; +import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.dto.scenario.request.RequestType; -import io.metersphere.commons.constants.MsRequestBodyType; -import org.apache.commons.lang3.StringUtils; +import io.metersphere.api.service.ApiModuleService; +import io.metersphere.base.domain.ApiModule; +import io.metersphere.commons.utils.CommonBeanFactory; +import org.apache.commons.collections.CollectionUtils; import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; public class MsParser extends ApiImportAbstractParser { @@ -18,43 +27,72 @@ public class MsParser extends ApiImportAbstractParser { public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) { String testStr = getApiTestStr(source); JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField); - if (testObject.get("projectName") == null) { - testStr = parsePluginFormat(testObject); + apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class); + this.projectId = request.getProjectId(); + if (testObject.get("projectName") != null) { + return parseMsFormat(testStr, request); + } else { + return parsePluginFormat(testObject); } - ApiDefinitionImport apiImport = JSON.parseObject(testStr, ApiDefinitionImport.class); + } + + private ApiDefinitionImport parseMsFormat(String testStr, ApiTestImportRequest importRequest) { + + ApiDefinitionImport apiDefinitionImport = JSON.parseObject(testStr, ApiDefinitionImport.class); + List data = apiDefinitionImport.getData(); + data.forEach(apiDefinition -> { + String id = UUID.randomUUID().toString(); + apiDefinition.setModuleId(null); + apiDefinition.setId(id); + apiDefinition.setProjectId(this.projectId); + String request = apiDefinition.getRequest(); + JSONObject requestObj = JSONObject.parseObject(request); + requestObj.put("id", id); + apiDefinition.setRequest(JSONObject.toJSONString(requestObj)); + }); + return apiDefinitionImport; + } + + private ApiDefinitionImport parsePluginFormat(JSONObject testObject) { + List results = new ArrayList<>(); + ApiDefinitionImport apiImport = new ApiDefinitionImport(); + apiImport.setProtocol(RequestType.HTTP); + apiImport.setData(results); + testObject.keySet().forEach(tag -> { + ApiModule module = apiModuleService.getNewModule(tag, this.projectId, 1); + createModule(module); + JSONObject requests = testObject.getJSONObject(tag); + requests.keySet().forEach(requestName -> { + + JSONObject requestObject = requests.getJSONObject(requestName); + String path = requestObject.getString("url"); + String method = requestObject.getString("method"); + + MsHTTPSamplerProxy request = buildRequest(requestName, path, method); + ApiDefinitionResult apiDefinition = buildApiDefinition(request.getId(), requestName, path, method); + apiDefinition.setModuleId(module.getId()); + apiDefinition.setProjectId(this.projectId); + + parseBody(requestObject, request.getBody()); + parseHeader(requestObject, request.getHeaders()); + apiDefinition.setRequest(JSONObject.toJSONString(request)); + results.add(apiDefinition); + }); + }); return apiImport; } - private String parsePluginFormat( JSONObject testObject) { - //插件格式 - JSONArray scenarios = new JSONArray(); - testObject.keySet().forEach(scenarioName -> { - JSONObject scenario = new JSONObject(); - scenario.put("name", scenarioName); - JSONArray requestsObjects = new JSONArray(); - JSONObject requestsObject = testObject.getJSONObject(scenarioName); - requestsObject.keySet().forEach(requestName -> { - JSONObject requestObject = new JSONObject(true); - JSONObject requestTmpObject = requestsObject.getJSONObject(requestName); - //排序,确保type在第一个,否则转换失败 - if (StringUtils.isBlank(requestTmpObject.getString("type"))) { - requestObject.put("type", RequestType.HTTP); - } - - requestTmpObject.keySet().forEach(key -> requestObject.put(key, requestTmpObject.get(key))); - requestObject.put("name", requestName); - parseBody(requestObject); - requestsObjects.add(requestObject); - }); - scenario.put("requests", requestsObjects); - scenarios.add(scenario); - }); - JSONObject result = new JSONObject(); - result.put("scenarios", scenarios); - return result.toJSONString(); + private void parseHeader(JSONObject requestObject, List msHeaders) { + JSONArray headers = requestObject.getJSONArray("headers"); + if (CollectionUtils.isNotEmpty(headers)) { + for (int i = 0; i < headers.size(); i++) { + JSONObject header = headers.getJSONObject(i); + msHeaders.add(new KeyValue(header.getString("name"), header.getString("value"))); + } + } } - private void parseBody(JSONObject requestObject) { + private void parseBody(JSONObject requestObject, Body msBody) { if (requestObject.containsKey("body")) { Object body = requestObject.get("body"); if (body instanceof JSONArray) { @@ -65,25 +103,18 @@ public class MsParser extends ApiImportAbstractParser { String tmp = bodies.getString(i); bodyStr.append(tmp); } - JSONObject bodyObject = new JSONObject(); - bodyObject.put("raw", bodyStr); - bodyObject.put("type", MsRequestBodyType.RAW.value()); - requestObject.put("body", bodyObject); + msBody.setType(Body.RAW); + msBody.setRaw(bodyStr.toString()); } } else if (body instanceof JSONObject) { JSONObject bodyObj = requestObject.getJSONObject("body"); if (bodyObj != null) { - JSONArray kvs = new JSONArray(); + ArrayList kvs = new ArrayList<>(); bodyObj.keySet().forEach(key -> { - JSONObject kv = new JSONObject(); - kv.put("name", key); - kv.put("value", bodyObj.getString(key)); - kvs.add(kv); + kvs.add(new KeyValue(key, bodyObj.getString(key))); }); - JSONObject bodyRes = new JSONObject(); - bodyRes.put("kvs", kvs); - bodyRes.put("type", MsRequestBodyType.KV.value()); - requestObject.put("body", bodyRes); + msBody.setKvs(kvs); + msBody.setType(Body.WWW_FROM); } } } diff --git a/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java b/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java index 112067cd4a..b5dea282b7 100644 --- a/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java +++ b/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java @@ -156,9 +156,9 @@ public class Swagger2Parser extends ApiImportAbstractParser { case "application/xml": bodyType = Body.XML; break; -// case "": //todo binary 啥类型 -// bodyType = Body.BINARY; -// break; + case "": + bodyType = Body.BINARY; + break; default: bodyType = Body.RAW; } @@ -235,7 +235,6 @@ public class Swagger2Parser extends ApiImportAbstractParser { refSet.add(simpleRef); if (model != null) { JSONObject bodyParameters = getBodyParameters(model.getProperties(), refSet); - //body.setRaw(bodyParameters.toJSONString()); return bodyParameters.toJSONString(); } } else if (schema instanceof ArrayModel) { @@ -250,7 +249,6 @@ public class Swagger2Parser extends ApiImportAbstractParser { Model model = definitions.get(simpleRef); JSONArray propertyList = new JSONArray(); propertyList.add(getBodyParameters(model.getProperties(), refSet)); - // body.setRaw(propertyList.toString()); return propertyList.toString(); } } diff --git a/frontend/src/business/components/xpack b/frontend/src/business/components/xpack index 8a972a1987..a22a3005d9 160000 --- a/frontend/src/business/components/xpack +++ b/frontend/src/business/components/xpack @@ -1 +1 @@ -Subproject commit 8a972a198775b3783ed6e4cef27197e53d1ebdc8 +Subproject commit a22a3005d9bd254793fcf634d72539cbdf31be3a From 7fe2164f34a810121fcfdc75944cc0e74dfe1242 Mon Sep 17 00:00:00 2001 From: BugKing Date: Tue, 8 Dec 2020 13:44:40 +0800 Subject: [PATCH 3/3] =?UTF-8?q?style:=20=E8=B0=83=E6=95=B4=E9=A1=B6?= =?UTF-8?q?=E9=83=A8=E5=AF=BC=E8=88=AA=E8=8F=9C=E5=8D=95=E9=AB=98=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/business/App.vue | 1 + frontend/src/business/components/common/head/HeaderTopMenus.vue | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/business/App.vue b/frontend/src/business/App.vue index 4efdc55ae0..8bc9c05ee2 100644 --- a/frontend/src/business/App.vue +++ b/frontend/src/business/App.vue @@ -86,6 +86,7 @@ export default { background-color: rgb(44, 42, 72); color: rgb(245, 245, 245); font-size: 14px; + height: 40px; } .logo { diff --git a/frontend/src/business/components/common/head/HeaderTopMenus.vue b/frontend/src/business/components/common/head/HeaderTopMenus.vue index 62b1fd9377..57907d9c7a 100644 --- a/frontend/src/business/components/common/head/HeaderTopMenus.vue +++ b/frontend/src/business/components/common/head/HeaderTopMenus.vue @@ -56,7 +56,7 @@ .el-menu >>> .el-menu-item { box-sizing: border-box; - height: 37px; + height: 40px; }