activiti自由跳转,撤回,重置到任意节点

本文介绍了一个自定义的Activiti流程引擎命令,用于实现流程实例中的任务跳转、撤回及重置功能。该命令通过处理进行中及已完成的任务,更新相关数据库表记录,并设置新的执行人及变量。

用过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对流程的回退确实没有很好的支持,但是如果对它了解的够深,你就会发现,它是提供了很多工具类和接口来帮助我们实现的,各位看官在实际开发当中,可以对本文的代码多加理解,然后结合自己实际需求,对代码查漏补缺,便可实现万恶的流程回退!

评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Despacito、、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值