mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-01 02:38:43 +08:00 
			
		
		
		
	BPM:增强 model 流程模型部署时,各种参数校验
This commit is contained in:
		| @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.io.IoUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; | ||||
| import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; | ||||
| @@ -112,7 +113,7 @@ public class BpmModelController { | ||||
|     @Operation(summary = "导入模型") | ||||
|     @PreAuthorize("@ss.hasPermission('bpm:model:import')") | ||||
|     public CommonResult<String> importModel(@Valid BpmModeImportReqVO importReqVO) throws IOException { | ||||
|         BpmModelCreateReqVO createReqVO = BpmModelConvert.INSTANCE.convert(importReqVO); | ||||
|         BpmModelCreateReqVO createReqVO = BeanUtils.toBean(importReqVO, BpmModelCreateReqVO.class); | ||||
|         // 读取文件 | ||||
|         String bpmnXml = IoUtils.readUtf8(importReqVO.getBpmnFile().getInputStream(), false); | ||||
|         return success(modelService.createModel(createReqVO, bpmnXml)); | ||||
|   | ||||
| @@ -104,7 +104,7 @@ public class BpmTaskController { | ||||
|                 convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); | ||||
|         // 获得 Form Map | ||||
|         Map<Long, BpmFormDO> formMap = formService.getFormMap( | ||||
|                 convertSet(taskList, task -> Long.parseLong(task.getFormKey()))); | ||||
|                 convertSet(taskList, task -> NumberUtils.parseLong(task.getFormKey()))); | ||||
|         return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, processInstance, | ||||
|                 formMap, userMap, deptMap)); | ||||
|     } | ||||
|   | ||||
| @@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.date.DateUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModeImportReqVO; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelCreateReqVO; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelRespVO; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelUpdateReqVO; | ||||
| @@ -15,13 +14,11 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmPro | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; | ||||
| import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; | ||||
| import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; | ||||
| import org.flowable.common.engine.impl.db.SuspensionState; | ||||
| import org.flowable.engine.repository.Deployment; | ||||
| import org.flowable.engine.repository.Model; | ||||
| import org.flowable.engine.repository.ProcessDefinition; | ||||
| import org.mapstruct.Mapper; | ||||
| import org.mapstruct.MappingTarget; | ||||
| import org.mapstruct.factory.Mappers; | ||||
|  | ||||
| import java.util.List; | ||||
| @@ -43,7 +40,7 @@ public interface BpmModelConvert { | ||||
|                                                       Map<String, BpmCategoryDO> categoryMap, Map<String, Deployment> deploymentMap, | ||||
|                                                       Map<String, ProcessDefinition> processDefinitionMap) { | ||||
|         List<BpmModelRespVO> list = CollectionUtils.convertList(pageResult.getList(), model -> { | ||||
|             BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); | ||||
|             BpmModelMetaInfoRespDTO metaInfo = buildMetaInfo(model); | ||||
|             BpmFormDO form = metaInfo != null ? formMap.get(metaInfo.getFormId()) : null; | ||||
|             BpmCategoryDO category = categoryMap.get(model.getCategory()); | ||||
|             Deployment deployment = model.getDeploymentId() != null ? deploymentMap.get(model.getDeploymentId()) : null; | ||||
| @@ -55,7 +52,7 @@ public interface BpmModelConvert { | ||||
|  | ||||
|     default BpmModelRespVO buildModel(Model model, | ||||
|                                      byte[] bpmnBytes) { | ||||
|         BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); | ||||
|         BpmModelMetaInfoRespDTO metaInfo = buildMetaInfo(model); | ||||
|         BpmModelRespVO modelVO = buildModel0(model, metaInfo, null, null, null, null); | ||||
|         if (ArrayUtil.isNotEmpty(bpmnBytes)) { | ||||
|             modelVO.setBpmnXml(new String(bpmnBytes)); | ||||
| @@ -95,27 +92,6 @@ public interface BpmModelConvert { | ||||
|         return modelRespVO; | ||||
|     } | ||||
|  | ||||
|     BpmModelCreateReqVO convert(BpmModeImportReqVO bean); | ||||
|  | ||||
|     default BpmProcessDefinitionCreateReqDTO convert2(Model model, BpmFormDO form) { | ||||
|         BpmProcessDefinitionCreateReqDTO createReqDTO = new BpmProcessDefinitionCreateReqDTO(); | ||||
|         createReqDTO.setModelId(model.getId()); | ||||
|         createReqDTO.setName(model.getName()); | ||||
|         createReqDTO.setKey(model.getKey()); | ||||
|         createReqDTO.setCategory(model.getCategory()); | ||||
|         BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); | ||||
|         // metaInfo | ||||
|         copyTo(metaInfo, createReqDTO); | ||||
|         // form | ||||
|         if (form != null) { | ||||
|             createReqDTO.setFormConf(form.getConf()); | ||||
|             createReqDTO.setFormFields(form.getFields()); | ||||
|         } | ||||
|         return createReqDTO; | ||||
|     } | ||||
|  | ||||
|     void copyTo(BpmModelMetaInfoRespDTO from, @MappingTarget BpmProcessDefinitionCreateReqDTO to); | ||||
|  | ||||
|     default void copyToCreateModel(Model model, BpmModelCreateReqVO bean) { | ||||
|         model.setName(bean.getName()); | ||||
|         model.setKey(bean.getKey()); | ||||
| @@ -126,7 +102,7 @@ public interface BpmModelConvert { | ||||
|     default void copyToUpdateModel(Model model, BpmModelUpdateReqVO bean) { | ||||
|         model.setName(bean.getName()); | ||||
|         model.setCategory(bean.getCategory()); | ||||
|         model.setMetaInfo(buildMetaInfoStr(JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class), | ||||
|         model.setMetaInfo(buildMetaInfoStr(buildMetaInfo(model), | ||||
|                 bean.getDescription(), bean.getFormType(), bean.getFormId(), | ||||
|                 bean.getFormCustomCreatePath(), bean.getFormCustomViewPath())); | ||||
|     } | ||||
| @@ -149,4 +125,8 @@ public interface BpmModelConvert { | ||||
|         return JsonUtils.toJsonString(metaInfo); | ||||
|     } | ||||
|  | ||||
|     default BpmModelMetaInfoRespDTO buildMetaInfo(Model model) { | ||||
|         return JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -10,7 +10,6 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmPro | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; | ||||
| import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; | ||||
| import org.flowable.common.engine.impl.db.SuspensionState; | ||||
| import org.flowable.engine.repository.Deployment; | ||||
| import org.flowable.engine.repository.ProcessDefinition; | ||||
| @@ -69,8 +68,6 @@ public interface BpmProcessDefinitionConvert { | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     BpmProcessDefinitionInfoDO convert2(BpmProcessDefinitionCreateReqDTO bean); | ||||
|  | ||||
|     @Mapping(source = "from.id", target = "to.id", ignore = true) | ||||
|     void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessDefinitionRespVO to); | ||||
|  | ||||
|   | ||||
| @@ -80,7 +80,7 @@ public interface BpmTaskConvert { | ||||
|             taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class)); | ||||
|             taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); | ||||
|             // 表单信息 | ||||
|             BpmFormDO form = MapUtil.get(formMap, Long.parseLong(task.getFormKey()), BpmFormDO.class); | ||||
|             BpmFormDO form = MapUtil.get(formMap, NumberUtils.parseLong(task.getFormKey()), BpmFormDO.class); | ||||
|             if (form != null) { | ||||
|                 taskVO.setFormId(form.getId()).setFormName(form.getName()).setFormConf(form.getConf()) | ||||
|                         .setFormFields(form.getFields()).setFormVariables(FlowableUtils.getTaskFormVariable(task)); | ||||
|   | ||||
| @@ -71,26 +71,15 @@ public class BpmnModelUtils { | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 比较 两个bpmnModel 是否相同 | ||||
|      * @param oldModel  老的bpmn model | ||||
|      * @param newModel 新的bpmn model | ||||
|      */ | ||||
|     public static boolean equals(BpmnModel oldModel, BpmnModel newModel) { | ||||
|         // 由于 BpmnModel 未提供 equals 方法,所以只能转成字节数组,进行比较 | ||||
|         return Arrays.equals(getBpmnBytes(oldModel), getBpmnBytes(newModel)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 把 bpmnModel 转换成 byte[] | ||||
|      * @param model  bpmnModel | ||||
|      */ | ||||
|     public static byte[] getBpmnBytes(BpmnModel model) { | ||||
|         if (model == null) { | ||||
|             return new byte[0]; | ||||
|     public static StartEvent getStartEvent(BpmnModel model) { | ||||
|         Process process = model.getMainProcess(); | ||||
|         // 从 initialFlowElement 找 | ||||
|         FlowElement startElement = process.getInitialFlowElement(); | ||||
|         if (startElement instanceof StartEvent) { | ||||
|             return (StartEvent) startElement; | ||||
|         } | ||||
|         BpmnXMLConverter converter = new BpmnXMLConverter(); | ||||
|         return converter.convertToXML(model); | ||||
|         // 从 flowElementList 找 | ||||
|         return (StartEvent) CollUtil.findOne(process.getFlowElements(), flowElement -> flowElement instanceof StartEvent); | ||||
|     } | ||||
|  | ||||
|     public static BpmnModel getBpmnModel(byte[] bpmnBytes) { | ||||
|   | ||||
| @@ -83,12 +83,4 @@ public interface BpmFormService { | ||||
|      */ | ||||
|     PageResult<BpmFormDO> getFormPage(BpmFormPageReqVO pageReqVO); | ||||
|  | ||||
|     /** | ||||
|      * 校验流程表单已配置 | ||||
|      * | ||||
|      * @param configStr  configStr 字段 | ||||
|      * @return 流程表单 | ||||
|      */ | ||||
|     BpmFormDO checkFormConfig(String  configStr); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -11,17 +11,14 @@ import cn.iocoder.yudao.module.bpm.convert.definition.BpmFormConvert; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; | ||||
| import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmFormMapper; | ||||
| import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; | ||||
| import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; | ||||
| import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmFormFieldRespDTO; | ||||
| import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; | ||||
| import jakarta.annotation.Resource; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
|  | ||||
| import jakarta.annotation.Resource; | ||||
| import java.util.*; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||
| import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; | ||||
|  | ||||
| /** | ||||
|  * 动态表单 Service 实现类 | ||||
| @@ -92,24 +89,6 @@ public class BpmFormServiceImpl implements BpmFormService { | ||||
|         return formMapper.selectPage(pageReqVO); | ||||
|     } | ||||
|  | ||||
|     // TODO @芋艿:这里没搞完! | ||||
|     @Override | ||||
|     public BpmFormDO checkFormConfig(String configStr) { | ||||
|         BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(configStr, BpmModelMetaInfoRespDTO.class); | ||||
|         if (metaInfo == null || metaInfo.getFormType() == null) { | ||||
|             throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); | ||||
|         } | ||||
|         // 校验表单存在 | ||||
|         if (Objects.equals(metaInfo.getFormType(), BpmModelFormTypeEnum.NORMAL.getType())) { | ||||
|             BpmFormDO form = getForm(metaInfo.getFormId()); | ||||
|             if (form == null) { | ||||
|                 throw exception(FORM_NOT_EXISTS); | ||||
|             } | ||||
|             return form; | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 校验 Field,避免 field 重复 | ||||
|      * | ||||
|   | ||||
| @@ -13,12 +13,14 @@ import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; | ||||
| import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; | ||||
| import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; | ||||
| import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; | ||||
| import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; | ||||
| import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; | ||||
| import jakarta.annotation.Resource; | ||||
| import jakarta.validation.Valid; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.flowable.bpmn.model.BpmnModel; | ||||
| import org.flowable.bpmn.model.StartEvent; | ||||
| import org.flowable.bpmn.model.UserTask; | ||||
| import org.flowable.common.engine.impl.db.SuspensionState; | ||||
| import org.flowable.engine.RepositoryService; | ||||
| import org.flowable.engine.repository.Model; | ||||
| @@ -85,7 +87,9 @@ public class BpmModelServiceImpl implements BpmModelService { | ||||
|     @Override | ||||
|     @Transactional(rollbackFor = Exception.class) | ||||
|     public String createModel(@Valid BpmModelCreateReqVO createReqVO, String bpmnXml) { | ||||
|         validateKeyNCName(createReqVO.getKey()); | ||||
|         if (!ValidationUtils.isXmlNCName(createReqVO.getName())) { | ||||
|             throw exception(MODEL_KEY_VALID); | ||||
|         } | ||||
|         // 校验流程标识已经存在 | ||||
|         Model keyModel = getModelByKey(createReqVO.getKey()); | ||||
|         if (keyModel != null) { | ||||
| @@ -129,26 +133,16 @@ public class BpmModelServiceImpl implements BpmModelService { | ||||
|             throw exception(MODEL_NOT_EXISTS); | ||||
|         } | ||||
|         // 1.2 校验流程图 | ||||
|         // TODO 芋艿:校验流程图的有效性;例如说,是否有开始的元素,是否有结束的元素; | ||||
|         byte[] bpmnBytes = getModelBpmnXML(model.getId()); | ||||
|         if (bpmnBytes == null) { | ||||
|             throw exception(MODEL_NOT_EXISTS); | ||||
|         } | ||||
|         validateBpmnXml(bpmnBytes); | ||||
|         // 1.3 校验表单已配 | ||||
|         BpmFormDO form = validateFormConfig(model.getMetaInfo()); | ||||
|         BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class); | ||||
|         BpmFormDO form = validateFormConfig(metaInfo); | ||||
|         // 1.4 校验任务分配规则已配置 | ||||
|         taskCandidateInvoker.validateBpmnConfig(bpmnBytes); | ||||
|  | ||||
|         // 1.5 校验模型是否发生修改。如果未修改,则不允许创建 | ||||
|         BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model, form) | ||||
|                 .setBpmnBytes(bpmnBytes); | ||||
|         // TODO @芋艿:这里比较可能有点问题 | ||||
| //        if (processDefinitionService.isProcessDefinitionEquals(definitionCreateReqDTO)) { // 流程定义的信息相等 | ||||
| //            throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS); | ||||
| //        } | ||||
|  | ||||
|         // 2.1 创建流程定义 | ||||
|         String definitionId = processDefinitionService.createProcessDefinition(definitionCreateReqDTO); | ||||
|         String definitionId = processDefinitionService.createProcessDefinition(model, metaInfo, bpmnBytes, form); | ||||
|  | ||||
|         // 2.2 将老的流程定义进行挂起。也就是说,只有最新部署的流程定义,才可以发起任务。 | ||||
|         updateProcessDefinitionSuspended(model.getDeploymentId()); | ||||
| @@ -159,6 +153,25 @@ public class BpmModelServiceImpl implements BpmModelService { | ||||
|         repositoryService.saveModel(model); | ||||
|     } | ||||
|  | ||||
|     private void validateBpmnXml(byte[] bpmnBytes) { | ||||
|         BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes); | ||||
|         if (bpmnModel == null) { | ||||
|             throw exception(MODEL_NOT_EXISTS); | ||||
|         } | ||||
|         // 1. 没有 StartEvent | ||||
|         StartEvent startEvent = BpmnModelUtils.getStartEvent(bpmnModel); | ||||
|         if (startEvent == null) { | ||||
|             throw exception(MODEL_DEPLOY_FAIL_BPMN_START_EVENT_NOT_EXISTS); | ||||
|         } | ||||
|         // 2. 校验 UserTask 的 name 都配置了 | ||||
|         List<UserTask> userTasks = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class); | ||||
|         userTasks.forEach(userTask -> { | ||||
|             if (StrUtil.isEmpty(userTask.getName())) { | ||||
|                 throw exception(MODEL_DEPLOY_FAIL_BPMN_USER_TASK_NAME_NOT_EXISTS, userTask.getId()); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     @Transactional(rollbackFor = Exception.class) | ||||
|     public void deleteModel(String id) { | ||||
| @@ -195,32 +208,32 @@ public class BpmModelServiceImpl implements BpmModelService { | ||||
|         return repositoryService.getBpmnModel(processDefinitionId); | ||||
|     } | ||||
|  | ||||
|     private void validateKeyNCName(String key) { | ||||
|         if (!ValidationUtils.isXmlNCName(key)) { | ||||
|             throw exception(MODEL_KEY_VALID); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 校验流程表单已配置 | ||||
|      * | ||||
|      * @param metaInfoStr 流程模型 metaInfo 字段 | ||||
|      * @return 流程表单 | ||||
|      * @param metaInfo 流程模型元数据 | ||||
|      * @return 表单配置 | ||||
|      */ | ||||
|     private BpmFormDO validateFormConfig(String  metaInfoStr) { | ||||
|         BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(metaInfoStr, BpmModelMetaInfoRespDTO.class); | ||||
|     private BpmFormDO validateFormConfig(BpmModelMetaInfoRespDTO  metaInfo) { | ||||
|         if (metaInfo == null || metaInfo.getFormType() == null) { | ||||
|             throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); | ||||
|         } | ||||
|         // 校验表单存在 | ||||
|         if (Objects.equals(metaInfo.getFormType(), BpmModelFormTypeEnum.NORMAL.getType())) { | ||||
|             if (metaInfo.getFormId() == null) { | ||||
|                 throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); | ||||
|             } | ||||
|             BpmFormDO form = bpmFormService.getForm(metaInfo.getFormId()); | ||||
|             if (form == null) { | ||||
|                 throw exception(FORM_NOT_EXISTS); | ||||
|             } | ||||
|             return form; | ||||
|         } else { | ||||
|             if (StrUtil.isEmpty(metaInfo.getFormCustomCreatePath()) || StrUtil.isEmpty(metaInfo.getFormCustomViewPath())) { | ||||
|                 throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG); | ||||
|             } | ||||
|             return null; | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     private void saveModelBpmnXml(Model model, String bpmnXml) { | ||||
| @@ -231,8 +244,11 @@ public class BpmModelServiceImpl implements BpmModelService { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 挂起 deploymentId 对应的流程定义。 这里一个deploymentId 只关联一个流程定义 | ||||
|      * @param deploymentId 流程发布Id. | ||||
|      * 挂起 deploymentId 对应的流程定义 | ||||
|      * | ||||
|      * 注意:这里一个 deploymentId 只关联一个流程定义 | ||||
|      * | ||||
|      * @param deploymentId 流程发布Id | ||||
|      */ | ||||
|     private void updateProcessDefinitionSuspended(String deploymentId) { | ||||
|         if (StrUtil.isEmpty(deploymentId)) { | ||||
|   | ||||
| @@ -2,10 +2,11 @@ package cn.iocoder.yudao.module.bpm.service.definition; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; | ||||
| import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; | ||||
| import jakarta.validation.Valid; | ||||
| import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; | ||||
| import org.flowable.engine.repository.Deployment; | ||||
| import org.flowable.engine.repository.Model; | ||||
| import org.flowable.engine.repository.ProcessDefinition; | ||||
|  | ||||
| import java.util.Collection; | ||||
| @@ -41,12 +42,15 @@ public interface BpmProcessDefinitionService { | ||||
|     List<ProcessDefinition> getProcessDefinitionListBySuspensionState(Integer suspensionState); | ||||
|  | ||||
|     /** | ||||
|      * 创建流程定义 | ||||
|      * 基于流程模型,创建流程定义 | ||||
|      * | ||||
|      * @param createReqDTO 创建信息 | ||||
|      * @param model 流程模型 | ||||
|      * @param modelMetaInfo 流程模型元信息 | ||||
|      * @param bpmnBytes BPMN XML 字节数组 | ||||
|      * @param form 表单 | ||||
|      * @return 流程编号 | ||||
|      */ | ||||
|     String createProcessDefinition(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO); | ||||
|     String createProcessDefinition(Model model, BpmModelMetaInfoRespDTO modelMetaInfo, byte[] bpmnBytes, BpmFormDO form); | ||||
|  | ||||
|     /** | ||||
|      * 更新流程定义状态 | ||||
|   | ||||
| @@ -3,22 +3,23 @@ package cn.iocoder.yudao.module.bpm.service.definition; | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||||
| import cn.iocoder.yudao.framework.common.util.object.PageUtils; | ||||
| import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | ||||
| import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; | ||||
| import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConvert; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; | ||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; | ||||
| import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmProcessDefinitionInfoMapper; | ||||
| import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; | ||||
| import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; | ||||
| import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; | ||||
| import jakarta.annotation.Resource; | ||||
| import jakarta.validation.Valid; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.flowable.bpmn.converter.BpmnXMLConverter; | ||||
| import org.flowable.bpmn.model.BpmnModel; | ||||
| import org.flowable.common.engine.impl.db.SuspensionState; | ||||
| import org.flowable.engine.RepositoryService; | ||||
| import org.flowable.engine.repository.Deployment; | ||||
| import org.flowable.engine.repository.Model; | ||||
| import org.flowable.engine.repository.ProcessDefinition; | ||||
| import org.flowable.engine.repository.ProcessDefinitionQuery; | ||||
| import org.springframework.stereotype.Service; | ||||
| @@ -103,11 +104,12 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String createProcessDefinition(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO) { | ||||
|     public String createProcessDefinition(Model model, BpmModelMetaInfoRespDTO modelMetaInfo, | ||||
|                                           byte[] bpmnBytes, BpmFormDO form) { | ||||
|         // 创建 Deployment 部署 | ||||
|         Deployment deploy = repositoryService.createDeployment() | ||||
|                 .key(createReqDTO.getKey()).name(createReqDTO.getName()).category(createReqDTO.getCategory()) | ||||
|                 .addBytes(createReqDTO.getKey() + BpmnModelConstants.BPMN_FILE_SUFFIX, createReqDTO.getBpmnBytes()) | ||||
|                 .key(model.getKey()).name(model.getName()).category(model.getCategory()) | ||||
|                 .addBytes(model.getKey() + BpmnModelConstants.BPMN_FILE_SUFFIX, bpmnBytes) | ||||
|                 .tenantId(TenantContextHolder.getTenantIdStr()) | ||||
|                 .disableSchemaValidation() // 禁用 XML Schema 验证,因为有自定义的属性 | ||||
|                 .deploy(); | ||||
| @@ -115,20 +117,23 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ | ||||
|         // 设置 ProcessDefinition 的 category 分类 | ||||
|         ProcessDefinition definition = repositoryService.createProcessDefinitionQuery() | ||||
|                 .deploymentId(deploy.getId()).singleResult(); | ||||
|         repositoryService.setProcessDefinitionCategory(definition.getId(), createReqDTO.getCategory()); | ||||
|         repositoryService.setProcessDefinitionCategory(definition.getId(), model.getCategory()); | ||||
|         // 注意 1,ProcessDefinition 的 key 和 name 是通过 BPMN 中的 <bpmn2:process /> 的 id 和 name 决定 | ||||
|         // 注意 2,目前该项目的设计上,需要保证 Model、Deployment、ProcessDefinition 使用相同的 key,保证关联性。 | ||||
|         //          否则,会导致 ProcessDefinition 的分页无法查询到。 | ||||
|         if (!Objects.equals(definition.getKey(), createReqDTO.getKey())) { | ||||
|             throw exception(PROCESS_DEFINITION_KEY_NOT_MATCH, createReqDTO.getKey(), definition.getKey()); | ||||
|         if (!Objects.equals(definition.getKey(), model.getKey())) { | ||||
|             throw exception(PROCESS_DEFINITION_KEY_NOT_MATCH, model.getKey(), definition.getKey()); | ||||
|         } | ||||
|         if (!Objects.equals(definition.getName(), createReqDTO.getName())) { | ||||
|             throw exception(PROCESS_DEFINITION_NAME_NOT_MATCH, createReqDTO.getName(), definition.getName()); | ||||
|         if (!Objects.equals(definition.getName(), model.getName())) { | ||||
|             throw exception(PROCESS_DEFINITION_NAME_NOT_MATCH, model.getName(), definition.getName()); | ||||
|         } | ||||
|  | ||||
|         // 插入拓展表 | ||||
|         BpmProcessDefinitionInfoDO definitionDO = BpmProcessDefinitionConvert.INSTANCE.convert2(createReqDTO) | ||||
|                 .setProcessDefinitionId(definition.getId()); | ||||
|         BpmProcessDefinitionInfoDO definitionDO = BeanUtils.toBean(modelMetaInfo, BpmProcessDefinitionInfoDO.class) | ||||
|                 .setModelId(model.getId()).setProcessDefinitionId(definition.getId()); | ||||
|         if (form != null) { | ||||
|             definitionDO.setFormFields(form.getFields()).setFormConf(form.getConf()); | ||||
|         } | ||||
|         processDefinitionMapper.insert(definitionDO); | ||||
|         return definition.getId(); | ||||
|     } | ||||
|   | ||||
| @@ -7,6 +7,8 @@ import lombok.Data; | ||||
|  * BPM 流程 MetaInfo Response DTO | ||||
|  * 主要用于 { Model#setMetaInfo(String)} 的存储 | ||||
|  * | ||||
|  * 最终,它的字段和 {@link cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO} 是一致的 | ||||
|  * | ||||
|  * @author 芋道源码 | ||||
|  */ | ||||
| @Data | ||||
|   | ||||
| @@ -1,15 +1,11 @@ | ||||
| package cn.iocoder.yudao.module.bpm.service.definition.dto; | ||||
|  | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; | ||||
| import lombok.Data; | ||||
|  | ||||
| import jakarta.validation.constraints.AssertTrue; | ||||
| import jakarta.validation.constraints.NotEmpty; | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.util.List; | ||||
| import java.util.Objects; | ||||
|  | ||||
| /** | ||||
|  * 流程定义创建 Request DTO | ||||
| @@ -82,22 +78,4 @@ public class BpmProcessDefinitionCreateReqDTO { | ||||
|      */ | ||||
|     private String formCustomViewPath; | ||||
|  | ||||
|     @AssertTrue(message = "流程表单信息不全") | ||||
|     public boolean isNormalFormTypeValid() { | ||||
|         // 如果非业务表单,则直接通过 | ||||
|         if (!Objects.equals(formType, BpmModelFormTypeEnum.NORMAL.getType())) { | ||||
|             return true; | ||||
|         } | ||||
|         return formId != null && StrUtil.isNotEmpty(formConf) && CollUtil.isNotEmpty(formFields); | ||||
|     } | ||||
|  | ||||
|     @AssertTrue(message = "业务表单信息不全") | ||||
|     public boolean isNormalCustomTypeValid() { | ||||
|         // 如果非业务表单,则直接通过 | ||||
|         if (!Objects.equals(formType, BpmModelFormTypeEnum.CUSTOM.getType())) { | ||||
|             return true; | ||||
|         } | ||||
|         return StrUtil.isNotEmpty(formCustomCreatePath) && StrUtil.isNotEmpty(formCustomViewPath); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV