Commit 8a8dc67d72c95ad1bc0d411e319e48014fe3a5d7

Authored by jason
1 parent ca1d9e68

【功能新增】新增Simple 设计器触发器节点

Showing 11 changed files with 354 additions and 65 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmListenerParamTypeEnum.java renamed to yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmHttpRequestParamSettingType.java
... ... @@ -7,13 +7,13 @@ import lombok.Getter;
7 7 import java.util.Arrays;
8 8  
9 9 /**
10   - * BPM 任务监听器键值对类型
  10 + * BPM HTTP 请求参数设置类型。用于 Simple 设计器任务监听器和触发器配置。
11 11 *
12 12 * @author Lesan
13 13 */
14 14 @Getter
15 15 @AllArgsConstructor
16   -public enum BpmListenerParamTypeEnum implements IntArrayValuable {
  16 +public enum BpmHttpRequestParamSettingType implements IntArrayValuable {
17 17  
18 18 FIXED_VALUE(1, "固定值"),
19 19 FROM_FORM(2, "表单");
... ... @@ -21,7 +21,7 @@ public enum BpmListenerParamTypeEnum implements IntArrayValuable {
21 21 private final Integer type;
22 22 private final String name;
23 23  
24   - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmListenerParamTypeEnum::getType).toArray();
  24 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmHttpRequestParamSettingType::getType).toArray();
25 25  
26 26 @Override
27 27 public int[] array() {
... ...
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java
... ... @@ -27,6 +27,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable {
27 27 COPY_NODE(12, "抄送人", "serviceTask"),
28 28  
29 29 DELAY_TIMER_NODE(14, "延迟器", "receiveTask"),
  30 + TRIGGER_NODE(15, "触发器", "serviceTask"),
30 31  
31 32 // 50 ~ 条件分支
32 33 CONDITION_NODE(50, "条件", "sequenceFlow"), // 用于构建流转条件的表达式
... ...
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTriggerType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.enums.definition;
  2 +
  3 +import cn.hutool.core.util.ArrayUtil;
  4 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  5 +import lombok.AllArgsConstructor;
  6 +import lombok.Getter;
  7 +
  8 +import java.util.Arrays;
  9 +
  10 +/**
  11 + * BPM Simple 触发器类型枚举
  12 + *
  13 + * @author jason
  14 + */
  15 +@Getter
  16 +@AllArgsConstructor
  17 +public enum BpmTriggerType implements IntArrayValuable {
  18 +
  19 + HTTP_REQUEST(1, "发起 HTTP 请求");
  20 +
  21 + /**
  22 + * 触发器执行动作类型
  23 + */
  24 + private final Integer type;
  25 +
  26 + /**
  27 + * 触发器执行动作描述
  28 + */
  29 + private final String desc;
  30 +
  31 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmTriggerType::getType).toArray();
  32 +
  33 + @Override
  34 + public int[] array() {
  35 + return ARRAYS;
  36 + }
  37 +
  38 + public static BpmTriggerType typeOf(Integer type) {
  39 + return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
  40 + }
  41 +}
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
... ... @@ -9,6 +9,7 @@ import jakarta.validation.Valid;
9 9 import jakarta.validation.constraints.NotEmpty;
10 10 import jakarta.validation.constraints.NotNull;
11 11 import lombok.Data;
  12 +import org.hibernate.validator.constraints.URL;
12 13  
13 14 import java.util.List;
14 15 import java.util.Map;
... ... @@ -115,6 +116,11 @@ public class BpmSimpleModelNodeVO {
115 116 @Schema(description = "路由分支默认分支 ID", example = "Flow_xxx", hidden = true) // 由后端生成,所以 hidden = true
116 117 private String routerDefaultFlowId; // 仅用于路由分支节点 BpmSimpleModelNodeType.ROUTER_BRANCH_NODE
117 118  
  119 + /**
  120 + * 触发器节点设置
  121 + */
  122 + private TriggerSetting triggerSetting;
  123 +
118 124 @Schema(description = "任务监听器")
119 125 @Valid
120 126 @Data
... ... @@ -128,27 +134,28 @@ public class BpmSimpleModelNodeVO {
128 134 private String path;
129 135  
130 136 @Schema(description = "请求头", example = "[]")
131   - private List<ListenerParam> header;
  137 + private List<HttpRequestParamSetting> header;
132 138  
133 139 @Schema(description = "请求体", example = "[]")
134   - private List<ListenerParam> body;
135   -
136   - // TODO @芋艿:这里后续要不要复用;
  140 + private List<HttpRequestParamSetting> body;
  141 + }
137 142  
138   - @Schema(description = "任务监听器键值对")
139   - @Data
140   - public static class ListenerParam {
  143 + @Schema(description = "HTTP 请求参数设置")
  144 + @Data
  145 + public static class HttpRequestParamSetting {
141 146  
142   - @Schema(description = "值类型", example = "1")
143   - @InEnum(BpmListenerParamTypeEnum.class)
144   - private Integer type;
  147 + @Schema(description = "值类型", example = "1")
  148 + @InEnum(BpmHttpRequestParamSettingType.class)
  149 + @NotNull(message = "值类型不能为空")
  150 + private Integer type;
145 151  
146   - @Schema(description = "键", example = "xxx")
147   - private String key;
  152 + @Schema(description = "键", example = "xxx")
  153 + @NotEmpty(message = "键不能为空")
  154 + private String key;
148 155  
149   - @Schema(description = "值", example = "xxx")
150   - private String value;
151   - }
  156 + @Schema(description = "值", example = "xxx")
  157 + @NotEmpty(message = "值不能为空")
  158 + private String value;
152 159 }
153 160  
154 161 @Schema(description = "审批节点拒绝处理策略")
... ... @@ -318,4 +325,39 @@ public class BpmSimpleModelNodeVO {
318 325 @Schema(description = "条件组", example = "{}")
319 326 private ConditionGroups conditionGroups;
320 327 }
  328 +
  329 + @Schema(description = "触发器节点配置")
  330 + @Data
  331 + @Valid
  332 + public static class TriggerSetting {
  333 +
  334 + @Schema(description = "触发器类型", example = "1")
  335 + @InEnum(BpmTriggerType.class)
  336 + @NotNull(message = "触发器类型不能为空")
  337 + private Integer type;
  338 +
  339 + /**
  340 + * http 请求触发器设置
  341 + */
  342 + @Valid
  343 + private HttpRequestTriggerSetting httpRequestSetting;
  344 +
  345 + @Schema(description = "http 请求触发器设置", example = "{}")
  346 + @Data
  347 + public static class HttpRequestTriggerSetting {
  348 +
  349 + @Schema(description = "请求路径", example = "http://127.0.0.1")
  350 + @NotEmpty(message = "请求 URL 不能为空")
  351 + @URL(message = "请求 URL 格式不正确")
  352 + private String url;
  353 +
  354 + @Schema(description = "请求头参数设置", example = "[]")
  355 + @Valid
  356 + private List<HttpRequestParamSetting> header;
  357 +
  358 + @Schema(description = "请求头参数设置", example = "[]")
  359 + @Valid
  360 + private List<HttpRequestParamSetting> body;
  361 + }
  362 + }
321 363 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java
... ... @@ -101,6 +101,16 @@ public interface BpmnModelConstants {
101 101 String BUTTON_SETTING_ELEMENT_ENABLE_ATTRIBUTE = "enable";
102 102  
103 103 /**
  104 + * BPMN ExtensionElement 的扩展属性,用于标记触发器的类型
  105 + */
  106 + String TRIGGER_TYPE = "triggerType";
  107 +
  108 + /**
  109 + * BPMN ExtensionElement 的扩展属性,用于标记触发器参数
  110 + */
  111 + String TRIGGER_PARAM = "triggerParam";
  112 +
  113 + /**
104 114 * BPMN Start Event Node Id
105 115 */
106 116 String START_EVENT_NODE_ID = "StartEvent";
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTriggerTaskDelegate.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener;
  2 +
  3 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTriggerType;
  4 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
  5 +import cn.iocoder.yudao.module.bpm.service.task.trigger.BpmTrigger;
  6 +import jakarta.annotation.PostConstruct;
  7 +import jakarta.annotation.Resource;
  8 +import lombok.extern.slf4j.Slf4j;
  9 +import org.flowable.bpmn.model.FlowElement;
  10 +import org.flowable.engine.delegate.DelegateExecution;
  11 +import org.flowable.engine.delegate.JavaDelegate;
  12 +import org.springframework.stereotype.Component;
  13 +
  14 +import java.util.EnumMap;
  15 +import java.util.List;
  16 +
  17 +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmTriggerTaskDelegate.BEAN_NAME;
  18 +
  19 +
  20 +/**
  21 + * 处理触发器任务 {@link JavaDelegate} 的实现类
  22 + * <p>
  23 + * 目前只有 Simple 设计器【触发器节点】使用
  24 + *
  25 + * @author jason
  26 + */
  27 +@Component(BEAN_NAME)
  28 +@Slf4j
  29 +public class BpmTriggerTaskDelegate implements JavaDelegate {
  30 +
  31 + public static final String BEAN_NAME = "bpmTriggerTaskDelegate";
  32 +
  33 + @Resource
  34 + private List<BpmTrigger> triggers;
  35 +
  36 + private final EnumMap<BpmTriggerType, BpmTrigger> triggerMap = new EnumMap<>(BpmTriggerType.class);
  37 +
  38 + @PostConstruct
  39 + private void init() {
  40 + triggers.forEach(trigger -> triggerMap.put(trigger.getType(), trigger));
  41 + }
  42 +
  43 + @Override
  44 + public void execute(DelegateExecution execution) {
  45 + FlowElement flowElement = execution.getCurrentFlowElement();
  46 + BpmTriggerType bpmTriggerType = BpmnModelUtils.parserTriggerType(flowElement);
  47 + BpmTrigger bpmTrigger = triggerMap.get(bpmTriggerType);
  48 + if (bpmTrigger == null) {
  49 + log.error("[execute], FlowElement[{}], {} 找不到匹配的 BpmTrigger", execution.getCurrentActivityId(), flowElement);
  50 + return;
  51 + }
  52 + bpmTrigger.execute(execution.getProcessInstanceId(), BpmnModelUtils.parserTriggerParam(flowElement));
  53 + }
  54 +}
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
... ... @@ -4,17 +4,16 @@ import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.convert.Convert;
5 5 import cn.hutool.core.lang.Assert;
6 6 import cn.hutool.core.map.MapUtil;
7   -import cn.hutool.core.util.*;
  7 +import cn.hutool.core.util.ArrayUtil;
  8 +import cn.hutool.core.util.ObjUtil;
  9 +import cn.hutool.core.util.StrUtil;
8 10 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
9 11 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
10 12 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
11 13 import cn.iocoder.yudao.framework.common.util.string.StrUtils;
12 14 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
13 15 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
14   -import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskApproveTypeEnum;
15   -import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskAssignEmptyHandlerTypeEnum;
16   -import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskAssignStartUserHandlerTypeEnum;
17   -import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType;
  16 +import cn.iocoder.yudao.module.bpm.enums.definition.*;
18 17 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
19 18 import com.google.common.collect.Maps;
20 19 import lombok.extern.slf4j.Slf4j;
... ... @@ -395,6 +394,15 @@ public class BpmnModelUtils {
395 394 return JsonUtils.parseObject(expressionText, BpmSimpleModelNodeVO.ListenerHandler.class);
396 395 }
397 396  
  397 + public static BpmTriggerType parserTriggerType(FlowElement flowElement) {
  398 + Integer triggerType = NumberUtils.parseInt(parseExtensionElement(flowElement, TRIGGER_TYPE));
  399 + return BpmTriggerType.typeOf(triggerType);
  400 + }
  401 +
  402 + public static String parserTriggerParam(FlowElement flowElement) {
  403 + return parseExtensionElement(flowElement, TRIGGER_PARAM);
  404 + }
  405 +
398 406 // ========== BPM 简单查找相关的方法 ==========
399 407  
400 408 /**
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
... ... @@ -5,17 +5,20 @@ import cn.hutool.core.lang.Assert;
5 5 import cn.hutool.core.map.MapUtil;
6 6 import cn.hutool.core.util.*;
7 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  8 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
8 9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
9 10 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups;
10 11 import cn.iocoder.yudao.module.bpm.enums.definition.*;
11 12 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
12 13 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
13 14 import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmCopyTaskDelegate;
  15 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmTriggerTaskDelegate;
14 16 import org.flowable.bpmn.BpmnAutoLayout;
15 17 import org.flowable.bpmn.constants.BpmnXMLConstants;
16 18 import org.flowable.bpmn.model.Process;
17 19 import org.flowable.bpmn.model.*;
18 20 import org.flowable.engine.delegate.TaskListener;
  21 +import org.springframework.util.MultiValueMap;
19 22  
20 23 import java.util.*;
21 24  
... ... @@ -39,7 +42,7 @@ public class SimpleModelUtils {
39 42 static {
40 43 List<NodeConvert> converts = asList(new StartNodeConvert(), new EndNodeConvert(),
41 44 new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(),
42   - new DelayTimerNodeConvert(),
  45 + new DelayTimerNodeConvert(), new TriggerNodeConvert(),
43 46 new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert(), new RouteBranchNodeConvert());
44 47 converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert));
45 48 }
... ... @@ -93,7 +96,7 @@ public class SimpleModelUtils {
93 96 /**
94 97 * 遍历节点,构建 FlowNode 元素
95 98 *
96   - * @param node SIMPLE 节点
  99 + * @param node SIMPLE 节点
97 100 * @param process BPMN 流程
98 101 */
99 102 private static void traverseNodeToBuildFlowNode(BpmSimpleModelNodeVO node, Process process) {
... ... @@ -124,8 +127,8 @@ public class SimpleModelUtils {
124 127 /**
125 128 * 遍历节点,构建 SequenceFlow 元素
126 129 *
127   - * @param process Bpmn 流程
128   - * @param node 当前节点
  130 + * @param process Bpmn 流程
  131 + * @param node 当前节点
129 132 * @param targetNodeId 目标节点 ID
130 133 */
131 134 private static void traverseNodeToBuildSequenceFlow(Process process, BpmSimpleModelNodeVO node, String targetNodeId) {
... ... @@ -152,8 +155,8 @@ public class SimpleModelUtils {
152 155 /**
153 156 * 遍历普通(非条件)节点,构建 SequenceFlow 元素
154 157 *
155   - * @param process Bpmn 流程
156   - * @param node 当前节点
  158 + * @param process Bpmn 流程
  159 + * @param node 当前节点
157 160 * @param targetNodeId 目标节点 ID
158 161 */
159 162 private static void traverseNormalNodeToBuildSequenceFlow(Process process, BpmSimpleModelNodeVO node, String targetNodeId) {
... ... @@ -161,7 +164,7 @@ public class SimpleModelUtils {
161 164 boolean isChildNodeValid = isValidNode(childNode);
162 165 // 情况一:有“子”节点,则建立连线
163 166 // 情况二:没有“子节点”,则直接跟 targetNodeId 建立连线。例如说,结束节点、条件分支(分支节点的孩子节点或聚合节点)的最后一个节点
164   - String finalTargetNodeId = isChildNodeValid? childNode.getId() : targetNodeId;
  167 + String finalTargetNodeId = isChildNodeValid ? childNode.getId() : targetNodeId;
165 168 SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), finalTargetNodeId);
166 169 process.addFlowElement(sequenceFlow);
167 170  
... ... @@ -174,8 +177,8 @@ public class SimpleModelUtils {
174 177 /**
175 178 * 遍历条件节点,构建 SequenceFlow 元素
176 179 *
177   - * @param process Bpmn 流程
178   - * @param node 当前节点
  180 + * @param process Bpmn 流程
  181 + * @param node 当前节点
179 182 * @param targetNodeId 目标节点 ID
180 183 */
181 184 private static void traverseBranchNodeToBuildSequenceFlow(Process process, BpmSimpleModelNodeVO node, String targetNodeId) {
... ... @@ -231,7 +234,7 @@ public class SimpleModelUtils {
231 234 String nextNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId;
232 235 SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId);
233 236 process.addFlowElement(sequenceFlow);
234   - // 4.2 如果是路由分支,需要连接后续节点为默认路由
  237 + // 4.2 如果是路由分支,需要连接后续节点为默认路由
235 238 } else if (nodeType == BpmSimpleModelNodeType.ROUTER_BRANCH_NODE) {
236 239 SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), branchEndNodeId, node.getRouterDefaultFlowId(),
237 240 null, null);
... ... @@ -449,7 +452,7 @@ public class SimpleModelUtils {
449 452 private void addUserTaskListener(BpmSimpleModelNodeVO node, UserTask userTask) {
450 453 List<FlowableListener> flowableListeners = new ArrayList<>(3);
451 454 if (node.getTaskCreateListener() != null
452   - && Boolean.TRUE.equals(node.getTaskCreateListener().getEnable())) {
  455 + && Boolean.TRUE.equals(node.getTaskCreateListener().getEnable())) {
453 456 FlowableListener flowableListener = new FlowableListener();
454 457 flowableListener.setEvent(TaskListener.EVENTNAME_CREATE);
455 458 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
... ... @@ -458,7 +461,7 @@ public class SimpleModelUtils {
458 461 flowableListeners.add(flowableListener);
459 462 }
460 463 if (node.getTaskAssignListener() != null
461   - && Boolean.TRUE.equals(node.getTaskAssignListener().getEnable())) {
  464 + && Boolean.TRUE.equals(node.getTaskAssignListener().getEnable())) {
462 465 FlowableListener flowableListener = new FlowableListener();
463 466 flowableListener.setEvent(TaskListener.EVENTNAME_ASSIGNMENT);
464 467 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
... ... @@ -467,7 +470,7 @@ public class SimpleModelUtils {
467 470 flowableListeners.add(flowableListener);
468 471 }
469 472 if (node.getTaskCompleteListener() != null
470   - && Boolean.TRUE.equals(node.getTaskCompleteListener().getEnable())) {
  473 + && Boolean.TRUE.equals(node.getTaskCompleteListener().getEnable())) {
471 474 FlowableListener flowableListener = new FlowableListener();
472 475 flowableListener.setEvent(TaskListener.EVENTNAME_COMPLETE);
473 476 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
... ... @@ -693,9 +696,9 @@ public class SimpleModelUtils {
693 696 boundaryEvent.setAttachedToRef(receiveTask);
694 697 // 2.2 定义超时时间
695 698 TimerEventDefinition eventDefinition = new TimerEventDefinition();
696   - if (node.getDelaySetting().getDelayType().equals(BpmDelayTimerType.FIXED_DATE_TIME.getType())){
  699 + if (node.getDelaySetting().getDelayType().equals(BpmDelayTimerType.FIXED_DATE_TIME.getType())) {
697 700 eventDefinition.setTimeDuration(node.getDelaySetting().getDelayTime());
698   - } else if (node.getDelaySetting().getDelayType().equals(BpmDelayTimerType.FIXED_TIME_DURATION.getType())){
  701 + } else if (node.getDelaySetting().getDelayType().equals(BpmDelayTimerType.FIXED_TIME_DURATION.getType())) {
699 702 eventDefinition.setTimeDate(node.getDelaySetting().getDelayTime());
700 703 }
701 704 boundaryEvent.addEventDefinition(eventDefinition);
... ... @@ -711,6 +714,32 @@ public class SimpleModelUtils {
711 714 }
712 715 }
713 716  
  717 + public static class TriggerNodeConvert implements NodeConvert {
  718 +
  719 + @Override
  720 + public ServiceTask convert(BpmSimpleModelNodeVO node) {
  721 + // 触发器使用 ServiceTask 来实现
  722 + ServiceTask serviceTask = new ServiceTask();
  723 + serviceTask.setId(node.getId());
  724 + serviceTask.setName(node.getName());
  725 + serviceTask.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
  726 + serviceTask.setImplementation("${" + BpmTriggerTaskDelegate.BEAN_NAME + "}");
  727 + if (node.getTriggerSetting() != null) {
  728 + addExtensionElement(serviceTask, TRIGGER_TYPE, node.getTriggerSetting().getType());
  729 + if (node.getTriggerSetting().getHttpRequestSetting() != null) {
  730 + addExtensionElement(serviceTask, TRIGGER_PARAM,
  731 + JsonUtils.toJsonString(node.getTriggerSetting().getHttpRequestSetting()));
  732 + }
  733 + }
  734 + return serviceTask;
  735 + }
  736 +
  737 + @Override
  738 + public BpmSimpleModelNodeType getType() {
  739 + return BpmSimpleModelNodeType.TRIGGER_NODE;
  740 + }
  741 + }
  742 +
714 743 public static class RouteBranchNodeConvert implements NodeConvert {
715 744  
716 745 @Override
... ... @@ -751,7 +780,7 @@ public class SimpleModelUtils {
751 780 }
752 781  
753 782 private static void simulateNextNode(BpmSimpleModelNodeVO currentNode, Map<String, Object> variables,
754   - List<BpmSimpleModelNodeVO> resultNodes) {
  783 + List<BpmSimpleModelNodeVO> resultNodes) {
755 784 // 如果不合法(包括为空),则直接结束
756 785 if (!isValidNode(currentNode)) {
757 786 return;
... ... @@ -761,10 +790,10 @@ public class SimpleModelUtils {
761 790  
762 791 // 情况:START_NODE/START_USER_NODE/APPROVE_NODE/COPY_NODE/END_NODE
763 792 if (nodeType == BpmSimpleModelNodeType.START_NODE
764   - || nodeType == BpmSimpleModelNodeType.START_USER_NODE
765   - || nodeType == BpmSimpleModelNodeType.APPROVE_NODE
766   - || nodeType == BpmSimpleModelNodeType.COPY_NODE
767   - || nodeType == BpmSimpleModelNodeType.END_NODE) {
  793 + || nodeType == BpmSimpleModelNodeType.START_USER_NODE
  794 + || nodeType == BpmSimpleModelNodeType.APPROVE_NODE
  795 + || nodeType == BpmSimpleModelNodeType.COPY_NODE
  796 + || nodeType == BpmSimpleModelNodeType.END_NODE) {
768 797 // 添加元素
769 798 resultNodes.add(currentNode);
770 799 }
... ... @@ -774,7 +803,7 @@ public class SimpleModelUtils {
774 803 // 查找满足条件的 BpmSimpleModelNodeVO 节点
775 804 BpmSimpleModelNodeVO matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(),
776 805 conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())
777   - && evalConditionExpress(variables, conditionNode));
  806 + && evalConditionExpress(variables, conditionNode));
778 807 if (matchConditionNode == null) {
779 808 matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(),
780 809 conditionNode -> BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()));
... ... @@ -815,4 +844,25 @@ public class SimpleModelUtils {
815 844 return BpmnModelUtils.evalConditionExpress(variables, ConditionNodeConvert.buildConditionExpression(conditionNode));
816 845 }
817 846  
  847 + /**
  848 + * 添加 HTTP 请求参数。请求头或者请求体
  849 + *
  850 + * @param params HTTP 请求参数
  851 + * @param paramSettings HTTP 请求参数设置
  852 + * @param processVariables 流程变量
  853 + */
  854 + public static void addHttpRequestParam(MultiValueMap<String, String> params,
  855 + List<BpmSimpleModelNodeVO.HttpRequestParamSetting> paramSettings,
  856 + Map<String, Object> processVariables) {
  857 + if (CollUtil.isEmpty(paramSettings)) {
  858 + return;
  859 + }
  860 + paramSettings.forEach(item -> {
  861 + if (item.getType().equals(BpmHttpRequestParamSettingType.FIXED_VALUE.getType())) {
  862 + params.add(item.getKey(), item.getValue());
  863 + } else if (item.getType().equals(BpmHttpRequestParamSettingType.FROM_FORM.getType())) {
  864 + params.add(item.getKey(), processVariables.get(item.getValue()).toString());
  865 + }
  866 + });
  867 + }
818 868 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmUserTaskListener.java
1 1 package cn.iocoder.yudao.module.bpm.service.task.listener;
2 2  
3   -import cn.hutool.core.collection.CollUtil;
4 3 import cn.hutool.core.util.StrUtil;
5 4 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
6   -import cn.iocoder.yudao.module.bpm.enums.definition.BpmListenerParamTypeEnum;
  5 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.SimpleModelUtils;
7 6 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
8 7 import jakarta.annotation.Resource;
9 8 import lombok.Setter;
... ... @@ -22,7 +21,6 @@ import org.springframework.util.MultiValueMap;
22 21 import org.springframework.web.client.RestClientException;
23 22 import org.springframework.web.client.RestTemplate;
24 23  
25   -import java.util.List;
26 24 import java.util.Map;
27 25  
28 26 import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
... ... @@ -59,8 +57,8 @@ public class BpmUserTaskListener implements TaskListener {
59 57 Map<String, Object> processVariables = processInstance.getProcessVariables();
60 58 MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
61 59 MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
62   - parseListenerParam(listenerHandler.getHeader(), processVariables, headers);
63   - parseListenerParam(listenerHandler.getBody(), processVariables, body);
  60 + SimpleModelUtils.addHttpRequestParam(headers, listenerHandler.getHeader(), processVariables);
  61 + SimpleModelUtils.addHttpRequestParam(body, listenerHandler.getBody(), processVariables);
64 62 // 2.1 请求头默认参数
65 63 if (StrUtil.isNotEmpty(delegateTask.getTenantId())) {
66 64 headers.add(HEADER_TENANT_ID, delegateTask.getTenantId());
... ... @@ -94,20 +92,4 @@ public class BpmUserTaskListener implements TaskListener {
94 92 }
95 93 // 4. 是否需要后续操作?TODO 芋艿:待定!
96 94 }
97   -
98   - private void parseListenerParam(List<BpmSimpleModelNodeVO.ListenerHandler.ListenerParam> list,
99   - Map<String, Object> processVariables,
100   - MultiValueMap<String, String> to) {
101   - if (CollUtil.isEmpty(list)) {
102   - return;
103   - }
104   - list.forEach(item -> {
105   - if (item.getType().equals(BpmListenerParamTypeEnum.FIXED_VALUE.getType())) {
106   - to.add(item.getKey(), item.getValue());
107   - } else if (item.getType().equals(BpmListenerParamTypeEnum.FROM_FORM.getType())) {
108   - to.add(item.getKey(), processVariables.get(item.getValue()).toString());
109   - }
110   - });
111   - }
112   -
113 95 }
114 96 \ No newline at end of file
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/BpmHttpRequestTrigger.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.service.task.trigger;
  2 +
  3 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  4 +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.TriggerSetting.HttpRequestTriggerSetting;
  5 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTriggerType;
  6 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.SimpleModelUtils;
  7 +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
  8 +import jakarta.annotation.Resource;
  9 +import lombok.extern.slf4j.Slf4j;
  10 +import org.flowable.engine.runtime.ProcessInstance;
  11 +import org.springframework.http.HttpEntity;
  12 +import org.springframework.http.HttpMethod;
  13 +import org.springframework.http.ResponseEntity;
  14 +import org.springframework.stereotype.Component;
  15 +import org.springframework.util.LinkedMultiValueMap;
  16 +import org.springframework.util.MultiValueMap;
  17 +import org.springframework.web.client.RestClientException;
  18 +import org.springframework.web.client.RestTemplate;
  19 +
  20 +import java.util.Map;
  21 +
  22 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
  23 +
  24 +/**
  25 + * BPM 发送 HTTP 请求触发器
  26 + *
  27 + * @author jason
  28 + */
  29 +@Component
  30 +@Slf4j
  31 +public class BpmHttpRequestTrigger implements BpmTrigger {
  32 +
  33 + @Resource
  34 + private BpmProcessInstanceService processInstanceService;
  35 +
  36 + @Resource
  37 + private RestTemplate restTemplate;
  38 +
  39 + @Override
  40 + public BpmTriggerType getType() {
  41 + return BpmTriggerType.HTTP_REQUEST;
  42 + }
  43 +
  44 + @Override
  45 + public void execute(String processInstanceId, String param) {
  46 + // 1. 解析 http 请求配置
  47 + HttpRequestTriggerSetting httpRequestSetting = JsonUtils.parseObject(param, HttpRequestTriggerSetting.class);
  48 + if (httpRequestSetting == null) {
  49 + log.error("[execute] HTTP 触发器请求配置为空");
  50 + return;
  51 + }
  52 + // 2.1 设置请求头
  53 + ProcessInstance processInstance = processInstanceService.getProcessInstance(processInstanceId);
  54 + Map<String, Object> processVariables = processInstance.getProcessVariables();
  55 + MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
  56 + headers.add(HEADER_TENANT_ID, processInstance.getTenantId());
  57 + SimpleModelUtils.addHttpRequestParam(headers, httpRequestSetting.getHeader(), processVariables);
  58 + // 2.2 设置请求体
  59 + MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
  60 + SimpleModelUtils.addHttpRequestParam(body, httpRequestSetting.getBody(), processVariables);
  61 + body.add("processInstanceId", processInstanceId);
  62 +
  63 + // 3. 发起请求
  64 + HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers);
  65 + try {
  66 + ResponseEntity<String> responseEntity = restTemplate.exchange(httpRequestSetting.getUrl(), HttpMethod.POST,
  67 + requestEntity, String.class);
  68 + log.info("[execute][HTTP 触发器,请求头:{},请求体:{},响应结果:{}]", headers, body, responseEntity);
  69 + } catch (RestClientException e) {
  70 + log.error("[execute][HTTP 触发器,请求头:{},请求体:{},请求出错:{}]", headers, body, e.getMessage());
  71 + }
  72 + }
  73 +}
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/BpmTrigger.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.service.task.trigger;
  2 +
  3 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTriggerType;
  4 +
  5 +/**
  6 + * BPM 触发器接口
  7 + * <p>
  8 + * 处理不同的动作
  9 + *
  10 + * @author jason
  11 + */
  12 +public interface BpmTrigger {
  13 +
  14 + /**
  15 + * 对应触发器类型
  16 + *
  17 + * @return 触发器类型
  18 + */
  19 + BpmTriggerType getType();
  20 +
  21 + /**
  22 + * 触发器执行
  23 + *
  24 + * @param processInstanceId 流程实例编号
  25 + * @param param 触发器参数
  26 + */
  27 + void execute(String processInstanceId, String param);
  28 +}
... ...