add - 新增流程推算执行顺序的节点信息
This commit is contained in:
parent
912bf296f4
commit
35cc172cf3
@ -55,6 +55,7 @@ public enum BpmErrorCode implements IProjectRespCode {
|
||||
FORM_DEFINITION_PARSER_ERROR("08002", "表单定义内容解析出错"),
|
||||
// ========== form Instance 09-001 ==========
|
||||
// ========== flowable Engine 10-001 ==========
|
||||
ENGINE_EXECUTION_LOST_ID_ERROR("10001", "Execution 丢失"),
|
||||
|
||||
|
||||
// // ========== 流程模型 01-001 ==========
|
||||
|
||||
@ -205,7 +205,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
|
||||
return true;
|
||||
}
|
||||
log.error("[updateProcessDefinitionState][流程定义({}) 修改未知状态({})]", processDefinitionId, status);
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package cn.axzo.workflow.core.service.support;
|
||||
|
||||
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
|
||||
import cn.azxo.framework.common.utils.StringUtils;
|
||||
import org.flowable.common.engine.api.delegate.Expression;
|
||||
import org.flowable.common.engine.impl.interceptor.Command;
|
||||
@ -7,10 +8,10 @@ import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
|
||||
import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.axzo.workflow.core.common.enums.BpmErrorCode.ENGINE_EXECUTION_LOST_ID_ERROR;
|
||||
|
||||
/**
|
||||
* 流程定义内部的表达式评估命令器
|
||||
@ -24,17 +25,13 @@ public class ExpressionConditionCmd implements Command<Boolean>, Serializable {
|
||||
protected final String processInstanceId;
|
||||
protected final String exp;
|
||||
|
||||
protected Map<String, Object> variableMap;
|
||||
|
||||
public ExpressionConditionCmd(RuntimeService runtimeService,
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration,
|
||||
String processInstanceId, String exp,
|
||||
Map<String, Object> variableMap) {
|
||||
String processInstanceId, String exp) {
|
||||
this.runtimeService = runtimeService;
|
||||
this.processEngineConfiguration = processEngineConfiguration;
|
||||
this.processInstanceId = processInstanceId;
|
||||
this.exp = exp;
|
||||
this.variableMap = variableMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -42,11 +39,12 @@ public class ExpressionConditionCmd implements Command<Boolean>, Serializable {
|
||||
Expression expression = processEngineConfiguration.getExpressionManager().createExpression(this.exp);
|
||||
ExecutionEntity executionEntity;
|
||||
if (StringUtils.isNotBlank(this.processInstanceId)) {
|
||||
executionEntity =
|
||||
(ExecutionEntity) runtimeService.createProcessInstanceQuery().processInstanceId(this.processInstanceId).includeProcessVariables().singleResult();
|
||||
executionEntity = (ExecutionEntity) runtimeService.createProcessInstanceQuery()
|
||||
.processInstanceId(this.processInstanceId).includeProcessVariables().singleResult();
|
||||
} else {
|
||||
executionEntity = new ExecutionEntityImpl();
|
||||
executionEntity.setVariables(variableMap);
|
||||
// 不能单纯的 new ExecutionEntityImpl, 后续在调用 setVariables 时,
|
||||
// 引擎用了很多 ExecutionEntityImpl 的其他属性,这些属性都是在 new 不会自动生成的
|
||||
throw new WorkflowEngineException(ENGINE_EXECUTION_LOST_ID_ERROR);
|
||||
}
|
||||
Object value = expression.getValue(executionEntity);
|
||||
return value != null && "true".equals(value.toString());
|
||||
|
||||
@ -1,15 +1,19 @@
|
||||
package cn.axzo.workflow.core.service.support;
|
||||
|
||||
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.core.service.support.forecast.AbstractForecast;
|
||||
import cn.axzo.workflow.core.service.support.forecast.Forecast;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.StartEvent;
|
||||
import org.flowable.engine.RepositoryService;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
@ -20,11 +24,13 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static cn.axzo.workflow.core.common.enums.BpmErrorCode.PROCESS_INSTANCE_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* 审批实例的运行节点预测/推断
|
||||
* <p>
|
||||
* 一个流程定义中所有的节点都是 FlowElement 类型,而 FlowElement 是引擎中的一个基类, 如果要完整推测审批流程执行顺序不亚于重写一套流程执行引擎
|
||||
* 所以这里仅按照业务所需的节点类型进行处理.
|
||||
* 所以这里仅按照业务所需的节点类型进行处理.并且每个节点都未处理出口是多个的情况,目前仅支持单出口!
|
||||
* <p>
|
||||
* 全量的接入类型如下:
|
||||
* <pre>
|
||||
@ -84,25 +90,33 @@ import java.util.Optional;
|
||||
@Service
|
||||
public class FlowNodeForecastService implements InitializingBean {
|
||||
|
||||
public final static Map<Class, AbstractForecast> FORECAST_MAP = new HashMap<>();
|
||||
public final static Map<Class<?>, AbstractForecast<? extends FlowElement>> FORECAST_MAP = new HashMap<>();
|
||||
@Resource
|
||||
private RepositoryService repositoryService;
|
||||
@Resource
|
||||
private List<Forecast> forecasts;
|
||||
private RuntimeService runtimeService;
|
||||
@Resource
|
||||
private List<Forecast<? extends FlowElement>> forecasts;
|
||||
|
||||
/**
|
||||
* 执行流程预测
|
||||
* 执行运行中的流程预测
|
||||
* <p>
|
||||
* 某个实例的 bpmnModel 可以通过该方式得到:
|
||||
* <pre>
|
||||
* HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||
* BpmnModel bpmnModel = repositoryService.getBpmnModel(instance.getProcessDefinitionId());
|
||||
* </pre>
|
||||
* 已完成的流程可以直接查询流程审批记录就行
|
||||
*
|
||||
* @param bpmnModel 指定流程定义配置元数据
|
||||
* @param variableMap 指定流程实例的全量变量表
|
||||
* @param processInstanceId 指定运行时的流程实例 ID
|
||||
*/
|
||||
public List<FlowElement> performProcessForecasting(BpmnModel bpmnModel, Map<String, Object> variableMap) {
|
||||
public List<FlowElement> performProcessForecasting(String processInstanceId) {
|
||||
if (!StringUtils.hasLength(processInstanceId)) {
|
||||
throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS);
|
||||
}
|
||||
|
||||
ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId)
|
||||
.includeProcessVariables().singleResult();
|
||||
if (Objects.isNull(instance)) {
|
||||
throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS);
|
||||
}
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(instance.getProcessDefinitionId());
|
||||
|
||||
// 保持推测出来的节点执行顺序的容器
|
||||
List<FlowElement> orderNodes = new ArrayList<>();
|
||||
// 流程定义中所有的FlowElement
|
||||
@ -113,17 +127,17 @@ public class FlowNodeForecastService implements InitializingBean {
|
||||
addOrderFlowNodes(orderNodes, startNode);
|
||||
});
|
||||
|
||||
startForecasting(orderNodes, variableMap);
|
||||
startForecasting(orderNodes, instance);
|
||||
return orderNodes;
|
||||
}
|
||||
|
||||
private void startForecasting(List<FlowElement> orderNodes, Map<String, Object> variableMap) {
|
||||
private void startForecasting(List<FlowElement> orderNodes, ProcessInstance instance) {
|
||||
getLastNode(orderNodes).ifPresent(flowElement -> forecasts.forEach(i -> {
|
||||
if (i.support(flowElement)) {
|
||||
List<FlowElement> list = i.nextFlowElement(flowElement, variableMap);
|
||||
List<FlowElement> list = i.nextFlowElement(flowElement, instance);
|
||||
if (!CollectionUtils.isEmpty(list)) {
|
||||
addOrderFlowNodes(orderNodes, list.get(0));
|
||||
startForecasting(orderNodes, variableMap);
|
||||
startForecasting(orderNodes, instance);
|
||||
}
|
||||
}
|
||||
}));
|
||||
@ -162,7 +176,7 @@ public class FlowNodeForecastService implements InitializingBean {
|
||||
forecasts.forEach(i -> {
|
||||
Class<?> rawClass = ResolvableType.forClass(i.getClass(), Forecast.class)
|
||||
.getSuperType().getGenerics()[0].getRawClass();
|
||||
FORECAST_MAP.put(rawClass, (AbstractForecast) i);
|
||||
FORECAST_MAP.put(rawClass, (AbstractForecast<? extends FlowElement>) i);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
package cn.axzo.workflow.core.service.support.forecast;
|
||||
|
||||
import cn.axzo.workflow.core.service.support.forecast.impl.SequenceFlowForecasting;
|
||||
import cn.axzo.workflow.core.service.support.spring.FlowableConditionEvaluatorAware;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -13,7 +16,7 @@ import java.util.stream.Collectors;
|
||||
import static cn.axzo.workflow.core.service.support.FlowNodeForecastService.FORECAST_MAP;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* 抽象的流程预测
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/10/10 10:55
|
||||
@ -22,48 +25,33 @@ public abstract class AbstractForecast<T extends FlowElement> implements Forecas
|
||||
|
||||
private FlowableConditionEvaluator conditionEvaluator;
|
||||
|
||||
/**
|
||||
* 将节点来源强制转换成目标节点类型
|
||||
*
|
||||
* @param sourceFlowElements
|
||||
* @return
|
||||
*/
|
||||
private List<T> cast(List<FlowElement> sourceFlowElements) {
|
||||
if (CollectionUtils.isEmpty(sourceFlowElements)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<T> convertList = new ArrayList<>(sourceFlowElements.size());
|
||||
sourceFlowElements.forEach(i -> convertList.add((T) i));
|
||||
return convertList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<FlowElement> nextFlowElement(FlowElement sourceFlowElement, Map<String, Object> variableMap) {
|
||||
return forecastNextNodes(getOutgoing((T) sourceFlowElement), variableMap);
|
||||
public final List<FlowElement> nextFlowElement(FlowElement sourceFlowElement, ProcessInstance instance) {
|
||||
return forecastNextNodes(getOutgoing((T) sourceFlowElement), instance);
|
||||
}
|
||||
|
||||
protected abstract List<? extends FlowElement> getOutgoing(T flowElement);
|
||||
|
||||
/**
|
||||
* 计算出口节点,此时的入参 sourceFlowElement 已经不等会泛型类
|
||||
* 计算出口节点,此时的入参 sourceFlowElement 已经不等于泛型类
|
||||
*
|
||||
* @param sourceFlowElements 当前节点的出口节点集合
|
||||
* @param variableMap 流程实例变量
|
||||
* @param instance 流程实例
|
||||
* @return
|
||||
*/
|
||||
protected final List<FlowElement> forecastNextNodes(List<? extends FlowElement> sourceFlowElements, Map<String
|
||||
, Object> variableMap) {
|
||||
private List<FlowElement> forecastNextNodes(List<? extends FlowElement> sourceFlowElements,
|
||||
ProcessInstance instance) {
|
||||
if (CollectionUtils.isEmpty(sourceFlowElements)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Map<? extends Class<? extends FlowElement>, ? extends List<? extends FlowElement>> elementGroup =
|
||||
Map<Class<? extends FlowElement>, List<FlowElement>> elementGroup =
|
||||
sourceFlowElements.stream().collect(Collectors.groupingBy(FlowElement::getClass, Collectors.toList()));
|
||||
|
||||
List result = new ArrayList();
|
||||
List<FlowElement> result = new ArrayList<>();
|
||||
elementGroup.forEach((k, v) -> {
|
||||
AbstractForecast forecast = FORECAST_MAP.get(k);
|
||||
if (Objects.nonNull(forecast)) {
|
||||
result.addAll(forecast.calcRealOutgoingNodes(v, variableMap));
|
||||
result.addAll(forecast.calcRealOutgoingNodes(v, instance));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
@ -73,10 +61,10 @@ public abstract class AbstractForecast<T extends FlowElement> implements Forecas
|
||||
* 由于每个节点的下级节点是多个,且有可能是不同类型, 在预测下级节点时,需要将同类型的节点传递给对应类型的预测器来计算
|
||||
*
|
||||
* @param flowElements
|
||||
* @param variableMap
|
||||
* @param instance
|
||||
* @return
|
||||
*/
|
||||
public List<? extends FlowElement> calcRealOutgoingNodes(List<T> flowElements, Map<String, Object> variableMap) {
|
||||
public List<? extends FlowElement> calcRealOutgoingNodes(List<T> flowElements, ProcessInstance instance) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@ -85,7 +73,15 @@ public abstract class AbstractForecast<T extends FlowElement> implements Forecas
|
||||
this.conditionEvaluator = conditionEvaluator;
|
||||
}
|
||||
|
||||
protected final Boolean conditionOn(String exp, Map<String, Object> variableMap) {
|
||||
return conditionEvaluator.conditionOn(exp, variableMap);
|
||||
/**
|
||||
* 提供给所有实现类的通用调用引擎评估节点可能存在的条件表达式
|
||||
*
|
||||
* @param exp 表达式
|
||||
* @param processInstanceId 实例 ID
|
||||
* @return
|
||||
* @see SequenceFlowForecasting#calcRealOutgoingNodes(List, ProcessInstance) 参考这里的用法
|
||||
*/
|
||||
protected final Boolean conditionOn(String exp, String processInstanceId) {
|
||||
return conditionEvaluator.conditionOn(exp, processInstanceId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,8 +7,6 @@ import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 基于 Flowable 引擎能力的表达式评估器
|
||||
*
|
||||
@ -26,13 +24,14 @@ public class FlowableConditionEvaluator {
|
||||
/**
|
||||
* 计算表达式真假, 需结合引擎能力
|
||||
*
|
||||
* @param exp 条件表达式
|
||||
* @param variables 流程变量
|
||||
* @param exp 条件表达式
|
||||
* @param variables 流程变量
|
||||
* @param processInstanceId 流程实例 ID (可与 variables 参入二选一, 如果都传,则直接用实例 ID 去引擎中查真实的变量表)
|
||||
* @return true Or false
|
||||
*/
|
||||
public Boolean conditionOn(String exp, Map<String, Object> variables) {
|
||||
public Boolean conditionOn(String exp, String processInstanceId) {
|
||||
return managementService.executeCommand(new ExpressionConditionCmd(runtimeService,
|
||||
processEngineConfiguration, null, exp, variables));
|
||||
processEngineConfiguration, processInstanceId, exp));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package cn.axzo.workflow.core.service.support.forecast;
|
||||
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程节点顺序预测接口
|
||||
@ -19,7 +19,7 @@ public interface Forecast<T extends FlowElement> {
|
||||
* @param t Flowable 的子类
|
||||
* @return
|
||||
*/
|
||||
Boolean support(FlowElement t);
|
||||
Boolean support(FlowElement flowElement);
|
||||
|
||||
/**
|
||||
* 通过给定的源 FlowElement 结合 Flowable 的条件评估器去计算符合条件的下一级节点
|
||||
@ -27,9 +27,9 @@ public interface Forecast<T extends FlowElement> {
|
||||
* 由于标准的 BPMN 协议中很多节点都是允许多条路并行走的, 所以接口返回模型定义为 List 集合,
|
||||
* 但实际上, 按照现在的业务定义, 只允许存在 0 或 1 个下一级节点.
|
||||
*
|
||||
* @param sourceFlowElement 上级节点
|
||||
* @param variableMap 流程运行实例的完全变量
|
||||
* @param sourceFlowElement 当前节点, 实现类中该方法则是通过 getOutgoing 获取出口节点集合, 并调用对应类型中的 calcRealOutgoingNodes 查找真正的下级节点
|
||||
* @param instance 流程运行实例
|
||||
* @return
|
||||
*/
|
||||
List<FlowElement> nextFlowElement(FlowElement sourceFlowElement, Map<String, Object> variableMap);
|
||||
List<FlowElement> nextFlowElement(FlowElement sourceFlowElement, ProcessInstance instance);
|
||||
}
|
||||
|
||||
@ -3,15 +3,15 @@ package cn.axzo.workflow.core.service.support.forecast.impl;
|
||||
import cn.axzo.workflow.core.service.support.forecast.AbstractForecast;
|
||||
import org.flowable.bpmn.model.EndEvent;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* 结束节点
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/10/10 18:58
|
||||
@ -29,11 +29,10 @@ public class EndEventForecasting extends AbstractForecast<EndEvent> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends FlowElement> calcRealOutgoingNodes(List<EndEvent> flowElements,
|
||||
Map<String, Object> variableMap) {
|
||||
public List<? extends FlowElement> calcRealOutgoingNodes(List<EndEvent> flowElements, ProcessInstance instance) {
|
||||
if (CollectionUtils.isEmpty(flowElements)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return super.calcRealOutgoingNodes(flowElements, variableMap);
|
||||
return super.calcRealOutgoingNodes(flowElements, instance);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
package cn.axzo.workflow.core.service.support.forecast.impl;
|
||||
|
||||
import cn.axzo.workflow.core.service.support.forecast.AbstractForecast;
|
||||
import org.flowable.bpmn.model.ExclusiveGateway;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 排他网关
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/10/11 09:57
|
||||
*/
|
||||
@Component
|
||||
public class ExclusiveGatewayForecasting extends AbstractForecast<ExclusiveGateway> {
|
||||
@Override
|
||||
public Boolean support(FlowElement flowElement) {
|
||||
return flowElement instanceof ExclusiveGateway;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<? extends FlowElement> getOutgoing(ExclusiveGateway flowElement) {
|
||||
return flowElement.getOutgoingFlows();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends FlowElement> calcRealOutgoingNodes(List<ExclusiveGateway> flowElements,
|
||||
ProcessInstance instance) {
|
||||
if (CollectionUtils.isEmpty(flowElements)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (flowElements.size() == 1) {
|
||||
return flowElements;
|
||||
}
|
||||
return super.calcRealOutgoingNodes(flowElements, instance);
|
||||
}
|
||||
}
|
||||
@ -4,13 +4,13 @@ import cn.axzo.workflow.core.service.support.forecast.AbstractForecast;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.SequenceFlow;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -34,7 +34,7 @@ public class SequenceFlowForecasting extends AbstractForecast<SequenceFlow> {
|
||||
|
||||
@Override
|
||||
public List<? extends FlowElement> calcRealOutgoingNodes(List<SequenceFlow> flowElements,
|
||||
Map<String, Object> variableMap) {
|
||||
ProcessInstance instance) {
|
||||
if (CollectionUtils.isEmpty(flowElements)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@ -42,7 +42,7 @@ public class SequenceFlowForecasting extends AbstractForecast<SequenceFlow> {
|
||||
// 评估顺序流集合中条件为 true 的顺序流
|
||||
List<SequenceFlow> executableFlows =
|
||||
flowElements.stream().filter(i -> StringUtils.hasLength(i.getConditionExpression()))
|
||||
.filter(i -> conditionOn(i.getConditionExpression(), variableMap)).collect(Collectors.toList());
|
||||
.filter(i -> conditionOn(i.getConditionExpression(), instance.getId())).collect(Collectors.toList());
|
||||
if (!CollectionUtils.isEmpty(executableFlows) && executableFlows.size() == 1) {
|
||||
return Lists.newArrayList(executableFlows.get(0));
|
||||
}
|
||||
@ -53,6 +53,6 @@ public class SequenceFlowForecasting extends AbstractForecast<SequenceFlow> {
|
||||
if (!CollectionUtils.isEmpty(defaultFlows) && defaultFlows.size() == 1) {
|
||||
return Lists.newArrayList(defaultFlows.get(0));
|
||||
}
|
||||
return super.calcRealOutgoingNodes(flowElements, variableMap);
|
||||
return super.calcRealOutgoingNodes(flowElements, instance);
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,5 +26,4 @@ public class StartEventForecasting extends AbstractForecast<StartEvent> {
|
||||
return flowElement.getOutgoingFlows();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -3,12 +3,12 @@ package cn.axzo.workflow.core.service.support.forecast.impl;
|
||||
import cn.axzo.workflow.core.service.support.forecast.AbstractForecast;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 用户任务节点预测
|
||||
@ -29,14 +29,13 @@ public class UserTaskForecasting extends AbstractForecast<UserTask> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends FlowElement> calcRealOutgoingNodes(List<UserTask> flowElements,
|
||||
Map<String, Object> variableMap) {
|
||||
public List<? extends FlowElement> calcRealOutgoingNodes(List<UserTask> flowElements, ProcessInstance instance) {
|
||||
if (CollectionUtils.isEmpty(flowElements)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (flowElements.size() == 1) {
|
||||
return flowElements;
|
||||
}
|
||||
return super.calcRealOutgoingNodes(flowElements, variableMap);
|
||||
return super.calcRealOutgoingNodes(flowElements, instance);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
package cn.axzo.workflow.core.service.support.forecast;
|
||||
package cn.axzo.workflow.core.service.support.spring;
|
||||
|
||||
import cn.axzo.workflow.core.service.support.forecast.FlowableConditionEvaluator;
|
||||
|
||||
/**
|
||||
* 按照 Spring 规范提供一个 Flowable Condition Evaluator 的 Aware
|
||||
@ -0,0 +1,28 @@
|
||||
package cn.axzo.workflow.core.service.support.spring;
|
||||
|
||||
import cn.axzo.workflow.core.service.support.forecast.FlowableConditionEvaluator;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 自定义的 Aware 模式的接口处理类
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/10/11 10:23
|
||||
*/
|
||||
@Component
|
||||
public class FlowableConditionEvaluatorAwareProcessor implements BeanPostProcessor {
|
||||
|
||||
private final FlowableConditionEvaluator conditionEvaluator;
|
||||
|
||||
public FlowableConditionEvaluatorAwareProcessor(FlowableConditionEvaluator conditionEvaluator) {this.conditionEvaluator = conditionEvaluator;}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof FlowableConditionEvaluatorAware) {
|
||||
((FlowableConditionEvaluatorAware) bean).setConditionEvaluator(conditionEvaluator);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
@ -2,11 +2,9 @@ package cn.axzo.workflow.server.controller.web;
|
||||
|
||||
import cn.axzo.workflow.core.service.support.FlowNodeForecastService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.engine.HistoryService;
|
||||
import org.flowable.engine.RepositoryService;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -37,11 +35,8 @@ public class TestController {
|
||||
|
||||
@GetMapping("/test")
|
||||
public void test(@RequestParam String processInstanceId) {
|
||||
HistoricProcessInstance instance =
|
||||
historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(instance.getProcessDefinitionId());
|
||||
List<FlowElement> flowElements = forecastService.performProcessForecasting(bpmnModel,
|
||||
instance.getProcessVariables());
|
||||
|
||||
List<FlowElement> flowElements = forecastService.performProcessForecasting(processInstanceId);
|
||||
|
||||
System.out.println("flowElements = " + flowElements);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user