应用场景
针对activiti中国式需求,实现平行网关回退,部分代码上文有说道,但是上文有个bug(后文称为旧版),就是回退会推进进程,何为推进进程看图
如果使用上文的方法,在c2已经执行完的情况下,b2进行回退给b1,就会出现两个任务同时存在的情况下
原因是因为,在act_ru_execution表有记录并行的任务,当b2和c2完成任务后将推进
这显然是不符合预期的,所以本篇为了解决这个问题,采用了新的回退方式
我把这种方式叫任务跳转
解决思路
activiti在每个正在执行的任务都有一个执行器,即ru_task表(数据表act_ru_task,后面介绍到数据表会省略act_)的数据会与ru_execution有相对应的关系,当前的跳转实现就用到这个执行器,俗话说就是鸠占鹊巢的方法
- 获取当前任务id,获取需要跳转节点id
- 根据任务id获取当前任务对象
- 根据跳转节点id获取节点对象,即(ActivityImpl)
- 创建新的工作流任务,节点使用的是步骤3获取的节点,执行器id使用的是步骤2执行器id
- 删除步骤2的任务已经相关联的数据
与旧版对比
旧版:使用改变节点的去向,然后使用taskService.complete的方法将任务强行回退给指定的节点,然后在恢复节点的去向,这种的如果用在非并行流程其实是没问题的。
新版:使用跳转的方式,不会推动进程,改变的最少,需要删除比较多的数据
核心代码
只展示部分核心代码,完整代码涉及一些隐私,请见谅
创建新的工作流任务代码
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.runtime.AtomicOperation;
public class CreateActivityCmd implements Command<Void> {
private ActivityImpl _activity;
private String _executionId;
public CreateActivityCmd(String executionId, ActivityImpl activity) {
_activity = activity;
_executionId = executionId;
}
@Override
public Void execute(CommandContext commandContext) {
//创建新任务
ExecutionEntity execution = commandContext.getExecutionEntityManager().findExecutionById(_executionId);
execution.setActivity(_activity);
execution.performOperation(AtomicOperation.ACTIVITY_START);
return null;
}
}
跳转代码
@Transactional(rollbackFor = Exception.class)
public void backToAnyTask(String taskId, String backToActivityId, String comment, Map<String, Object> variables, Integer backFlag) {
// 判断是否为多实例任务
if (this.isMultiInstance(taskId)) {
throw new RenException(ErrorCode.REJECT_PROCESS_PARALLEL_ERROR);
}
//创建managementService
ManagementService managementService = ProcessEngines.getDefaultProcessEngine().getManagementService();
// 获取当前任务
TaskEntity currTask = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult();
ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(currTask.getProcessDefinitionId());
if (processDefinitionEntity == null) {
throw new RenException(ErrorCode.NONE_EXIST_PROCESS);
}
List<HistoricActivityInstance> backHistoricActivityInstances = historyService
.createHistoricActivityInstanceQuery().activityType("userTask")
.processInstanceId(currTask.getProcessInstanceId())
.finished()
.activityId(backToActivityId).list();
if (backHistoricActivityInstances == null || backHistoricActivityInstances.isEmpty()) {
throw new RuntimeException("不存在activity:" + backToActivityId);
}
//退回活动节点
ActivityImpl backActivity = processDefinitionEntity.findActivity(backToActivityId);
// 并行任务额外操作
//判断是否要删除任务,默认不删除
Boolean isDeleteTask = false;
//用于保存需要删除的执行器的任务
// 判断回退任务是否在并行任务中
List<ActivityImpl> canBackActivitys = new ArrayList<>();
// 如果没有并行网关不用递归
if (modelNodeService.isParallelGatewayInModel(currTask.getProcessDefinitionId())){
this.endActivityCanBackListByParallelGateway(currTask.getTaskDefinitionKey(), processDefinitionEntity, canBackActivitys, backToActivityId);
}
if (canBackActivitys.isEmpty()) {
// 通过historyService获取当前任务
HistoricTaskInstance historicCurrTask = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
this.deleteCanBackActivityByParallelGateway(backToActivityId, processDefinitionEntity, historicCurrTask, canBackActivitys);
isDeleteTask = true;
}
//退回节点的历史任务
List<HistoricTaskInstance> hisTasks = historyService.createHistoricTaskInstanceQuery()
.taskDefinitionKey(backToActivityId)
.processDefinitionId(currTask.getProcessDefinitionId())
.processInstanceId(currTask.getProcessInstanceId())
.orderByHistoricTaskInstanceEndTime().desc()
.list();
//查找并行网关的结束并行网关,并删除执行器
if (isDeleteTask && canBackActivitys.isEmpty() && backFlag != 0) {
this.getParallelGatewayOrderActivity(processDefinitionEntity.findActivity(currTask.getTaskDefinitionKey()),currTask.getProcessInstanceId());
}
// 指向命令进行回退
//创建新工作流任务
managementService.executeCommand(new CreateActivityCmd(currTask.getExecutionId(), backActivity));
//最后再删除原来的任务
this.deleteTask(currTask.getId(), currTask.getExecutionId());
//回退后新任务
Task newTask = taskService.createTaskQuery()
.processInstanceId(currTask.getProcessInstanceId())
.processDefinitionId(currTask.getProcessDefinitionId())
.taskDefinitionKey(backToActivityId)
.singleResult();
taskService.setVariablesLocal(newTask.getId(), variables);
String thisAssigness = "";
for (HistoricTaskInstance hisTask : hisTasks) {
if (!"".equals(hisTask.getAssignee()) && hisTask.getAssignee() != null) {
thisAssigness = hisTask.getAssignee();
break;
}
}
//设置审批人
taskService.setAssignee(newTask.getId(), thisAssigness);
if ( !BACK_FLAG.equals(backFlag)) {
//处理并行回退操作
for (ActivityImpl canBackActivity : canBackActivitys) {
if (isDeleteTask) {
// 并行内部回退至外部需要删除任务
List<Task> deleteTaskList = taskService.createTaskQuery()
.processInstanceId(currTask.getProcessInstanceId())
.processDefinitionId(currTask.getProcessDefinitionId())
.taskDefinitionKey(canBackActivity.getId())
.list();
//删除任务
for (Task deleteTask : deleteTaskList) {
// 包括执行器之类的
this.deleteTaskAll(deleteTask.getId(), deleteTask.getExecutionId());
}
}
}
// 删除回退节点后面的所有节点
this.deleteAllActivityAfterBackActivity(backActivity, currTask.getProcessInstanceId(), currTask.getProcessDefinitionId());
}
}