diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java b/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java index 54ec106dbc..31fed91906 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java @@ -13,6 +13,7 @@ import io.metersphere.api.dto.swaggerurl.SwaggerTaskResult; import io.metersphere.api.dto.swaggerurl.SwaggerUrlRequest; import io.metersphere.api.service.ApiDefinitionService; import io.metersphere.api.service.EsbApiParamService; +import io.metersphere.api.service.EsbImportService; import io.metersphere.base.domain.ApiDefinition; import io.metersphere.base.domain.Schedule; import io.metersphere.commons.constants.RoleConstants; @@ -32,6 +33,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; import java.net.MalformedURLException; import java.util.Date; import java.util.List; @@ -49,6 +51,8 @@ public class ApiDefinitionController { private CheckPermissionService checkPermissionService; @Resource private EsbApiParamService esbApiParamService; + @Resource + private EsbImportService esbImportService; @PostMapping("/list/{goPage}/{pageSize}") public Pager> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiDefinitionRequest request) { @@ -254,4 +258,10 @@ public class ApiDefinitionController { public String preview(@RequestBody String jsonSchema) { return JSONSchemaGenerator.getJson(jsonSchema); } + + @GetMapping("/export/esbExcelTemplate") + @RequiresRoles(value = {RoleConstants.ADMIN, RoleConstants.ORG_ADMIN, RoleConstants.TEST_MANAGER}, logical = Logical.OR) + public void testCaseTemplateExport(HttpServletResponse response) { + esbImportService.templateExport(response); + } } diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/EsbDataStruct.java b/backend/src/main/java/io/metersphere/api/dto/automation/EsbDataStruct.java index 0fa226b32f..49f30fdfcd 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/EsbDataStruct.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/EsbDataStruct.java @@ -8,6 +8,7 @@ import org.dom4j.Element; import java.util.ArrayList; import java.util.List; +import java.util.UUID; /** * //ESB数据格式 @@ -19,15 +20,69 @@ import java.util.List; @Getter @Setter public class EsbDataStruct { + private String uuid; private String name; private String value; private String type; private String systemName; private String contentType; - private String required; + private boolean required; private String description; private List children; + public void init(){ + this.uuid = UUID.randomUUID().toString(); + this.systemName = ""; + this.description = ""; + this.value=""; + this.required = true; + this.contentType = ""; + this.type = ""; + this.children = new ArrayList<>(); + } + + public boolean initDefaultData(String name, String typeLength,String chineseName,String desc){ + this.init(); + if(StringUtils.isEmpty(name)){return false; } + if(typeLength == null){ + typeLength = ""; + }else{ + typeLength = typeLength.trim(); + typeLength = typeLength.toLowerCase(); + } + + this.name = name; + + if(typeLength.startsWith("string")){ + this.type = "string"; + String lengthStr = typeLength.substring(6); + if(lengthStr.startsWith("(") && lengthStr.endsWith(")")){ + try { + int length = Integer.parseInt(lengthStr.substring(1,lengthStr.length()-1)); + this.contentType = String.valueOf(length); + }catch (Exception e){ } + + } + }else if(typeLength.startsWith("array")){ + this.type = "array"; + }else{ + this.type = "object"; + } + + if(StringUtils.isEmpty(desc)){desc = "";} + if(StringUtils.isNotEmpty(chineseName)){ + this.description = chineseName+":"+desc; + }else{ + this.description =desc; + } + + if(this.description.endsWith(":")){ + this.description = this.description.substring(0,this.description.length()-1); + } + + return true; + } + public EsbDataStruct copy(boolean copyChildren) { EsbDataStruct returnObj = new EsbDataStruct(); returnObj.name = this.name; 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 c58d775624..cc1c6626d7 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 @@ -1,12 +1,12 @@ package io.metersphere.api.dto.definition.parse; -import io.metersphere.api.dto.definition.request.MsScenario; import io.metersphere.base.domain.ApiDefinitionWithBLOBs; -import io.metersphere.base.domain.ApiScenarioWithBLOBs; import io.metersphere.base.domain.ApiTestCaseWithBLOBs; +import io.metersphere.base.domain.EsbApiParamsWithBLOBs; import lombok.Data; import java.util.List; +import java.util.Map; @Data public class ApiDefinitionImport { @@ -16,4 +16,7 @@ public class ApiDefinitionImport { // 新版本带用例导出 private List cases; + + //ESB文件导入的附属数据类 + private Map esbApiParamsMap; } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImportParserFactory.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImportParserFactory.java index f7db9334b0..3fb2000af7 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImportParserFactory.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImportParserFactory.java @@ -14,6 +14,8 @@ public class ApiDefinitionImportParserFactory { return new Swagger2Parser(); }else if (StringUtils.equals(ApiImportPlatform.Har.name(), platform)) { return new HarParser(); + }else if (StringUtils.equals(ApiImportPlatform.ESB.name(), platform)) { + return new ESBParser(); } return null; } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/ESBParser.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/ESBParser.java new file mode 100644 index 0000000000..0c6c51fdd0 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/ESBParser.java @@ -0,0 +1,769 @@ +package io.metersphere.api.dto.definition.parse; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import io.metersphere.api.dto.ApiTestImportRequest; +import io.metersphere.api.dto.automation.EsbDataStruct; +import io.metersphere.api.dto.definition.parse.esb.EsbExcelDataStruct; +import io.metersphere.api.dto.definition.parse.esb.EsbSheetDataStruct; +import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor; +import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler; +import io.metersphere.api.dto.scenario.request.RequestType; +import io.metersphere.base.domain.ApiDefinitionWithBLOBs; +import io.metersphere.base.domain.ApiModule; +import io.metersphere.base.domain.EsbApiParamsWithBLOBs; +import io.metersphere.commons.utils.SessionUtils; +import io.swagger.models.Model; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.usermodel.*; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.net.URLEncoder; +import java.text.DateFormat; +import java.util.*; +import java.util.regex.Pattern; + +/** + * @author song.tianyang + * @Date 2021/3/10 11:14 上午 + * @Description + */ +public class ESBParser extends EsbAbstractParser { + + private final int REQUEST_MESSAGE_ROW = 5; + + private Map definitions = null; + + public static void export(HttpServletResponse response, String fileName) { + + XSSFWorkbook wb = null; + ServletOutputStream out = null; + try { + wb = getTemplate(); + out = response.getOutputStream(); + response.reset(); + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx"); + wb.write(out); + wb.close(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (out != null) { + try { + out.close(); + } catch (Exception e) { + + } + } + if (wb != null) { + try { + wb.close(); + } catch (Exception e) { + + } + } + } + } + + private static XSSFWorkbook getTemplate() { + XSSFWorkbook workbook = new XSSFWorkbook(); + XSSFFont font = workbook.createFont(); + font.setFontHeightInPoints((short) 9); + Map cellStyleMap = createCellStle(workbook); + XSSFSheet headSheet = workbook.createSheet("公共报文头"); + generateSheet(headSheet,true, font,cellStyleMap); + XSSFSheet bodySheet = workbook.createSheet("接口报文信息"); + generateSheet(bodySheet, false,font,cellStyleMap); + return workbook; + } + + private static Map createCellStle(XSSFWorkbook workbook) { + Map cellStype = new HashMap<>(); + short[] colorIndexArr = {IndexedColors.LIGHT_GREEN.getIndex(), IndexedColors.ORCHID.getIndex(), IndexedColors.YELLOW.getIndex()}; + for (short colorIndex : colorIndexArr) { + XSSFCellStyle style = workbook.createCellStyle(); +// style.setFillForegroundColor(IndexedColors.VIOLET.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + style.setBorderTop(BorderStyle.THIN); + + String name = ""; + if(colorIndex == IndexedColors.LIGHT_GREEN.getIndex()){ + style.setFillForegroundColor(new XSSFColor(new java.awt.Color(204, 255, 204))); + name = "green"; + }else if(colorIndex == IndexedColors.ORCHID.getIndex()){ + style.setFillForegroundColor(new XSSFColor(new java.awt.Color(151, 50, 101))); + name = "pop"; + }else if(colorIndex == IndexedColors.YELLOW.getIndex()){ + style.setFillForegroundColor(new XSSFColor(new java.awt.Color(255, 255, 153))); + name = "yellow"; + }else{ + name = "default"; + } + cellStype.put(name,style); + } + return cellStype; + } + + private static void generateSheet(XSSFSheet sheet,boolean isHead, XSSFFont font,Map cellStyleMap) { + if (sheet == null) { + return; + } + + sheet.setColumnWidth(0, 4000); + sheet.setColumnWidth(1, 4000); + sheet.setColumnWidth(2, 4000); + sheet.setColumnWidth(3, 4000); + if(isHead){ + sheet.setColumnWidth(4, 880); + sheet.setColumnWidth(5, 4000); + sheet.setColumnWidth(6, 4000); + sheet.setColumnWidth(7, 4000); + sheet.setColumnWidth(8, 4000); + sheet.setColumnWidth(9, 4000); + }else { + sheet.setColumnWidth(4, 4000); + sheet.setColumnWidth(5, 880); + sheet.setColumnWidth(6, 4000); + sheet.setColumnWidth(7, 4000); + sheet.setColumnWidth(8, 4000); + sheet.setColumnWidth(9, 4000); + sheet.setColumnWidth(10, 4000); + } + + /** + * 模版生成: + * 字体大小:9 + * row1: 1交易码 2交易名称 (head的话是5)6(紫色[pop]背景空白单元格,下同) 7服务名称 8服务场景 + * row2: 1.请输入交易码(必填) 2请输入交易名称(必填) 7请输入服务名称(如果不填,则以交易名称为主) 8请输入服务场景(选填) + * row3: 合并7-10单元格,输入:请输入系统名称 背景色:黄色[yellow] + * row4: 1.英文名称2.中文名称3.数据类型/长度4.是否必输5.备注 7.英文名称8.数据类型/长度9.中文名称 10备注 背景色:黄色 + * row5: 整行都是青色【green】,1:输入 + * row6: 3:请输入STRING(具体长度) 或 ARRAY; 8:同3 + * row7:无 + * row8: 整行都是青色,1:输出 + * row9: 3:请输入STRING(具体长度) 或 ARRAY; 8:同3 + */ + XSSFRow row1 = sheet.createRow(0); + setCellValue("交易码", row1.createCell(0), font,cellStyleMap.get("default")); + setCellValue("交易名称", row1.createCell(1), font,cellStyleMap.get("default")); + setCellValue("", row1.createCell(2), font,cellStyleMap.get("default")); + setCellValue("", row1.createCell(3), font,cellStyleMap.get("default")); + if(isHead){ + setCellValue("", row1.createCell(4), font,cellStyleMap.get("default")); + setCellValue("服务名称", row1.createCell(5), font,cellStyleMap.get("default")); + setCellValue("服务场景", row1.createCell(6), font,cellStyleMap.get("default")); + setCellValue("", row1.createCell(7), font,cellStyleMap.get("default")); + setCellValue("", row1.createCell(8), font,cellStyleMap.get("default")); + setCellValue("", row1.createCell(9), font,cellStyleMap.get("default")); + + }else{ + setCellValue("", row1.createCell(4), font,cellStyleMap.get("default")); + setCellValue("", row1.createCell(5), font,cellStyleMap.get("pop")); + setCellValue("服务名称", row1.createCell(6), font,cellStyleMap.get("default")); + setCellValue("服务场景", row1.createCell(7), font,cellStyleMap.get("default")); + setCellValue("", row1.createCell(8), font,cellStyleMap.get("default")); + setCellValue("", row1.createCell(9), font,cellStyleMap.get("default")); + setCellValue("", row1.createCell(10), font,cellStyleMap.get("default")); + } + + + XSSFRow row2 = sheet.createRow(1); + setCellValue("请输入交易码(必填)", row2.createCell(0), font,cellStyleMap.get("default")); + setCellValue("请输入交易名称(必填)", row2.createCell(1), font,cellStyleMap.get("default")); + setCellValue("", row2.createCell(2), font,cellStyleMap.get("default")); + setCellValue("", row2.createCell(3), font,cellStyleMap.get("default")); + if(isHead){ + setCellValue("", row2.createCell(4), font,cellStyleMap.get("pop")); + setCellValue("请输入服务名称(如果不填,则以交易名称为主)", row2.createCell(5), font,null); + setCellValue("请输入服务场景(选填)", row2.createCell(6), font,cellStyleMap.get("default")); + setCellValue("", row2.createCell(7), font,cellStyleMap.get("default")); + setCellValue("", row2.createCell(8), font,cellStyleMap.get("default")); + setCellValue("", row2.createCell(9), font,cellStyleMap.get("default")); + }else{ + setCellValue("", row2.createCell(4), font,cellStyleMap.get("default")); + setCellValue("", row2.createCell(5), font,cellStyleMap.get("pop")); + setCellValue("请输入服务名称(如果不填,则以交易名称为主)", row2.createCell(6), font,null); + setCellValue("请输入服务场景(选填)", row2.createCell(7), font,cellStyleMap.get("default")); + setCellValue("", row2.createCell(8), font,cellStyleMap.get("default")); + setCellValue("", row2.createCell(9), font,cellStyleMap.get("default")); + setCellValue("", row2.createCell(10), font,cellStyleMap.get("default")); + } + + XSSFRow row3 = sheet.createRow(2); + setCellValue("", row3.createCell(0), font,cellStyleMap.get("yellow")); + setCellValue("", row3.createCell(1), font,cellStyleMap.get("yellow")); + setCellValue("", row3.createCell(2), font,cellStyleMap.get("yellow")); + setCellValue("", row3.createCell(3), font,cellStyleMap.get("yellow")); + if(isHead){ + setCellValue("", row3.createCell(4), font,cellStyleMap.get("yellow")); + setCellValue("请输入系统名称", row3.createCell(5), font,cellStyleMap.get("yellow")); + setCellValue("", row3.createCell(6), font,cellStyleMap.get("yellow")); + setCellValue("", row3.createCell(7), font,cellStyleMap.get("yellow")); + setCellValue("", row3.createCell(8), font,cellStyleMap.get("yellow")); + setCellValue("", row3.createCell(9), font,cellStyleMap.get("yellow")); + CellRangeAddress region1 = new CellRangeAddress(2, 2, 0, 3); + sheet.addMergedRegion(region1); + CellRangeAddress region2 = new CellRangeAddress(2, 2, 5, 9); + sheet.addMergedRegion(region2); + }else{ + setCellValue("", row3.createCell(4), font,cellStyleMap.get("yellow")); + setCellValue("", row3.createCell(5), font,cellStyleMap.get("yellow")); + setCellValue("请输入系统名称", row3.createCell(6), font,cellStyleMap.get("yellow")); + setCellValue("", row3.createCell(7), font,cellStyleMap.get("yellow")); + setCellValue("", row3.createCell(8), font,cellStyleMap.get("yellow")); + setCellValue("", row3.createCell(9), font,cellStyleMap.get("yellow")); + setCellValue("", row3.createCell(10), font,cellStyleMap.get("yellow")); + CellRangeAddress region1 = new CellRangeAddress(2, 2, 0, 4); + sheet.addMergedRegion(region1); + CellRangeAddress region2 = new CellRangeAddress(2, 2, 6, 10); + sheet.addMergedRegion(region2); + } + + XSSFRow row4 = sheet.createRow(3); + setCellValue("英文名称", row4.createCell(0), font,cellStyleMap.get("yellow")); + setCellValue("中文名称", row4.createCell(1), font,cellStyleMap.get("yellow")); + setCellValue("数据类型/长度", row4.createCell(2), font,cellStyleMap.get("yellow")); + if(isHead){ + setCellValue("备注", row4.createCell(3), font,cellStyleMap.get("yellow")); + setCellValue("", row4.createCell(4), font,cellStyleMap.get("pop")); + setCellValue("英文名称", row4.createCell(5), font,cellStyleMap.get("yellow")); + setCellValue("数据类型/长度", row4.createCell(6), font,cellStyleMap.get("yellow")); + setCellValue("中文名称", row4.createCell(7), font,cellStyleMap.get("yellow")); + setCellValue("备注", row4.createCell(8), font,cellStyleMap.get("yellow")); + setCellValue("所在报文位置", row4.createCell(9), font,cellStyleMap.get("yellow")); + }else { + setCellValue("是否必输", row4.createCell(3), font,cellStyleMap.get("yellow")); + setCellValue("备注", row4.createCell(4), font,cellStyleMap.get("yellow")); + setCellValue("", row4.createCell(5), font,cellStyleMap.get("pop")); + setCellValue("英文名称", row4.createCell(6), font,cellStyleMap.get("yellow")); + setCellValue("数据类型/长度", row4.createCell(7), font,cellStyleMap.get("yellow")); + setCellValue("中文名称", row4.createCell(8), font,cellStyleMap.get("yellow")); + setCellValue("备注", row4.createCell(9), font,cellStyleMap.get("yellow")); + setCellValue("所在报文位置", row4.createCell(10), font,cellStyleMap.get("yellow")); + } + + XSSFRow row5 = sheet.createRow(4); + setCellValue("输入", row5.createCell(0), font,cellStyleMap.get("green")); + setCellValue("", row5.createCell(1), font,cellStyleMap.get("green")); + setCellValue("", row5.createCell(2), font,cellStyleMap.get("green")); + setCellValue("", row5.createCell(3), font,cellStyleMap.get("green")); + setCellValue("", row5.createCell(4), font,cellStyleMap.get("green")); + setCellValue("", row5.createCell(5), font,cellStyleMap.get("green")); + setCellValue("", row5.createCell(6), font,cellStyleMap.get("green")); + setCellValue("", row5.createCell(7), font,cellStyleMap.get("green")); + setCellValue("", row5.createCell(8), font,cellStyleMap.get("green")); + setCellValue("", row5.createCell(9), font,cellStyleMap.get("green")); + if(!isHead){ + setCellValue("", row5.createCell(10), font,cellStyleMap.get("green")); + } + + XSSFRow row6 = sheet.createRow(5); + setCellValue("", row6.createCell(0), font,cellStyleMap.get("default")); + setCellValue("", row6.createCell(1), font,cellStyleMap.get("default")); + setCellValue("请输入STRING(具体长度) 或 ARRAY", row6.createCell(2), font,cellStyleMap.get("default")); + setCellValue("", row6.createCell(3), font,cellStyleMap.get("default")); + if(isHead){ + setCellValue("", row6.createCell(4), font,cellStyleMap.get("pop")); + setCellValue("", row6.createCell(5), font,cellStyleMap.get("default")); + setCellValue("请输入STRING(具体长度) 或 ARRAY", row6.createCell(6), font,cellStyleMap.get("default")); + setCellValue("", row6.createCell(7), font,cellStyleMap.get("default")); + setCellValue("", row6.createCell(8), font,cellStyleMap.get("default")); + setCellValue("", row6.createCell(9), font,cellStyleMap.get("default")); + }else { + setCellValue("", row6.createCell(4), font,cellStyleMap.get("default")); + setCellValue("", row6.createCell(5), font,cellStyleMap.get("pop")); + setCellValue("", row6.createCell(6), font,cellStyleMap.get("default")); + setCellValue("请输入STRING(具体长度) 或 ARRAY", row6.createCell(7), font,cellStyleMap.get("default")); + setCellValue("", row6.createCell(8), font,cellStyleMap.get("default")); + setCellValue("", row6.createCell(9), font,cellStyleMap.get("default")); + setCellValue("", row6.createCell(10), font,cellStyleMap.get("default")); + } + + + XSSFRow row7 = sheet.createRow(6); + setCellValue("", row7.createCell(1), font,cellStyleMap.get("default")); + setCellValue("", row7.createCell(2), font,cellStyleMap.get("default")); + setCellValue("", row7.createCell(3), font,cellStyleMap.get("default")); + if(isHead){ + setCellValue("", row7.createCell(4), font,cellStyleMap.get("pop")); + setCellValue("", row7.createCell(5), font,cellStyleMap.get("default")); + setCellValue("", row7.createCell(6), font,cellStyleMap.get("default")); + setCellValue("", row7.createCell(7), font,cellStyleMap.get("default")); + setCellValue("", row7.createCell(8), font,cellStyleMap.get("default")); + setCellValue("", row7.createCell(9), font,cellStyleMap.get("default")); + }else { + setCellValue("", row7.createCell(4), font,cellStyleMap.get("default")); + setCellValue("", row7.createCell(5), font,cellStyleMap.get("pop")); + setCellValue("", row7.createCell(6), font,cellStyleMap.get("default")); + setCellValue("", row7.createCell(7), font,cellStyleMap.get("default")); + setCellValue("", row7.createCell(8), font,cellStyleMap.get("default")); + setCellValue("", row7.createCell(9), font,cellStyleMap.get("default")); + setCellValue("", row7.createCell(10), font,cellStyleMap.get("default")); + } + + + XSSFRow row8 = sheet.createRow(7); + setCellValue("输出", row8.createCell(0), font,cellStyleMap.get("green")); + setCellValue("", row8.createCell(1), font,cellStyleMap.get("green")); + setCellValue("", row8.createCell(2), font,cellStyleMap.get("green")); + setCellValue("", row8.createCell(3), font,cellStyleMap.get("green")); + setCellValue("", row8.createCell(4), font,cellStyleMap.get("green")); + setCellValue("", row8.createCell(5), font,cellStyleMap.get("green")); + setCellValue("", row8.createCell(6), font,cellStyleMap.get("green")); + setCellValue("", row8.createCell(7), font,cellStyleMap.get("green")); + setCellValue("", row8.createCell(8), font,cellStyleMap.get("green")); + setCellValue("", row8.createCell(9), font,cellStyleMap.get("green")); + if(!isHead){ + setCellValue("", row8.createCell(10), font,cellStyleMap.get("green")); + } + + + XSSFRow row9 = sheet.createRow(8); + setCellValue("", row9.createCell(0), font,cellStyleMap.get("default")); + setCellValue("", row9.createCell(1), font,cellStyleMap.get("default")); + setCellValue("请输入STRING(具体长度) 或 ARRAY", row9.createCell(2), font,cellStyleMap.get("default")); + setCellValue("", row9.createCell(3), font,cellStyleMap.get("default")); + if(isHead){ + setCellValue("", row9.createCell(4), font,cellStyleMap.get("pop")); + setCellValue("", row9.createCell(5), font,cellStyleMap.get("default")); + setCellValue("请输入STRING(具体长度) 或 ARRAY", row9.createCell(6), font,cellStyleMap.get("default")); + setCellValue("", row9.createCell(7), font,cellStyleMap.get("default")); + setCellValue("", row9.createCell(8), font,cellStyleMap.get("default")); + setCellValue("", row9.createCell(9), font,cellStyleMap.get("default")); + }else { + setCellValue("", row9.createCell(4), font,cellStyleMap.get("default")); + setCellValue("", row9.createCell(5), font,cellStyleMap.get("pop")); + setCellValue("", row9.createCell(6), font,cellStyleMap.get("default")); + setCellValue("请输入STRING(具体长度) 或 ARRAY", row9.createCell(7), font,cellStyleMap.get("default")); + setCellValue("", row9.createCell(7), font,cellStyleMap.get("default")); + setCellValue("", row9.createCell(8), font,cellStyleMap.get("default")); + setCellValue("", row9.createCell(9), font,cellStyleMap.get("default")); + setCellValue("", row9.createCell(10), font,cellStyleMap.get("default")); + } + + } + + private static void setCellValue(String textValue, Cell cell, XSSFFont font,XSSFCellStyle cellStyle) { +// HSSFRichTextString richString = new HSSFRichTextString(textValue); + XSSFRichTextString richString = new XSSFRichTextString(textValue); + richString.applyFont(font); + if(cellStyle!=null){ + cell.setCellStyle(cellStyle); + } + cell.setCellValue(richString); + } + + + @Override + public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) throws Exception { + EsbSheetDataStruct esbImportDataStruct = new EsbSheetDataStruct(); + EsbExcelDataStruct excelDataStruct = this.esbImport(source); + + this.projectId = request.getProjectId(); + ApiDefinitionImport definitionImport = this.parseApiDefinitionImport(excelDataStruct, request); + + return definitionImport; + } + + public EsbExcelDataStruct esbImport(InputStream source) throws IOException, InvalidFormatException { + Workbook workbook = WorkbookFactory.create(source); + int sheetCount = workbook.getNumberOfSheets(); + EsbSheetDataStruct headStruct = null; + List interfaceStruct = new ArrayList<>(); + if (sheetCount > 0) { + Sheet headSheet = workbook.getSheetAt(0); + headStruct = this.parseExcelSheet(headSheet, true); + for (int index = 1; index < sheetCount; index++) { + Sheet dataSheet = workbook.getSheetAt(index); + EsbSheetDataStruct bodyStruct = this.parseExcelSheet(dataSheet, false); + interfaceStruct.add(bodyStruct); + } + } + + EsbExcelDataStruct excelData = new EsbExcelDataStruct(); + excelData.setHeadData(headStruct); + excelData.setInterfaceList(interfaceStruct); + return excelData; + } + + private EsbSheetDataStruct parseExcelSheet(Sheet headSheet, boolean isHeadSheet) { + EsbSheetDataStruct importDataStruct = new EsbSheetDataStruct(); + if (headSheet == null) { + return importDataStruct; + } + int simpleCodeIndex = 0; + int simpleNameIndex = 1; + int apiNameIndex = 6; + int apiDescIndex = 7; + int chineNameIndex = 8; + int descIndex = 9; + int apiPositionIndex = 10; + int cellCount = 11; + if(isHeadSheet){ + apiNameIndex = 5; + apiDescIndex = 6; + chineNameIndex = 7; + descIndex = 8; + apiPositionIndex = 9; + cellCount = 10; + } + + int rowCount = headSheet.getLastRowNum(); + //根据模版样式,如果不是报文头,则要取接口信息 + if (!isHeadSheet) { + Row interfaceInfoRow = headSheet.getRow(1); + if (interfaceInfoRow != null) { + List rowDataArr = this.getRowDataByStartIndexAndEndIndex(interfaceInfoRow, 0, cellCount-1); + if (rowDataArr.size() >= cellCount) { + String interfaceCode = rowDataArr.get(simpleCodeIndex); + String interfaceName = rowDataArr.get(apiNameIndex); + String interfaceDesc = rowDataArr.get(apiDescIndex); + if (StringUtils.isEmpty(interfaceName)) { + interfaceName = rowDataArr.get(simpleNameIndex); + } + importDataStruct.setInterfaceInfo(interfaceCode, interfaceName, interfaceDesc); + } + } + } + //超过5行为空白,直接退出。 + //部分office/wpf生成的文件会出现几万多空行,容易造成内存溢出。这里进行判断,连续五行为空白时认为读取结束。 + int blankRowCount = 0; + boolean isRequest = true; + for (int startRow = REQUEST_MESSAGE_ROW; startRow < rowCount; startRow++) { + Row row = headSheet.getRow(startRow); + List rowDataArr = this.getRowDataByStartIndexAndEndIndex(row, 0, cellCount-1); + boolean isBlankRow = this.checkBlankRow(rowDataArr, cellCount); + if (!isBlankRow) { + String cellFlag = rowDataArr.get(0); + if (StringUtils.equals(cellFlag, "输出")) { + isRequest = false; + } + } + if (isBlankRow) { + if (isRequest) { + isRequest = false; + } + blankRowCount++; + if (blankRowCount > 5) { + break; + } + } else { + blankRowCount = 0; + EsbDataStruct dataStruct = new EsbDataStruct(); + boolean initDataSuccess = dataStruct.initDefaultData(rowDataArr.get(apiNameIndex), rowDataArr.get(apiDescIndex), rowDataArr.get(chineNameIndex), rowDataArr.get(descIndex)); + if (!initDataSuccess) { + continue; + } + boolean isHead = isHeadSheet; + if (rowDataArr.size() > cellCount) { + if (StringUtils.equals(rowDataArr.get(apiPositionIndex), "SYS_HEAD")) { + isHead = true; + } + + } + if (isRequest) { + if (isHead) { + importDataStruct.getReqHeadList().add(dataStruct); + } else { + importDataStruct.getRequestList().add(dataStruct); + } + } else { + if (isHead) { + importDataStruct.getRspHeadList().add(dataStruct); + } else { + importDataStruct.getResponseList().add(dataStruct); + } + } + } + } + return importDataStruct; + } + + private boolean checkBlankRow(List rowDataArr, int rowCheckLength) { + if (rowDataArr == null || rowDataArr.size() < rowCheckLength) { + return true; + } + for (String str : rowDataArr) { + if (StringUtils.isNotEmpty(str)) { + return false; + } + } + return true; + } + + private List getRowDataByStartIndexAndEndIndex(Row row, int startCell, int endCell) { + List returnArray = new ArrayList<>(); + if (row == null) { + return returnArray; + } + for (int i = startCell; i <= endCell; i++) { + Cell cell = row.getCell(i); + if (cell != null) { + returnArray.add(getCellValue(cell)); + }else { + returnArray.add(""); + } + } + return returnArray; + } + + private String getCellValue(Cell cell) { + String returnCellValue = ""; + int cellType = cell.getCellType(); + switch (cellType) { + case Cell.CELL_TYPE_BLANK: + returnCellValue = ""; + break; + case Cell.CELL_TYPE_BOOLEAN: + returnCellValue = String.valueOf(cell.getBooleanCellValue()); + break; + case Cell.CELL_TYPE_ERROR: + returnCellValue = ""; + break; + case Cell.CELL_TYPE_NUMERIC: + returnCellValue = getValueOfNumericCell(cell); + break; + case Cell.CELL_TYPE_FORMULA: + try { + returnCellValue = getValueOfNumericCell(cell); + } catch (IllegalStateException e) { + try { + returnCellValue = cell.getRichStringCellValue().toString(); + } catch (IllegalStateException e2) { + } + } catch (Exception e) { + e.printStackTrace(); + } + break; + default: + returnCellValue = cell.getRichStringCellValue().getString(); + } + if (returnCellValue == null) { + returnCellValue = ""; + } + return returnCellValue; + } + + private String getValueOfNumericCell(Cell cell) { + Boolean isDate = DateUtil.isCellDateFormatted(cell); + Double d = cell.getNumericCellValue(); + String o = null; + if (isDate) { + o = DateFormat.getDateTimeInstance() + .format(cell.getDateCellValue()); + } else { + o = getRealStringValueOfDouble(d); + } + return o; + } + + // 处理科学计数法与普通计数法的字符串显示,尽最大努力保持精度 + private static String getRealStringValueOfDouble(Double d) { + String doubleStr = d.toString(); + boolean b = doubleStr.contains("E"); + int indexOfPoint = doubleStr.indexOf('.'); + if (b) { + int indexOfE = doubleStr.indexOf('E'); + // 小数部分 + BigInteger xs = new BigInteger(doubleStr.substring(indexOfPoint + + BigInteger.ONE.intValue(), indexOfE)); + // 指数 + int pow = Integer.valueOf(doubleStr.substring(indexOfE + + BigInteger.ONE.intValue())); + int xsLen = xs.toByteArray().length; + int scale = xsLen - pow > 0 ? xsLen - pow : 0; + doubleStr = String.format("%." + scale + "f", d); + } else { + java.util.regex.Pattern p = Pattern.compile(".0$"); + java.util.regex.Matcher m = p.matcher(doubleStr); + if (m.find()) { + doubleStr = doubleStr.replace(".0", ""); + } + } + return doubleStr; + } + + private ApiDefinitionImport parseApiDefinitionImport(EsbExcelDataStruct esbExcelDataStruct, ApiTestImportRequest importRequest) { + ApiDefinitionImport resultModel = new ApiDefinitionImport(); + List apiDataList = new ArrayList<>(); + + ApiModule parentNode = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId()); + EsbSheetDataStruct headSheetData = esbExcelDataStruct.getHeadData(); + List interfaceDataList = esbExcelDataStruct.getInterfaceList(); + List savedNames = new ArrayList<>(); + Map esbApiParams = new HashMap<>(); + for (EsbSheetDataStruct interfaceData : interfaceDataList) { + String reqName = interfaceData.getServiceName(); + if (savedNames.contains(reqName)) { + continue; + } else { + savedNames.add(reqName); + } + + String apiId = UUID.randomUUID().toString(); + ApiDefinitionWithBLOBs apiDefinition = new ApiDefinitionWithBLOBs(); + apiDefinition.setName(reqName); + apiDefinition.setMethod("ESB"); + apiDefinition.setId(apiId); + apiDefinition.setProjectId(this.projectId); + apiDefinition.setRequest(genTCPSampler()); + if (StringUtils.equalsIgnoreCase("schedule", importRequest.getType())) { + apiDefinition.setUserId(importRequest.getUserId()); + } else { + apiDefinition.setUserId(SessionUtils.getUserId()); + } + apiDefinition.setProtocol(RequestType.TCP); + buildModule(parentNode, apiDefinition, null); + apiDataList.add(apiDefinition); + + EsbApiParamsWithBLOBs apiParams = new EsbApiParamsWithBLOBs(); + apiParams.setId(UUID.randomUUID().toString()); + apiParams.setResourceId(apiId); + String reqDataStructStr = generateDataStrcut(headSheetData, interfaceData, true); + String respDataStrutStr = generateDataStrcut(headSheetData, interfaceData, false); + + apiParams.setDataStruct(reqDataStructStr); + apiParams.setResponseDataStruct(respDataStrutStr); + esbApiParams.put(apiId, apiParams); + } + + resultModel.setData(apiDataList); + resultModel.setEsbApiParamsMap(esbApiParams); + + return resultModel; + } + + private String genTCPSampler() { + MsTCPSampler tcpSampler = new MsTCPSampler(); + MsJSR223PreProcessor preProcessor = new MsJSR223PreProcessor(); + tcpSampler.setTcpPreProcessor(preProcessor); + tcpSampler.setProtocol("ESB"); + tcpSampler.setClassname("TCPSampler"); + + return JSON.toJSONString(tcpSampler); + } + + private String generateDataStrcut(EsbSheetDataStruct head, EsbSheetDataStruct body, boolean isRequest) { + EsbDataStruct dataStruct = new EsbDataStruct(); + dataStruct.initDefaultData("SERVICE", null, null, null); + List headList = new ArrayList<>(); + List bodyList = new ArrayList<>(); + if (head != null) { + if (isRequest) { + headList.addAll(head.getReqHeadList()); + bodyList.addAll(head.getRequestList()); + } else { + headList.addAll(head.getRspHeadList()); + bodyList.addAll(head.getResponseList()); + } + } + if (body != null) { + if (isRequest) { + headList.addAll(body.getReqHeadList()); + bodyList.addAll(body.getRequestList()); + } else { + headList.addAll(body.getRspHeadList()); + bodyList.addAll(body.getResponseList()); + } + } + + if (!headList.isEmpty()) { + EsbDataStruct headStruct = new EsbDataStruct(); + headStruct.initDefaultData("SYS_HEAD", null, null, null); + dataStruct.getChildren().add(headStruct); + Map childrenEsbDataStructMap = new HashMap<>(); + //用来判断节点有没有在array节点内 + String lastArrayDataStrcutName = null; + for (EsbDataStruct headData : headList) { + if (StringUtils.equalsIgnoreCase("array", headData.getType())) { + if (lastArrayDataStrcutName == null) { + lastArrayDataStrcutName = headData.getName(); + EsbDataStruct arrayStrcut = new EsbDataStruct(); + arrayStrcut.initDefaultData(headData.getName(), headData.getType(), headData.getContentType(), headData.getDescription()); + headStruct.getChildren().add(arrayStrcut); + childrenEsbDataStructMap.put(lastArrayDataStrcutName, arrayStrcut); + } else { + lastArrayDataStrcutName = null; + } + } else { + if (lastArrayDataStrcutName == null) { + headStruct.getChildren().add(headData); + } else { + EsbDataStruct arrayStrcut = childrenEsbDataStructMap.get(lastArrayDataStrcutName); + if (arrayStrcut != null) { + arrayStrcut.getChildren().add(headData); + } + } + } + } + } + + if (!bodyList.isEmpty()) { + EsbDataStruct bodyStruct = new EsbDataStruct(); + bodyStruct.initDefaultData("SYS_BODY", null, null, null); + dataStruct.getChildren().add(bodyStruct); + Map childrenEsbDataStructMap = new HashMap<>(); + //用来判断节点有没有在array节点内 + String lastArrayDataStrcutName = null; + for (EsbDataStruct bodyData : bodyList) { + if (StringUtils.equalsIgnoreCase("array", bodyData.getType())) { + if (lastArrayDataStrcutName == null) { + lastArrayDataStrcutName = bodyData.getName(); + EsbDataStruct arrayStrcut = new EsbDataStruct(); + arrayStrcut.initDefaultData(bodyData.getName(), bodyData.getType(), bodyData.getContentType(), bodyData.getDescription()); + bodyStruct.getChildren().add(arrayStrcut); + childrenEsbDataStructMap.put(lastArrayDataStrcutName, arrayStrcut); + } else { + lastArrayDataStrcutName = null; + } + } else { + if (lastArrayDataStrcutName == null) { + bodyStruct.getChildren().add(bodyData); + } else { + EsbDataStruct arrayStrcut = childrenEsbDataStructMap.get(lastArrayDataStrcutName); + if (arrayStrcut != null) { + arrayStrcut.getChildren().add(bodyData); + } + } + } + } + } + List list = new ArrayList<>(); + list.add(dataStruct); + return JSONArray.toJSONString(list); + } + +// private void parseParameters(HarRequest harRequest, MsHTTPSamplerProxy request) { +// List queryStringList = harRequest.queryString; +// queryStringList.forEach(harQueryParm -> { +// parseQueryParameters(harQueryParm, request.getArguments()); +// }); +// List harHeaderList = harRequest.headers; +// harHeaderList.forEach(harHeader -> { +// parseHeaderParameters(harHeader, request.getHeaders()); +// }); +// List harCookieList = harRequest.cookies; +// harCookieList.forEach(harCookie -> { +// parseCookieParameters(harCookie, request.getHeaders()); +// }); +// } + + + private String getDefaultStringValue(String val) { + return StringUtils.isBlank(val) ? "" : val; + } + + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/EsbAbstractParser.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/EsbAbstractParser.java new file mode 100644 index 0000000000..b049b5bc46 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/EsbAbstractParser.java @@ -0,0 +1,28 @@ +package io.metersphere.api.dto.definition.parse; + + +import io.metersphere.api.parse.ApiImportAbstractParser; +import io.metersphere.base.domain.ApiDefinitionWithBLOBs; +import io.metersphere.base.domain.ApiModule; + +import java.util.List; + +/** + * @author song.tianyang + * @Date 2021/3/10 11:15 上午 + * @Description + */ +public abstract class EsbAbstractParser extends ApiImportAbstractParser { + + protected void buildModule(ApiModule parentModule, ApiDefinitionWithBLOBs apiDefinition, List tags) { + if (tags != null) { + tags.forEach(tag -> { + ApiModule module = ApiDefinitionImportUtil.buildModule(parentModule, tag, this.projectId); + apiDefinition.setModuleId(module.getId()); + }); + }else { + apiDefinition.setModuleId(parentModule.getId()); + } + } + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/esb/EsbExcelDataStruct.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/esb/EsbExcelDataStruct.java new file mode 100644 index 0000000000..90e238819b --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/esb/EsbExcelDataStruct.java @@ -0,0 +1,19 @@ +package io.metersphere.api.dto.definition.parse.esb; + +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author song.tianyang + * @Date 2021/3/23 12:55 下午 + * @Description + */ +@Getter +@Setter +public class EsbExcelDataStruct { + private EsbSheetDataStruct headData; + private List interfaceList = new ArrayList<>(); +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/esb/EsbSheetDataStruct.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/esb/EsbSheetDataStruct.java new file mode 100644 index 0000000000..6f8899b7a4 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/esb/EsbSheetDataStruct.java @@ -0,0 +1,44 @@ +package io.metersphere.api.dto.definition.parse.esb; + +import io.metersphere.api.dto.automation.EsbDataStruct; +import io.metersphere.commons.exception.MSException; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author song.tianyang + * @Date 2021/3/22 9:42 下午 + * @Description + */ +@Getter +@Setter +public class EsbSheetDataStruct { + private String serviceName; + private String serviceDesc; + private List requestList = new ArrayList<>(); + private List responseList = new ArrayList<>(); + + //单个接口内也可能有报文头中要增加的数据 + private List reqHeadList = new ArrayList<>(); + private List rspHeadList = new ArrayList<>(); + + + public void setInterfaceInfo(String interfaceCode, String interfaceName, String interfaceDesc) { + if(StringUtils.isEmpty(interfaceCode) && StringUtils.isEmpty(interfaceName)){ + MSException.throwException("接口的交易码或服务名称不能都为空"); + } + if(StringUtils.isNotEmpty(interfaceCode)){ + this.serviceName = interfaceCode+":"+interfaceName; + }else { + this.serviceName = interfaceName; + } + if (this.serviceName.endsWith(":")){ + this.serviceName = this.serviceName.substring(0,this.serviceName.length()-1); + } + this.serviceDesc = interfaceDesc; + } +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/controller/MsIfController.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/controller/MsIfController.java index 5b7df4a228..61867a6079 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/controller/MsIfController.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/controller/MsIfController.java @@ -43,10 +43,13 @@ public class MsIfController extends MsTestElement { private IfController ifController() { IfController ifController = new IfController(); ifController.setEnabled(this.isEnable()); - ifController.setName(StringUtils.isEmpty(this.getName()) ? "IfController" : this.getName()); + if (StringUtils.isEmpty(this.getName())) { + this.setName(getLabelName()); + } + ifController.setName(this.getName()); ifController.setProperty(TestElement.TEST_CLASS, IfController.class.getName()); ifController.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("IfControllerPanel")); - ifController.setCondition(this.getCondition()); + ifController.setCondition("true"); ifController.setEvaluateAll(false); ifController.setUseExpression(true); return ifController; @@ -61,13 +64,13 @@ public class MsIfController extends MsTestElement { public String getLabelName() { if (isValid()) { - String label = variable + " " + operator; + String label = "条件控制器:" + variable + " " + operator; if (StringUtils.isNotBlank(value)) { label += " " + this.value; } return label; } - return ""; + return "IfController"; } public String getCondition() { 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 d3017c710a..9619cb4fe9 100644 --- a/backend/src/main/java/io/metersphere/api/parse/ApiImportParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/ApiImportParser.java @@ -1,9 +1,11 @@ package io.metersphere.api.parse; import io.metersphere.api.dto.ApiTestImportRequest; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import java.io.IOException; import java.io.InputStream; public interface ApiImportParser { - T parse(InputStream source, ApiTestImportRequest request); + T parse(InputStream source, ApiTestImportRequest request) throws IOException, InvalidFormatException, Exception; } 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 1980bbe42c..a6cc7ed85e 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -14,6 +14,7 @@ import io.metersphere.api.dto.definition.parse.Swagger3Parser; import io.metersphere.api.dto.definition.request.ParameterConfig; import io.metersphere.api.dto.definition.request.ScheduleInfoSwaggerUrlRequest; import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; +import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler; import io.metersphere.api.dto.scenario.environment.EnvironmentConfig; import io.metersphere.api.dto.scenario.request.RequestType; import io.metersphere.api.dto.swaggerurl.SwaggerTaskResult; @@ -343,26 +344,43 @@ public class ApiDefinitionService { private void _importCreate(List sameRequest, ApiDefinitionMapper batchMapper, ApiDefinitionWithBLOBs apiDefinition, ApiTestCaseMapper apiTestCaseMapper, ApiTestImportRequest apiTestImportRequest, List cases) { if (CollectionUtils.isEmpty(sameRequest)) { - String request = setImportHashTree(apiDefinition); - batchMapper.insert(apiDefinition); - apiDefinition.setRequest(request); - importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, true); + if(StringUtils.equalsIgnoreCase(apiDefinition.getProtocol(),RequestType.HTTP)){ + String request = setImportHashTree(apiDefinition); + batchMapper.insert(apiDefinition); + apiDefinition.setRequest(request); + importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, true); + }else{ + if(StringUtils.equalsAnyIgnoreCase(apiDefinition.getProtocol(),RequestType.TCP)){ + String request = setImportTCPHashTree(apiDefinition); + } + batchMapper.insert(apiDefinition); + } + } else { String originId = apiDefinition.getId(); - //如果存在则修改 - apiDefinition.setId(sameRequest.get(0).getId()); - String request = setImportHashTree(apiDefinition); - apiDefinitionMapper.updateByPrimaryKeyWithBLOBs(apiDefinition); - apiDefinition.setRequest(request); - importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, false); - // 如果是带用例导出,重新设置接口id - if (CollectionUtils.isNotEmpty(cases)) { - cases.forEach(item -> { - if (StringUtils.equals(item.getApiDefinitionId(), originId)) { - item.setApiDefinitionId(apiDefinition.getId()); - } - }); + if(StringUtils.equalsIgnoreCase(apiDefinition.getProtocol(),RequestType.HTTP)){ + //如果存在则修改 + apiDefinition.setId(sameRequest.get(0).getId()); + String request = setImportHashTree(apiDefinition); + apiDefinitionMapper.updateByPrimaryKeyWithBLOBs(apiDefinition); + apiDefinition.setRequest(request); + importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, false); + // 如果是带用例导出,重新设置接口id + if (CollectionUtils.isNotEmpty(cases)) { + cases.forEach(item -> { + if (StringUtils.equals(item.getApiDefinitionId(), originId)) { + item.setApiDefinitionId(apiDefinition.getId()); + } + }); + } + }else { + apiDefinition.setId(sameRequest.get(0).getId()); + if(StringUtils.equalsAnyIgnoreCase(apiDefinition.getProtocol(),RequestType.TCP)){ + String request = setImportTCPHashTree(apiDefinition); + } + apiDefinitionMapper.updateByPrimaryKeyWithBLOBs(apiDefinition); } + } } @@ -374,6 +392,14 @@ public class ApiDefinitionService { apiDefinition.setRequest(JSONObject.toJSONString(msHTTPSamplerProxy)); return request; } + private String setImportTCPHashTree(ApiDefinitionWithBLOBs apiDefinition) { + String request = apiDefinition.getRequest(); + MsTCPSampler tcpSampler = JSONObject.parseObject(request, MsTCPSampler.class); + tcpSampler.setId(apiDefinition.getId()); + tcpSampler.setHashTree(new LinkedList<>()); + apiDefinition.setRequest(JSONObject.toJSONString(tcpSampler)); + return request; + } private void importMsCase(ApiDefinitionImport apiImport, SqlSession sqlSession, ApiTestCaseMapper apiTestCaseMapper) { List cases = apiImport.getCases(); @@ -567,11 +593,40 @@ public class ApiDefinitionService { item.setName(item.getName().substring(0, 255)); } item.setNum(num++); - importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases()); + //如果EsbData需要存储,则需要进行接口是否更新的判断 + if(apiImport.getEsbApiParamsMap()!= null){ + String apiId = item.getId(); + EsbApiParamsWithBLOBs model = apiImport.getEsbApiParamsMap().get(apiId); + importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases()); + if(model!=null){ + apiImport.getEsbApiParamsMap().remove(apiId); + model.setResourceId(item.getId()); + apiImport.getEsbApiParamsMap().put(item.getId(),model); + } + }else { + importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases()); + } if (i % 300 == 0) { sqlSession.flushStatements(); } } + //判断EsbData是否需要存储 + if(apiImport.getEsbApiParamsMap()!= null && apiImport.getEsbApiParamsMap().size() > 0){ + EsbApiParamsMapper esbApiParamsMapper = sqlSession.getMapper(EsbApiParamsMapper.class); + for (EsbApiParamsWithBLOBs model : apiImport.getEsbApiParamsMap().values()) { + EsbApiParamsExample example = new EsbApiParamsExample(); + example.createCriteria().andResourceIdEqualTo(model.getResourceId()); + List exiteModelList = esbApiParamsMapper.selectByExampleWithBLOBs(example); + if(exiteModelList.isEmpty()){ + esbApiParamsMapper.insert(model); + }else{ + model.setId(exiteModelList.get(0).getId()); + esbApiParamsMapper.updateByPrimaryKeyWithBLOBs(model); + } + + } + } + if (!CollectionUtils.isEmpty(apiImport.getCases())) { for (int i = 0; i < apiImport.getCases().size(); i++) { importMsCase(apiImport, sqlSession, apiTestCaseMapper); diff --git a/backend/src/main/java/io/metersphere/api/service/EsbApiParamService.java b/backend/src/main/java/io/metersphere/api/service/EsbApiParamService.java index a8d38ced9e..09a80dda05 100644 --- a/backend/src/main/java/io/metersphere/api/service/EsbApiParamService.java +++ b/backend/src/main/java/io/metersphere/api/service/EsbApiParamService.java @@ -75,7 +75,7 @@ public class EsbApiParamService { kv.setType(request.getType()); kv.setDescription(request.getDescription()); kv.setContentType(request.getContentType()); - kv.setRequired(Boolean.parseBoolean(request.getRequired())); + kv.setRequired(request.isRequired()); returnList.add(kv); if (request.getChildren() != null) { List childValueList = this.genKeyValueByEsbDataStruct(request.getChildren(), itemName); @@ -351,4 +351,5 @@ public class EsbApiParamService { example.createCriteria().andResourceIdIn(apiIds); esbApiParamsMapper.deleteByExample(example); } + } diff --git a/backend/src/main/java/io/metersphere/api/service/EsbImportService.java b/backend/src/main/java/io/metersphere/api/service/EsbImportService.java new file mode 100644 index 0000000000..7c8b0ee971 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/service/EsbImportService.java @@ -0,0 +1,80 @@ +package io.metersphere.api.service; + +import io.metersphere.api.dto.definition.parse.ESBParser; +import io.metersphere.commons.constants.TestCaseConstants; +import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.user.SessionUser; +import io.metersphere.commons.utils.SessionUtils; +import io.metersphere.excel.domain.UserExcelData; +import io.metersphere.excel.domain.UserExcelDataFactory; +import io.metersphere.excel.utils.EasyExcelExporter; +import io.metersphere.i18n.Translator; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; + +/** + * @author song.tianyang + * @Date 2021/3/22 7:02 下午 + * @Description + */ +@Service +@Transactional(rollbackFor = Exception.class) +public class EsbImportService { + + public void esbTemplateExport(HttpServletResponse response) { + try { + EasyExcelExporter easyExcelExporter = new EasyExcelExporter(new UserExcelDataFactory().getExcelDataByLocal()); + easyExcelExporter.export(response, generateExportTemplate(), + Translator.get("user_import_template_name"), Translator.get("user_import_template_sheet")); + } catch (Exception e) { + MSException.throwException(e); + } + } + + private List generateExportTemplate() { + List list = new ArrayList<>(); + List types = TestCaseConstants.Type.getValues(); + List methods = TestCaseConstants.Method.getValues(); + SessionUser user = SessionUtils.getUser(); + for (int i = 1; i <= 2; i++) { + UserExcelData data = new UserExcelData(); + data.setId("user_id_" + i); + data.setName(Translator.get("user") + i); + String workspace = ""; + for (int workspaceIndex = 1; workspaceIndex <= i; workspaceIndex++) { + if (workspaceIndex == 1) { + workspace = "workspace" + workspaceIndex; + } else { + workspace = workspace + "\n" + "workspace" + workspaceIndex; + } + } + data.setUserIsAdmin(Translator.get("options_no")); + data.setUserIsTester(Translator.get("options_no")); + data.setUserIsOrgMember(Translator.get("options_no")); + data.setUserIsViewer(Translator.get("options_no")); + data.setUserIsTestManager(Translator.get("options_no")); + data.setUserIsOrgAdmin(Translator.get("options_yes")); + data.setOrgAdminOrganization(workspace); + list.add(data); + } + + list.add(new UserExcelData()); + UserExcelData explain = new UserExcelData(); + explain.setName(Translator.get("do_not_modify_header_order")); + explain.setOrgAdminOrganization("多个工作空间请换行展示"); + list.add(explain); + return list; + } + + public void templateExport(HttpServletResponse response) { + try { + ESBParser.export(response,"EsbTemplate"); + } catch (Exception e) { + MSException.throwException(e); + } + } +} diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionExecResultMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionExecResultMapper.xml index 95189a5806..22a84abd24 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionExecResultMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionExecResultMapper.xml @@ -36,9 +36,12 @@ SELECT * FROM ( SELECT testCase.testCaseID,testCase.testCaseName AS caseName,testCase.testPlanName AS testPlan ,caseErrorCountData.dataCountNumber AS failureTimes,'apiCase' AS caseType FROM ( - SELECT apiCase.id AS testCaseID,apiCase.`name` AS testCaseName,group_concat(testPlan.`name`) AS testPlanName FROM api_test_case apiCase + SELECT apiCase.id AS testCaseID,apiCase.`name` AS testCaseName,group_concat(testPlan.`name`) AS testPlanName, testPlanCase.update_time as updateTime + FROM api_test_case apiCase + inner join api_definition on api_definition.id = apiCase.api_definition_id INNER JOIN test_plan_api_case testPlanCase ON testPlanCase.api_case_id = apiCase.id INNER JOIN test_plan testPlan ON testPlan.id = testPlanCase.test_plan_id + and api_definition.status != 'Trash' GROUP BY apiCase.id ORDER BY apiCase.create_time DESC )testCase @@ -48,7 +51,7 @@ SELECT id FROM api_test_case WHERE project_id = #{projectId} ) and `status` = 'error' GROUP BY resource_id ) caseErrorCountData ON caseErrorCountData.testCaseID =testCase.testCaseID - WHERE caseErrorCountData.executeTime >= #{startTimestamp} + WHERE testCase.updateTime >= #{startTimestamp} UNION SELECT scene.id AS testCaseID,scene.`name` AS caseName,apiScene.testPlanName AS testPlan,count(report.id) AS failureTimes,'scenario' AS caseType FROM api_scenario_report report diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml index 82948829e2..b23321eba5 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestCaseMapper.xml @@ -387,7 +387,8 @@ union all select tpac.id as s from test_plan_api_case tpac join api_test_case on tpac.api_case_id = api_test_case.id - where tpac.test_plan_id = #{planId} + join api_definition on api_test_case.api_definition_id = api_definition.id + where tpac.test_plan_id = #{planId} and api_definition.status != 'Trash' union all select tplc.id as s from test_plan_load_case tplc join load_test on tplc.load_case_id = load_test.id diff --git a/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java b/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java index 95aed8d749..eb22a9b40b 100644 --- a/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java +++ b/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java @@ -1,5 +1,5 @@ package io.metersphere.commons.constants; public enum ApiImportPlatform { - Metersphere, Postman, Swagger2, Plugin, Jmeter, Har + Metersphere, Postman, Swagger2, Plugin, Jmeter, Har,ESB } diff --git a/backend/src/main/java/io/metersphere/excel/domain/EsbExcelData.java b/backend/src/main/java/io/metersphere/excel/domain/EsbExcelData.java new file mode 100644 index 0000000000..58d670701d --- /dev/null +++ b/backend/src/main/java/io/metersphere/excel/domain/EsbExcelData.java @@ -0,0 +1,9 @@ +package io.metersphere.excel.domain; + +/** + * @author song.tianyang + * @Date 2021/3/22 7:04 下午 + * @Description + */ +public class EsbExcelData { +} diff --git a/backend/src/main/java/io/metersphere/track/service/TrackService.java b/backend/src/main/java/io/metersphere/track/service/TrackService.java index 36377ea65c..a2aae3ce11 100644 --- a/backend/src/main/java/io/metersphere/track/service/TrackService.java +++ b/backend/src/main/java/io/metersphere/track/service/TrackService.java @@ -23,7 +23,6 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; @Service @Transactional(rollbackFor = Exception.class) @@ -87,18 +86,10 @@ public class TrackService { public List getCaseMaintenanceBar(String projectId) { List funcMaintainer = extTestCaseMapper.countFuncMaintainer(projectId); List relevanceMaintainer = extTestCaseMapper.countRelevanceMaintainer(projectId); - List list = relevanceMaintainer.stream().map(TrackCountResult::getGroupField).collect(Collectors.toList()); List charts = new ArrayList<>(); for (TrackCountResult result : funcMaintainer) { String groupField = result.getGroupField(); - if (!list.contains(groupField)) { - // 创建了功能用例,但是未关联测试 - TrackCountResult trackCount = new TrackCountResult(); - trackCount.setCountNumber(0); - trackCount.setGroupField(groupField); - relevanceMaintainer.add(trackCount); - } ChartsData chartsData = new ChartsData(); chartsData.setxAxis(groupField); chartsData.setyAxis(BigDecimal.valueOf(result.getCountNumber())); diff --git a/frontend/src/business/components/api/automation/ApiAutomation.vue b/frontend/src/business/components/api/automation/ApiAutomation.vue index 95a3ab2f8b..4548ab4f3a 100644 --- a/frontend/src/business/components/api/automation/ApiAutomation.vue +++ b/frontend/src/business/components/api/automation/ApiAutomation.vue @@ -133,6 +133,9 @@ }); } } + }, + selectNodeIds() { + this.activeName = "default"; } }, methods: { diff --git a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue index 610518d3aa..770bf7bf68 100644 --- a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue @@ -164,7 +164,7 @@ - + - + @@ -288,7 +288,7 @@ loading: false, apiListVisible: false, customizeVisible: false, - scenarioVisible: false, + isBtnHide: false, debugVisible: false, customizeRequest: {protocol: "HTTP", type: "API", hashTree: [], referenced: 'Created', active: false}, operatingElements: [], @@ -442,6 +442,9 @@ }, }, methods: { + setHideBtn() { + this.isBtnHide = false; + }, // 打开引用的场景 openScenario(data) { this.$emit('openScenario', data); @@ -533,6 +536,7 @@ this.scenarioDefinition.push(new LoopController()); break; case ELEMENT_TYPE.scenario: + this.isBtnHide = true; this.$refs.scenarioRelevance.open(); break; default: @@ -560,12 +564,14 @@ } }, showAll() { - if (!this.customizeVisible) { + // 控制当有弹出页面操作时禁止刷新按钮列表 + if (!this.customizeVisible && !this.isBtnHide) { this.operatingElements = ELEMENTS.get("ALL"); this.selectedTreeNode = undefined; } }, apiListImport() { + this.isBtnHide = true; this.$refs.scenarioApiRelevance.open(); }, recursiveSorting(arr) { @@ -632,13 +638,17 @@ item.hashTree = []; } item.enable === undefined ? item.enable = true : item.enable; - this.scenarioDefinition.push(item); + if (this.selectedTreeNode != undefined) { + this.selectedTreeNode.hashTree.push(item); + } else { + this.scenarioDefinition.push(item); + } }) } + this.isBtnHide = false; this.sort(); this.reload(); this.initProjectIds(); - this.scenarioVisible = false; }, setApiParameter(item, refType, referenced) { let request = {}; @@ -677,6 +687,7 @@ data.forEach(item => { this.setApiParameter(item, refType, referenced); }); + this.isBtnHide = false; this.sort(); this.reload(); this.initProjectIds(); diff --git a/frontend/src/business/components/api/automation/scenario/api/AddBasisApi.vue b/frontend/src/business/components/api/automation/scenario/api/AddBasisApi.vue index 60ef124715..13f043723f 100644 --- a/frontend/src/business/components/api/automation/scenario/api/AddBasisApi.vue +++ b/frontend/src/business/components/api/automation/scenario/api/AddBasisApi.vue @@ -244,6 +244,9 @@ }); }, list(data) { + if (data.protocol === "dubbo://") { + data.protocol = "DUBBO"; + } let url = "/api/module/list/" + getCurrentProjectID() + "/" + data.protocol; this.result = this.$get(url, response => { if (response.data != undefined && response.data != null) { diff --git a/frontend/src/business/components/api/automation/scenario/api/ApiRelevance.vue b/frontend/src/business/components/api/automation/scenario/api/ApiRelevance.vue index c27bce8408..1a453d7153 100644 --- a/frontend/src/business/components/api/automation/scenario/api/ApiRelevance.vue +++ b/frontend/src/business/components/api/automation/scenario/api/ApiRelevance.vue @@ -128,6 +128,7 @@ export default { } }, close() { + this.$emit('close'); this.refresh(); this.$refs.relevanceDialog.close(); }, diff --git a/frontend/src/business/components/api/automation/scenario/api/ScenarioRelevance.vue b/frontend/src/business/components/api/automation/scenario/api/ScenarioRelevance.vue index e73d8b202a..f69e67365f 100644 --- a/frontend/src/business/components/api/automation/scenario/api/ScenarioRelevance.vue +++ b/frontend/src/business/components/api/automation/scenario/api/ScenarioRelevance.vue @@ -90,8 +90,10 @@ response.data.forEach(item => { let scenarioDefinition = JSON.parse(item.scenarioDefinition); if (scenarioDefinition && scenarioDefinition.hashTree) { - let obj = {id: item.id, name: item.name, type: "scenario", headers: scenarioDefinition.headers, variables: scenarioDefinition.variables, environmentMap: scenarioDefinition.environmentMap, - referenced: 'Copy', resourceId: getUUID(), hashTree: scenarioDefinition.hashTree, projectId: item.projectId}; + let obj = { + id: item.id, name: item.name, type: "scenario", headers: scenarioDefinition.headers, variables: scenarioDefinition.variables, environmentMap: scenarioDefinition.environmentMap, + referenced: 'Copy', resourceId: getUUID(), hashTree: scenarioDefinition.hashTree, projectId: item.projectId + }; scenarios.push(obj); } }); @@ -101,6 +103,7 @@ }) }, close() { + this.$emit('close'); this.refresh(); this.$refs.relevanceDialog.close(); }, diff --git a/frontend/src/business/components/api/automation/scenario/common/ApiBaseComponent.vue b/frontend/src/business/components/api/automation/scenario/common/ApiBaseComponent.vue index 0e9f8d2806..cf5fa0edc0 100644 --- a/frontend/src/business/components/api/automation/scenario/common/ApiBaseComponent.vue +++ b/frontend/src/business/components/api/automation/scenario/common/ApiBaseComponent.vue @@ -6,7 +6,7 @@
{{data.index}}
{{title}} - {{data.method}} + {{getMethod()}} @@ -125,6 +125,17 @@ //this.$set(this.data, 'active', !this.data.active); this.$emit('active'); }, + getMethod() { + if (this.data.protocol === "HTTP") { + return this.data.method; + } + else if (this.data.protocol === "dubbo://") { + return "DUBBO"; + } + else { + return this.data.protocol; + } + }, copyRow() { this.$emit('copy'); }, diff --git a/frontend/src/business/components/api/automation/scenario/component/LoopController.vue b/frontend/src/business/components/api/automation/scenario/component/LoopController.vue index f279355cf1..a61d1f1e68 100644 --- a/frontend/src/business/components/api/automation/scenario/component/LoopController.vue +++ b/frontend/src/business/components/api/automation/scenario/component/LoopController.vue @@ -90,6 +90,7 @@ import ApiResponseComponent from "./ApiResponseComponent"; import MsRun from "../DebugRun"; import {getUUID} from "@/common/js/utils"; + import {ELEMENT_TYPE, ELEMENTS} from "../Setting"; export default { name: "MsLoopController", @@ -186,7 +187,37 @@ this.controller.countController.proceed = true; return; } + // 递归遍历所有请求数量 + if (this.controller.hashTree && this.controller.hashTree.length === 1 + && this.controller.hashTree[0].hashTree && this.controller.hashTree[0].hashTree.length > 0) { + let count = 0; + this.controller.hashTree[0].hashTree.forEach(item => { + if (ELEMENTS.get("AllSamplerProxy").indexOf(item.type) != -1) { + count++; + } + if (item.hashTree && item.hashTree.length > 0) { + this.recursive(item.hashTree, count); + } + }) + + if (count > 1) { + this.$warning("当前循环下超过一个请求,不能关闭状态") + this.controller.countController.proceed = true; + return; + } + } }, + recursive(arr, count) { + for (let i in arr) { + if (ELEMENTS.get("AllSamplerProxy").indexOf(arr[i].type) != -1) { + count++; + } + if (arr[i].hashTree && arr[i].hashTree.length > 0) { + this.recursive(arr[i].hashTree, count); + } + } + }, + runDebug() { if (!this.controller.hashTree || this.controller.hashTree.length < 1) { this.$warning("当前循环下没有请求,不能执行") diff --git a/frontend/src/business/components/api/automation/scenario/component/StepExtendBtns.vue b/frontend/src/business/components/api/automation/scenario/component/StepExtendBtns.vue index 3e81f770a1..d028acef6b 100644 --- a/frontend/src/business/components/api/automation/scenario/component/StepExtendBtns.vue +++ b/frontend/src/business/components/api/automation/scenario/component/StepExtendBtns.vue @@ -13,7 +13,7 @@ - + @@ -32,6 +32,7 @@ data() { return { allSamplers: ELEMENTS.get('AllSamplerProxy'), + currentProtocol: "HTTP", } }, methods: { @@ -63,7 +64,8 @@ } }); }, - saveAsApi(){ + saveAsApi() { + this.currentProtocol = this.data.protocol; this.$refs.api.open(this.data); } } diff --git a/frontend/src/business/components/api/definition/ApiDefinition.vue b/frontend/src/business/components/api/definition/ApiDefinition.vue index dc13136a3c..6f7a3c3e0a 100644 --- a/frontend/src/business/components/api/definition/ApiDefinition.vue +++ b/frontend/src/business/components/api/definition/ApiDefinition.vue @@ -1,152 +1,152 @@