add - 新增处理运行时,解析各种节点的配置,关于 BPMN 中的原数据解析,统一在 BpmnMetaParserHelper 类型中
This commit is contained in:
parent
50c1bd5fc6
commit
638624ae6c
@ -37,7 +37,7 @@ public interface BpmnConstants {
|
||||
String COUNTERSIGN_ORIGIN_ASSIGNER = "COUNTERSIGN_ORIGIN_ASSIGNER";
|
||||
|
||||
String PROCESS_PREFIX = "Flowable";
|
||||
String FLOW_NODE_JSON = "jsonMetaValue";
|
||||
String FLOW_NODE_JSON = "jsonValue";
|
||||
String FLOW_SERVER_VERSION = "serverVersion";
|
||||
String FLOW_SERVER_VERSION_121 = "1.2.1";
|
||||
String CONFIG_NOTICE = "noticeConfig";
|
||||
@ -55,7 +55,7 @@ public interface BpmnConstants {
|
||||
String CONFIG_FIELD_META = "field";
|
||||
String CONFIG_FIELD_PERMISSION = "fieldPermission";
|
||||
String CONFIG_FIELD_OPTION = "option";
|
||||
|
||||
String CONFIG_NODE_TYPE = "nodeType";
|
||||
String CONFIG_BUTTON_TYPE_INITIATOR = "initiator";
|
||||
String CONFIG_BUTTON_TYPE_CURRENT = "current";
|
||||
String CONFIG_BUTTON_TYPE_HISTORY = "history";
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
public enum BpmnFlowNodeType {
|
||||
|
||||
//0 发起人 1审批 2抄送 3条件 4路由
|
||||
@ -44,4 +47,10 @@ public enum BpmnFlowNodeType {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public static BpmnFlowNodeType valueOfType(String type) {
|
||||
return Arrays.stream(BpmnFlowNodeType.values())
|
||||
.filter(i -> Objects.equals(i.getType(), type))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +91,10 @@ import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CONVERTOR_COMMON_
|
||||
* @author wangli
|
||||
* @since 2023/10/12 11:43
|
||||
*/
|
||||
public class BpmnJsonConverterUtil {
|
||||
public final class BpmnJsonConverterUtil {
|
||||
private BpmnJsonConverterUtil() {
|
||||
}
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BpmnJsonConverterUtil.class);
|
||||
private static Map<Class<? extends BaseElement>, AbstractBpmnJsonConverter<? extends BaseElement>> converters =
|
||||
new HashMap<>();
|
||||
|
||||
@ -0,0 +1,54 @@
|
||||
package cn.axzo.workflow.core.common.utils;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
|
||||
import org.flowable.bpmn.model.ExtensionElement;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVAL_METHOD;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_NODE_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_VALUE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION;
|
||||
|
||||
/**
|
||||
* 协助解析 BPMN 文件中的自定义扩展字段和属性
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/11/15 22:51
|
||||
*/
|
||||
public final class BpmnMetaParserHelper {
|
||||
private BpmnMetaParserHelper() {}
|
||||
|
||||
public static Optional<String> getProcessServerVersion(Process process) {
|
||||
return Optional.ofNullable(process.getAttributeValue(null, FLOW_SERVER_VERSION));
|
||||
}
|
||||
|
||||
public static Optional<BpmnFlowNodeType> getNodeType(FlowElement flowElement) {
|
||||
return defaultValid(flowElement, CONFIG_NODE_TYPE)
|
||||
.map(element -> BpmnFlowNodeType.valueOfType(element.getElementText()));
|
||||
}
|
||||
|
||||
public static Optional<String> getApprovalMethod(UserTask userTask) {
|
||||
return defaultValid(userTask, CONFIG_APPROVAL_METHOD)
|
||||
.map(element -> element.getAttributeValue(null, ELEMENT_ATTRIBUTE_VALUE));
|
||||
}
|
||||
|
||||
private static Optional<ExtensionElement> defaultValid(FlowElement flowElement, String elementName) {
|
||||
if (CollectionUtils.isEmpty(flowElement.getExtensionElements())
|
||||
|| !flowElement.getExtensionElements().containsKey(elementName)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
List<ExtensionElement> elements = flowElement.getExtensionElements().getOrDefault(elementName,
|
||||
Collections.emptyList());
|
||||
if (CollectionUtils.isEmpty(elements)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.ofNullable(elements.get(0));
|
||||
}
|
||||
}
|
||||
@ -3,15 +3,16 @@ package cn.axzo.workflow.core.converter.json;
|
||||
import cn.axzo.framework.jackson.utility.JSON;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode;
|
||||
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
|
||||
import org.flowable.bpmn.model.ExtensionAttribute;
|
||||
import org.flowable.bpmn.model.ExtensionElement;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.bpmn.model.SequenceFlow;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_NODE_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_NODE_JSON;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* 抽象的 JSON 转 BPMN 协议的转换器
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/10/12 11:06
|
||||
@ -22,17 +23,20 @@ public abstract class AbstractBpmnJsonConverter<T extends FlowElement> {
|
||||
throw new WorkflowEngineException("暂不支持 BPMN 转 JSON");
|
||||
}
|
||||
|
||||
public final void addTypeAttribute(T flowElement, BpmnJsonNode node) {
|
||||
ExtensionAttribute typeAttribute = new ExtensionAttribute();
|
||||
typeAttribute.setName(ELEMENT_ATTRIBUTE_TYPE);
|
||||
typeAttribute.setValue(node.getType().getType());
|
||||
flowElement.addAttribute(typeAttribute);
|
||||
public final void addTypeAttribute(T flowElement, BpmnJsonNode jsonNode) {
|
||||
ExtensionElement nodeTypeElement = new ExtensionElement();
|
||||
nodeTypeElement.setName(CONFIG_NODE_TYPE);
|
||||
nodeTypeElement.setElementText(jsonNode.getType().getType());
|
||||
flowElement.addExtensionElement(nodeTypeElement);
|
||||
}
|
||||
|
||||
public final void addJsonValueAttribute(T flowElement, BpmnJsonNode jsonNode) {
|
||||
ExtensionAttribute extensionAttribute = new ExtensionAttribute();
|
||||
extensionAttribute.setName(FLOW_NODE_JSON);
|
||||
extensionAttribute.setValue(JSON.toJSONString(jsonNode));
|
||||
flowElement.addAttribute(extensionAttribute);
|
||||
if (flowElement instanceof SequenceFlow) {
|
||||
return;
|
||||
}
|
||||
ExtensionElement jsonValueElement = new ExtensionElement();
|
||||
jsonValueElement.setName(FLOW_NODE_JSON);
|
||||
jsonValueElement.setElementText(JSON.toJSONString(jsonNode));
|
||||
flowElement.addExtensionElement(jsonValueElement);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
package cn.axzo.workflow.core.engine.listener;
|
||||
|
||||
import cn.axzo.workflow.common.constant.BpmnConstants;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.deletage.BpmnTaskCalculateDTO;
|
||||
import cn.axzo.workflow.core.deletage.BpmnTaskDelegate;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.ExtensionElement;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.engine.RepositoryService;
|
||||
@ -20,15 +20,17 @@ import org.springframework.util.StringUtils;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_ALLOW_SKIP_USER_TASK;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVAL_METHOD;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_121;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_TASK;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprovalMethod;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNodeType;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getProcessServerVersion;
|
||||
|
||||
|
||||
/**
|
||||
@ -57,52 +59,82 @@ public class EngineExecutionStartListener implements ExecutionListener {
|
||||
Process mainProcess = repositoryService.getBpmnModel(execution.getProcessDefinitionId()).getMainProcess();
|
||||
UserTask userTask = (UserTask) mainProcess.getFlowElement(currentActivityId);
|
||||
|
||||
String flowServerVersion = mainProcess.getAttributeValue(null, FLOW_SERVER_VERSION);
|
||||
if (Objects.equals(FLOW_SERVER_VERSION_121, flowServerVersion)) {
|
||||
Map<String, List<ExtensionElement>> extensionElements = userTask.getExtensionElements();
|
||||
extensionElements.get(CONFIG_APPROVAL_METHOD);
|
||||
|
||||
} else {
|
||||
// 枢智版本的逻辑
|
||||
BpmnTaskCalculateDTO calculateDTO = new BpmnTaskCalculateDTO();
|
||||
calculateDTO.setTaskId(userTask.getId());
|
||||
calculateDTO.setCategory(userTask.getCategory());
|
||||
calculateDTO.setProcessDefinitionId(execution.getProcessDefinitionId());
|
||||
calculateDTO.setProcessInstanceId(execution.getProcessInstanceId());
|
||||
calculateDTO.setTaskName(userTask.getName());
|
||||
calculateDTO.setTenantId(execution.getTenantId());
|
||||
calculateDTO.setTaskDefinitionKey(currentActivityId);
|
||||
calculateDTO.setVariables(execution.getVariables());
|
||||
|
||||
|
||||
bpmTaskDelegate.ifAvailable(delegate -> {
|
||||
List<BpmnTaskDelegateAssigner> assigners = delegate.calculateAssignerAtExecution(calculateDTO);
|
||||
List<String> assigneeIdList = new ArrayList<>();
|
||||
if (!CollectionUtils.isEmpty(assigners)) {
|
||||
for (BpmnTaskDelegateAssigner user : assigners) {
|
||||
assigneeIdList.add(user.buildAssigneeId());
|
||||
// 从 version=1.2.1-SNAPSHOT 开始,才给 process 节点增加了 serverVersion 属性
|
||||
getProcessServerVersion(mainProcess).ifPresent(version -> {
|
||||
Optional<BpmnFlowNodeType> nodeType = getNodeType(userTask);
|
||||
if (Objects.equals(FLOW_SERVER_VERSION_121, version)
|
||||
&& nodeType.isPresent()
|
||||
&& Objects.equals(NODE_TASK, nodeType.get())) {
|
||||
getApprovalMethod(userTask).ifPresent(method -> {
|
||||
switch (method) {
|
||||
case "autoPassed":
|
||||
case "autoRejection":
|
||||
// nothing to do,
|
||||
// TODO 不要调用查询审批人的接口, 只需要保证该节点在实际运行过程中,能自动通过和拒绝即可
|
||||
// 通过的功能可以参考下面枢智的方法,拒绝还需研究(可以结合 task 相关的事件去处理)
|
||||
break;
|
||||
default:
|
||||
// 这里只会是 human 这一种情况, 因为 nobody 在转 BPMN 协议时,Activity 直接变成了 ReceiveTask 节点了。
|
||||
// TODO 结合不同配置,开始执行查询审批人的逻辑
|
||||
break;
|
||||
}
|
||||
// 审批人为空并且当前节点设置了自动跳过条件
|
||||
} else if (StringUtils.hasLength(userTask.getSkipExpression())) {
|
||||
// 自动通过的默认引擎参数必须设置为 true
|
||||
execution.setTransientVariable(BpmnConstants.FLOWABLE_SKIP_EXPRESSION_ENABLE, true);
|
||||
// 设置当前 UserTask 使用的 skip 表达式
|
||||
execution.setTransientVariable(BPM_ALLOW_SKIP_USER_TASK, true);
|
||||
}
|
||||
});
|
||||
|
||||
// UserTask 非多实例
|
||||
if (!userTask.hasMultiInstanceLoopCharacteristics()) {
|
||||
if (!CollectionUtils.isEmpty(assigneeIdList)) {
|
||||
userTask.setAssignee(assigneeIdList.get(0));
|
||||
}
|
||||
} else {
|
||||
// UserTask 多实例, 该变量用于引擎
|
||||
execution.setVariable(assigneeListVariableName, assigneeIdList);
|
||||
}
|
||||
});
|
||||
|
||||
defaultCalcTaskAssigner(execution, userTask, currentActivityId, assigneeListVariableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 枢智版本的逻辑, 不太兼容了,暂时先放在这里
|
||||
*
|
||||
* @param execution
|
||||
* @param userTask
|
||||
* @param currentActivityId
|
||||
* @param assigneeListVariableName
|
||||
*/
|
||||
@Deprecated
|
||||
private void defaultCalcTaskAssigner(DelegateExecution execution, UserTask userTask, String currentActivityId,
|
||||
String assigneeListVariableName) {
|
||||
|
||||
BpmnTaskCalculateDTO calculateDTO = new BpmnTaskCalculateDTO();
|
||||
calculateDTO.setTaskId(userTask.getId());
|
||||
calculateDTO.setCategory(userTask.getCategory());
|
||||
calculateDTO.setProcessDefinitionId(execution.getProcessDefinitionId());
|
||||
calculateDTO.setProcessInstanceId(execution.getProcessInstanceId());
|
||||
calculateDTO.setTaskName(userTask.getName());
|
||||
calculateDTO.setTenantId(execution.getTenantId());
|
||||
calculateDTO.setTaskDefinitionKey(currentActivityId);
|
||||
calculateDTO.setVariables(execution.getVariables());
|
||||
|
||||
bpmTaskDelegate.ifAvailable(delegate -> {
|
||||
List<BpmnTaskDelegateAssigner> assigners = delegate.calculateAssignerAtExecution(calculateDTO);
|
||||
List<String> assigneeIdList = new ArrayList<>();
|
||||
if (!CollectionUtils.isEmpty(assigners)) {
|
||||
for (BpmnTaskDelegateAssigner user : assigners) {
|
||||
assigneeIdList.add(user.buildAssigneeId());
|
||||
}
|
||||
// 将当次审批节点下计算出来的人存储起来,方便后续对 task 保持审批人快照
|
||||
execution.setVariableLocal(INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + currentActivityId,
|
||||
assigners);
|
||||
});
|
||||
}
|
||||
// 审批人为空并且当前节点设置了自动跳过条件
|
||||
} else if (StringUtils.hasLength(userTask.getSkipExpression())) {
|
||||
// 自动通过的默认引擎参数必须设置为 true
|
||||
execution.setTransientVariable(BpmnConstants.FLOWABLE_SKIP_EXPRESSION_ENABLE, true);
|
||||
// 设置当前 UserTask 使用的 skip 表达式
|
||||
execution.setTransientVariable(BPM_ALLOW_SKIP_USER_TASK, true);
|
||||
}
|
||||
|
||||
// UserTask 非多实例
|
||||
if (!userTask.hasMultiInstanceLoopCharacteristics()) {
|
||||
if (!CollectionUtils.isEmpty(assigneeIdList)) {
|
||||
userTask.setAssignee(assigneeIdList.get(0));
|
||||
}
|
||||
} else {
|
||||
// UserTask 多实例, 该变量用于引擎
|
||||
execution.setVariable(assigneeListVariableName, assigneeIdList);
|
||||
}
|
||||
// 将当次审批节点下计算出来的人存储起来,方便后续对 task 保持审批人快照
|
||||
execution.setVariableLocal(INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + currentActivityId,
|
||||
assigners);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package cn.axzo.workflow.server.controller.listener.task;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
|
||||
import cn.axzo.workflow.core.listener.BpmnTaskEventListener;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -12,7 +13,6 @@ import org.flowable.engine.TaskService;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@ -45,13 +45,17 @@ public class StartNodeAutoCompleteEventListener implements BpmnTaskEventListener
|
||||
Process mainProcess = repositoryService.getBpmnModel(delegateTask.getProcessDefinitionId()).getMainProcess();
|
||||
UserTask userTask = (UserTask) mainProcess.getFlowElement(delegateTask.getTaskDefinitionKey());
|
||||
|
||||
if (Objects.equals(NODE_STARTER.getType(), delegateTask.getTaskDefinitionKey())
|
||||
&& !StringUtils.hasLength(delegateTask.getAssignee())) {
|
||||
BpmnTaskDelegateAssigner initiator = delegateTask.getVariable(INTERNAL_INITIATOR,
|
||||
BpmnTaskDelegateAssigner.class);
|
||||
delegateTask.setVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + delegateTask.getId(), initiator);
|
||||
// 直接完成
|
||||
taskService.complete(delegateTask.getId(), runtimeService.getVariables(delegateTask.getExecutionId()));
|
||||
}
|
||||
// 这一个通用的“发起人“节点,完全不需要审批,
|
||||
// 为什么要创建这个节点?只是为了在审批记录中有一个发起人的记录信息而已!!!
|
||||
BpmnMetaParserHelper.getNodeType(userTask).ifPresent(nodeType -> {
|
||||
if (Objects.equals(NODE_STARTER, nodeType)) {
|
||||
BpmnTaskDelegateAssigner initiator = delegateTask.getVariable(INTERNAL_INITIATOR,
|
||||
BpmnTaskDelegateAssigner.class);
|
||||
delegateTask.setVariable(INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + delegateTask.getId(),
|
||||
initiator);
|
||||
// 直接完成
|
||||
taskService.complete(delegateTask.getId(), runtimeService.getVariables(delegateTask.getExecutionId()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user