仿钉钉流程设计- code review 修改

This commit is contained in:
jason 2024-05-28 00:19:28 +08:00
parent 4d176c8494
commit 8f31e745dd
2 changed files with 70 additions and 65 deletions

View File

@ -19,6 +19,7 @@ import org.flowable.bpmn.BpmnAutoLayout;
import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*; import org.flowable.bpmn.model.*;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -49,8 +50,9 @@ public class SimpleModelUtils {
*/ */
public static final String ANY_OF_APPROVE_COMPLETE_EXPRESSION = "${ nrOfCompletedInstances > 0 }"; public static final String ANY_OF_APPROVE_COMPLETE_EXPRESSION = "${ nrOfCompletedInstances > 0 }";
// TODO @jason建议方法名改成 buildBpmnModel // TODO-DONE @jason建议方法名改成 buildBpmnModel
// TODO @yunai注释需要完善下 // TODO @yunai注释需要完善下
/** /**
* 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model (待完善 * 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model (待完善
* *
@ -59,11 +61,12 @@ public class SimpleModelUtils {
* @param simpleModelNode 仿钉钉流程设计模型数据结构 * @param simpleModelNode 仿钉钉流程设计模型数据结构
* @return Bpmn Model * @return Bpmn Model
*/ */
public static BpmnModel convertSimpleModelToBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) { public static BpmnModel buildBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) {
BpmnModel bpmnModel = new BpmnModel(); BpmnModel bpmnModel = new BpmnModel();
bpmnModel.setTargetNamespace(BPMN2_NAMESPACE); // TODO @jason待定是不是搞个自定义的 namespace bpmnModel.setTargetNamespace(BPMN2_NAMESPACE); // TODO @jason待定是不是搞个自定义的 namespace
// TODO 芋艿后续在 review // TODO 芋艿后续在 review
// 不加这个 解析 Message 会报 NPE 异常 // @芋艿 这个 Message 可以去掉 暂时用不上
// 不加这个 解析 Message 会报 NPE 异常 .
Message rejectPostProcessMsg = new Message(); Message rejectPostProcessMsg = new Message();
rejectPostProcessMsg.setName(REJECT_POST_PROCESS_MESSAGE_NAME); rejectPostProcessMsg.setName(REJECT_POST_PROCESS_MESSAGE_NAME);
bpmnModel.addMessage(rejectPostProcessMsg); bpmnModel.addMessage(rejectPostProcessMsg);
@ -76,13 +79,9 @@ public class SimpleModelUtils {
// 前端模型数据结构 // 前端模型数据结构
// SimpleModel 构建 FlowNode 并添加到 Main Process // SimpleModel 构建 FlowNode 并添加到 Main Process
buildAndAddBpmnFlowNode(simpleModelNode, process); traverseNodeToBuildFlowNode(simpleModelNode, process);
// 找到 end event // 找到 end event
EndEvent endEvent = (EndEvent) CollUtil.findOne(process.getFlowElements(), item -> item instanceof EndEvent); EndEvent endEvent = (EndEvent) CollUtil.findOne(process.getFlowElements(), item -> item instanceof EndEvent);
if (endEvent == null) {
// TODO 暂时为了兼容 单独构建 end event 节点. 后面去掉
endEvent = buildAndAddBpmnEndEvent(process);
}
// 构建并添加节点之间的连线 Sequence Flow // 构建并添加节点之间的连线 Sequence Flow
buildAndAddBpmnSequenceFlow(process, simpleModelNode, endEvent.getId()); buildAndAddBpmnSequenceFlow(process, simpleModelNode, endEvent.getId());
@ -202,95 +201,100 @@ public class SimpleModelUtils {
return sequenceFlow; return sequenceFlow;
} }
// TODO @jason要不改成 recursionNode 递归节点然后把 build 名字让出来专门用于构建各种 Node // TODO-DONE @jason要不改成 recursionNode 递归节点然后把 build 名字让出来专门用于构建各种 Node
// TODO @jasonsimpleModelNode 改成 nodemainProcess 改成 process更符合递归的感觉哈处理当前节点 // @芋艿 改成了 traverseNodeToBuildFlowNode 连线的叫 traverseNodeToBuildSequenceFlow
private static void buildAndAddBpmnFlowNode(BpmSimpleModelNodeVO simpleModelNode, Process mainProcess) { // TODO-DONE @jasonnode 改成 nodeprocess 改成 process更符合递归的感觉哈处理当前节点
// 节点为 null 退出 private static void traverseNodeToBuildFlowNode(BpmSimpleModelNodeVO node, Process process) {
// TODO @jason是不是写个 isValidNode 方法判断是否为有效节点 // 判断是否有效节点
if (simpleModelNode == null || simpleModelNode.getId() == null) { // TODO-DONE @jason是不是写个 isValidNode 方法判断是否为有效节点
if (!isValidNode(node)) {
return; return;
} }
BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(simpleModelNode.getType()); BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType());
Assert.notNull(nodeType, "模型节点类型不支持"); Assert.notNull(nodeType, "模型节点类型不支持");
// TODO @jason要不抽个 buildNode 方法然后返回一个 List<FlowElement>之后这个方法 addFlowElement原因是让当前这个方法有主干逻辑不然现在太长了
// TODO-DONE @jason要不抽个 buildNode 方法然后返回一个 List<FlowElement>之后这个方法 addFlowElement原因是让当前这个方法有主干逻辑不然现在太长了
List<FlowElement> flowElements = buildFlowNode(node, nodeType);
flowElements.forEach(process::addFlowElement);
// 如果不是网关类型的接口 并且chileNode为空退出
// TODO-DONE @jason建议这个判断去掉可以更简洁一点因为往下走如果不成功本身也就会结束哈主要是这里多了一个这样的判断增加了理解成本
// 如果是分支节点则递归处理条件
if (BpmSimpleModelNodeType.isBranchNode(node.getType())
&& ArrayUtil.isNotEmpty(node.getConditionNodes())) {
// TODO-DONE @jason可以搞成 stream 写成一行哈
node.getConditionNodes().forEach(item -> traverseNodeToBuildFlowNode(item.getChildNode(), process));
}
// 如果有节点则递归处理子节点
// TODO-DONE @jason这个是不是不写判断直接继续调用因为本身 buildAndAddBpmnFlowNode 就会最开始判断了哈就不重复判断了
traverseNodeToBuildFlowNode(node.getChildNode(), process);
}
private static boolean isValidNode(BpmSimpleModelNodeVO node) {
return node != null && node.getId() != null;
}
private static List<FlowElement> buildFlowNode(BpmSimpleModelNodeVO node, BpmSimpleModelNodeType nodeType) {
List<FlowElement> list = new ArrayList<>();
switch (nodeType) { switch (nodeType) {
case START_EVENT: { case START_EVENT: {
// TODO @jason每个 nodeTypebuildXXX 方法要不更明确并且去掉 Bpmn // TODO-DONE @jason每个 nodeTypebuildXXX 方法要不更明确并且去掉 Bpmn
StartEvent startEvent = buildBpmnStartEvent(simpleModelNode); StartEvent startEvent = buildStartEvent(node);
mainProcess.addFlowElement(startEvent); list.add(startEvent);
break; break;
} }
case USER_TASK: { case USER_TASK: {
// TODO @jason这个搞成一个 buildUserTask然后把下面这 2 种节点搞在一起实现类这样 buildNode 里面可以更简洁 // TODO @jason这个搞成一个 buildUserTask然后把下面这 2 种节点搞在一起实现类这样 buildNode 里面可以更简洁
// TODO @jason这里还有个想法是不是可以所有的都叫 buildXXXNode然后里面有一些是 bpmn 相关的构建叫做 buildBpmnUserTask用于区分 // TODO @jason这里还有个想法是不是可以所有的都叫 buildXXXNode然后里面有一些是 bpmn 相关的构建叫做 buildBpmnUserTask用于区分
// 获取用户任务的配置 // 获取用户任务的配置
SimpleModelUserTaskConfig userTaskConfig = BeanUtil.toBean(simpleModelNode.getAttributes(), SimpleModelUserTaskConfig.class); SimpleModelUserTaskConfig userTaskConfig = BeanUtil.toBean(node.getAttributes(), SimpleModelUserTaskConfig.class);
UserTask userTask = buildBpmnUserTask(simpleModelNode, userTaskConfig); UserTask userTask = buildBpmnUserTask(node, userTaskConfig);
mainProcess.addFlowElement(userTask); list.add(userTask);
if (userTaskConfig.getTimeoutHandler() != null && userTaskConfig.getTimeoutHandler().getEnable()) { if (userTaskConfig.getTimeoutHandler() != null && userTaskConfig.getTimeoutHandler().getEnable()) {
// 添加用户任务的 Timer Boundary Event, 用于任务的超时处理 // 添加用户任务的 Timer Boundary Event, 用于任务的超时处理
BoundaryEvent boundaryEvent = buildUserTaskTimerBoundaryEvent(userTask, userTaskConfig.getTimeoutHandler()); BoundaryEvent boundaryEvent = buildUserTaskTimerBoundaryEvent(userTask, userTaskConfig.getTimeoutHandler());
mainProcess.addFlowElement(boundaryEvent); //process.addFlowElement(boundaryEvent);
list.add(boundaryEvent);
} }
break; break;
} }
case COPY_TASK: { case COPY_TASK: {
ServiceTask serviceTask = buildBpmnServiceTask(simpleModelNode); ServiceTask serviceTask = buildServiceTask(node);
mainProcess.addFlowElement(serviceTask); list.add(serviceTask);
break; break;
} }
case EXCLUSIVE_GATEWAY: { case EXCLUSIVE_GATEWAY: {
ExclusiveGateway exclusiveGateway = buildBpmnExclusiveGateway(simpleModelNode); ExclusiveGateway exclusiveGateway = buildExclusiveGateway(node);
mainProcess.addFlowElement(exclusiveGateway); list.add(exclusiveGateway);
break; break;
} }
case PARALLEL_GATEWAY_FORK: case PARALLEL_GATEWAY_FORK:
case PARALLEL_GATEWAY_JOIN: { case PARALLEL_GATEWAY_JOIN: {
ParallelGateway parallelGateway = buildBpmnParallelGateway(simpleModelNode); ParallelGateway parallelGateway = buildParallelGateway(node);
mainProcess.addFlowElement(parallelGateway); list.add(parallelGateway);
break; break;
} }
case INCLUSIVE_GATEWAY_FORK: { case INCLUSIVE_GATEWAY_FORK: {
InclusiveGateway inclusiveGateway = buildBpmnInclusiveGateway(simpleModelNode, Boolean.TRUE); InclusiveGateway inclusiveGateway = buildInclusiveGateway(node, Boolean.TRUE);
mainProcess.addFlowElement(inclusiveGateway); list.add(inclusiveGateway);
break; break;
} }
case INCLUSIVE_GATEWAY_JOIN: { case INCLUSIVE_GATEWAY_JOIN: {
InclusiveGateway inclusiveGateway = buildBpmnInclusiveGateway(simpleModelNode, Boolean.FALSE); InclusiveGateway inclusiveGateway = buildInclusiveGateway(node, Boolean.FALSE);
mainProcess.addFlowElement(inclusiveGateway); list.add(inclusiveGateway);
break; break;
} }
case END_EVENT: { case END_EVENT: {
EndEvent endEvent = buildBpmnEndEvent(simpleModelNode); EndEvent endEvent = buildEndEvent(node);
mainProcess.addFlowElement(endEvent); list.add(endEvent);
break; break;
} }
default: { default: {
// TODO 其它节点类型的实现 // TODO 其它节点类型的实现
} }
} }
return list;
// 如果不是网关类型的接口 并且chileNode为空退出
// TODO @jason建议这个判断去掉可以更简洁一点因为往下走如果不成功本身也就会结束哈主要是这里多了一个这样的判断增加了理解成本
if (!BpmSimpleModelNodeType.isBranchNode(simpleModelNode.getType()) && simpleModelNode.getChildNode() == null) {
return;
}
// 如果是条件节点则递归处理条件
if (BpmSimpleModelNodeType.isBranchNode(simpleModelNode.getType())
&& ArrayUtil.isNotEmpty(simpleModelNode.getConditionNodes())) {
// TODO @jason可以搞成 stream 写成一行哈
for (BpmSimpleModelNodeVO node : simpleModelNode.getConditionNodes()) {
buildAndAddBpmnFlowNode(node.getChildNode(), mainProcess);
}
}
// 如果有节点则递归处理子节点
// chileNode不为空递归添加子节点
// TODO @jason这个是不是不写判断直接继续调用因为本身 buildAndAddBpmnFlowNode 就会最开始判断了哈就不重复判断了
if (simpleModelNode.getChildNode() != null) {
buildAndAddBpmnFlowNode(simpleModelNode.getChildNode(), mainProcess);
}
} }
private static BoundaryEvent buildUserTaskTimerBoundaryEvent(UserTask userTask, SimpleModelUserTaskConfig.TimeoutHandler timeoutHandler) { private static BoundaryEvent buildUserTaskTimerBoundaryEvent(UserTask userTask, SimpleModelUserTaskConfig.TimeoutHandler timeoutHandler) {
@ -315,7 +319,7 @@ public class SimpleModelUtils {
return boundaryEvent; return boundaryEvent;
} }
private static ParallelGateway buildBpmnParallelGateway(BpmSimpleModelNodeVO node) { private static ParallelGateway buildParallelGateway(BpmSimpleModelNodeVO node) {
ParallelGateway parallelGateway = new ParallelGateway(); ParallelGateway parallelGateway = new ParallelGateway();
parallelGateway.setId(node.getId()); parallelGateway.setId(node.getId());
// TODO @jasonsetName // TODO @jasonsetName
@ -324,7 +328,7 @@ public class SimpleModelUtils {
return parallelGateway; return parallelGateway;
} }
private static ServiceTask buildBpmnServiceTask(BpmSimpleModelNodeVO node) { private static ServiceTask buildServiceTask(BpmSimpleModelNodeVO node) {
ServiceTask serviceTask = new ServiceTask(); ServiceTask serviceTask = new ServiceTask();
serviceTask.setId(node.getId()); serviceTask.setId(node.getId());
serviceTask.setName(node.getName()); serviceTask.setName(node.getName());
@ -340,7 +344,8 @@ public class SimpleModelUtils {
// 添加表单字段权限属性元素 // 添加表单字段权限属性元素
// TODO @芋艿这块关注下哈 // TODO @芋艿这块关注下哈
List<Map<String, String>> fieldsPermissions = MapUtil.get(node.getAttributes(), List<Map<String, String>> fieldsPermissions = MapUtil.get(node.getAttributes(),
FORM_FIELD_PERMISSION_ELEMENT, new TypeReference<>() {}); FORM_FIELD_PERMISSION_ELEMENT, new TypeReference<>() {
});
addFormFieldsPermission(fieldsPermissions, serviceTask); addFormFieldsPermission(fieldsPermissions, serviceTask);
return serviceTask; return serviceTask;
} }
@ -354,7 +359,7 @@ public class SimpleModelUtils {
addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, candidateParam); addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, candidateParam);
} }
private static ExclusiveGateway buildBpmnExclusiveGateway(BpmSimpleModelNodeVO node) { private static ExclusiveGateway buildExclusiveGateway(BpmSimpleModelNodeVO node) {
Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空");
ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
exclusiveGateway.setId(node.getId()); exclusiveGateway.setId(node.getId());
@ -367,7 +372,7 @@ public class SimpleModelUtils {
return exclusiveGateway; return exclusiveGateway;
} }
private static InclusiveGateway buildBpmnInclusiveGateway(BpmSimpleModelNodeVO node, Boolean isFork) { private static InclusiveGateway buildInclusiveGateway(BpmSimpleModelNodeVO node, Boolean isFork) {
InclusiveGateway inclusiveGateway = new InclusiveGateway(); InclusiveGateway inclusiveGateway = new InclusiveGateway();
inclusiveGateway.setId(node.getId()); inclusiveGateway.setId(node.getId());
// TODO @jason这里是不是 setName // TODO @jason这里是不是 setName
@ -483,7 +488,7 @@ public class SimpleModelUtils {
// ========== 各种 build 节点的方法 ========== // ========== 各种 build 节点的方法 ==========
private static StartEvent buildBpmnStartEvent(BpmSimpleModelNodeVO node) { private static StartEvent buildStartEvent(BpmSimpleModelNodeVO node) {
StartEvent startEvent = new StartEvent(); StartEvent startEvent = new StartEvent();
startEvent.setId(node.getId()); startEvent.setId(node.getId());
startEvent.setName(node.getName()); startEvent.setName(node.getName());
@ -492,7 +497,7 @@ public class SimpleModelUtils {
return startEvent; return startEvent;
} }
private static EndEvent buildBpmnEndEvent(BpmSimpleModelNodeVO node) { private static EndEvent buildEndEvent(BpmSimpleModelNodeVO node) {
EndEvent endEvent = new EndEvent(); EndEvent endEvent = new EndEvent();
endEvent.setId(node.getId()); endEvent.setId(node.getId());
endEvent.setName(node.getName()); endEvent.setName(node.getName());

View File

@ -231,7 +231,7 @@ public class BpmModelServiceImpl implements BpmModelService {
throw exception(MODEL_NOT_EXISTS); throw exception(MODEL_NOT_EXISTS);
} }
// 1.2 JSON 转换成 bpmnModel // 1.2 JSON 转换成 bpmnModel
BpmnModel bpmnModel = SimpleModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); BpmnModel bpmnModel = SimpleModelUtils.buildBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody());
// 2.1 保存 Bpmn XML // 2.1 保存 Bpmn XML
saveModelBpmnXml(model.getId(), StrUtil.utf8Bytes(BpmnModelUtils.getBpmnXml(bpmnModel))); saveModelBpmnXml(model.getId(), StrUtil.utf8Bytes(BpmnModelUtils.getBpmnXml(bpmnModel)));
// 2.2 保存 JSON 数据 // 2.2 保存 JSON 数据