flowable 流程实例新增临时节点
flowable 流程实例新增临时节点需求目的flowable 自带实现方式结果分析:**解决方案**功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowch
flowable 流程实例新增临时节点
需求目的
最近经常有人问我动态添加节点如何实现呢?所以我整理此文档,希望可以帮助有缘人。
当流程运行中,可能需要临时新增一个节点,并且该节点只对当前流程实例生效。那么flowable是否支持呢,该如何实现呢?接下来我们拭目以待。
比如流程定义为 : A->B->C 现在要改成 A->B->D->C,
flowable 自带实现方式
因为新增临时节点的话一定会涉及调整BpmnModel,因此我们可以从DynamicBpmnService着手,查看其API,果真包含 新增临时节点接口,截图如下:
1. 方法介绍
2. 参数
processInstaceId 流程实例编号
dynamicUserTaskBuilder 动态节点,可以直接new ,对应参数含义如下:
String dynamicUserId = "UserTaskAdd"+UUID.randomUUID().toString().replaceAll("-","");
DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder();
dynamicUserTaskBuilder.setId(dynamicUserId);
dynamicUserTaskBuilder.setName("新增节点1");
dynamicUserTaskBuilder.setAssignee("632511");
-
方法调用
String processInstaceId = "363259926905892864"; String dynamicUserId = "UserTaskAdd"+UUID.randomUUID().toString().replaceAll("-",""); DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder(); dynamicUserTaskBuilder.setId(dynamicUserId); dynamicUserTaskBuilder.setName("新增节点1"); dynamicUserTaskBuilder.setAssignee("632511"); processEngine.getDynamicBpmnService().injectUserTaskInProcessInstance(processInstaceId,dynamicUserTaskBuilder);
-
调用前
-
调用后;
结果分析:
虽然流程实例新增了临时节点,但是在开始节点后新增的,并不符合我们的预期效果。那么,我们可以通过分析源代码,进行改造。
源代码 ;
源代码分析
通过调用 InjectUserTaskInProcessInstanceCmd 命令类,然后在这个命令类中的 updateBpmnProcess 方法修改了 对应的bpmnModel 和 新增了 绘制节点的坐标。
这里会被 createDerivedProcessDefinitionForProcessInstance 所调用的方法将修改后的bpmnModel 重新部署,并更新当前流程实例的 proc_def_id,如下图所示:
解决方案
新增一个CustomInjectUserTaskInProcessInstanceCmd 命令类,在updateBpmnProcess 找到我们要插入节点后,新增 临时节点的 bpmnModel 及 修改后续节点的位置信息,然后通过 processEngine.getManagementService().executeCommand() 执行我们的命令类;
package com.zhenai.oa.flow.core;/**
* Created by Administrator on 2020/4/8.
*/
import com.zhenai.oa.flow.handler.SnowKeyGen;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.cmd.AbstractDynamicInjectionCmd;
import org.flowable.engine.impl.context.Context;
import org.flowable.engine.impl.dynamic.BaseDynamicSubProcessInjectUtil;
import org.flowable.engine.impl.dynamic.DynamicUserTaskBuilder;
import org.flowable.engine.impl.persistence.entity.DeploymentEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.BeanUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* todo:
*
* @author : zhoulin.zhu
* @date : 2020/4/8 14:46
*/
public class CustomInjectUserTaskInProcessInstanceCmd extends AbstractDynamicInjectionCmd implements Command<Void> {
protected String processInstanceId;
protected DynamicUserTaskBuilder dynamicUserTaskBuilder;
protected FlowElement currentFlowElemet;
public CustomInjectUserTaskInProcessInstanceCmd(String processInstanceId, DynamicUserTaskBuilder dynamicUserTaskBuilder, FlowElement currentFlowElemet) {
this.processInstanceId = processInstanceId;
this.dynamicUserTaskBuilder = dynamicUserTaskBuilder;
this.currentFlowElemet = currentFlowElemet;
}
@Override
public Void execute(CommandContext commandContext) {
createDerivedProcessDefinitionForProcessInstance(commandContext, processInstanceId);
return null;
}
@Override
protected void updateBpmnProcess(CommandContext commandContext, Process process,
BpmnModel bpmnModel, ProcessDefinitionEntity originalProcessDefinitionEntity, DeploymentEntity newDeploymentEntity) {
List<StartEvent> startEvents = process.findFlowElementsOfType(StartEvent.class);
StartEvent initialStartEvent = null;
for (StartEvent startEvent : startEvents) {
if (startEvent.getEventDefinitions().size() == 0) {
initialStartEvent = startEvent;
break;
} else if (initialStartEvent == null) {
initialStartEvent = startEvent;
}
}
if(currentFlowElemet != null ){
UserTask userTask = new UserTask();
BeanUtils.copyProperties(currentFlowElemet,userTask);
if (dynamicUserTaskBuilder.getId() != null) {
userTask.setId(dynamicUserTaskBuilder.getId());
} else {
userTask.setId(dynamicUserTaskBuilder.nextTaskId(process.getFlowElementMap()));
}
dynamicUserTaskBuilder.setDynamicTaskId(userTask.getId());
userTask.setName(dynamicUserTaskBuilder.getName());
userTask.setAssignee(dynamicUserTaskBuilder.getAssignee());
UserTask currentFlowElemet = (UserTask) this.currentFlowElemet;
SequenceFlow sequenceFlow = null;
List<SequenceFlow> outgoingFlows = new ArrayList<>();
for (SequenceFlow sequenceFlow1 : currentFlowElemet.getOutgoingFlows()) {
sequenceFlow = new SequenceFlow(userTask.getId(),sequenceFlow1.getTargetRef());
sequenceFlow.setSkipExpression(sequenceFlow1.getSkipExpression());
sequenceFlow.setConditionExpression(sequenceFlow1.getConditionExpression());
sequenceFlow.setExtensionElements(sequenceFlow1.getExtensionElements());
sequenceFlow.setExecutionListeners(sequenceFlow1.getExecutionListeners());
sequenceFlow.setName(sequenceFlow1.getName());
sequenceFlow.setId("seq_"+ new SnowKeyGen().getNextId() );
outgoingFlows.add(sequenceFlow);
//删除原先节点的出线
process.removeFlowElement(sequenceFlow1.getId());
process.addFlowElement(sequenceFlow);
}
List<SequenceFlow> incomingFlows = new ArrayList<>();
SequenceFlow incomingFlow = new SequenceFlow(currentFlowElemet.getId(),userTask.getId());
// 可以设置唯一编号,这里通过雪花算法设置
incomingFlow.setId("seq_"+new SnowKeyGen().getNextId() );
incomingFlows.add(incomingFlow);
process.addFlowElement(incomingFlow);
userTask.setOutgoingFlows(outgoingFlows);
userTask.setIncomingFlows(incomingFlows);
process.addFlowElement(userTask);
//新增坐标 点
GraphicInfo elementGraphicInfo = bpmnModel.getGraphicInfo(currentFlowElemet.getId());
if (elementGraphicInfo != null) {
double yDiff = 0;
double xDiff = 80;
if (elementGraphicInfo.getY() < 173) {
yDiff = 173 - elementGraphicInfo.getY();
elementGraphicInfo.setY(173);
}
Map<String, GraphicInfo> locationMap = bpmnModel.getLocationMap();
for (String locationId : locationMap.keySet()) {
if (initialStartEvent.getId().equals(locationId)) {
continue;
}
GraphicInfo locationGraphicInfo = locationMap.get(locationId);
locationGraphicInfo.setX(locationGraphicInfo.getX() + xDiff);
locationGraphicInfo.setY(locationGraphicInfo.getY() + yDiff);
}
Map<String, List<GraphicInfo>> flowLocationMap = bpmnModel.getFlowLocationMap();
for (String flowId : flowLocationMap.keySet()) {
// if (flowFromStart.getId().equals(flowId)) {
// continue;
// }
List<GraphicInfo> flowGraphicInfoList = flowLocationMap.get(flowId);
for (GraphicInfo flowGraphicInfo : flowGraphicInfoList) {
flowGraphicInfo.setX(flowGraphicInfo.getX() + xDiff);
flowGraphicInfo.setY(flowGraphicInfo.getY() + yDiff);
}
}
/* 以下代码 可以替换以下步骤,推荐使用这种
步骤一: 引入 自动排版jar
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-bpmn-layout</artifactId>
<version>6.4.1</version>
</dependency>
步骤二 调用自动排版方法:
new BpmnAutoLayout(bpmnModel).execute();
*/
/* 手动绘制节点 */
GraphicInfo newTaskGraphicInfo = new GraphicInfo(elementGraphicInfo.getX() + 185, elementGraphicInfo.getY() - 163, 80, 100);
bpmnModel.addGraphicInfo(userTask.getId(), newTaskGraphicInfo);
bpmnModel.addFlowGraphicInfoList(userTask.getId(), createWayPoints(elementGraphicInfo.getX() + 95, elementGraphicInfo.getY() - 5,
elementGraphicInfo.getX() + 95, elementGraphicInfo.getY() - 123, elementGraphicInfo.getX() + 185, elementGraphicInfo.getY() - 123));
List<SequenceFlow> addFlows = new ArrayList<>();
addFlows.addAll(outgoingFlows);
addFlows.addAll(incomingFlows);
/* 绘制连线 */
for(SequenceFlow sequenceFlow1 : addFlows){
bpmnModel.addFlowGraphicInfoList(sequenceFlow1.getId(), createWayPoints(elementGraphicInfo.getX() + 30, elementGraphicInfo.getY() + 15,
elementGraphicInfo.getX() + 75, elementGraphicInfo.getY() + 15));
}
}
} else {
ParallelGateway parallelGateway = new ParallelGateway();
parallelGateway.setId(dynamicUserTaskBuilder.nextForkGatewayId(process.getFlowElementMap()));
process.addFlowElement(parallelGateway);
UserTask userTask = new UserTask();
if (dynamicUserTaskBuilder.getId() != null) {
userTask.setId(dynamicUserTaskBuilder.getId());
} else {
userTask.setId(dynamicUserTaskBuilder.nextTaskId(process.getFlowElementMap()));
}
dynamicUserTaskBuilder.setDynamicTaskId(userTask.getId());
userTask.setName(dynamicUserTaskBuilder.getName());
userTask.setAssignee(dynamicUserTaskBuilder.getAssignee());
process.addFlowElement(userTask);
EndEvent endEvent = new EndEvent();
endEvent.setId(dynamicUserTaskBuilder.nextEndEventId(process.getFlowElementMap()));
process.addFlowElement(endEvent);
SequenceFlow flowToUserTask = new SequenceFlow(parallelGateway.getId(), userTask.getId());
flowToUserTask.setId(dynamicUserTaskBuilder.nextFlowId(process.getFlowElementMap()));
process.addFlowElement(flowToUserTask);
SequenceFlow flowFromUserTask = new SequenceFlow(userTask.getId(), endEvent.getId());
flowFromUserTask.setId(dynamicUserTaskBuilder.nextFlowId(process.getFlowElementMap()));
process.addFlowElement(flowFromUserTask);
SequenceFlow initialFlow = initialStartEvent.getOutgoingFlows().get(0);
initialFlow.setSourceRef(parallelGateway.getId());
SequenceFlow flowFromStart = new SequenceFlow(initialStartEvent.getId(), parallelGateway.getId());
flowFromStart.setId(dynamicUserTaskBuilder.nextFlowId(process.getFlowElementMap()));
process.addFlowElement(flowFromStart);
//跳整节点的布局
GraphicInfo elementGraphicInfo = bpmnModel.getGraphicInfo(initialStartEvent.getId());
if (elementGraphicInfo != null) {
double yDiff = 0;
double xDiff = 80;
if (elementGraphicInfo.getY() < 173) {
yDiff = 173 - elementGraphicInfo.getY();
elementGraphicInfo.setY(173);
}
Map<String, GraphicInfo> locationMap = bpmnModel.getLocationMap();
for (String locationId : locationMap.keySet()) {
if (initialStartEvent.getId().equals(locationId)) {
continue;
}
GraphicInfo locationGraphicInfo = locationMap.get(locationId);
locationGraphicInfo.setX(locationGraphicInfo.getX() + xDiff);
locationGraphicInfo.setY(locationGraphicInfo.getY() + yDiff);
}
Map<String, List<GraphicInfo>> flowLocationMap = bpmnModel.getFlowLocationMap();
for (String flowId : flowLocationMap.keySet()) {
if (flowFromStart.getId().equals(flowId)) {
continue;
}
List<GraphicInfo> flowGraphicInfoList = flowLocationMap.get(flowId);
for (GraphicInfo flowGraphicInfo : flowGraphicInfoList) {
flowGraphicInfo.setX(flowGraphicInfo.getX() + xDiff);
flowGraphicInfo.setY(flowGraphicInfo.getY() + yDiff);
}
}
GraphicInfo forkGraphicInfo = new GraphicInfo(elementGraphicInfo.getX() + 75, elementGraphicInfo.getY() - 5, 40, 40);
bpmnModel.addGraphicInfo(parallelGateway.getId(), forkGraphicInfo);
bpmnModel.addFlowGraphicInfoList(flowFromStart.getId(), createWayPoints(elementGraphicInfo.getX() + 30, elementGraphicInfo.getY() + 15,
elementGraphicInfo.getX() + 75, elementGraphicInfo.getY() + 15));
GraphicInfo newTaskGraphicInfo = new GraphicInfo(elementGraphicInfo.getX() + 185, elementGraphicInfo.getY() - 163, 80, 100);
bpmnModel.addGraphicInfo(userTask.getId(), newTaskGraphicInfo);
bpmnModel.addFlowGraphicInfoList(flowToUserTask.getId(), createWayPoints(elementGraphicInfo.getX() + 95, elementGraphicInfo.getY() - 5,
elementGraphicInfo.getX() + 95, elementGraphicInfo.getY() - 123, elementGraphicInfo.getX() + 185, elementGraphicInfo.getY() - 123));
GraphicInfo endGraphicInfo = new GraphicInfo(elementGraphicInfo.getX() + 335, elementGraphicInfo.getY() - 137, 28, 28);
bpmnModel.addGraphicInfo(endEvent.getId(), endGraphicInfo);
bpmnModel.addFlowGraphicInfoList(flowFromUserTask.getId(), createWayPoints(elementGraphicInfo.getX() + 285, elementGraphicInfo.getY() - 123,
elementGraphicInfo.getX() + 335, elementGraphicInfo.getY() - 123));
}
}
BaseDynamicSubProcessInjectUtil.processFlowElements(commandContext, process, bpmnModel, originalProcessDefinitionEntity, newDeploymentEntity);
}
@Override
protected void updateExecutions(CommandContext commandContext, ProcessDefinitionEntity processDefinitionEntity,
ExecutionEntity processInstance, List<ExecutionEntity> childExecutions) {
ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(commandContext);
List<ExecutionEntity> oldExecution = executionEntityManager.findChildExecutionsByProcessInstanceId(processInstance.getProcessInstanceId());
ExecutionEntity execution = executionEntityManager.createChildExecution(processInstance);
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionEntity.getId());
org.flowable.task.service.TaskService taskService = CommandContextUtil.getTaskService(commandContext);
List<TaskEntity> taskEntities= taskService.findTasksByProcessInstanceId(processInstanceId);
// 删除当前活动任务
for (TaskEntity taskEntity:taskEntities) {
taskEntity.getIdentityLinks().stream().forEach(identityLinkEntity -> {
if(identityLinkEntity.isGroup()){
taskEntity.deleteGroupIdentityLink(identityLinkEntity.getGroupId(),"candidate");
}else{
taskEntity.deleteUserIdentityLink(identityLinkEntity.getUserId(),"participant");
}
});
if(taskEntity.getTaskDefinitionKey().equals(currentFlowElemet.getId())){
taskService.deleteTask(taskEntity,false);
}
}
//设置活动后的节点
UserTask userTask = (UserTask) bpmnModel.getProcessById(processDefinitionEntity.getKey()).getFlowElement(dynamicUserTaskBuilder.getId());
execution.setCurrentFlowElement(userTask);
Context.getAgenda().planContinueProcessOperation(execution);
}
}
- 如何调用
String processInstaceId = "370826427805687808";
String dynamicUserId = "UserTaskAdd"+UUID.randomUUID().toString().replaceAll("-","");
DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder();
dynamicUserTaskBuilder.setId(dynamicUserId);
dynamicUserTaskBuilder.setName("新增节点3");
dynamicUserTaskBuilder.setAssignee("632511");
// Process process = processEngine.getManagementService().executeCommand(new GetProcessCmd("sign_process:3:fdfa56d0-ba81-11e9-94e8-deb024405116"));
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionId);
Process process = bpmnModel.getProcesses().get(0);
try {
processEngine.getManagementService().executeCommand(new CustomInjectUserTaskInProcessInstanceCmd(processInstaceId, dynamicUserTaskBuilder,process.getFlowElement("sid-process-8-2")));
}catch (Exception e){
e.printStackTrace();
}
- 修改后效果
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)