Эх сурвалжийг харах

!1187 Simple设计器优化
Merge pull request !1187 from Lesan/feature/bpm-n

芋道源码 7 сар өмнө
parent
commit
a008b313ec

+ 10 - 4
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 {
      */
     private AssignEmptyHandler assignEmptyHandler;
 
-    // TODO @lesan:建议改成 taskCreateListener;
     /**
      * 创建任务监听器
      */
-    private ListenerHandler createTaskListener;
+    private ListenerHandler taskCreateListener;
+    /**
+     * 指派任务监听器
+     */
+    private ListenerHandler taskAssignListener;
+    /**
+     * 完成任务监听器
+     */
+    private ListenerHandler taskCompleteListener;
 
     @Schema(description = "任务监听器")
     @Valid
     @Data
     public static class ListenerHandler {
 
-        // TODO @lesan:参数校验,需要加下
-
         @Schema(description = "是否开启任务监听器", example = "false")
+        @NotNull(message = "是否开启任务监听器不能为空")
         private Boolean enable;
 
         @Schema(description = "请求路径", example = "http://xxxxx")

+ 40 - 0
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;
 import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
 import cn.iocoder.yudao.framework.common.util.string.StrUtils;
 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
@@ -56,6 +57,18 @@ public class BpmnModelUtils {
         element.addExtensionElement(extensionElement);
     }
 
+    public static void addExtensionElementJson(FlowElement element, String name, Object value) {
+        if (value == null) {
+            return;
+        }
+        ExtensionElement extensionElement = new ExtensionElement();
+        extensionElement.setNamespace(FLOWABLE_EXTENSIONS_NAMESPACE);
+        extensionElement.setNamespacePrefix(FLOWABLE_EXTENSIONS_PREFIX);
+        extensionElement.setElementText(JsonUtils.toJsonString(value));
+        extensionElement.setName(name);
+        element.addExtensionElement(extensionElement);
+    }
+
     public static void addExtensionElement(FlowElement element, String name, Integer value) {
         if (value == null) {
             return;
@@ -93,6 +106,33 @@ public class BpmnModelUtils {
         return element != null ? element.getElementText() : null;
     }
 
+    public static <T> T parseExtensionElementJson(FlowElement flowElement, String elementName, Class<T> clazz) {
+        if (flowElement == null) {
+            return null;
+        }
+        ExtensionElement element = CollUtil.getFirst(flowElement.getExtensionElements().get(elementName));
+        return element != null ? JsonUtils.parseObject(element.getElementText(), clazz) : null;
+    }
+
+    /**
+     * 给节点添加Simple设计器配置Json
+     *
+     * @param userTask 节点
+     * @param node 节点对象
+     */
+    public static void addSimpleConfigInfo(FlowElement userTask, Object node) {
+        addExtensionElementJson(userTask, "config", node);
+    }
+
+    /**
+     * 解析Simple设计器配置Json
+     *
+     * @param userTask 节点
+     */
+    public static BpmSimpleModelNodeVO parseSimpleConfigInfo(FlowElement userTask) {
+        return parseExtensionElementJson(userTask, "config", BpmSimpleModelNodeVO.class);
+    }
+
     /**
      * 给节点添加候选人元素
      *

+ 22 - 9
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;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.*;
-import cn.hutool.json.JSONUtil;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups;
@@ -23,7 +22,6 @@ import java.util.*;
 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*;
 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*;
 import static cn.iocoder.yudao.module.bpm.service.task.listener.BpmUserTaskListener.DELEGATE_EXPRESSION;
-import static cn.iocoder.yudao.module.bpm.service.task.listener.BpmUserTaskListener.EXTENSION_SUFFIX;
 import static java.util.Arrays.asList;
 
 /**
@@ -440,23 +438,38 @@ public class SimpleModelUtils {
                 userTask.setDueDate(node.getTimeoutHandler().getTimeDuration());
             }
             // 设置监听器
+            addUserTaskListener(node, userTask);
+            // 设置Simple设计器节点配置
+            addSimpleConfigInfo(userTask, node);
+            return userTask;
+        }
+
+        private void addUserTaskListener(BpmSimpleModelNodeVO node, UserTask userTask) {
             List<FlowableListener> flowableListeners = new ArrayList<>(3);
-            if (node.getCreateTaskListener().getEnable()) {
+            if (node.getTaskCreateListener().getEnable()) {
                 FlowableListener flowableListener = new FlowableListener();
                 flowableListener.setEvent(TaskListener.EVENTNAME_CREATE);
                 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
                 flowableListener.setImplementation(DELEGATE_EXPRESSION);
-                // TODO @lesan:可以加个 addExtensionElementJson() 方法;
-                // TODO @lesan:是不是不用带 "create" + EXTENSION_SUFFIX 这种,直接给个 "config" 就完事了!
-                addExtensionElement(userTask, "create" + EXTENSION_SUFFIX,
-                        // TODO @lesan:默认使用项目里的 JsonUtils 方法
-                        JSONUtil.toJsonStr(node.getCreateTaskListener()));
+                flowableListeners.add(flowableListener);
+            }
+            if (node.getTaskAssignListener().getEnable()) {
+                FlowableListener flowableListener = new FlowableListener();
+                flowableListener.setEvent(TaskListener.EVENTNAME_ASSIGNMENT);
+                flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
+                flowableListener.setImplementation(DELEGATE_EXPRESSION);
+                flowableListeners.add(flowableListener);
+            }
+            if (node.getTaskCompleteListener().getEnable()) {
+                FlowableListener flowableListener = new FlowableListener();
+                flowableListener.setEvent(TaskListener.EVENTNAME_COMPLETE);
+                flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
+                flowableListener.setImplementation(DELEGATE_EXPRESSION);
                 flowableListeners.add(flowableListener);
             }
             if (CollUtil.isNotEmpty(flowableListeners)) {
                 userTask.setTaskListeners(flowableListeners);
             }
-            return userTask;
         }
 
         private void processMultiInstanceLoopCharacteristics(Integer approveMethod, Integer approveRatio, UserTask userTask) {

+ 52 - 31
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmUserTaskListener.java

@@ -1,7 +1,6 @@
 package cn.iocoder.yudao.module.bpm.service.task.listener;
 
-import cn.hutool.http.HttpRequest;
-import cn.hutool.json.JSONUtil;
+import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
 import cn.iocoder.yudao.module.bpm.enums.definition.BpmListenerMapType;
 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
@@ -14,12 +13,18 @@ import org.flowable.bpmn.model.FlowElement;
 import org.flowable.engine.delegate.TaskListener;
 import org.flowable.engine.history.HistoricProcessInstance;
 import org.flowable.task.service.delegate.DelegateTask;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Component;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
 
-import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
-import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseExtensionElement;
+import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseSimpleConfigInfo;
 
 /**
  * BPM 用户任务通用监听器
@@ -32,52 +37,68 @@ public class BpmUserTaskListener implements TaskListener {
 
     public static final String DELEGATE_EXPRESSION = "${bpmUserTaskListener}";
 
-    public static final String EXTENSION_SUFFIX = "TaskListenerMetaInfo";
-
     @Resource
     private BpmModelService modelService;
 
     @Resource
     private BpmProcessInstanceService processInstanceService;
 
+    @Resource
+    private RestTemplate restTemplate;
+
     @Override
     public void notify(DelegateTask delegateTask) {
         // 1. 获取所需基础信息
         HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(delegateTask.getProcessInstanceId());
         BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(delegateTask.getProcessDefinitionId());
-        FlowElement userTaskElement = BpmnModelUtils.getFlowElementById(bpmnModel, delegateTask.getTaskDefinitionKey());
-        // TODO @lesan:可以写到 FlowableUtils 里,简化解析逻辑!
-        BpmSimpleModelNodeVO.ListenerHandler listenerHandler = JSONUtil.toBean(
-                parseExtensionElement(userTaskElement, delegateTask.getEventName() + EXTENSION_SUFFIX),
-                BpmSimpleModelNodeVO.ListenerHandler.class);
+        FlowElement userTask = BpmnModelUtils.getFlowElementById(bpmnModel, delegateTask.getTaskDefinitionKey());
+        BpmSimpleModelNodeVO node = parseSimpleConfigInfo(userTask);
+        BpmSimpleModelNodeVO.ListenerHandler listenerHandler = getListenerHandlerByEvent(delegateTask.getEventName(), node);
 
         // 2. 获取请求头和请求体
         Map<String, Object> processVariables = processInstance.getProcessVariables();
-        Map<String, String> headers = new HashMap<>();
-        Map<String, Object> body = new HashMap<>();
-        listenerHandler.getHeader().forEach(item -> {
-            // TODO @lesan:可以写个统一的方法,解析参数。然后非空,put 到 headers 或者 body 里!
-            if (item.getType().equals(BpmListenerMapType.FIXED_VALUE.getType())) {
-                headers.put(item.getKey(), item.getValue());
-            } else if (item.getType().equals(BpmListenerMapType.FROM_FORM.getType())) {
-                headers.put(item.getKey(), processVariables.getOrDefault(item.getValue(), "").toString());
-            }
-        });
-        // TODO @lesan:header 里面,需要添加下 tenant-id!
-        listenerHandler.getBody().forEach(item -> {
+        MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
+        MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
+        parseListenerMap(listenerHandler.getHeader(), processVariables, headers);
+        parseListenerMap(listenerHandler.getBody(), processVariables, body);
+        // 2.1 请求头默认参数
+        headers.add("tenant-id", delegateTask.getTenantId());
+        // 2.2 请求体默认参数
+        body.add("processInstanceId", delegateTask.getProcessInstanceId());
+        body.add("assignee", delegateTask.getAssignee());
+        body.add("taskDefinitionKey", delegateTask.getTaskDefinitionKey());
+        body.add("taskId", delegateTask.getId());
+
+        // 3. 异步发起请求
+        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers);
+        ResponseEntity<String> responseEntity = restTemplate.exchange(listenerHandler.getPath(), HttpMethod.POST,
+                requestEntity, String.class);
+        log.info("[BpmUserTaskListener][的响应结果({})]", responseEntity);
+        // 4. 是否需要后续操作?TODO 芋艿:待定!
+    }
+
+    private void parseListenerMap(List<BpmSimpleModelNodeVO.ListenerHandler.ListenerMap> list,
+                                  Map<String, Object> processVariables,
+                                  MultiValueMap<String, String> to) {
+        if (CollUtil.isEmpty(list)) {
+            return;
+        }
+        list.forEach(item -> {
             if (item.getType().equals(BpmListenerMapType.FIXED_VALUE.getType())) {
-                body.put(item.getKey(), item.getValue());
+                to.add(item.getKey(), item.getValue());
             } else if (item.getType().equals(BpmListenerMapType.FROM_FORM.getType())) {
-                body.put(item.getKey(), processVariables.getOrDefault(item.getValue(), ""));
+                to.add(item.getKey(), processVariables.get(item.getValue()).toString());
             }
         });
+    }
 
-        // 3. 异步发起请求
-        // TODO @lesan:最好打印下日志!
-        HttpRequest.post(listenerHandler.getPath())
-                .addHeaders(headers).form(body).executeAsync();
-
-        // 4. 是否需要后续操作?TODO 芋艿:待定!
+    private BpmSimpleModelNodeVO.ListenerHandler getListenerHandlerByEvent(String eventName, BpmSimpleModelNodeVO node) {
+        return switch (eventName) {
+            case TaskListener.EVENTNAME_CREATE -> node.getTaskCreateListener();
+            case TaskListener.EVENTNAME_ASSIGNMENT -> node.getTaskAssignListener();
+            case TaskListener.EVENTNAME_COMPLETE -> node.getTaskCompleteListener();
+            default -> null;
+        };
     }
 
 }