ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java
@@ -115,7 +115,7 @@ @RepeatSubmit() @PutMapping("/migrationDefinition/{currentProcessDefinitionId}/{fromProcessDefinitionId}") public R<Void> migrationDefinition(@NotBlank(message = "当前流程定义id") @PathVariable String currentProcessDefinitionId, @NotBlank(message = "需要迁移到的流程定义id") @PathVariable String fromProcessDefinitionId) { @NotBlank(message = "需要迁移到的流程定义id") @PathVariable String fromProcessDefinitionId) { return toAjax(actProcessDefinitionService.migrationDefinition(currentProcessDefinitionId, fromProcessDefinitionId)); } @@ -139,8 +139,8 @@ */ @Log(title = "流程定义管理", businessType = BusinessType.INSERT) @PostMapping("/deployByFile") public R<Void> deployByFile(@RequestParam("file") MultipartFile file, @RequestParam("categoryCode") String categoryCode) { return toAjax(actProcessDefinitionService.deployByFile(file, categoryCode)); public void deployByFile(@RequestParam("file") MultipartFile file, @RequestParam("categoryCode") String categoryCode) { actProcessDefinitionService.deployByFile(file, categoryCode); } } ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActModelService.java
@@ -7,6 +7,8 @@ import org.dromara.workflow.domain.vo.ModelVo; import org.flowable.engine.repository.Model; import java.util.List; /** * 模型管理 服务层 @@ -66,8 +68,8 @@ /** * 导出模型zip压缩包 * * @param modelId 模型id * @param modelIds 模型id * @param response 相应 */ void exportZip(String modelId, HttpServletResponse response); void exportZip(List<String> modelIds, HttpServletResponse response); } ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessDefinitionService.java
@@ -86,7 +86,6 @@ * * @param file 文件 * @param categoryCode 分类 * @return 结果 */ boolean deployByFile(MultipartFile file, String categoryCode); void deployByFile(MultipartFile file, String categoryCode); } ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java
@@ -281,35 +281,37 @@ /** * 导出模型zip压缩包 * * @param modelId 模型id * @param modelIds 模型id * @param response 相应 */ @Override public void exportZip(String modelId, HttpServletResponse response) { public void exportZip(List<String> modelIds, HttpServletResponse response) { ZipOutputStream zos = null; try { zos = ZipUtil.getZipOutputStream(response.getOutputStream(), StandardCharsets.UTF_8); // 压缩包文件名 String zipName = "模型不存在"; // 查询模型基本信息 Model model = repositoryService.getModel(modelId); byte[] xmlBytes = repositoryService.getModelEditorSource(modelId); if (ObjectUtil.isNotNull(model)) { if (JSONUtil.isTypeJSON(IOUtils.toString(xmlBytes, StandardCharsets.UTF_8.toString())) && ArrayUtil.isEmpty(ModelUtils.bpmnJsonToXmlBytes(xmlBytes))) { zipName = "模型不能为空,请至少设计一条主线流程!"; zos.putNextEntry(new ZipEntry(zipName + ".txt")); zos.write(zipName.getBytes(StandardCharsets.UTF_8)); } else if (ArrayUtil.isEmpty(xmlBytes)) { zipName = "模型数据为空,请先设计流程定义模型,再进行部署!"; zos.putNextEntry(new ZipEntry(zipName + ".txt")); zos.write(zipName.getBytes(StandardCharsets.UTF_8)); } else { String fileName = model.getName() + "-" + model.getKey(); // 压缩包文件名 zipName = fileName + ".zip"; // 将xml添加到压缩包中(指定xml文件名:请假流程.bpmn20.xml zos.putNextEntry(new ZipEntry(fileName + ".bpmn20.xml")); zos.write(xmlBytes); for (String modelId : modelIds) { Model model = repositoryService.getModel(modelId); byte[] xmlBytes = repositoryService.getModelEditorSource(modelId); if (ObjectUtil.isNotNull(model)) { if (JSONUtil.isTypeJSON(IOUtils.toString(xmlBytes, StandardCharsets.UTF_8.toString())) && ArrayUtil.isEmpty(ModelUtils.bpmnJsonToXmlBytes(xmlBytes))) { zipName = "模型不能为空,请至少设计一条主线流程!"; zos.putNextEntry(new ZipEntry(zipName + ".txt")); zos.write(zipName.getBytes(StandardCharsets.UTF_8)); } else if (ArrayUtil.isEmpty(xmlBytes)) { zipName = "模型数据为空,请先设计流程定义模型,再进行部署!"; zos.putNextEntry(new ZipEntry(zipName + ".txt")); zos.write(zipName.getBytes(StandardCharsets.UTF_8)); } else { String fileName = model.getName() + "-" + model.getKey(); // 压缩包文件名 zipName = fileName + ".zip"; // 将xml添加到压缩包中(指定xml文件名:请假流程.bpmn20.xml zos.putNextEntry(new ZipEntry(fileName + ".bpmn20.xml")); zos.write(xmlBytes); } } } response.setHeader("Content-Disposition", ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java
@@ -4,6 +4,7 @@ import cn.hutool.core.codec.Base64; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.ObjectUtil; import lombok.RequiredArgsConstructor; @@ -28,6 +29,7 @@ import org.flowable.engine.repository.*; import org.flowable.task.api.history.HistoricTaskInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; @@ -36,6 +38,7 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; /** @@ -265,59 +268,69 @@ * @param file 文件 * @param categoryCode 分类 */ @SneakyThrows @Override public boolean deployByFile(MultipartFile file, String categoryCode) { try { WfCategory wfCategory = wfCategoryService.queryByCategoryCode(categoryCode); if (wfCategory == null) { throw new ServiceException("流程分类不存在"); } // 文件名 = 流程名称-流程key String filename = file.getOriginalFilename(); assert filename != null; String[] splitFilename = filename.substring(0, filename.lastIndexOf(".")).split("-"); if (splitFilename.length < 2) { throw new ServiceException("流程分类不能为空(文件名 = 流程名称-流程key)"); } //流程名称 String processName = splitFilename[0]; //流程key String processKey = splitFilename[1]; // 文件后缀名 String suffix = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase(); InputStream inputStream = file.getInputStream(); Deployment deployment; if (FlowConstant.ZIP.equals(suffix)) { DeploymentBuilder builder = repositoryService.createDeployment(); deployment = builder.addZipInputStream(new ZipInputStream(inputStream)) .tenantId(TenantHelper.getTenantId()) .name(processName).key(processKey).category(categoryCode).deploy(); } else { String[] list = ResourceNameUtil.BPMN_RESOURCE_SUFFIXES; boolean flag = false; for (String str : list) { if (filename.contains(str)) { flag = true; break; } } if (flag) { @Transactional(rollbackFor = Exception.class) public void deployByFile(MultipartFile file, String categoryCode) { WfCategory wfCategory = wfCategoryService.queryByCategoryCode(categoryCode); if (wfCategory == null) { throw new ServiceException("流程分类不存在"); } // 文件后缀名 String suffix = FileUtil.extName(file.getOriginalFilename()); InputStream inputStream = file.getInputStream(); if (FlowConstant.ZIP.equalsIgnoreCase(suffix)) { ZipInputStream zipInputStream = null; try { zipInputStream = new ZipInputStream(inputStream); ZipEntry zipEntry; while ((zipEntry = zipInputStream.getNextEntry()) != null) { String filename = zipEntry.getName(); String[] splitFilename = filename.substring(0, filename.lastIndexOf(".")).split("-"); //流程名称 String processName = splitFilename[0]; //流程key String processKey = splitFilename[1]; DeploymentBuilder builder = repositoryService.createDeployment(); deployment = builder.addInputStream(filename, inputStream) Deployment deployment = builder.addInputStream(filename, zipInputStream) .tenantId(TenantHelper.getTenantId()) .name(processName).key(processKey).category(categoryCode).deploy(); } else { throw new ServiceException("文件类型上传错误!"); ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult(); repositoryService.setProcessDefinitionCategory(definition.getId(), categoryCode); zipInputStream.closeEntry(); } } catch (IOException e) { throw new RuntimeException(e); } finally { if (zipInputStream != null) { zipInputStream.close(); } } // 更新分类 ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult(); repositoryService.setProcessDefinitionCategory(definition.getId(), categoryCode); return true; } catch (IOException e) { e.printStackTrace(); throw new ServiceException("部署失败" + e.getMessage()); } else { String originalFilename = file.getOriginalFilename(); String bpmnResourceSuffix = ResourceNameUtil.BPMN_RESOURCE_SUFFIXES[0]; if (originalFilename.contains(bpmnResourceSuffix)) { // 文件名 = 流程名称-流程key String[] splitFilename = originalFilename.substring(0, originalFilename.lastIndexOf(".")).split("-"); if (splitFilename.length < 2) { throw new ServiceException("文件名 = 流程名称-流程KEY"); } //流程名称 String processName = splitFilename[0]; //流程key String processKey = splitFilename[1]; DeploymentBuilder builder = repositoryService.createDeployment(); Deployment deployment = builder.addInputStream(originalFilename, inputStream) .tenantId(TenantHelper.getTenantId()) .name(processName).key(processKey).category(categoryCode).deploy(); // 更新分类 ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult(); repositoryService.setProcessDefinitionCategory(definition.getId(), categoryCode); } else { throw new ServiceException("文件类型上传错误!"); } } } } ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/ModelUtils.java
@@ -195,7 +195,7 @@ * * @param processDefinitionId 流程定义id */ public Map<String, List<ExtensionElement>> getExtensionElements(String processDefinitionId) { public static Map<String, List<ExtensionElement>> getExtensionElements(String processDefinitionId) { Map<String, List<ExtensionElement>> map = new HashMap<>(); List<FlowElement> flowElements = getFlowElements(processDefinitionId); for (FlowElement flowElement : flowElements) { @@ -212,7 +212,7 @@ * @param processDefinitionId 流程定义id * @param flowElementId 节点id */ public Map<String, List<ExtensionElement>> getExtensionElement(String processDefinitionId, String flowElementId) { public static Map<String, List<ExtensionElement>> getExtensionElement(String processDefinitionId, String flowElementId) { BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionId); Process process = bpmnModel.getMainProcess(); FlowElement flowElement = process.getFlowElement(flowElementId); ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiProcinstMapper.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.dromara.workflow.mapper.ActHiProcinstMapper"> </mapper> ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiTaskinstMapper.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.dromara.workflow.mapper.ActHiTaskinstMapper"> </mapper> ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.dromara.workflow.mapper.TestLeaveMapper"> </mapper> ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfCategoryMapper.xml
@@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.dromara.workflow.mapper.WfCategoryMapper"> </mapper>