用过activiti的同学都知道,activiti对于跳转,撤回,重置这些操作并没有很好的支持,
本人苦苦研究多日,终于写出了一个万能的Command.
copy前必看:
1.代码中有涉及的枚举类,这里没有贴出,自行脑补
2.代码中有很详细的注释,这里不再赘述实现方法
3.逻辑大概为:
1)进行跳转,撤回,重置时,需要先查询出流程中要跳转到的目标节点后的所有节点list->toDealTaskDefIdList
2)处理进行中的任务,修改进行中的任务的相关表数据(变量表:act_ru_variable,执行表:act_ru_execution)
3)处理已完成的任务,修改已完成的任务的相关表数据(变量表:act_ru_variable,执行表:act_ru_execution,历史动作表:act_hi_actinst)
4)设置要跳转到的节点的执行人,变量等,然后交给activiti引擎流转
话不多说,直接上代码:
public class Jump2FrontTargetFlowNodeCommand implements Command<Void> {
//流程实例Id
private final String processInstanceId;
//要跳转到的目标节点们后面所有的节点
private List<String> toDealTaskDefIdList;
//跳转的原因,动作,比如本步骤撤销,审核拒绝,撤回到上面某一步
private String action;
//要跳转到的目标节点列表
private List<String> targetFlowNodeIdList;
private Map assigneeMap;
//目标节点的类型,如果是会签这种多个执行人的节点为"multi",如果是正常的单个执行人的节点为"single"
private String targetFlowNodeType;
//bpmnModel
private BpmnModel bpmnModel;
private RuntimeService runtimeService;
/**
* 保存撤回节点的变量map
*/
private Map<String, List<VariableInstanceEntity>> varMap = new ConcurrentHashMap<>();
public Jump2FrontTargetFlowNodeCommand(String processInstanceId, List<String> toDealTaskDefIdList,
List<String> targetFlowNodeIdList, Map assigneeMap,
String targetFlowNodeType,
BpmnModel bpmnModel, String action,
RuntimeService runtimeService) {
this.processInstanceId = processInstanceId;
this.bpmnModel = bpmnModel;
this.action = action;
this.toDealTaskDefIdList = toDealTaskDefIdList;
this.targetFlowNodeIdList = targetFlowNodeIdList;
this.assigneeMap = assigneeMap;
this.targetFlowNodeType = targetFlowNodeType;
this.runtimeService = runtimeService;
}
@Override
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
// 处理进行中的任务
handleDoingTask(commandContext);
// 处理已经完成的任务
handleCompletedTask(commandContext);
targetFlowNodeIdList.forEach(targetId -> {
UserTask userTask = (UserTask) bpmnModel.getFlowElement(targetId);
// 创建子执行流,开启任务
ExecutionEntity processExecution = executionEntityManager.findById(processInstanceId);
ExecutionEntity childExecution = executionEntityManager.createChildExecution(processExecution);
childExecution.setCurrentFlowElement(userTask);
// 设置执行变量
VariableInstanceEntityManager variableManager = commandContext.getVariableInstanceEntityManager();
List<VariableInstanceEntity> variableInstanceEntities = varMap.get(userTask.getId());
if (CollectionUtil.isNotEmpty(variableInstanceEntities)) {
variableInstanceEntities.forEach(var -> {
var.setExecution(childExecution);
variableManager.insert(var);
});
}
//设置执行人
targetFlowNodeIdList.forEach(stepId ->{
if(assigneeMap.get(stepId) != null){
String assigneeStr = assigneeMap.get(stepId).toString();
//设置执行人,如果是多人的,参数应该传list
if(CommonEnum.NODE_ASSIGNEE_MULTI.getValue().equals(targetFlowNodeType)){
List<String> assigneeList = CommonUtil.strToList(assigneeStr);
childExecution.setVariable(stepId, assigneeList);
}else if(CommonEnum.NODE_ASSIGNEE_SINGLE.getValue().equals(targetFlowNodeType)){
childExecution.setVariable(stepId, assigneeStr);
}
}
});
commandContext.getExecutionEntityManager().insert(childExecution);
// 交给activiti流转
commandContext.getAgenda().planContinueProcessOperation(childExecution);
});
return null;
}
private void handleCompletedTask(CommandContext commandContext) {
HistoricTaskInstanceEntityManager historicTaskManager = commandContext.getHistoricTaskInstanceEntityManager();
VariableInstanceEntityManager variableInstanceEntityManager = commandContext.getVariableInstanceEntityManager();
ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
List<String> deleteExecutionIdList = new ArrayList<>();
for (String str : toDealTaskDefIdList) {
HistoricActivityInstanceQueryImpl query =
new HistoricActivityInstanceQueryImpl().activityId(str).processInstanceId(processInstanceId);
List<HistoricActivityInstance> activityInstances =
commandContext.getHistoricActivityInstanceEntityManager().findHistoricActivityInstancesByQueryCriteria(query, new Page(0, Integer.MAX_VALUE));
for (HistoricActivityInstance activity : activityInstances) {
HistoricActivityInstanceEntity activityEntity = (HistoricActivityInstanceEntity) activity;
//删除act_ru_execution表
ExecutionEntity executionEntity = executionEntityManager.findById(activity.getExecutionId());
//删除父Execution时,好像会自动删除他的子Execution,这里如果不加判断,到了删除子Execution时,就会报乐观锁异常,所以,
//每删除一个Execution,找出他的子Execution,这些子Execution不在进行删除
if(executionEntity!=null&&(deleteExecutionIdList.size()==0||!deleteExecutionIdList.contains(executionEntity.getId()))){
//因为外键约束,首先要删除variable表中的execution相关数据
List<VariableInstanceEntity> variableInstances =
variableInstanceEntityManager.findVariableInstancesByExecutionId(executionEntity.getId());
varMap.put(executionEntity.getActivityId(), variableInstances);
variableInstances.forEach(variableInstanceEntityManager::delete);
executionEntityManager.delete(executionEntity);
List<ExecutionEntity> childExecutions =
executionEntityManager.findChildExecutionsByParentExecutionId(executionEntity.getId());
deleteExecutionIdList.addAll(childExecutions.stream().map(ExecutionEntity::getId).collect(Collectors.toList()));
}
//删除act_hi_actinst表
activityEntity.setDeleted(true);
activityEntity.setDeleteReason(action);
commandContext.getHistoricActivityInstanceEntityManager().update(activityEntity);
historicTaskManager.delete(activity.getTaskId());
}
}
}
private void handleDoingTask(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
HistoricTaskInstanceEntityManager historicTaskManager = commandContext.getHistoricTaskInstanceEntityManager();
VariableInstanceEntityManager variableManager = commandContext.getVariableInstanceEntityManager();
for (String str : toDealTaskDefIdList) {
List<Execution> executionEntities = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).activityId(str).list();
for (Execution parentExecution : executionEntities) {
//关闭未完成的任务执行流
List<ExecutionEntity> childExecutions =
executionEntityManager.findChildExecutionsByParentExecutionId(parentExecution.getId());
for (ExecutionEntity childExecution : childExecutions) {
//因为外键约束,首先要删除variable表中的execution相关数据
List<VariableInstanceEntity> variableInstances =
variableManager.findVariableInstancesByExecutionId(childExecution.getId());
varMap.put(parentExecution.getActivityId(), variableInstances);
variableInstances.forEach(variableManager::delete);
executionEntityManager.deleteExecutionAndRelatedData(childExecution, action, false);
// 删除历史实例
HistoricTaskInstanceQueryImpl query = new HistoricTaskInstanceQueryImpl().executionId(childExecution.getId()).processInstanceId(processInstanceId);
List<HistoricTaskInstance> historicTaskInstancesByQueryCriteria =
historicTaskManager.findHistoricTaskInstancesByQueryCriteria(query);
if (CollectionUtil.isNotEmpty(historicTaskInstancesByQueryCriteria)) {
for (HistoricTaskInstance historicTaskInstancesByQueryCriterion :
historicTaskInstancesByQueryCriteria) {
commandContext.getHistoricTaskInstanceEntityManager().delete(historicTaskInstancesByQueryCriterion.getId());
}
}
}
//父执行流关闭
List<VariableInstanceEntity> variableInstances =
variableManager.findVariableInstancesByExecutionId(parentExecution.getId());
varMap.put(parentExecution.getActivityId(), variableInstances);
variableInstances.forEach(variableManager::delete);
ExecutionEntity parentExecution1 = (ExecutionEntity) parentExecution;
executionEntityManager.deleteExecutionAndRelatedData(parentExecution1, action, false);
}
}
}
}
什么?还不知道怎样用Command类,不要慌,这就告诉你:
managementService.executeCommand(new Jump2FrontTargetFlowNodeCommand("这里补充所需参数即可");
写在最后:
activiti对流程的回退确实没有很好的支持,但是如果对它了解的够深,你就会发现,它是提供了很多工具类和接口来帮助我们实现的,各位看官在实际开发当中,可以对本文的代码多加理解,然后结合自己实际需求,对代码查漏补缺,便可实现万恶的流程回退!
本文介绍了一个自定义的Activiti流程引擎命令,用于实现流程实例中的任务跳转、撤回及重置功能。该命令通过处理进行中及已完成的任务,更新相关数据库表记录,并设置新的执行人及变量。
2021





