Commit a008b313ecdf39da1cd539f8fef3fa4ff9f49b61

Authored by 芋道源码
Committed by Gitee
2 parents ae3c63eb da9f6ab7

!1187 Simple设计器优化

Merge pull request !1187 from Lesan/feature/bpm-n
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
@@ -97,20 +97,26 @@ public class BpmSimpleModelNodeVO { @@ -97,20 +97,26 @@ public class BpmSimpleModelNodeVO {
97 */ 97 */
98 private AssignEmptyHandler assignEmptyHandler; 98 private AssignEmptyHandler assignEmptyHandler;
99 99
100 - // TODO @lesan:建议改成 taskCreateListener;  
101 /** 100 /**
102 * 创建任务监听器 101 * 创建任务监听器
103 */ 102 */
104 - private ListenerHandler createTaskListener; 103 + private ListenerHandler taskCreateListener;
  104 + /**
  105 + * 指派任务监听器
  106 + */
  107 + private ListenerHandler taskAssignListener;
  108 + /**
  109 + * 完成任务监听器
  110 + */
  111 + private ListenerHandler taskCompleteListener;
105 112
106 @Schema(description = "任务监听器") 113 @Schema(description = "任务监听器")
107 @Valid 114 @Valid
108 @Data 115 @Data
109 public static class ListenerHandler { 116 public static class ListenerHandler {
110 117
111 - // TODO @lesan:参数校验,需要加下  
112 -  
113 @Schema(description = "是否开启任务监听器", example = "false") 118 @Schema(description = "是否开启任务监听器", example = "false")
  119 + @NotNull(message = "是否开启任务监听器不能为空")
114 private Boolean enable; 120 private Boolean enable;
115 121
116 @Schema(description = "请求路径", example = "http://xxxxx") 122 @Schema(description = "请求路径", example = "http://xxxxx")
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
@@ -6,6 +6,7 @@ import cn.hutool.core.util.ArrayUtil; @@ -6,6 +6,7 @@ import cn.hutool.core.util.ArrayUtil;
6 import cn.hutool.core.util.ObjUtil; 6 import cn.hutool.core.util.ObjUtil;
7 import cn.hutool.core.util.StrUtil; 7 import cn.hutool.core.util.StrUtil;
8 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 8 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  9 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
9 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 10 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
10 import cn.iocoder.yudao.framework.common.util.string.StrUtils; 11 import cn.iocoder.yudao.framework.common.util.string.StrUtils;
11 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; 12 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
@@ -56,6 +57,18 @@ public class BpmnModelUtils { @@ -56,6 +57,18 @@ public class BpmnModelUtils {
56 element.addExtensionElement(extensionElement); 57 element.addExtensionElement(extensionElement);
57 } 58 }
58 59
  60 + public static void addExtensionElementJson(FlowElement element, String name, Object value) {
  61 + if (value == null) {
  62 + return;
  63 + }
  64 + ExtensionElement extensionElement = new ExtensionElement();
  65 + extensionElement.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE);
  66 + extensionElement.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX);
  67 + extensionElement.setElementText(JsonUtils.toJsonString(value));
  68 + extensionElement.setName(name);
  69 + element.addExtensionElement(extensionElement);
  70 + }
  71 +
59 public static void addExtensionElement(FlowElement element, String name, Integer value) { 72 public static void addExtensionElement(FlowElement element, String name, Integer value) {
60 if (value == null) { 73 if (value == null) {
61 return; 74 return;
@@ -93,6 +106,33 @@ public class BpmnModelUtils { @@ -93,6 +106,33 @@ public class BpmnModelUtils {
93 return element != null ? element.getElementText() : null; 106 return element != null ? element.getElementText() : null;
94 } 107 }
95 108
  109 + public static <T> T parseExtensionElementJson(FlowElement flowElement, String elementName, Class<T> clazz) {
  110 + if (flowElement == null) {
  111 + return null;
  112 + }
  113 + ExtensionElement element = CollUtil.getFirst(flowElement.getExtensionElements().get(elementName));
  114 + return element != null ? JsonUtils.parseObject(element.getElementText(), clazz) : null;
  115 + }
  116 +
  117 + /**
  118 + * 给节点添加Simple设计器配置Json
  119 + *
  120 + * @param userTask 节点
  121 + * @param node 节点对象
  122 + */
  123 + public static void addSimpleConfigInfo(FlowElement userTask, Object node) {
  124 + addExtensionElementJson(userTask, "config", node);
  125 + }
  126 +
  127 + /**
  128 + * 解析Simple设计器配置Json
  129 + *
  130 + * @param userTask 节点
  131 + */
  132 + public static BpmSimpleModelNodeVO parseSimpleConfigInfo(FlowElement userTask) {
  133 + return parseExtensionElementJson(userTask, "config", BpmSimpleModelNodeVO.class);
  134 + }
  135 +
96 /** 136 /**
97 * 给节点添加候选人元素 137 * 给节点添加候选人元素
98 * 138 *
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
@@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil; @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.lang.Assert; 4 import cn.hutool.core.lang.Assert;
5 import cn.hutool.core.map.MapUtil; 5 import cn.hutool.core.map.MapUtil;
6 import cn.hutool.core.util.*; 6 import cn.hutool.core.util.*;
7 -import cn.hutool.json.JSONUtil;  
8 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; 8 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
10 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups; 9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups;
@@ -23,7 +22,6 @@ import java.util.*; @@ -23,7 +22,6 @@ import java.util.*;
23 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; 22 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*;
24 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*; 23 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*;
25 import static cn.iocoder.yudao.module.bpm.service.task.listener.BpmUserTaskListener.DELEGATE_EXPRESSION; 24 import static cn.iocoder.yudao.module.bpm.service.task.listener.BpmUserTaskListener.DELEGATE_EXPRESSION;
26 -import static cn.iocoder.yudao.module.bpm.service.task.listener.BpmUserTaskListener.EXTENSION_SUFFIX;  
27 import static java.util.Arrays.asList; 25 import static java.util.Arrays.asList;
28 26
29 /** 27 /**
@@ -440,23 +438,38 @@ public class SimpleModelUtils { @@ -440,23 +438,38 @@ public class SimpleModelUtils {
440 userTask.setDueDate(node.getTimeoutHandler().getTimeDuration()); 438 userTask.setDueDate(node.getTimeoutHandler().getTimeDuration());
441 } 439 }
442 // 设置监听器 440 // 设置监听器
  441 + addUserTaskListener(node, userTask);
  442 + // 设置Simple设计器节点配置
  443 + addSimpleConfigInfo(userTask, node);
  444 + return userTask;
  445 + }
  446 +
  447 + private void addUserTaskListener(BpmSimpleModelNodeVO node, UserTask userTask) {
443 List<FlowableListener> flowableListeners = new ArrayList<>(3); 448 List<FlowableListener> flowableListeners = new ArrayList<>(3);
444 - if (node.getCreateTaskListener().getEnable()) { 449 + if (node.getTaskCreateListener().getEnable()) {
445 FlowableListener flowableListener = new FlowableListener(); 450 FlowableListener flowableListener = new FlowableListener();
446 flowableListener.setEvent(TaskListener.EVENTNAME_CREATE); 451 flowableListener.setEvent(TaskListener.EVENTNAME_CREATE);
447 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); 452 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
448 flowableListener.setImplementation(DELEGATE_EXPRESSION); 453 flowableListener.setImplementation(DELEGATE_EXPRESSION);
449 - // TODO @lesan:可以加个 addExtensionElementJson() 方法;  
450 - // TODO @lesan:是不是不用带 "create" + EXTENSION_SUFFIX 这种,直接给个 "config" 就完事了!  
451 - addExtensionElement(userTask, "create" + EXTENSION_SUFFIX,  
452 - // TODO @lesan:默认使用项目里的 JsonUtils 方法  
453 - JSONUtil.toJsonStr(node.getCreateTaskListener())); 454 + flowableListeners.add(flowableListener);
  455 + }
  456 + if (node.getTaskAssignListener().getEnable()) {
  457 + FlowableListener flowableListener = new FlowableListener();
  458 + flowableListener.setEvent(TaskListener.EVENTNAME_ASSIGNMENT);
  459 + flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
  460 + flowableListener.setImplementation(DELEGATE_EXPRESSION);
  461 + flowableListeners.add(flowableListener);
  462 + }
  463 + if (node.getTaskCompleteListener().getEnable()) {
  464 + FlowableListener flowableListener = new FlowableListener();
  465 + flowableListener.setEvent(TaskListener.EVENTNAME_COMPLETE);
  466 + flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
  467 + flowableListener.setImplementation(DELEGATE_EXPRESSION);
454 flowableListeners.add(flowableListener); 468 flowableListeners.add(flowableListener);
455 } 469 }
456 if (CollUtil.isNotEmpty(flowableListeners)) { 470 if (CollUtil.isNotEmpty(flowableListeners)) {
457 userTask.setTaskListeners(flowableListeners); 471 userTask.setTaskListeners(flowableListeners);
458 } 472 }
459 - return userTask;  
460 } 473 }
461 474
462 private void processMultiInstanceLoopCharacteristics(Integer approveMethod, Integer approveRatio, UserTask userTask) { 475 private void processMultiInstanceLoopCharacteristics(Integer approveMethod, Integer approveRatio, UserTask userTask) {
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmUserTaskListener.java
1 package cn.iocoder.yudao.module.bpm.service.task.listener; 1 package cn.iocoder.yudao.module.bpm.service.task.listener;
2 2
3 -import cn.hutool.http.HttpRequest;  
4 -import cn.hutool.json.JSONUtil; 3 +import cn.hutool.core.collection.CollUtil;
5 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; 4 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
6 import cn.iocoder.yudao.module.bpm.enums.definition.BpmListenerMapType; 5 import cn.iocoder.yudao.module.bpm.enums.definition.BpmListenerMapType;
7 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; 6 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
@@ -14,12 +13,18 @@ import org.flowable.bpmn.model.FlowElement; @@ -14,12 +13,18 @@ import org.flowable.bpmn.model.FlowElement;
14 import org.flowable.engine.delegate.TaskListener; 13 import org.flowable.engine.delegate.TaskListener;
15 import org.flowable.engine.history.HistoricProcessInstance; 14 import org.flowable.engine.history.HistoricProcessInstance;
16 import org.flowable.task.service.delegate.DelegateTask; 15 import org.flowable.task.service.delegate.DelegateTask;
  16 +import org.springframework.http.HttpEntity;
  17 +import org.springframework.http.HttpMethod;
  18 +import org.springframework.http.ResponseEntity;
17 import org.springframework.stereotype.Component; 19 import org.springframework.stereotype.Component;
  20 +import org.springframework.util.LinkedMultiValueMap;
  21 +import org.springframework.util.MultiValueMap;
  22 +import org.springframework.web.client.RestTemplate;
18 23
19 -import java.util.HashMap; 24 +import java.util.List;
20 import java.util.Map; 25 import java.util.Map;
21 26
22 -import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseExtensionElement; 27 +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseSimpleConfigInfo;
23 28
24 /** 29 /**
25 * BPM 用户任务通用监听器 30 * BPM 用户任务通用监听器
@@ -32,52 +37,68 @@ public class BpmUserTaskListener implements TaskListener { @@ -32,52 +37,68 @@ public class BpmUserTaskListener implements TaskListener {
32 37
33 public static final String DELEGATE_EXPRESSION = "${bpmUserTaskListener}"; 38 public static final String DELEGATE_EXPRESSION = "${bpmUserTaskListener}";
34 39
35 - public static final String EXTENSION_SUFFIX = "TaskListenerMetaInfo";  
36 -  
37 @Resource 40 @Resource
38 private BpmModelService modelService; 41 private BpmModelService modelService;
39 42
40 @Resource 43 @Resource
41 private BpmProcessInstanceService processInstanceService; 44 private BpmProcessInstanceService processInstanceService;
42 45
  46 + @Resource
  47 + private RestTemplate restTemplate;
  48 +
43 @Override 49 @Override
44 public void notify(DelegateTask delegateTask) { 50 public void notify(DelegateTask delegateTask) {
45 // 1. 获取所需基础信息 51 // 1. 获取所需基础信息
46 HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(delegateTask.getProcessInstanceId()); 52 HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(delegateTask.getProcessInstanceId());
47 BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(delegateTask.getProcessDefinitionId()); 53 BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(delegateTask.getProcessDefinitionId());
48 - FlowElement userTaskElement = BpmnModelUtils.getFlowElementById(bpmnModel, delegateTask.getTaskDefinitionKey());  
49 - // TODO @lesan:可以写到 FlowableUtils 里,简化解析逻辑!  
50 - BpmSimpleModelNodeVO.ListenerHandler listenerHandler = JSONUtil.toBean(  
51 - parseExtensionElement(userTaskElement, delegateTask.getEventName() + EXTENSION_SUFFIX),  
52 - BpmSimpleModelNodeVO.ListenerHandler.class); 54 + FlowElement userTask = BpmnModelUtils.getFlowElementById(bpmnModel, delegateTask.getTaskDefinitionKey());
  55 + BpmSimpleModelNodeVO node = parseSimpleConfigInfo(userTask);
  56 + BpmSimpleModelNodeVO.ListenerHandler listenerHandler = getListenerHandlerByEvent(delegateTask.getEventName(), node);
53 57
54 // 2. 获取请求头和请求体 58 // 2. 获取请求头和请求体
55 Map<String, Object> processVariables = processInstance.getProcessVariables(); 59 Map<String, Object> processVariables = processInstance.getProcessVariables();
56 - Map<String, String> headers = new HashMap<>();  
57 - Map<String, Object> body = new HashMap<>();  
58 - listenerHandler.getHeader().forEach(item -> {  
59 - // TODO @lesan:可以写个统一的方法,解析参数。然后非空,put 到 headers 或者 body 里!  
60 - if (item.getType().equals(BpmListenerMapType.FIXED_VALUE.getType())) {  
61 - headers.put(item.getKey(), item.getValue());  
62 - } else if (item.getType().equals(BpmListenerMapType.FROM_FORM.getType())) {  
63 - headers.put(item.getKey(), processVariables.getOrDefault(item.getValue(), "").toString());  
64 - }  
65 - });  
66 - // TODO @lesan:header 里面,需要添加下 tenant-id!  
67 - listenerHandler.getBody().forEach(item -> { 60 + MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
  61 + MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
  62 + parseListenerMap(listenerHandler.getHeader(), processVariables, headers);
  63 + parseListenerMap(listenerHandler.getBody(), processVariables, body);
  64 + // 2.1 请求头默认参数
  65 + headers.add("tenant-id", delegateTask.getTenantId());
  66 + // 2.2 请求体默认参数
  67 + body.add("processInstanceId", delegateTask.getProcessInstanceId());
  68 + body.add("assignee", delegateTask.getAssignee());
  69 + body.add("taskDefinitionKey", delegateTask.getTaskDefinitionKey());
  70 + body.add("taskId", delegateTask.getId());
  71 +
  72 + // 3. 异步发起请求
  73 + HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers);
  74 + ResponseEntity<String> responseEntity = restTemplate.exchange(listenerHandler.getPath(), HttpMethod.POST,
  75 + requestEntity, String.class);
  76 + log.info("[BpmUserTaskListener][的响应结果({})]", responseEntity);
  77 + // 4. 是否需要后续操作?TODO 芋艿:待定!
  78 + }
  79 +
  80 + private void parseListenerMap(List<BpmSimpleModelNodeVO.ListenerHandler.ListenerMap> list,
  81 + Map<String, Object> processVariables,
  82 + MultiValueMap<String, String> to) {
  83 + if (CollUtil.isEmpty(list)) {
  84 + return;
  85 + }
  86 + list.forEach(item -> {
68 if (item.getType().equals(BpmListenerMapType.FIXED_VALUE.getType())) { 87 if (item.getType().equals(BpmListenerMapType.FIXED_VALUE.getType())) {
69 - body.put(item.getKey(), item.getValue()); 88 + to.add(item.getKey(), item.getValue());
70 } else if (item.getType().equals(BpmListenerMapType.FROM_FORM.getType())) { 89 } else if (item.getType().equals(BpmListenerMapType.FROM_FORM.getType())) {
71 - body.put(item.getKey(), processVariables.getOrDefault(item.getValue(), "")); 90 + to.add(item.getKey(), processVariables.get(item.getValue()).toString());
72 } 91 }
73 }); 92 });
  93 + }
74 94
75 - // 3. 异步发起请求  
76 - // TODO @lesan:最好打印下日志!  
77 - HttpRequest.post(listenerHandler.getPath())  
78 - .addHeaders(headers).form(body).executeAsync();  
79 -  
80 - // 4. 是否需要后续操作?TODO 芋艿:待定! 95 + private BpmSimpleModelNodeVO.ListenerHandler getListenerHandlerByEvent(String eventName, BpmSimpleModelNodeVO node) {
  96 + return switch (eventName) {
  97 + case TaskListener.EVENTNAME_CREATE -> node.getTaskCreateListener();
  98 + case TaskListener.EVENTNAME_ASSIGNMENT -> node.getTaskAssignListener();
  99 + case TaskListener.EVENTNAME_COMPLETE -> node.getTaskCompleteListener();
  100 + default -> null;
  101 + };
81 } 102 }
82 103
83 } 104 }
84 \ No newline at end of file 105 \ No newline at end of file