Commit 8f31e745dd838189ad4d5a9ff78d32b3ef0dcf85
1 parent
4d176c84
仿钉钉流程设计- code review 修改
Showing
2 changed files
with
70 additions
and
65 deletions
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
| ... | ... | @@ -19,6 +19,7 @@ import org.flowable.bpmn.BpmnAutoLayout; |
| 19 | 19 | import org.flowable.bpmn.model.Process; |
| 20 | 20 | import org.flowable.bpmn.model.*; |
| 21 | 21 | |
| 22 | +import java.util.ArrayList; | |
| 22 | 23 | import java.util.List; |
| 23 | 24 | import java.util.Map; |
| 24 | 25 | import java.util.Objects; |
| ... | ... | @@ -49,8 +50,9 @@ public class SimpleModelUtils { |
| 49 | 50 | */ |
| 50 | 51 | public static final String ANY_OF_APPROVE_COMPLETE_EXPRESSION = "${ nrOfCompletedInstances > 0 }"; |
| 51 | 52 | |
| 52 | - // TODO @jason:建议方法名,改成 buildBpmnModel | |
| 53 | + // TODO-DONE @jason:建议方法名,改成 buildBpmnModel | |
| 53 | 54 | // TODO @yunai:注释需要完善下; |
| 55 | + | |
| 54 | 56 | /** |
| 55 | 57 | * 仿钉钉流程设计模型数据结构(json) 转换成 Bpmn Model (待完善) |
| 56 | 58 | * |
| ... | ... | @@ -59,11 +61,12 @@ public class SimpleModelUtils { |
| 59 | 61 | * @param simpleModelNode 仿钉钉流程设计模型数据结构 |
| 60 | 62 | * @return Bpmn Model |
| 61 | 63 | */ |
| 62 | - public static BpmnModel convertSimpleModelToBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) { | |
| 64 | + public static BpmnModel buildBpmnModel(String processId, String processName, BpmSimpleModelNodeVO simpleModelNode) { | |
| 63 | 65 | BpmnModel bpmnModel = new BpmnModel(); |
| 64 | 66 | bpmnModel.setTargetNamespace(BPMN2_NAMESPACE); // TODO @jason:待定:是不是搞个自定义的 namespace; |
| 65 | 67 | // TODO 芋艿:后续在 review |
| 66 | - // 不加这个 解析 Message 会报 NPE 异常 | |
| 68 | + // @芋艿 这个 Message 可以去掉 暂时用不上 | |
| 69 | + // 不加这个 解析 Message 会报 NPE 异常 . | |
| 67 | 70 | Message rejectPostProcessMsg = new Message(); |
| 68 | 71 | rejectPostProcessMsg.setName(REJECT_POST_PROCESS_MESSAGE_NAME); |
| 69 | 72 | bpmnModel.addMessage(rejectPostProcessMsg); |
| ... | ... | @@ -76,13 +79,9 @@ public class SimpleModelUtils { |
| 76 | 79 | |
| 77 | 80 | // 前端模型数据结构 |
| 78 | 81 | // 从 SimpleModel 构建 FlowNode 并添加到 Main Process |
| 79 | - buildAndAddBpmnFlowNode(simpleModelNode, process); | |
| 82 | + traverseNodeToBuildFlowNode(simpleModelNode, process); | |
| 80 | 83 | // 找到 end event |
| 81 | 84 | EndEvent endEvent = (EndEvent) CollUtil.findOne(process.getFlowElements(), item -> item instanceof EndEvent); |
| 82 | - if (endEvent == null) { | |
| 83 | - // TODO 暂时为了兼容 单独构建 end event 节点. 后面去掉 | |
| 84 | - endEvent = buildAndAddBpmnEndEvent(process); | |
| 85 | - } | |
| 86 | 85 | |
| 87 | 86 | // 构建并添加节点之间的连线 Sequence Flow |
| 88 | 87 | buildAndAddBpmnSequenceFlow(process, simpleModelNode, endEvent.getId()); |
| ... | ... | @@ -202,95 +201,100 @@ public class SimpleModelUtils { |
| 202 | 201 | return sequenceFlow; |
| 203 | 202 | } |
| 204 | 203 | |
| 205 | - // TODO @jason:要不改成 recursionNode 递归节点,然后把 build 名字让出来,专门用于构建各种 Node | |
| 206 | - // TODO @jason:simpleModelNode 改成 node,mainProcess 改成 process;更符合递归的感觉哈,处理当前节点 | |
| 207 | - private static void buildAndAddBpmnFlowNode(BpmSimpleModelNodeVO simpleModelNode, Process mainProcess) { | |
| 208 | - // 节点为 null 退出 | |
| 209 | - // TODO @jason:是不是写个 isValidNode 方法:判断是否为有效节点; | |
| 210 | - if (simpleModelNode == null || simpleModelNode.getId() == null) { | |
| 204 | + // TODO-DONE @jason:要不改成 recursionNode 递归节点,然后把 build 名字让出来,专门用于构建各种 Node | |
| 205 | + // @芋艿 改成了 traverseNodeToBuildFlowNode, 连线的叫 traverseNodeToBuildSequenceFlow | |
| 206 | + // TODO-DONE @jason:node 改成 node,process 改成 process;更符合递归的感觉哈,处理当前节点 | |
| 207 | + private static void traverseNodeToBuildFlowNode(BpmSimpleModelNodeVO node, Process process) { | |
| 208 | + // 判断是否有效节点 | |
| 209 | + // TODO-DONE @jason:是不是写个 isValidNode 方法:判断是否为有效节点; | |
| 210 | + if (!isValidNode(node)) { | |
| 211 | 211 | return; |
| 212 | 212 | } |
| 213 | - BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(simpleModelNode.getType()); | |
| 213 | + BpmSimpleModelNodeType nodeType = BpmSimpleModelNodeType.valueOf(node.getType()); | |
| 214 | 214 | Assert.notNull(nodeType, "模型节点类型不支持"); |
| 215 | - // TODO @jason:要不抽个 buildNode 方法,然后返回一个 List<FlowElement>,之后这个方法 addFlowElement;原因是,让当前这个方法,有主干逻辑;不然现在太长了; | |
| 215 | + | |
| 216 | + // TODO-DONE @jason:要不抽个 buildNode 方法,然后返回一个 List<FlowElement>,之后这个方法 addFlowElement;原因是,让当前这个方法,有主干逻辑;不然现在太长了; | |
| 217 | + List<FlowElement> flowElements = buildFlowNode(node, nodeType); | |
| 218 | + flowElements.forEach(process::addFlowElement); | |
| 219 | + | |
| 220 | + // 如果不是网关类型的接口, 并且chileNode为空退出 | |
| 221 | + // TODO-DONE @jason:建议这个判断去掉,可以更简洁一点;因为往下走;如果不成功,本身也就会结束哈;主要是,这里多了一个这样的判断,增加了理解成本; | |
| 222 | + // 如果是“分支”节点,则递归处理条件 | |
| 223 | + if (BpmSimpleModelNodeType.isBranchNode(node.getType()) | |
| 224 | + && ArrayUtil.isNotEmpty(node.getConditionNodes())) { | |
| 225 | + // TODO-DONE @jason:可以搞成 stream 写成一行哈 | |
| 226 | + node.getConditionNodes().forEach(item -> traverseNodeToBuildFlowNode(item.getChildNode(), process)); | |
| 227 | + } | |
| 228 | + | |
| 229 | + // 如果有“子”节点,则递归处理子节点 | |
| 230 | + // TODO-DONE @jason:这个,是不是不写判断,直接继续调用;因为本身 buildAndAddBpmnFlowNode 就会最开始判断了哈,就不重复判断了; | |
| 231 | + traverseNodeToBuildFlowNode(node.getChildNode(), process); | |
| 232 | + } | |
| 233 | + | |
| 234 | + private static boolean isValidNode(BpmSimpleModelNodeVO node) { | |
| 235 | + return node != null && node.getId() != null; | |
| 236 | + } | |
| 237 | + | |
| 238 | + private static List<FlowElement> buildFlowNode(BpmSimpleModelNodeVO node, BpmSimpleModelNodeType nodeType) { | |
| 239 | + List<FlowElement> list = new ArrayList<>(); | |
| 216 | 240 | switch (nodeType) { |
| 217 | 241 | case START_EVENT: { |
| 218 | - // TODO @jason:每个 nodeType,buildXXX 方法要不更明确,并且去掉 Bpmn; | |
| 219 | - StartEvent startEvent = buildBpmnStartEvent(simpleModelNode); | |
| 220 | - mainProcess.addFlowElement(startEvent); | |
| 242 | + // TODO-DONE @jason:每个 nodeType,buildXXX 方法要不更明确,并且去掉 Bpmn; | |
| 243 | + StartEvent startEvent = buildStartEvent(node); | |
| 244 | + list.add(startEvent); | |
| 221 | 245 | break; |
| 222 | 246 | } |
| 223 | 247 | case USER_TASK: { |
| 224 | 248 | // TODO @jason:这个,搞成一个 buildUserTask,然后把下面这 2 种节点,搞在一起实现类;这样 buildNode 里面可以更简洁; |
| 225 | 249 | // TODO @jason:这里还有个想法,是不是可以所有的都叫 buildXXXNode,然后里面有一些是 bpmn 相关的构建,叫做 buildBpmnUserTask,用于区分; |
| 226 | 250 | // 获取用户任务的配置 |
| 227 | - SimpleModelUserTaskConfig userTaskConfig = BeanUtil.toBean(simpleModelNode.getAttributes(), SimpleModelUserTaskConfig.class); | |
| 228 | - UserTask userTask = buildBpmnUserTask(simpleModelNode, userTaskConfig); | |
| 229 | - mainProcess.addFlowElement(userTask); | |
| 251 | + SimpleModelUserTaskConfig userTaskConfig = BeanUtil.toBean(node.getAttributes(), SimpleModelUserTaskConfig.class); | |
| 252 | + UserTask userTask = buildBpmnUserTask(node, userTaskConfig); | |
| 253 | + list.add(userTask); | |
| 230 | 254 | if (userTaskConfig.getTimeoutHandler() != null && userTaskConfig.getTimeoutHandler().getEnable()) { |
| 231 | 255 | // 添加用户任务的 Timer Boundary Event, 用于任务的超时处理 |
| 232 | 256 | BoundaryEvent boundaryEvent = buildUserTaskTimerBoundaryEvent(userTask, userTaskConfig.getTimeoutHandler()); |
| 233 | - mainProcess.addFlowElement(boundaryEvent); | |
| 257 | + //process.addFlowElement(boundaryEvent); | |
| 258 | + list.add(boundaryEvent); | |
| 234 | 259 | } |
| 235 | 260 | break; |
| 236 | 261 | } |
| 237 | 262 | case COPY_TASK: { |
| 238 | - ServiceTask serviceTask = buildBpmnServiceTask(simpleModelNode); | |
| 239 | - mainProcess.addFlowElement(serviceTask); | |
| 263 | + ServiceTask serviceTask = buildServiceTask(node); | |
| 264 | + list.add(serviceTask); | |
| 240 | 265 | break; |
| 241 | 266 | } |
| 242 | 267 | case EXCLUSIVE_GATEWAY: { |
| 243 | - ExclusiveGateway exclusiveGateway = buildBpmnExclusiveGateway(simpleModelNode); | |
| 244 | - mainProcess.addFlowElement(exclusiveGateway); | |
| 268 | + ExclusiveGateway exclusiveGateway = buildExclusiveGateway(node); | |
| 269 | + list.add(exclusiveGateway); | |
| 245 | 270 | break; |
| 246 | 271 | } |
| 247 | 272 | case PARALLEL_GATEWAY_FORK: |
| 248 | 273 | case PARALLEL_GATEWAY_JOIN: { |
| 249 | - ParallelGateway parallelGateway = buildBpmnParallelGateway(simpleModelNode); | |
| 250 | - mainProcess.addFlowElement(parallelGateway); | |
| 274 | + ParallelGateway parallelGateway = buildParallelGateway(node); | |
| 275 | + list.add(parallelGateway); | |
| 251 | 276 | break; |
| 252 | 277 | } |
| 253 | 278 | case INCLUSIVE_GATEWAY_FORK: { |
| 254 | - InclusiveGateway inclusiveGateway = buildBpmnInclusiveGateway(simpleModelNode, Boolean.TRUE); | |
| 255 | - mainProcess.addFlowElement(inclusiveGateway); | |
| 279 | + InclusiveGateway inclusiveGateway = buildInclusiveGateway(node, Boolean.TRUE); | |
| 280 | + list.add(inclusiveGateway); | |
| 256 | 281 | break; |
| 257 | 282 | } |
| 258 | 283 | case INCLUSIVE_GATEWAY_JOIN: { |
| 259 | - InclusiveGateway inclusiveGateway = buildBpmnInclusiveGateway(simpleModelNode, Boolean.FALSE); | |
| 260 | - mainProcess.addFlowElement(inclusiveGateway); | |
| 284 | + InclusiveGateway inclusiveGateway = buildInclusiveGateway(node, Boolean.FALSE); | |
| 285 | + list.add(inclusiveGateway); | |
| 261 | 286 | break; |
| 262 | 287 | } |
| 263 | 288 | case END_EVENT: { |
| 264 | - EndEvent endEvent = buildBpmnEndEvent(simpleModelNode); | |
| 265 | - mainProcess.addFlowElement(endEvent); | |
| 289 | + EndEvent endEvent = buildEndEvent(node); | |
| 290 | + list.add(endEvent); | |
| 266 | 291 | break; |
| 267 | 292 | } |
| 268 | 293 | default: { |
| 269 | 294 | // TODO 其它节点类型的实现 |
| 270 | 295 | } |
| 271 | 296 | } |
| 272 | - | |
| 273 | - // 如果不是网关类型的接口, 并且chileNode为空退出 | |
| 274 | - // TODO @jason:建议这个判断去掉,可以更简洁一点;因为往下走;如果不成功,本身也就会结束哈;主要是,这里多了一个这样的判断,增加了理解成本; | |
| 275 | - if (!BpmSimpleModelNodeType.isBranchNode(simpleModelNode.getType()) && simpleModelNode.getChildNode() == null) { | |
| 276 | - return; | |
| 277 | - } | |
| 278 | - | |
| 279 | - // 如果是“条件”节点,则递归处理条件 | |
| 280 | - if (BpmSimpleModelNodeType.isBranchNode(simpleModelNode.getType()) | |
| 281 | - && ArrayUtil.isNotEmpty(simpleModelNode.getConditionNodes())) { | |
| 282 | - // TODO @jason:可以搞成 stream 写成一行哈; | |
| 283 | - for (BpmSimpleModelNodeVO node : simpleModelNode.getConditionNodes()) { | |
| 284 | - buildAndAddBpmnFlowNode(node.getChildNode(), mainProcess); | |
| 285 | - } | |
| 286 | - } | |
| 287 | - | |
| 288 | - // 如果有“子”节点,则递归处理子节点 | |
| 289 | - // chileNode不为空,递归添加子节点 | |
| 290 | - // TODO @jason:这个,是不是不写判断,直接继续调用;因为本身 buildAndAddBpmnFlowNode 就会最开始判断了哈,就不重复判断了; | |
| 291 | - if (simpleModelNode.getChildNode() != null) { | |
| 292 | - buildAndAddBpmnFlowNode(simpleModelNode.getChildNode(), mainProcess); | |
| 293 | - } | |
| 297 | + return list; | |
| 294 | 298 | } |
| 295 | 299 | |
| 296 | 300 | private static BoundaryEvent buildUserTaskTimerBoundaryEvent(UserTask userTask, SimpleModelUserTaskConfig.TimeoutHandler timeoutHandler) { |
| ... | ... | @@ -315,7 +319,7 @@ public class SimpleModelUtils { |
| 315 | 319 | return boundaryEvent; |
| 316 | 320 | } |
| 317 | 321 | |
| 318 | - private static ParallelGateway buildBpmnParallelGateway(BpmSimpleModelNodeVO node) { | |
| 322 | + private static ParallelGateway buildParallelGateway(BpmSimpleModelNodeVO node) { | |
| 319 | 323 | ParallelGateway parallelGateway = new ParallelGateway(); |
| 320 | 324 | parallelGateway.setId(node.getId()); |
| 321 | 325 | // TODO @jason:setName |
| ... | ... | @@ -324,7 +328,7 @@ public class SimpleModelUtils { |
| 324 | 328 | return parallelGateway; |
| 325 | 329 | } |
| 326 | 330 | |
| 327 | - private static ServiceTask buildBpmnServiceTask(BpmSimpleModelNodeVO node) { | |
| 331 | + private static ServiceTask buildServiceTask(BpmSimpleModelNodeVO node) { | |
| 328 | 332 | ServiceTask serviceTask = new ServiceTask(); |
| 329 | 333 | serviceTask.setId(node.getId()); |
| 330 | 334 | serviceTask.setName(node.getName()); |
| ... | ... | @@ -340,7 +344,8 @@ public class SimpleModelUtils { |
| 340 | 344 | // 添加表单字段权限属性元素 |
| 341 | 345 | // TODO @芋艿:这块关注下哈; |
| 342 | 346 | List<Map<String, String>> fieldsPermissions = MapUtil.get(node.getAttributes(), |
| 343 | - FORM_FIELD_PERMISSION_ELEMENT, new TypeReference<>() {}); | |
| 347 | + FORM_FIELD_PERMISSION_ELEMENT, new TypeReference<>() { | |
| 348 | + }); | |
| 344 | 349 | addFormFieldsPermission(fieldsPermissions, serviceTask); |
| 345 | 350 | return serviceTask; |
| 346 | 351 | } |
| ... | ... | @@ -354,7 +359,7 @@ public class SimpleModelUtils { |
| 354 | 359 | addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, candidateParam); |
| 355 | 360 | } |
| 356 | 361 | |
| 357 | - private static ExclusiveGateway buildBpmnExclusiveGateway(BpmSimpleModelNodeVO node) { | |
| 362 | + private static ExclusiveGateway buildExclusiveGateway(BpmSimpleModelNodeVO node) { | |
| 358 | 363 | Assert.notEmpty(node.getConditionNodes(), "网关节点的条件节点不能为空"); |
| 359 | 364 | ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); |
| 360 | 365 | exclusiveGateway.setId(node.getId()); |
| ... | ... | @@ -367,7 +372,7 @@ public class SimpleModelUtils { |
| 367 | 372 | return exclusiveGateway; |
| 368 | 373 | } |
| 369 | 374 | |
| 370 | - private static InclusiveGateway buildBpmnInclusiveGateway(BpmSimpleModelNodeVO node, Boolean isFork) { | |
| 375 | + private static InclusiveGateway buildInclusiveGateway(BpmSimpleModelNodeVO node, Boolean isFork) { | |
| 371 | 376 | InclusiveGateway inclusiveGateway = new InclusiveGateway(); |
| 372 | 377 | inclusiveGateway.setId(node.getId()); |
| 373 | 378 | // TODO @jason:这里是不是 setName 哈; |
| ... | ... | @@ -483,7 +488,7 @@ public class SimpleModelUtils { |
| 483 | 488 | |
| 484 | 489 | // ========== 各种 build 节点的方法 ========== |
| 485 | 490 | |
| 486 | - private static StartEvent buildBpmnStartEvent(BpmSimpleModelNodeVO node) { | |
| 491 | + private static StartEvent buildStartEvent(BpmSimpleModelNodeVO node) { | |
| 487 | 492 | StartEvent startEvent = new StartEvent(); |
| 488 | 493 | startEvent.setId(node.getId()); |
| 489 | 494 | startEvent.setName(node.getName()); |
| ... | ... | @@ -492,7 +497,7 @@ public class SimpleModelUtils { |
| 492 | 497 | return startEvent; |
| 493 | 498 | } |
| 494 | 499 | |
| 495 | - private static EndEvent buildBpmnEndEvent(BpmSimpleModelNodeVO node) { | |
| 500 | + private static EndEvent buildEndEvent(BpmSimpleModelNodeVO node) { | |
| 496 | 501 | EndEvent endEvent = new EndEvent(); |
| 497 | 502 | endEvent.setId(node.getId()); |
| 498 | 503 | endEvent.setName(node.getName()); | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java
| ... | ... | @@ -231,7 +231,7 @@ public class BpmModelServiceImpl implements BpmModelService { |
| 231 | 231 | throw exception(MODEL_NOT_EXISTS); |
| 232 | 232 | } |
| 233 | 233 | // 1.2 JSON 转换成 bpmnModel |
| 234 | - BpmnModel bpmnModel = SimpleModelUtils.convertSimpleModelToBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); | |
| 234 | + BpmnModel bpmnModel = SimpleModelUtils.buildBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModelBody()); | |
| 235 | 235 | // 2.1 保存 Bpmn XML |
| 236 | 236 | saveModelBpmnXml(model.getId(), StrUtil.utf8Bytes(BpmnModelUtils.getBpmnXml(bpmnModel))); |
| 237 | 237 | // 2.2 保存 JSON 数据 | ... | ... |