From 14b3c88d5729802f8e505e7ac319bd0cf6107acf Mon Sep 17 00:00:00 2001 From: pengjie <17373303529@163.com> Date: Mon, 16 Dec 2024 10:59:39 +0800 Subject: [PATCH] =?UTF-8?q?bug=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wflow/workflow/WFlowToBpmnCreator.java | 176 ++++++++++-------- 1 file changed, 101 insertions(+), 75 deletions(-) diff --git a/src/main/java/com/wflow/workflow/WFlowToBpmnCreator.java b/src/main/java/com/wflow/workflow/WFlowToBpmnCreator.java index 8266ab9..c864103 100644 --- a/src/main/java/com/wflow/workflow/WFlowToBpmnCreator.java +++ b/src/main/java/com/wflow/workflow/WFlowToBpmnCreator.java @@ -7,6 +7,7 @@ import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.wflow.workflow.bean.process.ProcessNode; +import com.wflow.workflow.bean.process.enums.ApprovalModeEnum; import com.wflow.workflow.bean.process.enums.ApprovalTypeEnum; import com.wflow.workflow.bean.process.enums.ConditionModeEnum; import com.wflow.workflow.bean.process.enums.NodeTypeEnum; @@ -29,6 +30,7 @@ import java.util.stream.Collectors; /** * json -> bpmn核心转换器 + * * @author : willian fu * @date : 2022/8/19 */ @@ -54,6 +56,7 @@ public class WFlowToBpmnCreator { private boolean isSub; private final static List taskListeners = new ArrayList<>(); + static { System.setProperty("java.util.Arrays.useLegacyMergeSort", "true"); FlowableListener taskListener = new FlowableListener(); @@ -65,13 +68,14 @@ public class WFlowToBpmnCreator { /** * wflow -> bpmnModel 转换 - * @param id 表单流程模型id - * @param name 流程名 - * @param root 根节点 + * + * @param id 表单流程模型id + * @param name 流程名 + * @param root 根节点 * @param isSub 是否是子流程 * @return 返回转换后的bpmnModel数据 */ - public BpmnModel loadBpmnFlowXmlByProcess(String id, String name, ProcessNode root, boolean isSub){ + public BpmnModel loadBpmnFlowXmlByProcess(String id, String name, ProcessNode root, boolean isSub) { this.isSub = isSub; StartEvent startEvent = new StartEvent(); startEvent.setId("start"); @@ -92,7 +96,7 @@ public class WFlowToBpmnCreator { lastNode.ifPresent(node -> { SequenceFlow line = createdConnectLine(node, endNode.getId()); FlowElement element = elementMap.get(node); - if (element instanceof Gateway){ + if (element instanceof Gateway) { ((Gateway) element).setOutgoingFlows(CollectionUtil.newArrayList(line)); } process.addFlowElement(line); @@ -112,7 +116,7 @@ public class WFlowToBpmnCreator { /** * 加载结束节点 */ - private void loadProcessEndNode(){ + private void loadProcessEndNode() { endNode.setId("process-end"); endNode.setName("审批流程结束"); cancelEndNode.setId("cancel-end"); @@ -130,12 +134,13 @@ public class WFlowToBpmnCreator { /** * 节点props属性强制转换 + * * @param node 节点 */ - public synchronized static void coverProps(ProcessNode node){ - if (node.getType().getTypeClass() != Object.class){ + public synchronized static void coverProps(ProcessNode node) { + if (node.getType().getTypeClass() != Object.class) { JSONObject props = (JSONObject) node.getProps(); - if (props.get("listeners") instanceof JSONArray){ + if (props.get("listeners") instanceof JSONArray) { //兼容旧版本,旧版本是数组,新版本是对象 props.put("listeners", "{}"); } @@ -145,23 +150,24 @@ public class WFlowToBpmnCreator { /** * 判断并加载分支末端所有的节点 + * * @param node 当前节点 */ - private void loadBranchEndNodes(ProcessNode node){ - if (!hasChildren(node) && currentBranchStack.size() > 0){ + private void loadBranchEndNodes(ProcessNode node) { + if (!hasChildren(node) && currentBranchStack.size() > 0) { //没有后续节点,代表该分支部分结束,塞入末端缓存 Optional.ofNullable(currentBranchStack.peek()).ifPresent(bn -> { List endNodes = footerNode.get(bn.getId()); - if (CollectionUtil.isEmpty(endNodes)){ + if (CollectionUtil.isEmpty(endNodes)) { endNodes = new ArrayList<>(); footerNode.put(bn.getId(), endNodes); } - if (NodeTypeEnum.EMPTY.equals(node.getType())){ + if (NodeTypeEnum.EMPTY.equals(node.getType())) { currentBranchStack.pop(); - if (currentBranchStack.size() > 0){ + if (currentBranchStack.size() > 0) { Optional.ofNullable(currentBranchStack.peek()).ifPresent(beforeBranch -> { List bfed = footerNode.get(beforeBranch.getId()); - if (CollectionUtil.isEmpty(bfed)){ + if (CollectionUtil.isEmpty(bfed)) { bfed = new ArrayList<>(); footerNode.put(beforeBranch.getId(), bfed); } @@ -169,7 +175,7 @@ public class WFlowToBpmnCreator { }); } currentBranchStack.push(bn); - }else { + } else { endNodes.add(node.getId()); //末端如果是审批节点,默认添加一条驳回的链接线 } @@ -179,6 +185,7 @@ public class WFlowToBpmnCreator { /** * 校验是否存在后续子节点 + * * @param node 当前节点 * @return 1/0 */ @@ -188,22 +195,23 @@ public class WFlowToBpmnCreator { /** * 递归加载所有流程树 + * * @param node 起始节点 */ - public void loadProcess(ProcessNode node){ - if (Objects.isNull(node) || Objects.isNull(node.getId())){ + public void loadProcess(ProcessNode node) { + if (Objects.isNull(node) || Objects.isNull(node.getId())) { return; } loadBranchEndNodes(node); coverProps(node); nodeMap.put(node.getId(), node); FlowElement element = null; - switch (node.getType()){ + switch (node.getType()) { case ROOT: - if (isSub){ + if (isSub) { //子流程的发起人节点换成初始化任务节点 element = createSubProcInitTask(node.getId()); - }else { + } else { element = createInitiatorNode(node.getId(), node.getName()); } break; @@ -239,7 +247,7 @@ public class WFlowToBpmnCreator { element = createTriggerTask((ProcessNode) node); break; case EMPTY: - if (NodeTypeEnum.CONCURRENTS.equals(node.getParentType())){ + if (NodeTypeEnum.CONCURRENTS.equals(node.getParentType())) { //并行网关成对存在,因此再添加一个聚合节点 element = createConcurrentNode(node); } else if (NodeTypeEnum.CONDITIONS.equals(node.getParentType())) { @@ -250,7 +258,7 @@ public class WFlowToBpmnCreator { } break; } - if (Objects.nonNull(element)){ + if (Objects.nonNull(element)) { addFlowEl(element); } addAndCreateConnLine(node); @@ -267,9 +275,9 @@ public class WFlowToBpmnCreator { callActivity.setBehavior(WflowCallActivityBehavior.class); //将主流程内子流程节点id绑定到子流程的业务key callActivity.setBusinessKey(node.getId()); - if (node.getProps().getSubAll()){ + if (node.getProps().getSubAll()) { callActivity.setInheritVariables(true); - }else { + } else { //挨个设置输入变量 List ioParams = getIoParams(node.getProps().getInVar(), false); callActivity.setInParameters(ioParams); @@ -280,7 +288,7 @@ public class WFlowToBpmnCreator { } //发起人节点 - private UserTask createInitiatorNode(String id, String name){ + private UserTask createInitiatorNode(String id, String name) { UserTask userTask = new UserTask(); userTask.setId(id); userTask.setName(name); @@ -299,19 +307,19 @@ public class WFlowToBpmnCreator { } //将当前节点向上连接,向上查找应该连接到本节点的所有父节点 - private void addAndCreateConnLine(ProcessNode node){ - if (NodeTypeEnum.EMPTY.equals(node.getType())){ + private void addAndCreateConnLine(ProcessNode node) { + if (NodeTypeEnum.EMPTY.equals(node.getType())) { //空节点代表一个分支结束,缓存出栈 ProcessNode branch = currentBranchStack.pop(); footerNode.get(branch.getId()).forEach(en -> { SequenceFlow connectLine = createdConnectLine(en, node.getId()); ProcessNode endNode = nodeMap.get(en); if (NodeTypeEnum.CONDITION.equals(endNode.getType()) - || NodeTypeEnum.INCLUSIVE.equals(endNode.getType())){ + || NodeTypeEnum.INCLUSIVE.equals(endNode.getType())) { //分支只有一个条件节点,那么就直连排他网关 connectLine.setId(endNode.getId()); connectLine.setSourceRef(endNode.getParentId()); - }else if (NodeTypeEnum.EMPTY.equals(endNode.getType())){ + } else if (NodeTypeEnum.EMPTY.equals(endNode.getType())) { //末端是网关,要为其构建出口 Gateway gateway = (Gateway) elementMap.get(en); gateway.setOutgoingFlows(CollectionUtil.newArrayList(connectLine)); @@ -319,7 +327,7 @@ public class WFlowToBpmnCreator { addFlowEl(connectLine); }); if (NodeTypeEnum.CONDITIONS.equals(node.getParentType()) - || NodeTypeEnum.INCLUSIVES.equals(node.getParentType())){ + || NodeTypeEnum.INCLUSIVES.equals(node.getParentType())) { //为条件网关构造出口及默认流 Gateway cdgw = (Gateway) elementMap.get(node.getParentId()); List outgoing = branch.getBranchs().stream() @@ -335,17 +343,17 @@ public class WFlowToBpmnCreator { .collect(Collectors.toList()); cdgw.setOutgoingFlows(outgoing); } - }else if (Objects.nonNull(node.getParentId())){ + } else if (Objects.nonNull(node.getParentId())) { //非空节点,特殊处理,判断父级是啥子 ProcessNode parentNode = nodeMap.get(node.getParentId()); if (Objects.isNull(parentNode) || NodeTypeEnum.CONDITION.equals(node.getType()) || NodeTypeEnum.CONCURRENT.equals(node.getType()) - || NodeTypeEnum.INCLUSIVE.equals(node.getType())){ + || NodeTypeEnum.INCLUSIVE.equals(node.getType())) { return; } SequenceFlow line = null; - switch (parentNode.getType()){ + switch (parentNode.getType()) { case CONCURRENT: case CONDITION: case INCLUSIVE: @@ -353,11 +361,11 @@ public class WFlowToBpmnCreator { line = createdConnectLine(parentNode.getParentId(), node.getId()); line.setId(parentNode.getId()); line.setName(parentNode.getName()); - if (parentNode.getProps() instanceof ConditionProps){ + if (parentNode.getProps() instanceof ConditionProps) { ConditionProps props = (ConditionProps) parentNode.getProps(); - if (CollectionUtil.isNotEmpty(props.getGroups())){ + if (CollectionUtil.isNotEmpty(props.getGroups())) { String conditionExplainCreator = conditionExplainCreator(line.getId(), (ConditionProps) parentNode.getProps()); - if (StrUtil.isNotBlank(conditionExplainCreator)){ + if (StrUtil.isNotBlank(conditionExplainCreator)) { line.setConditionExpression(conditionExplainCreator); } } @@ -367,7 +375,7 @@ public class WFlowToBpmnCreator { case TASK: //父级节点是审批/办理节点 line = createdConnectLine(parentNode.getId(), node.getId()); - line.setName(NodeTypeEnum.APPROVAL.equals(parentNode.getType()) ? "同意": "提交"); + line.setName(NodeTypeEnum.APPROVAL.equals(parentNode.getType()) ? "同意" : "提交"); break; case EMPTY: line = createdConnectLine(parentNode.getId(), node.getId()); @@ -380,13 +388,13 @@ public class WFlowToBpmnCreator { break; } addFlowEl(line); - }else if (NodeTypeEnum.ROOT.equals(node.getType())){ + } else if (NodeTypeEnum.ROOT.equals(node.getType())) { //发起人节点链接到开始节点 addFlowEl(createdConnectLine("start", node.getId())); } } - private void addFlowEl(FlowElement element){ + private void addFlowEl(FlowElement element) { elementMap.put(element.getId(), element); } @@ -397,27 +405,27 @@ public class WFlowToBpmnCreator { ApprovalProps props = node.getProps(); //全部按多人审批处理 userTask.setTaskListeners(taskListeners); - if(ApprovalTypeEnum.SELF.equals(props.getAssignedType())){ + if (ApprovalTypeEnum.SELF.equals(props.getAssignedType())) { //发起人自己审批 userTask.setAssignee("${" + WflowGlobalVarDef.INITIATOR + "}"); - }else { + } else { userTask.setAssignee("${assignee}"); userTask.setLoopCharacteristics(createAndOrMode(node.getId(), props)); } userTask.setId(node.getId()); //处理审批超时,添加定时器边界事件 ApprovalProps.TimeLimit timeLimit = props.getTimeLimit(); - if (Objects.nonNull(timeLimit.getTimeout().getValue()) && timeLimit.getTimeout().getValue() > 0){ + if (Objects.nonNull(timeLimit.getTimeout().getValue()) && timeLimit.getTimeout().getValue() > 0) { BoundaryEvent boundaryEvent = new BoundaryEvent(); boundaryEvent.setId(node.getId() + "-timeout"); boundaryEvent.setName("审批超时"); TimerEventDefinition timerEventDefinition = new TimerEventDefinition(); String timeValue = getISO8601Time(timeLimit.getTimeout().getValue(), timeLimit.getTimeout().getUnit()); timerEventDefinition.setTimeDuration(timeValue); - if (ApprovalProps.TimeLimit.Handler.HandlerType.NOTIFY.equals(timeLimit.getHandler().getType())){ + if (ApprovalProps.TimeLimit.Handler.HandlerType.NOTIFY.equals(timeLimit.getHandler().getType())) { //根据是否循环提醒来修改定时规则 ApprovalProps.TimeLimit.Handler.Notify notify = timeLimit.getHandler().getNotify(); - if (!notify.isOnce()){ + if (!notify.isOnce()) { timerEventDefinition.setTimeDuration(null); //默认最大10次,这里参考 https://en.wikipedia.org/wiki/ISO_8601#Repeating_intervals timerEventDefinition.setTimeCycle("R10/" + timeValue); @@ -443,7 +451,7 @@ public class WFlowToBpmnCreator { private ParallelGateway createConcurrentNode(ProcessNode node) { ParallelGateway parallelGateway = new ParallelGateway(); parallelGateway.setId(node.getId()); - parallelGateway.setName(NodeTypeEnum.EMPTY.equals(node.getType()) ? "并行分支聚合":"并行分支"); + parallelGateway.setName(NodeTypeEnum.EMPTY.equals(node.getType()) ? "并行分支聚合" : "并行分支"); return parallelGateway; } @@ -491,7 +499,7 @@ public class WFlowToBpmnCreator { ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); exclusiveGateway.setExclusive(true); exclusiveGateway.setId(node.getId()); - exclusiveGateway.setName(NodeTypeEnum.EMPTY.equals(node.getType()) ? "条件分支聚合":"条件分支"); + exclusiveGateway.setName(NodeTypeEnum.EMPTY.equals(node.getType()) ? "条件分支聚合" : "条件分支"); return exclusiveGateway; } @@ -500,7 +508,7 @@ public class WFlowToBpmnCreator { InclusiveGateway inclusiveGateway = new InclusiveGateway(); inclusiveGateway.setExclusive(true); inclusiveGateway.setId(node.getId()); - inclusiveGateway.setName(NodeTypeEnum.EMPTY.equals(node.getType()) ? "包容分支聚合":"包容分支"); + inclusiveGateway.setName(NodeTypeEnum.EMPTY.equals(node.getType()) ? "包容分支聚合" : "包容分支"); return inclusiveGateway; } @@ -514,12 +522,39 @@ public class WFlowToBpmnCreator { //构建条件表达式 private String conditionExplainCreator(String nodeId, ConditionProps conditions) { - if (CollectionUtil.isNotEmpty(conditions.getGroups())){ - return "${uelTools.conditionCompare('"+ nodeId + "', execution)}"; + if (CollectionUtil.isNotEmpty(conditions.getGroups())) { + return "${uelTools.conditionCompare('" + nodeId + "', execution)}"; } return null; } + //多人签署设置-会签/或签 +// private MultiInstanceLoopCharacteristics createAndOrMode(String nodeId, ApprovalProps props) { +// MultiInstanceLoopCharacteristics loopCharacteristics = new MultiInstanceLoopCharacteristics(); +// loopCharacteristics.setId(IdUtil.randomUUID()); +// loopCharacteristics.setElementVariable("assignee"); +// loopCharacteristics.setInputDataItem("${processTaskService.getNodeApprovalUsers(execution)}"); +// //设置完成条件,先判断会签还是或签 +// String completionCondition = ""; +// switch (props.getMode()) { +// case OR: //有任意一个人处理过就结束 +// completionCondition = "nrOfCompletedInstances >= 1"; +// loopCharacteristics.setSequential(false); +// break; +// case AND: //所有任务都结束 +// completionCondition = "nrOfActiveInstances == 0"; +// loopCharacteristics.setSequential(false); +// break; +// case NEXT: +// completionCondition = "nrOfActiveInstances == 0"; +// loopCharacteristics.setSequential(true); +// break; +// } +// loopCharacteristics.setCompletionCondition("${" + completionCondition + "}"); +// return loopCharacteristics; +// } + + //多人签署设置-会签/或签 private MultiInstanceLoopCharacteristics createAndOrMode(String nodeId, ApprovalProps props) { MultiInstanceLoopCharacteristics loopCharacteristics = new MultiInstanceLoopCharacteristics(); @@ -527,54 +562,45 @@ public class WFlowToBpmnCreator { loopCharacteristics.setElementVariable("assignee"); loopCharacteristics.setInputDataItem("${processTaskService.getNodeApprovalUsers(execution)}"); //设置完成条件,先判断会签还是或签 - String completionCondition = ""; - switch (props.getMode()) { - case OR: //有任意一个人处理过就结束 - completionCondition = "nrOfCompletedInstances >= 1"; - loopCharacteristics.setSequential(false); - break; - case AND: //所有任务都结束 - completionCondition = "nrOfActiveInstances == 0"; - loopCharacteristics.setSequential(false); - break; - case NEXT: - completionCondition = "nrOfActiveInstances == 0"; - loopCharacteristics.setSequential(true); - break; - } - loopCharacteristics.setCompletionCondition("${" + completionCondition + "}"); + loopCharacteristics.setSequential(ApprovalModeEnum.NEXT.equals(props.getMode())); + loopCharacteristics.setCompletionCondition("${uelTools.nodeIsComplete(execution, '" + props.getMode().toString() + "')}"); return loopCharacteristics; } /** * 获取ISO8601时间 + * * @param time 值 * @param unit 单位 * @return 格式化时间 */ - private String getISO8601Time(Integer time, String unit){ - switch (unit){ - case "D": return "P" + time + unit; - case "H": return "PT" + time + unit; - case "M": return "PT" + time + unit; + private String getISO8601Time(Integer time, String unit) { + switch (unit) { + case "D": + return "P" + time + unit; + case "H": + return "PT" + time + unit; + case "M": + return "PT" + time + unit; } return null; } /** * 构造主子流程变量传递参数 - * @param vars 参数 + * + * @param vars 参数 * @param reverse 是否为逆向传递 * @return 参数列表 */ - private List getIoParams(List vars, Boolean reverse){ + private List getIoParams(List vars, Boolean reverse) { return vars.stream().filter(v -> StrUtil.isNotBlank(reverse ? v.getSKey() : v.getMKey())) .map(v -> { IOParameter ip = new IOParameter(); - if (reverse){ + if (reverse) { ip.setSource(v.getSKey()); ip.setTarget(StrUtil.isNotBlank(v.getMKey()) ? v.getMKey() : v.getSKey()); - }else { + } else { ip.setSource(v.getMKey()); ip.setTarget(StrUtil.isNotBlank(v.getSKey()) ? v.getSKey() : v.getMKey()); }