BPM:增强 model 流程模型部署时,各种参数校验
This commit is contained in:
parent
559bab571a
commit
c104191821
@ -10,16 +10,9 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||
public interface ErrorCodeConstants {
|
||||
|
||||
// ========== 通用流程处理 模块 1-009-000-000 ==========
|
||||
ErrorCode HIGHLIGHT_IMG_ERROR = new ErrorCode(1_009_000_002, "获取高亮流程图异常");
|
||||
|
||||
// ========== OA 流程模块 1-009-001-000 ==========
|
||||
ErrorCode OA_LEAVE_NOT_EXISTS = new ErrorCode(1_009_001_001, "请假申请不存在");
|
||||
ErrorCode OA_PM_POST_NOT_EXISTS = new ErrorCode(1_009_001_002, "项目经理岗位未设置");
|
||||
ErrorCode OA_DEPART_PM_POST_NOT_EXISTS = new ErrorCode(1_009_001_009, "部门的项目经理不存在");
|
||||
ErrorCode OA_BM_POST_NOT_EXISTS = new ErrorCode(1_009_001_004, "部门经理岗位未设置");
|
||||
ErrorCode OA_DEPART_BM_POST_NOT_EXISTS = new ErrorCode(1_009_001_005, "部门的部门经理不存在");
|
||||
ErrorCode OA_HR_POST_NOT_EXISTS = new ErrorCode(1_009_001_006, "HR岗位未设置");
|
||||
ErrorCode OA_DAY_LEAVE_ERROR = new ErrorCode(1_009_001_007, "请假天数必须>=1");
|
||||
|
||||
// ========== 流程模型 1-009-002-000 ==========
|
||||
ErrorCode MODEL_KEY_EXISTS = new ErrorCode(1_009_002_000, "已经存在流程标识为【{}】的流程");
|
||||
@ -28,7 +21,8 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG = new ErrorCode(1_009_002_003, "部署流程失败,原因:流程表单未配置,请点击【修改流程】按钮进行配置");
|
||||
ErrorCode MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG = new ErrorCode(1_009_002_004, "部署流程失败," +
|
||||
"原因:用户任务({})未配置审批人,请点击【流程设计】按钮,选择该它的【任务(审批人)】进行配置");
|
||||
ErrorCode MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS = new ErrorCode(1_009_003_005, "流程定义部署失败,原因:信息未发生变化");
|
||||
ErrorCode MODEL_DEPLOY_FAIL_BPMN_START_EVENT_NOT_EXISTS = new ErrorCode(1_009_002_005, "部署流程失败,原因:BPMN 流程图中,没有开始事件");
|
||||
ErrorCode MODEL_DEPLOY_FAIL_BPMN_USER_TASK_NAME_NOT_EXISTS = new ErrorCode(1_009_002_006, "部署流程失败,原因:BPMN 流程图中,用户任务({})的名字不存在");
|
||||
|
||||
// ========== 流程定义 1-009-003-000 ==========
|
||||
ErrorCode PROCESS_DEFINITION_KEY_NOT_MATCH = new ErrorCode(1_009_003_000, "流程定义的标识期望是({}),当前是({}),请修改 BPMN 流程图");
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user