feat: Simple设计器-监听器

This commit is contained in:
Lesan 2025-01-07 16:31:44 +08:00
parent 34c8f4cae1
commit 955ad86db4
4 changed files with 121 additions and 46 deletions

View File

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

View File

@ -6,6 +6,7 @@ import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 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.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.string.StrUtils; import cn.iocoder.yudao.framework.common.util.string.StrUtils;
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;
@ -56,6 +57,18 @@ public class BpmnModelUtils {
element.addExtensionElement(extensionElement); 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) { public static void addExtensionElement(FlowElement element, String name, Integer value) {
if (value == null) { if (value == null) {
return; return;
@ -93,6 +106,33 @@ public class BpmnModelUtils {
return element != null ? element.getElementText() : null; 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);
}
/** /**
* 给节点添加候选人元素 * 给节点添加候选人元素
* *

View File

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

View File

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