Просмотр исходного кода

!1190 Simple设计器完善及优化
Merge pull request !1190 from Lesan/feature/bpm-n

芋道源码 7 месяцев назад
Родитель
Сommit
56f3177a81
12 измененных файлов с 95 добавлено и 83 удалено
  1. 1 0
      yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java
  2. 2 2
      yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java
  3. 3 5
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
  4. 3 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java
  5. 3 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java
  6. 2 1
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
  7. 2 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnVariableConstants.java
  8. 17 6
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
  9. 4 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java
  10. 16 26
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
  11. 10 1
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
  12. 32 42
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmUserTaskListener.java

+ 1 - 0
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java

@@ -54,6 +54,7 @@ public interface ErrorCodeConstants {
     ErrorCode TASK_TRANSFER_FAIL_USER_REPEAT = new ErrorCode(1_009_005_013, "任务转办失败,转办人和当前审批人为同一人");
     ErrorCode TASK_TRANSFER_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_014, "任务转办失败,转办人不存在");
     ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!");
+    ErrorCode TASK_SIGNATURE_NOT_EXISTS = new ErrorCode(1_009_005_015, "签名不能为空!");
 
     // ========== 动态表单模块 1-009-010-000 ==========
     ErrorCode FORM_NOT_EXISTS = new ErrorCode(1_009_010_000, "动态表单不存在");

+ 2 - 2
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java

@@ -33,7 +33,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable {
     CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"),
     PARALLEL_BRANCH_NODE(52, "并行分支", "parallelGateway"),
     INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"),
-    ROUTE_BRANCH_NODE(54, "路由分支", "exclusiveGateway")
+    ROUTER_BRANCH_NODE(54, "路由分支", "exclusiveGateway")
     ;
 
     public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray();
@@ -51,7 +51,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable {
         return Objects.equals(CONDITION_BRANCH_NODE.getType(), type)
                 || Objects.equals(PARALLEL_BRANCH_NODE.getType(), type)
                 || Objects.equals(INCLUSIVE_BRANCH_NODE.getType(), type)
-                || Objects.equals(ROUTE_BRANCH_NODE.getType(), type);
+                || Objects.equals(ROUTER_BRANCH_NODE.getType(), type);
     }
 
     public static BpmSimpleModelNodeType valueOf(Integer type) {

+ 3 - 5
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java

@@ -117,11 +117,10 @@ public class BpmSimpleModelNodeVO {
     private ConditionGroups conditionGroups; // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE
 
     @Schema(description = "路由分支组", example = "[]")
-    private List<RouteCondition> routerGroups;
+    private List<RouterCondition> routerGroups;
 
-    // TODO @lesan:这个目前前端是随机生成的。可以后端来随机么?
     @Schema(description = "默认分支 ID", example = "Flow_xxx")
-    private String defaultFlowId; // 仅用于路由分支节点 BpmSimpleModelNodeType.ROUTE_BRANCH_NODE
+    private String defaultFlowId; // 仅用于路由分支节点 BpmSimpleModelNodeType.ROUTER_BRANCH_NODE
 
     @Schema(description = "任务监听器")
     @Valid
@@ -290,11 +289,10 @@ public class BpmSimpleModelNodeVO {
 
     }
 
-    // TODO @lesan:还有相关的也要改下哈。route 到 router
     @Schema(description = "路由分支")
     @Data
     @Valid
-    public static class RouteCondition {
+    public static class RouterCondition {
 
         @Schema(description = "节点 Id", example = "Activity_xxx") // 跳转到该节点
         @NotEmpty(message = "节点 Id 不能为空")

+ 3 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java

@@ -101,6 +101,9 @@ public class BpmApprovalDetailRespVO {
         @Schema(description = "审批意见", example = "同意")
         private String reason;
 
+        @Schema(description = "签名", example = "http://xxx")
+        private String sign;
+
     }
 
 }

+ 3 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java

@@ -18,6 +18,9 @@ public class BpmTaskApproveReqVO {
     @NotEmpty(message = "审批意见不能为空")
     private String reason;
 
+    @Schema(description = "签名", example = "http://xxx")
+    private String sign;
+
     @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED)
     private Map<String, Object> variables;
 

+ 2 - 1
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java

@@ -186,7 +186,8 @@ public interface BpmProcessInstanceConvert {
             return null;
         }
         return BeanUtils.toBean(task, BpmApprovalDetailRespVO.ActivityNodeTask.class)
-                .setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task));
+                .setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task))
+                .setSign(FlowableUtils.getTaskSign(task));
     }
 
     default Set<Long> parseUserIds(HistoricProcessInstance processInstance,

+ 2 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnVariableConstants.java

@@ -59,4 +59,6 @@ public class BpmnVariableConstants {
      */
     public static final String TASK_VARIABLE_REASON = "TASK_REASON";
 
+    public static final String TASK_VARIABLE_SIGN = "TASK_SIGN";
+
 }

+ 17 - 6
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java

@@ -2,9 +2,11 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.util;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.Assert;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.*;
 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;
@@ -21,6 +23,7 @@ import org.flowable.bpmn.model.Process;
 import org.flowable.bpmn.model.*;
 import org.flowable.common.engine.api.FlowableException;
 import org.flowable.common.engine.impl.util.io.BytesStreamSource;
+import org.flowable.engine.impl.el.FixedValue;
 
 import java.util.*;
 
@@ -346,12 +349,7 @@ public class BpmnModelUtils {
     }
 
     public static void addSignEnable(Boolean signEnable, FlowElement userTask) {
-        // TODO @lesan:是不是改成表达式会好点  addExtensionElement(userTask, SIGN_ENABLE, ObjUtil.isNotNull(signEnable) ? )
-        if (ObjUtil.isNotNull(signEnable)) {
-            addExtensionElement(userTask, SIGN_ENABLE, signEnable.toString());
-        } else {
-            addExtensionElement(userTask, SIGN_ENABLE, "false");
-        }
+        addExtensionElement(userTask, SIGN_ENABLE, ObjUtil.isNotNull(signEnable) ? signEnable.toString() : "false");
     }
 
     public static Boolean parseSignEnable(BpmnModel bpmnModel, String flowElementId) {
@@ -366,6 +364,19 @@ public class BpmnModelUtils {
         return Convert.toBool(extensionElements.get(0).getElementText(), false);
     }
 
+    public static void addListenerConfig(FlowableListener flowableListener, BpmSimpleModelNodeVO.ListenerHandler handler) {
+        FieldExtension fieldExtension = new FieldExtension();
+        fieldExtension.setFieldName("listenerConfig");
+        fieldExtension.setStringValue(JsonUtils.toJsonString(handler));
+        flowableListener.getFieldExtensions().add(fieldExtension);
+    }
+
+    public static BpmSimpleModelNodeVO.ListenerHandler parseListenerConfig(FixedValue fixedValue) {
+        String expressionText = fixedValue.getExpressionText();
+        Assert.notNull(expressionText, "监听器扩展字段({})不能为空", expressionText);
+        return JsonUtils.parseObject(expressionText, BpmSimpleModelNodeVO.ListenerHandler.class);
+    }
+
     // ========== BPM 简单查找相关的方法 ==========
 
     /**

+ 4 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java

@@ -213,6 +213,10 @@ public class FlowableUtils {
         return (String) task.getTaskLocalVariables().get(BpmnVariableConstants.TASK_VARIABLE_REASON);
     }
 
+    public static String getTaskSign(TaskInfo task) {
+        return (String) task.getTaskLocalVariables().get(BpmnVariableConstants.TASK_VARIABLE_SIGN);
+    }
+
     /**
      * 获得任务的表单
      *

+ 16 - 26
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java

@@ -5,7 +5,6 @@ import cn.hutool.core.lang.Assert;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.*;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
-import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 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;
 import cn.iocoder.yudao.module.bpm.enums.definition.*;
@@ -188,7 +187,7 @@ public class SimpleModelUtils {
         // 分支终点节点 ID
         String branchEndNodeId = null;
         if (nodeType == BpmSimpleModelNodeType.CONDITION_BRANCH_NODE
-                || nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { // 条件分支或路由分支
+                || nodeType == BpmSimpleModelNodeType.ROUTER_BRANCH_NODE) { // 条件分支或路由分支
             // 分两种情况 1. 分支节点有孩子节点为孩子节点 Id 2. 分支节点孩子为无效节点时 (分支嵌套且为分支最后一个节点) 为分支终点节点 ID
             branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId;
         } else if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE
@@ -199,10 +198,10 @@ public class SimpleModelUtils {
         Assert.notEmpty(branchEndNodeId, "分支终点节点 Id 不能为空");
 
         // 3. 遍历分支节点
-        if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) {
+        if (nodeType == BpmSimpleModelNodeType.ROUTER_BRANCH_NODE) {
             // 路由分支遍历
-            for (BpmSimpleModelNodeVO.RouteCondition route : node.getRouterGroups()) {
-                SequenceFlow sequenceFlow = RouteBranchNodeConvert.buildSequenceFlow(node.getId(), route);
+            for (BpmSimpleModelNodeVO.RouterCondition router : node.getRouterGroups()) {
+                SequenceFlow sequenceFlow = RouteBranchNodeConvert.buildSequenceFlow(node.getId(), router);
                 process.addFlowElement(sequenceFlow);
             }
         } else {
@@ -233,7 +232,7 @@ public class SimpleModelUtils {
             SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId);
             process.addFlowElement(sequenceFlow);
         // 4.2 如果是路由分支,需要连接后续节点为默认路由
-        } else if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) {
+        } else if (nodeType == BpmSimpleModelNodeType.ROUTER_BRANCH_NODE) {
             SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), branchEndNodeId, node.getDefaultFlowId(),
                     null, null);
             process.addFlowElement(sequenceFlow);
@@ -453,10 +452,7 @@ public class SimpleModelUtils {
                 flowableListener.setEvent(TaskListener.EVENTNAME_CREATE);
                 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
                 flowableListener.setImplementation(DELEGATE_EXPRESSION);
-                FieldExtension fieldExtension = new FieldExtension();
-                fieldExtension.setFieldName("listenerConfig");
-                fieldExtension.setStringValue(JsonUtils.toJsonString(node.getTaskCreateListener()));
-                flowableListener.getFieldExtensions().add(fieldExtension);
+                addListenerConfig(flowableListener, node.getTaskCreateListener());
                 flowableListeners.add(flowableListener);
             }
             if (node.getTaskAssignListener() != null
@@ -465,11 +461,7 @@ public class SimpleModelUtils {
                 flowableListener.setEvent(TaskListener.EVENTNAME_ASSIGNMENT);
                 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
                 flowableListener.setImplementation(DELEGATE_EXPRESSION);
-                // TODO @lesan:可以在 BpmnModelUtils 搞个方法,类似 public static Integer parseCandidateStrategy。这样,就收敛啦!
-                FieldExtension fieldExtension = new FieldExtension();
-                fieldExtension.setFieldName("listenerConfig");
-                fieldExtension.setStringValue(JsonUtils.toJsonString(node.getTaskAssignListener()));
-                flowableListener.getFieldExtensions().add(fieldExtension);
+                addListenerConfig(flowableListener, node.getTaskAssignListener());
                 flowableListeners.add(flowableListener);
             }
             if (node.getTaskCompleteListener() != null
@@ -478,10 +470,7 @@ public class SimpleModelUtils {
                 flowableListener.setEvent(TaskListener.EVENTNAME_COMPLETE);
                 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
                 flowableListener.setImplementation(DELEGATE_EXPRESSION);
-                FieldExtension fieldExtension = new FieldExtension();
-                fieldExtension.setFieldName("listenerConfig");
-                fieldExtension.setStringValue(JsonUtils.toJsonString(node.getTaskCompleteListener()));
-                flowableListener.getFieldExtensions().add(fieldExtension);
+                addListenerConfig(flowableListener, node.getTaskCompleteListener());
                 flowableListeners.add(flowableListener);
             }
             if (CollUtil.isNotEmpty(flowableListeners)) {
@@ -646,9 +635,9 @@ public class SimpleModelUtils {
                     node.getConditionGroups());
         }
 
-        public static String buildConditionExpression(BpmSimpleModelNodeVO.RouteCondition route) {
-            return buildConditionExpression(route.getConditionType(), route.getConditionExpression(),
-                    route.getConditionGroups());
+        public static String buildConditionExpression(BpmSimpleModelNodeVO.RouterCondition router) {
+            return buildConditionExpression(router.getConditionType(), router.getConditionExpression(),
+                    router.getConditionGroups());
         }
 
         public static String buildConditionExpression(Integer conditionType, String conditionExpression,
@@ -728,18 +717,19 @@ public class SimpleModelUtils {
             exclusiveGateway.setId(node.getId());
 
             // 设置默认的序列流(条件)
+            node.setDefaultFlowId("Flow_" + IdUtil.fastUUID());
             exclusiveGateway.setDefaultFlow(node.getDefaultFlowId());
             return exclusiveGateway;
         }
 
         @Override
         public BpmSimpleModelNodeType getType() {
-            return BpmSimpleModelNodeType.ROUTE_BRANCH_NODE;
+            return BpmSimpleModelNodeType.ROUTER_BRANCH_NODE;
         }
 
-        public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouteCondition route) {
-            String conditionExpression = ConditionNodeConvert.buildConditionExpression(route);
-            return buildBpmnSequenceFlow(nodeId, route.getNodeId(), null, null, conditionExpression);
+        public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouterCondition router) {
+            String conditionExpression = ConditionNodeConvert.buildConditionExpression(router);
+            return buildBpmnSequenceFlow(nodeId, router.getNodeId(), null, null, conditionExpression);
         }
 
     }

+ 10 - 1
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java

@@ -482,6 +482,12 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         if (instance == null) {
             throw exception(PROCESS_INSTANCE_NOT_EXISTS);
         }
+        // 1.3 校验签名
+        BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
+        Boolean signEnable = parseSignEnable(bpmnModel, task.getTaskDefinitionKey());
+        if (signEnable && StrUtil.isEmpty(reqVO.getSign())) {
+            throw exception(TASK_SIGNATURE_NOT_EXISTS);
+        }
 
         // 情况一:被委派的任务,不调用 complete 去完成任务
         if (DelegationState.PENDING.equals(task.getDelegationState())) {
@@ -496,8 +502,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         }
 
         // 情况三:审批普通的任务。大多数情况下,都是这样
-        // 2.1 更新 task 状态、原因
+        // 2.1 更新 task 状态、原因、签字
         updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.APPROVE.getStatus(), reqVO.getReason());
+        if (signEnable) {
+            taskService.setVariableLocal(task.getId(), BpmnVariableConstants.TASK_VARIABLE_SIGN, reqVO.getSign());
+        }
         // 2.2 添加评论
         taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(),
                 BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason()));

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

@@ -1,35 +1,32 @@
 package cn.iocoder.yudao.module.bpm.service.task.listener;
 
 import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
 import cn.iocoder.yudao.module.bpm.enums.definition.BpmListenerParamTypeEnum;
-import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
-import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 import jakarta.annotation.Resource;
+import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
-import org.flowable.bpmn.model.BpmnModel;
-import org.flowable.bpmn.model.FieldExtension;
-import org.flowable.bpmn.model.FlowableListener;
-import org.flowable.bpmn.model.UserTask;
 import org.flowable.engine.delegate.TaskListener;
 import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.engine.impl.el.FixedValue;
 import org.flowable.task.service.delegate.DelegateTask;
+import org.springframework.context.annotation.Scope;
 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.RestClientException;
 import org.springframework.web.client.RestTemplate;
 
 import java.util.List;
 import java.util.Map;
 
 import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
+import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseListenerConfig;
 
 /**
  * BPM 用户任务通用监听器
@@ -38,34 +35,32 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_
  */
 @Component
 @Slf4j
+@Scope("prototype")
 public class BpmUserTaskListener implements TaskListener {
 
     public static final String DELEGATE_EXPRESSION = "${bpmUserTaskListener}";
 
-    @Resource
-    private BpmModelService modelService;
-
     @Resource
     private BpmProcessInstanceService processInstanceService;
 
     @Resource
     private RestTemplate restTemplate;
 
+    @Setter
+    private FixedValue listenerConfig;
+
     @Override
     public void notify(DelegateTask delegateTask) {
         // 1. 获取所需基础信息
         HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(delegateTask.getProcessInstanceId());
-        BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(delegateTask.getProcessDefinitionId());
-        UserTask userTask = (UserTask) BpmnModelUtils.getFlowElementById(bpmnModel, delegateTask.getTaskDefinitionKey());
-        BpmSimpleModelNodeVO.ListenerHandler listenerHandler = getListenerHandlerByEvent(delegateTask.getEventName(),
-                userTask.getTaskListeners());
+        BpmSimpleModelNodeVO.ListenerHandler listenerHandler = parseListenerConfig(listenerConfig);
 
         // 2. 获取请求头和请求体
         Map<String, Object> processVariables = processInstance.getProcessVariables();
         MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
         MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
-        parseListenerMap(listenerHandler.getHeader(), processVariables, headers);
-        parseListenerMap(listenerHandler.getBody(), processVariables, body);
+        parseListenerParam(listenerHandler.getHeader(), processVariables, headers);
+        parseListenerParam(listenerHandler.getBody(), processVariables, body);
         // 2.1 请求头默认参数
         if (StrUtil.isNotEmpty(delegateTask.getTenantId())) {
             headers.add(HEADER_TENANT_ID, delegateTask.getTenantId());
@@ -80,21 +75,29 @@ public class BpmUserTaskListener implements TaskListener {
         // 3. 异步发起请求
         // TODO @芋艿:确认要同步,还是异步
         HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers);
-        // TODO @lesan:可能需要 try catch 哇? RestClientException
-        ResponseEntity<String> responseEntity = restTemplate.exchange(listenerHandler.getPath(), HttpMethod.POST,
-                requestEntity, String.class);
-        log.info("[notify][监听器:{},事件类型:{},请求头:{},请求体:{},响应结果:{}]",
-                DELEGATE_EXPRESSION,
-                delegateTask.getEventName(),
-                headers,
-                body,
-                responseEntity);
+        try {
+            ResponseEntity<String> responseEntity = restTemplate.exchange(listenerHandler.getPath(), HttpMethod.POST,
+                    requestEntity, String.class);
+            log.info("[notify][监听器:{},事件类型:{},请求头:{},请求体:{},响应结果:{}]",
+                    DELEGATE_EXPRESSION,
+                    delegateTask.getEventName(),
+                    headers,
+                    body,
+                    responseEntity);
+        } catch (RestClientException e) {
+            log.error("[error][监听器:{},事件类型:{},请求头:{},请求体:{},请求出错:{}]",
+                    DELEGATE_EXPRESSION,
+                    delegateTask.getEventName(),
+                    headers,
+                    body,
+                    e.getMessage());
+        }
         // 4. 是否需要后续操作?TODO 芋艿:待定!
     }
 
-    private void parseListenerMap(List<BpmSimpleModelNodeVO.ListenerHandler.ListenerParam> list,
-                                  Map<String, Object> processVariables,
-                                  MultiValueMap<String, String> to) {
+    private void parseListenerParam(List<BpmSimpleModelNodeVO.ListenerHandler.ListenerParam> list,
+                                    Map<String, Object> processVariables,
+                                    MultiValueMap<String, String> to) {
         if (CollUtil.isEmpty(list)) {
             return;
         }
@@ -107,17 +110,4 @@ public class BpmUserTaskListener implements TaskListener {
         });
     }
 
-    private BpmSimpleModelNodeVO.ListenerHandler getListenerHandlerByEvent(String eventName, List<FlowableListener> node) {
-        FlowableListener flowableListener = node.stream()
-                .filter(item -> item.getEvent().equals(eventName))
-                .findFirst().orElse(null);
-        Assert.notNull(flowableListener, "监听器({})不能为空", flowableListener);
-        // TODO @lesan:BpmnModelUtils 提供一个 BpmSimpleModelNodeVO.ListenerHandler 解析方法,尽量收敛掉。
-        FieldExtension fieldExtension = flowableListener.getFieldExtensions().stream()
-                .filter(item -> item.getFieldName().equals("listenerConfig"))
-                .findFirst().orElse(null);
-        Assert.notNull(fieldExtension, "监听器扩展字段({})不能为空", fieldExtension);
-        return JsonUtils.parseObject(fieldExtension.getStringValue(), BpmSimpleModelNodeVO.ListenerHandler.class);
-    }
-
 }