Activiti6.0(十)任务处理人变更(改派)、自由跳转(回退)

目录

一、前言

二、改派实现

三、自由跳转实现

思路1

思路2


一、前言

流程流转时,某个环节的任务处理人变更(即改派)是一种非常常见的需求,本来任务处理人可能是A,但是A因为有事处理不了,管理员需要将该单子改派给B临时处理下。

在中国式流程中,流程的 回退 也是必不可少的,流程流转到某个环节时,处理人一看:咦 这填的都是啥玩意儿,根本不符合要求,想直接打回给上一环节或者走过的任意环节,那么就需要支持回退功能;有时候流程方面还有特殊的需求,比如越级上报,某些处理人权限比较高运行跳过某些环节直接执行,甚至说可以一步走到底,这便依赖Activiti的自由流程

本文就简单介绍下Activiti中如何实现改派和回退。

 

二、改派实现

在实际使用Activiti中,绝大多数公司都是有一套自己的用户管理系统,而且Activiti自身的用户和用户组功能其实也并不能满足部分需求,比如想分配给一个部门、一个角色等等。因此Activiti中的人员信息其实不是那么重要,在我们项目中甚至不会从里面去获取人员信息,仅仅只是设值。Activiti的任务处理人主要是存放在 ACT_RU_TASK 的 ASSIGNEE_ 字段中以及ACT_RU_IDENTITYLINK,前者主要是单个审核人的情况,后者主要是候选人的情况。

其实改派的实现很简单,就是为当前任务重新设置处理人,调用如下方法即可:

taskService.setAssignee("taskId", "userId");

当使用流程变量的方式设置处理人时,在业务上可能是多个处理人或处理组,因此在 ASSIGNEE_ 中存的可能是个用户数组,形如:[a,b,b] 。由于 ASSIGNEE_ 字段是varchar类型且仅为255,因此用户id如果是uuid格式的话,最多只能存储7个...

设置处理人的api还挺多,还有一种方式也行:

taskService.unclaim("taskId");
taskService.claim("taskId", "userId");

该方式与上面的主要区别是,claim方法会去检查当前是否已经有处理人,如果有则会抛错,需要先调用 unclaim 方法。

 

三、自由跳转实现

Activiti6的最大变化便是对代码的重构,其去掉了原先的pvm,直接针对bpmn处理,因此性能上会有些许提升(也没试验过,之前项目中使用的是Activiti5.22,因此原先的自由跳转与6的实现已经完全不一样了,题外话,pvm主要就是负责流程整个运行期的执行、流转等所有运行操作,其所有实现类都在org.activiti.engine.impl.pvm包里,但是6全部移除了...)

Activiti6.0(十)任务处理人变更(改派)、自由跳转(回退)_第1张图片

这里主要演示回退的场景,先看上面的流程图,假设当前任务已经流转到领导审批,领导一看,你这审批信息填的不正确鸭,需要驳回,啪一点,此时流程需回退到审批信息填写环节,如何实现呢?

思路1

在运行过程中,动态修改Activiti的流程定义,修改领导审批环节的出线,使之流转到审批信息填写,在流转完成后再恢领导审批原先的出线(即结束环节),该方式虽然也能实现自由跳转,但是存在并发的问题,假设A点击回退,此时流程定义已经被修改,领导审批的出线已经变为审批信息填写,同时B点击提交,却发现流程流转到了审批信息填写...B说简直见了鬼。因此不可取

思路2

使用执行计划直接指定当前流程实例执行所选环节,由于在并发情况下当前任务的执行id是唯一的,因此该方式也没有带来不安全性,下面基于此实现贴代码:

首先是两个命令,即删除当前任务命令以及执行自由跳转命令:

/**
 * 继承NeedsActiveTaskCmd主要是为了在跳转时要求当前任务不能是挂起状态,也可以直接实现Command接口
 * Created by xujia on 2020/2/10
 */
public class DeleteTaskCmd extends NeedsActiveTaskCmd {

    public DeleteTaskCmd(String taskId){
        super(taskId);
    }

    public String execute(CommandContext commandContext, TaskEntity currentTask){
        TaskEntityManagerImpl taskEntityManager = (TaskEntityManagerImpl)commandContext.getTaskEntityManager();
        // 获取当前任务的执行对象实例
        ExecutionEntity executionEntity = currentTask.getExecution();
        // 删除当前任务,来源任务
        taskEntityManager.deleteTask(currentTask, "jumpReason", false, false);
        // 返回当前任务的执行对象id
        return executionEntity.getId();
    }
    public String getSuspendedTaskException() {
        return "挂起的任务不能跳转";
    }
}

/**
 * 执行自由跳转命令
 * Created by xujia on 2020/2/10
 */
public class SetFLowNodeAndGoCmd implements Command {

    /**
     * 目标节点对象
     */
    private FlowNode flowElement;
    /**
     * 当前任务执行id
     */
    private String executionId;

    public SetFLowNodeAndGoCmd(FlowNode flowElement,String executionId){
        this.flowElement = flowElement;
        this.executionId = executionId;
    }

    public Void execute(CommandContext commandContext){
        // 获取目标节点的来源连线
        List flows = flowElement.getIncomingFlows();
        if(flows==null || flows.size()<1){
            throw new ActivitiException("回退错误,目标节点没有来源连线");
        }
        // 随便选一条目标节点的入线来执行,使当前执行计划为:从所选择的流程线流转到目标节点,实现跳转
        ExecutionEntity executionEntity = commandContext.getExecutionEntityManager().findById(executionId);
        executionEntity.setCurrentFlowElement(flows.get(0));
        commandContext.getAgenda().planTakeOutgoingSequenceFlowsOperation(executionEntity, true);
        return null;
    }
}

然后是调用:

@Test
    public void listTaskTest() {
        // 获取当前任务
        Task currentTask = taskService.createTaskQuery().taskId("132502").singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(currentTask.getProcessDefinitionId());
        // 获取流程定义
        Process process = bpmnModel.getMainProcess();
        // 获取目标节点定义
        FlowNode targetNode = (FlowNode) process.getFlowElement("sid-C24BA4F5-F744-4DD7-8D51-03C3698044D2");

        // 删除当前运行任务,同时返回执行id,该id在并发情况下也是唯一的
        String executionEntityId = managementService.executeCommand(new DeleteTaskCmd(currentTask.getId()));
        // 流程执行到来源节点
        managementService.executeCommand(new SetFLowNodeAndGoCmd(targetNode, executionEntityId));
    }

运行之后就会发现流程直接流转到审批信息填写环节,且处理人也变成原先的处理人,灵活运用可实现多种多样的需求。

你可能感兴趣的:(Activiti工作流,改派,自由跳转,回退)