diff --git a/backend/framework/domain/src/main/java/io/metersphere/functional/domain/ExportTask.java b/backend/framework/domain/src/main/java/io/metersphere/functional/domain/ExportTask.java index ae0b889efb..27ccb53537 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/functional/domain/ExportTask.java +++ b/backend/framework/domain/src/main/java/io/metersphere/functional/domain/ExportTask.java @@ -5,11 +5,10 @@ import io.metersphere.validation.groups.Updated; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; -import lombok.Data; - import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; +import lombok.Data; @Data public class ExportTask implements Serializable { @@ -27,7 +26,7 @@ public class ExportTask implements Serializable { private String type; @Schema(description = "文件id") - private String fileid; + private String fileId; @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank(message = "{export_task.state.not_blank}", groups = {Created.class}) @@ -51,19 +50,23 @@ public class ExportTask implements Serializable { @Size(min = 1, max = 50, message = "{export_task.project_id.length_range}", groups = {Created.class, Updated.class}) private String projectId; + @Schema(description = "文件类型") + private String fileType; + private static final long serialVersionUID = 1L; public enum Column { id("id", "id", "VARCHAR", false), name("name", "name", "VARCHAR", true), type("type", "type", "VARCHAR", true), - fileid("fileId", "fileid", "VARCHAR", false), + fileId("file_id", "fileId", "VARCHAR", false), state("state", "state", "VARCHAR", true), createUser("create_user", "createUser", "VARCHAR", false), createTime("create_time", "createTime", "BIGINT", false), updateUser("update_user", "updateUser", "VARCHAR", false), updateTime("update_time", "updateTime", "BIGINT", false), - projectId("project_id", "projectId", "VARCHAR", false); + projectId("project_id", "projectId", "VARCHAR", false), + fileType("file_type", "fileType", "VARCHAR", false); private static final String BEGINNING_DELIMITER = "`"; @@ -108,7 +111,7 @@ public class ExportTask implements Serializable { return this.getEscapedColumnName() + " ASC"; } - public static Column[] excludes(Column... excludes) { + public static Column[] excludes(Column ... excludes) { ArrayList columns = new ArrayList<>(Arrays.asList(Column.values())); if (excludes != null && excludes.length > 0) { columns.removeAll(new ArrayList<>(Arrays.asList(excludes))); diff --git a/backend/framework/domain/src/main/java/io/metersphere/functional/domain/ExportTaskExample.java b/backend/framework/domain/src/main/java/io/metersphere/functional/domain/ExportTaskExample.java index bcf5f6fe31..247a9f9dc1 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/functional/domain/ExportTaskExample.java +++ b/backend/framework/domain/src/main/java/io/metersphere/functional/domain/ExportTaskExample.java @@ -314,73 +314,73 @@ public class ExportTaskExample { return (Criteria) this; } - public Criteria andFileidIsNull() { - addCriterion("fileId is null"); + public Criteria andFileIdIsNull() { + addCriterion("file_id is null"); return (Criteria) this; } - public Criteria andFileidIsNotNull() { - addCriterion("fileId is not null"); + public Criteria andFileIdIsNotNull() { + addCriterion("file_id is not null"); return (Criteria) this; } - public Criteria andFileidEqualTo(String value) { - addCriterion("fileId =", value, "fileid"); + public Criteria andFileIdEqualTo(String value) { + addCriterion("file_id =", value, "fileId"); return (Criteria) this; } - public Criteria andFileidNotEqualTo(String value) { - addCriterion("fileId <>", value, "fileid"); + public Criteria andFileIdNotEqualTo(String value) { + addCriterion("file_id <>", value, "fileId"); return (Criteria) this; } - public Criteria andFileidGreaterThan(String value) { - addCriterion("fileId >", value, "fileid"); + public Criteria andFileIdGreaterThan(String value) { + addCriterion("file_id >", value, "fileId"); return (Criteria) this; } - public Criteria andFileidGreaterThanOrEqualTo(String value) { - addCriterion("fileId >=", value, "fileid"); + public Criteria andFileIdGreaterThanOrEqualTo(String value) { + addCriterion("file_id >=", value, "fileId"); return (Criteria) this; } - public Criteria andFileidLessThan(String value) { - addCriterion("fileId <", value, "fileid"); + public Criteria andFileIdLessThan(String value) { + addCriterion("file_id <", value, "fileId"); return (Criteria) this; } - public Criteria andFileidLessThanOrEqualTo(String value) { - addCriterion("fileId <=", value, "fileid"); + public Criteria andFileIdLessThanOrEqualTo(String value) { + addCriterion("file_id <=", value, "fileId"); return (Criteria) this; } - public Criteria andFileidLike(String value) { - addCriterion("fileId like", value, "fileid"); + public Criteria andFileIdLike(String value) { + addCriterion("file_id like", value, "fileId"); return (Criteria) this; } - public Criteria andFileidNotLike(String value) { - addCriterion("fileId not like", value, "fileid"); + public Criteria andFileIdNotLike(String value) { + addCriterion("file_id not like", value, "fileId"); return (Criteria) this; } - public Criteria andFileidIn(List values) { - addCriterion("fileId in", values, "fileid"); + public Criteria andFileIdIn(List values) { + addCriterion("file_id in", values, "fileId"); return (Criteria) this; } - public Criteria andFileidNotIn(List values) { - addCriterion("fileId not in", values, "fileid"); + public Criteria andFileIdNotIn(List values) { + addCriterion("file_id not in", values, "fileId"); return (Criteria) this; } - public Criteria andFileidBetween(String value1, String value2) { - addCriterion("fileId between", value1, value2, "fileid"); + public Criteria andFileIdBetween(String value1, String value2) { + addCriterion("file_id between", value1, value2, "fileId"); return (Criteria) this; } - public Criteria andFileidNotBetween(String value1, String value2) { - addCriterion("fileId not between", value1, value2, "fileid"); + public Criteria andFileIdNotBetween(String value1, String value2) { + addCriterion("file_id not between", value1, value2, "fileId"); return (Criteria) this; } @@ -783,6 +783,76 @@ public class ExportTaskExample { addCriterion("project_id not between", value1, value2, "projectId"); return (Criteria) this; } + + public Criteria andFileTypeIsNull() { + addCriterion("file_type is null"); + return (Criteria) this; + } + + public Criteria andFileTypeIsNotNull() { + addCriterion("file_type is not null"); + return (Criteria) this; + } + + public Criteria andFileTypeEqualTo(String value) { + addCriterion("file_type =", value, "fileType"); + return (Criteria) this; + } + + public Criteria andFileTypeNotEqualTo(String value) { + addCriterion("file_type <>", value, "fileType"); + return (Criteria) this; + } + + public Criteria andFileTypeGreaterThan(String value) { + addCriterion("file_type >", value, "fileType"); + return (Criteria) this; + } + + public Criteria andFileTypeGreaterThanOrEqualTo(String value) { + addCriterion("file_type >=", value, "fileType"); + return (Criteria) this; + } + + public Criteria andFileTypeLessThan(String value) { + addCriterion("file_type <", value, "fileType"); + return (Criteria) this; + } + + public Criteria andFileTypeLessThanOrEqualTo(String value) { + addCriterion("file_type <=", value, "fileType"); + return (Criteria) this; + } + + public Criteria andFileTypeLike(String value) { + addCriterion("file_type like", value, "fileType"); + return (Criteria) this; + } + + public Criteria andFileTypeNotLike(String value) { + addCriterion("file_type not like", value, "fileType"); + return (Criteria) this; + } + + public Criteria andFileTypeIn(List values) { + addCriterion("file_type in", values, "fileType"); + return (Criteria) this; + } + + public Criteria andFileTypeNotIn(List values) { + addCriterion("file_type not in", values, "fileType"); + return (Criteria) this; + } + + public Criteria andFileTypeBetween(String value1, String value2) { + addCriterion("file_type between", value1, value2, "fileType"); + return (Criteria) this; + } + + public Criteria andFileTypeNotBetween(String value1, String value2) { + addCriterion("file_type not between", value1, value2, "fileType"); + return (Criteria) this; + } } public static class Criteria extends GeneratedCriteria { diff --git a/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/ExportTaskMapper.xml b/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/ExportTaskMapper.xml index d35aa8c8de..3018f7da8f 100644 --- a/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/ExportTaskMapper.xml +++ b/backend/framework/domain/src/main/java/io/metersphere/functional/mapper/ExportTaskMapper.xml @@ -5,13 +5,14 @@ - + + @@ -72,8 +73,8 @@ - id, `name`, `type`, fileId, `state`, create_user, create_time, update_user, update_time, - project_id + id, `name`, `type`, file_id, `state`, create_user, create_time, update_user, update_time, + project_id, file_type @@ -200,8 +207,8 @@ `type` = #{record.type,jdbcType=VARCHAR}, - - fileId = #{record.fileid,jdbcType=VARCHAR}, + + file_id = #{record.fileId,jdbcType=VARCHAR}, `state` = #{record.state,jdbcType=VARCHAR}, @@ -221,6 +228,9 @@ project_id = #{record.projectId,jdbcType=VARCHAR}, + + file_type = #{record.fileType,jdbcType=VARCHAR}, + @@ -231,13 +241,14 @@ set id = #{record.id,jdbcType=VARCHAR}, `name` = #{record.name,jdbcType=VARCHAR}, `type` = #{record.type,jdbcType=VARCHAR}, - fileId = #{record.fileid,jdbcType=VARCHAR}, + file_id = #{record.fileId,jdbcType=VARCHAR}, `state` = #{record.state,jdbcType=VARCHAR}, create_user = #{record.createUser,jdbcType=VARCHAR}, create_time = #{record.createTime,jdbcType=BIGINT}, update_user = #{record.updateUser,jdbcType=VARCHAR}, update_time = #{record.updateTime,jdbcType=BIGINT}, - project_id = #{record.projectId,jdbcType=VARCHAR} + project_id = #{record.projectId,jdbcType=VARCHAR}, + file_type = #{record.fileType,jdbcType=VARCHAR} @@ -251,8 +262,8 @@ `type` = #{type,jdbcType=VARCHAR}, - - fileId = #{fileid,jdbcType=VARCHAR}, + + file_id = #{fileId,jdbcType=VARCHAR}, `state` = #{state,jdbcType=VARCHAR}, @@ -272,6 +283,9 @@ project_id = #{projectId,jdbcType=VARCHAR}, + + file_type = #{fileType,jdbcType=VARCHAR}, + where id = #{id,jdbcType=VARCHAR} @@ -279,25 +293,26 @@ update export_task set `name` = #{name,jdbcType=VARCHAR}, `type` = #{type,jdbcType=VARCHAR}, - fileId = #{fileid,jdbcType=VARCHAR}, + file_id = #{fileId,jdbcType=VARCHAR}, `state` = #{state,jdbcType=VARCHAR}, create_user = #{createUser,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=BIGINT}, update_user = #{updateUser,jdbcType=VARCHAR}, update_time = #{updateTime,jdbcType=BIGINT}, - project_id = #{projectId,jdbcType=VARCHAR} + project_id = #{projectId,jdbcType=VARCHAR}, + file_type = #{fileType,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR} insert into export_task - (id, `name`, `type`, fileId, `state`, create_user, create_time, update_user, update_time, - project_id) + (id, `name`, `type`, file_id, `state`, create_user, create_time, update_user, update_time, + project_id, file_type) values (#{item.id,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR}, #{item.type,jdbcType=VARCHAR}, - #{item.fileid,jdbcType=VARCHAR}, #{item.state,jdbcType=VARCHAR}, #{item.createUser,jdbcType=VARCHAR}, + #{item.fileId,jdbcType=VARCHAR}, #{item.state,jdbcType=VARCHAR}, #{item.createUser,jdbcType=VARCHAR}, #{item.createTime,jdbcType=BIGINT}, #{item.updateUser,jdbcType=VARCHAR}, #{item.updateTime,jdbcType=BIGINT}, - #{item.projectId,jdbcType=VARCHAR}) + #{item.projectId,jdbcType=VARCHAR}, #{item.fileType,jdbcType=VARCHAR}) @@ -319,8 +334,8 @@ #{item.type,jdbcType=VARCHAR} - - #{item.fileid,jdbcType=VARCHAR} + + #{item.fileId,jdbcType=VARCHAR} #{item.state,jdbcType=VARCHAR} @@ -340,6 +355,9 @@ #{item.projectId,jdbcType=VARCHAR} + + #{item.fileType,jdbcType=VARCHAR} + ) diff --git a/backend/framework/domain/src/main/resources/migration/3.2.0/ddl/V3.2.0_2__ga_ddl.sql b/backend/framework/domain/src/main/resources/migration/3.2.0/ddl/V3.2.0_2__ga_ddl.sql index 192fe0b066..13f3c1f0e9 100644 --- a/backend/framework/domain/src/main/resources/migration/3.2.0/ddl/V3.2.0_2__ga_ddl.sql +++ b/backend/framework/domain/src/main/resources/migration/3.2.0/ddl/V3.2.0_2__ga_ddl.sql @@ -11,7 +11,8 @@ CREATE TABLE export_task( `id` VARCHAR(50) NOT NULL COMMENT '任务唯一ID' , `name` VARCHAR(255) COMMENT '名称' , `type` VARCHAR(50) NOT NULL COMMENT '资源类型' , - `fileId` VARCHAR(255) COMMENT '文件id' , + `file_id` VARCHAR(255) COMMENT '文件id' , + `file_type` VARCHAR(64) COMMENT '文件类型' , `project_id` VARCHAR(255) NOT NULL COMMENT '项目id' , `state` VARCHAR(50) NOT NULL COMMENT '状态' , `create_user` VARCHAR(50) NOT NULL COMMENT '创建人' , diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/ExportMsgDTO.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/ExportMsgDTO.java new file mode 100644 index 0000000000..14b96ae8ae --- /dev/null +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/ExportMsgDTO.java @@ -0,0 +1,34 @@ +package io.metersphere.sdk.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Data +public class ExportMsgDTO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + /** + * fileId + */ + private String fileId; + /** + * 任务id + */ + private String taskId; + /** + * 数量 + */ + private int count; + /** + * 消息类型(LINK-链接标识,HEARTBEAT-心跳检查标识,EXEC_START-开始执行标识,EXEC_RESULT-执行结果标识) + */ + private String msgType; +} diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/controller/FunctionalCaseController.java b/backend/services/case-management/src/main/java/io/metersphere/functional/controller/FunctionalCaseController.java index 40fd4d46ed..c13a18cb1b 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/controller/FunctionalCaseController.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/controller/FunctionalCaseController.java @@ -287,7 +287,7 @@ public class FunctionalCaseController { @Operation(summary = "用例管理-功能用例-下载文件") @RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_EXPORT) public ResponseEntity downloadImgById(@PathVariable String projectId, @PathVariable String fileId) { - return functionalCaseFileService.downloadFile(projectId, fileId); + return functionalCaseFileService.downloadFile(projectId, fileId, SessionUtils.getUserId()); } @@ -297,4 +297,11 @@ public class FunctionalCaseController { public void caseExportXmind(@Validated @RequestBody FunctionalCaseExportRequest request) { functionalCaseXmindService.exportFunctionalCaseXmind(request, SessionUtils.getUserId()); } + + @GetMapping(value = "/check/export-task") + @Operation(summary = "用例管理-功能用例-导出任务校验") + @RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ_EXPORT) + public String checkExportTask() { + return functionalCaseFileService.checkExportTask(SessionUtils.getCurrentProjectId(), SessionUtils.getUserId()); + } } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseFileService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseFileService.java index 4b4e605c02..6d1e85aa9f 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseFileService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseFileService.java @@ -33,7 +33,7 @@ import io.metersphere.project.mapper.ExtBaseProjectVersionMapper; import io.metersphere.project.mapper.ProjectMapper; import io.metersphere.project.service.ProjectTemplateService; import io.metersphere.sdk.constants.*; -import io.metersphere.sdk.dto.SocketMsgDTO; +import io.metersphere.sdk.dto.ExportMsgDTO; import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.file.FileRequest; import io.metersphere.sdk.util.*; @@ -106,8 +106,8 @@ public class FunctionalCaseFileService { private ExportTaskManager exportTaskManager; @Resource private ExportTaskMapper exportTaskMapper; - private static final String XMIND = ".xmind"; - private static final String XLSX = ".xlsx"; + private static final String XLSX = "xlsx"; + private static final String ZIP = "zip"; /** * 下载excel导入模板 @@ -340,7 +340,7 @@ public class FunctionalCaseFileService { if (preparedCount > 0) { throw new MSException(Translator.get("export_case_task_existed")); } - exportTaskManager.exportAsyncTask(request.getProjectId(), userId, ExportConstants.ExportType.CASE.toString(), request, t -> exportFunctionalCaseZip(request, userId)); + exportTaskManager.exportAsyncTask(request.getProjectId(), request.getFileId(), userId, ExportConstants.ExportType.CASE.toString(), request, t -> exportFunctionalCaseZip(request, userId)); } catch (InterruptedException e) { LogUtils.error("导出失败:" + e); throw new MSException(e); @@ -356,39 +356,47 @@ public class FunctionalCaseFileService { public String exportFunctionalCaseZip(FunctionalCaseExportRequest request, String userId) { File tmpDir = null; Project project = projectMapper.selectByPrimaryKey(request.getProjectId()); + String fileType = ""; try { tmpDir = new File(getClass().getClassLoader().getResource(StringUtils.EMPTY).getPath() + EXPORT_CASE_TMP_DIR + File.separatorChar + EXPORT_CASE_TMP_DIR + "_" + IDGenerator.nextStr()); // 生成tmp随机目录 MsFileUtils.deleteDir(tmpDir.getPath()); tmpDir.mkdirs(); + //获取导出的ids集合 + List batchExcels = new ArrayList<>(); + List ids = functionalCaseService.doSelectIds(request, request.getProjectId()); + if (CollectionUtils.isEmpty(ids)) { + return null; + } // 生成EXCEL - List batchExcels = generateCaseExportExcel(tmpDir.getPath(), request, project); + batchExcels = generateCaseExportExcel(batchExcels, ids, tmpDir.getPath(), request, project); if (batchExcels.size() > 1) { // EXCEL -> ZIP (EXCEL数目大于1) File zipFile = CompressUtils.zipFilesToPath(tmpDir.getPath() + File.separatorChar + "Metersphere_case_" + project.getName() + ".zip", batchExcels); - uploadFileToMinio(zipFile, request.getFileId()); + fileType = ZIP; + uploadFileToMinio(fileType, zipFile, request.getFileId()); } else { // EXCEL (EXCEL数目等于1) File singeFile = batchExcels.get(0); - uploadFileToMinio(singeFile, request.getFileId()); + fileType = XLSX; + uploadFileToMinio(fileType, singeFile, request.getFileId()); } functionalCaseLogService.exportExcelLog(request); List exportTasks = getExportTasks(request.getProjectId(), userId); String taskId; if (CollectionUtils.isNotEmpty(exportTasks)) { taskId = exportTasks.getFirst().getId(); - updateExportTask(ExportConstants.ExportState.SUCCESS.name(), taskId, request.getFileId()); + updateExportTask(ExportConstants.ExportState.SUCCESS.name(), taskId, fileType); } else { taskId = MsgType.CONNECT.name(); } - SocketMsgDTO socketMsgDTO = new SocketMsgDTO(request.getFileId(), "", MsgType.CONNECT.name(), taskId); - socketMsgDTO.setReportId(request.getFileId()); - ExportWebSocketHandler.sendMessageSingle(socketMsgDTO); + ExportMsgDTO exportMsgDTO = new ExportMsgDTO(request.getFileId(), taskId, ids.size(), MsgType.CONNECT.name()); + ExportWebSocketHandler.sendMessageSingle(exportMsgDTO); } catch (Exception e) { List exportTasks = getExportTasks(request.getProjectId(), userId); if (CollectionUtils.isNotEmpty(exportTasks)) { - updateExportTask(ExportConstants.ExportState.ERROR.name(), exportTasks.getFirst().getId(), request.getFileId()); + updateExportTask(ExportConstants.ExportState.ERROR.name(), exportTasks.getFirst().getId(), fileType); } LogUtils.error(e); throw new MSException(e); @@ -404,17 +412,17 @@ public class FunctionalCaseFileService { return exportTaskMapper.selectByExample(exportTaskExample); } - public void updateExportTask(String state, String taskId, String fileId) { + public void updateExportTask(String state, String taskId, String fileType) { ExportTask exportTask = new ExportTask(); exportTask.setState(state); - exportTask.setFileid(fileId); + exportTask.setFileType(fileType); exportTask.setId(taskId); exportTaskMapper.updateByPrimaryKeySelective(exportTask); } - public void uploadFileToMinio(File file, String fileId) { + public void uploadFileToMinio(String fileType, File file, String fileId) { FileRequest fileRequest = new FileRequest(); - fileRequest.setFileName(fileId); + fileRequest.setFileName(fileId.concat(".").concat(fileType)); fileRequest.setFolder(DefaultRepositoryDir.getExportExcelTempDir()); fileRequest.setStorage(StorageType.MINIO.name()); try { @@ -425,15 +433,10 @@ public class FunctionalCaseFileService { } } - private List generateCaseExportExcel(String tmpZipPath, FunctionalCaseExportRequest request, Project project) { - List tmpExportExcelList = new ArrayList<>(); + private List generateCaseExportExcel(List tmpExportExcelList, List ids, String tmpZipPath, FunctionalCaseExportRequest request, Project project) { //excel表头 List> headList = getFunctionalCaseExportHeads(request); //获取导出的ids集合 - List ids = functionalCaseService.doSelectIds(request, request.getProjectId()); - if (CollectionUtils.isEmpty(ids)) { - return tmpExportExcelList; - } //获取当前项目下默认模板的自定义字段属性 List customFields = getCustomFields(request.getProjectId()); //默认字段+自定义字段的 options集合 @@ -785,11 +788,16 @@ public class FunctionalCaseFileService { return functionalCaseExportColumns; } - public ResponseEntity downloadFile(String projectId, String fileId) { + public ResponseEntity downloadFile(String projectId, String fileId, String userId) { + List exportTasks = getExportTasksByFileId(projectId, userId, fileId); + if (CollectionUtils.isEmpty(exportTasks)) { + throw new MSException("任务不存在"); + } + ExportTask tasksFirst = exportTasks.getFirst(); Project project = projectMapper.selectByPrimaryKey(projectId); byte[] bytes; FileRequest fileRequest = new FileRequest(); - fileRequest.setFileName(fileId); + fileRequest.setFileName(tasksFirst.getFileId().concat(tasksFirst.getFileType())); fileRequest.setFolder(DefaultRepositoryDir.getExportExcelTempDir()); fileRequest.setStorage(StorageType.MINIO.name()); try { @@ -797,13 +805,7 @@ public class FunctionalCaseFileService { } catch (Exception e) { throw new MSException("get file error"); } - String fileName = ""; - if (StringUtils.endsWith(fileId, XMIND)) { - fileName = "Metersphere_case_" + project.getName() + XMIND; - } - if (StringUtils.endsWith(fileId, XLSX)) { - fileName = "Metersphere_case_" + project.getName() + XLSX; - } + String fileName = "Metersphere_case_" + project.getName() + tasksFirst.getFileType(); try { return ResponseEntity.ok() @@ -815,7 +817,24 @@ public class FunctionalCaseFileService { } } + private List getExportTasksByFileId(String projectId, String userId, String fileId) { + ExportTaskExample exportTaskExample = new ExportTaskExample(); + exportTaskExample.createCriteria().andTypeEqualTo(ExportConstants.ExportType.CASE.toString()).andStateEqualTo(ExportConstants.ExportState.SUCCESS.toString()) + .andCreateUserEqualTo(userId).andProjectIdEqualTo(projectId).andFileIdEqualTo(fileId); + exportTaskExample.setOrderByClause("create_time desc"); + return exportTaskMapper.selectByExample(exportTaskExample); + } + public void stopExport(String taskId, String userId) { exportTaskManager.sendStopMessage(taskId, userId); } + + public String checkExportTask(String projectId, String userId) { + List exportTasks = getExportTasks(projectId, userId); + if (CollectionUtils.isNotEmpty(exportTasks)) { + return exportTasks.getFirst().getFileId(); + } else { + return StringUtils.EMPTY; + } + } } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseXmindService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseXmindService.java index 2dfa9ab4b0..358d75b508 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseXmindService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseXmindService.java @@ -11,7 +11,7 @@ import io.metersphere.functional.xmind.domain.FunctionalCaseXmindData; import io.metersphere.functional.xmind.utils.XmindExportUtil; import io.metersphere.sdk.constants.ModuleConstants; import io.metersphere.sdk.constants.MsgType; -import io.metersphere.sdk.dto.SocketMsgDTO; +import io.metersphere.sdk.dto.ExportMsgDTO; import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.LogUtils; @@ -59,6 +59,7 @@ public class FunctionalCaseXmindService { private ExportTaskManager exportTaskManager; @Resource private FunctionalCaseLogService functionalCaseLogService; + private static final String XMIND = "xmind"; public void downloadXmindTemplate(String projectId, HttpServletResponse response) { List customFields = functionalCaseFileService.getCustomFields(projectId); @@ -96,7 +97,7 @@ public class FunctionalCaseXmindService { */ public void exportFunctionalCaseXmind(FunctionalCaseExportRequest request, String userId) { try { - exportTaskManager.exportAsyncTask(request.getProjectId(), userId, ExportConstants.ExportType.CASE.toString(), request, t -> exportXmind(request, userId)); + exportTaskManager.exportAsyncTask(request.getProjectId(), request.getFileId(), userId, ExportConstants.ExportType.CASE.toString(), request, t -> exportXmind(request, userId)); } catch (InterruptedException e) { LogUtils.error("导出失败:" + e); throw new MSException(e); @@ -118,24 +119,23 @@ public class FunctionalCaseXmindService { List templateCustomFields = functionalCaseFileService.getCustomFields(request.getProjectId()); TemplateCustomFieldDTO templateCustomFieldDTO = templateCustomFields.stream().filter(item -> StringUtils.equalsIgnoreCase(item.getFieldName(), Translator.get("custom_field.functional_priority"))).findFirst().get(); XmindExportUtil.export(xmindData, request, tmpFile, templateCustomFieldDTO); - functionalCaseFileService.uploadFileToMinio(tmpFile, request.getFileId()); + functionalCaseFileService.uploadFileToMinio(XMIND, tmpFile, request.getFileId()); functionalCaseLogService.exportExcelLog(request); List exportTasks = functionalCaseFileService.getExportTasks(request.getProjectId(), userId); String taskId; if (CollectionUtils.isNotEmpty(exportTasks)) { taskId = exportTasks.getFirst().getId(); - functionalCaseFileService.updateExportTask(ExportConstants.ExportState.SUCCESS.name(), taskId, request.getFileId()); + functionalCaseFileService.updateExportTask(ExportConstants.ExportState.SUCCESS.name(), taskId, XMIND); } else { taskId = MsgType.CONNECT.name(); } - SocketMsgDTO socketMsgDTO = new SocketMsgDTO(request.getFileId(), "", MsgType.CONNECT.name(), taskId); - socketMsgDTO.setReportId(request.getFileId()); - ExportWebSocketHandler.sendMessageSingle(socketMsgDTO); + ExportMsgDTO exportMsgDTO = new ExportMsgDTO(request.getFileId(), taskId, ids.size(), MsgType.CONNECT.name()); + ExportWebSocketHandler.sendMessageSingle(exportMsgDTO); } catch (Exception e) { List exportTasks = functionalCaseFileService.getExportTasks(request.getProjectId(), userId); if (CollectionUtils.isNotEmpty(exportTasks)) { - functionalCaseFileService.updateExportTask(ExportConstants.ExportState.ERROR.name(), exportTasks.getFirst().getId(), request.getFileId()); + functionalCaseFileService.updateExportTask(ExportConstants.ExportState.ERROR.name(), exportTasks.getFirst().getId(), XMIND); } LogUtils.error(e); throw new MSException(e); diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/socket/ExportWebSocketHandler.java b/backend/services/case-management/src/main/java/io/metersphere/functional/socket/ExportWebSocketHandler.java index a107987ce0..f561e030b7 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/socket/ExportWebSocketHandler.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/socket/ExportWebSocketHandler.java @@ -1,7 +1,7 @@ package io.metersphere.functional.socket; import io.metersphere.sdk.constants.MsgType; -import io.metersphere.sdk.dto.SocketMsgDTO; +import io.metersphere.sdk.dto.ExportMsgDTO; import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.LogUtils; import jakarta.websocket.*; @@ -22,7 +22,7 @@ public class ExportWebSocketHandler { public static final Map ONLINE_EXPORT_EXCEL_SESSIONS = new ConcurrentHashMap<>(); - public static void sendMessage(Session session, SocketMsgDTO message) { + public static void sendMessage(Session session, ExportMsgDTO message) { if (session == null) { return; } @@ -35,8 +35,8 @@ public class ExportWebSocketHandler { async.sendText(JSON.toJSONString(message)); } - public static void sendMessageSingle(SocketMsgDTO dto) { - sendMessage(ONLINE_EXPORT_EXCEL_SESSIONS.get(Optional.ofNullable(dto.getReportId()) + public static void sendMessageSingle(ExportMsgDTO dto) { + sendMessage(ONLINE_EXPORT_EXCEL_SESSIONS.get(Optional.ofNullable(dto.getFileId()) .orElse(StringUtils.EMPTY)), dto); } @@ -49,7 +49,7 @@ public class ExportWebSocketHandler { ONLINE_EXPORT_EXCEL_SESSIONS.put(fileId, session); RemoteEndpoint.Async async = session.getAsyncRemote(); if (async != null) { - async.sendText(JSON.toJSONString(new SocketMsgDTO(fileId, "", MsgType.CONNECT.name(), MsgType.CONNECT.name()))); + async.sendText(JSON.toJSONString(new ExportMsgDTO(fileId, "", 0, MsgType.CONNECT.name()))); session.setMaxIdleTimeout(180000); } LogUtils.info("客户端: [" + fileId + "] : 连接成功!" + ExportWebSocketHandler.ONLINE_EXPORT_EXCEL_SESSIONS.size(), fileId); @@ -61,7 +61,7 @@ public class ExportWebSocketHandler { @OnMessage public void onMessage(@PathParam("fileId") String fileId, String message) { LogUtils.info("服务器收到:[" + fileId + "] : " + message); - SocketMsgDTO dto = JSON.parseObject(message, SocketMsgDTO.class); + ExportMsgDTO dto = JSON.parseObject(message, ExportMsgDTO.class); ExportWebSocketHandler.sendMessageSingle(dto); } @@ -92,7 +92,7 @@ public class ExportWebSocketHandler { @Scheduled(fixedRate = 60000) public void heartbeatCheck() { ExportWebSocketHandler.sendMessageSingle( - new SocketMsgDTO(MsgType.HEARTBEAT.name(), MsgType.HEARTBEAT.name(), MsgType.HEARTBEAT.name(), "heartbeat check") + new ExportMsgDTO(MsgType.HEARTBEAT.name(), MsgType.HEARTBEAT.name(), 0, "heartbeat check") ); } } diff --git a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalCaseControllerTests.java b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalCaseControllerTests.java index 6957d60436..1309b641f1 100644 --- a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalCaseControllerTests.java +++ b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalCaseControllerTests.java @@ -92,6 +92,7 @@ public class FunctionalCaseControllerTests extends BaseTest { public static final String DOWNLOAD_FILE_URL = "/functional/case/download/file/"; public static final String STOP_EXPORT_URL = "/functional/case/stop/"; public static final String EXPORT_XMIND_URL = "/functional/case/export/xmind"; + public static final String EXPORT_XMIND_CHECK_URL = "/functional/case/check/export-task"; @Resource private NotificationMapper notificationMapper; @@ -906,4 +907,11 @@ public class FunctionalCaseControllerTests extends BaseTest { request.setSelectIds(List.of("TEST_FUNCTIONAL_CASE_ID_8")); this.requestPost(EXPORT_XMIND_URL, request); } + + @Test + @Order(4) + public void checkExportTask() throws Exception { + this.requestGetExcel( EXPORT_XMIND_CHECK_URL); + } + } diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/manager/ExportTaskManager.java b/backend/services/system-setting/src/main/java/io/metersphere/system/manager/ExportTaskManager.java index 15436c5f3d..b842514a26 100644 --- a/backend/services/system-setting/src/main/java/io/metersphere/system/manager/ExportTaskManager.java +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/manager/ExportTaskManager.java @@ -34,8 +34,8 @@ public class ExportTaskManager { public static final String EXPORT_CONSUME = "export_consume"; - public void exportAsyncTask(String projectId, String userId, String type, T t, Function selectListFunc) throws InterruptedException { - ExportTask exportTask = buildExportTask(projectId, userId, type); + public void exportAsyncTask(String projectId, String fileId, String userId, String type, T t, Function selectListFunc) throws InterruptedException { + ExportTask exportTask = buildExportTask(projectId, fileId, userId, type); ExecutorService executorService = Executors.newFixedThreadPool(1); Future future = executorService.submit(() -> { while (!Thread.currentThread().isInterrupted()) { @@ -48,7 +48,7 @@ public class ExportTaskManager { map.put(exportTask.getId(), future); } - private ExportTask buildExportTask(String projectId, String userId, String type) { + private ExportTask buildExportTask(String projectId, String fileId, String userId, String type) { ExportTask exportTask = new ExportTask(); exportTask.setId(IDGenerator.nextStr()); exportTask.setType(type); @@ -58,6 +58,7 @@ public class ExportTaskManager { exportTask.setUpdateUser(userId); exportTask.setUpdateTime(System.currentTimeMillis()); exportTask.setProjectId(projectId); + exportTask.setFileType(fileId); exportTaskMapper.insert(exportTask); return exportTask; }