activity动态加签任意节点

前言

设想这么一种场景,一个流程有3级审批,其中第一级审批完毕后本应该到达二级审批的,但是可能觉得这个流程模板设置的不尽合理,需要再在上面增加一级审批人,即变成4级审批,这个需求该怎么做呢?

按照我们初步的设想,解决办法大概有这么两种思路:

第一,修改流程模板

这是一种大家很容易想到的方法,即重新更新一下流程定义文件,更改审批节点的审批人,所谓直接修改模板。在模板中添加节点以及连线,并修改实例的走向。

第二,修改流程定义对应的缓存数据

即不修改模板,新增的节点与当前需要加签的实例挂钩,关于缓存数据,我们可以先这么理解,即每个流程模板一旦启动一个实例之后,相当于是说在缓存中添加了一个流程定义的副本,这个副本被当前启动的这个流程实例使用,很明显这样做的好处就是,不会影响其他正在运行中的流程实例

需求原型:
activity动态加签任意节点_第1张图片
activity动态加签任意节点_第2张图片

比如说,我们这里的审批存在step1和step2两个审批节点,这时需要新增一个step1_2的节点进来,按照上面的思路,我们无需修改原有的流程定义文件,而是需要动态的构造出一个这样的step1_2的节点,将其加入到正在运行的实例中来,下面通过代码简单的演示一下这个功能的执行步骤

在编写代码之前,我们再次整理一下实现这个功能的具体做法:

  1. 首先从流程定义缓存中获取模板数据,因为流程运转的过程中,需要实时的获取该实例对应的模板数据才能知道该如何流转;
  2. 如果流程定义缓存丢失,则需要重新执行模板的解析工作并将其放置到流程定义缓存中

1、部署和启动流程

	//部署
    public static void main(String[] args) {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment =
                repositoryService.createDeployment().addClasspathResource("process/demo/demo10.bpmn").name("addStep").deploy();
        System.out.println("流程部署的id:" + deployment.getId());
        System.out.println("流程部署的name:" +deployment.getName());
    }

    //启动
    public static void main(String[] args) {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        runtimeService.startProcessInstanceByKey("addStep");
        System.out.println("启动成功");
    }

运行上述代码,观察任务表数据,当前节点为step1
在这里插入图片描述
2、动态添加任务节点

	//测试添加任务节点
    public static void main(String[] args) {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        ManagementService managementService = processEngine.getManagementService();
        String taskId = "2505";
        // 获取当前任务
        TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult();
        System.out.println(taskEntity.getId());
        //获取当前的流程实例对象
        String processDefinitionId = taskEntity.getProcessDefinitionId();
        Process process = managementService.executeCommand(new ProcessGetCmd(processDefinitionId));
        System.out.println(process.getName());
        //构造动态的任务userTask对象
        UserTask userTask = new UserTask();
        userTask.setId("step1_2");
        userTask.setName("新增的任务节点D");
        userTask.setAssignee("zcy");
        //设置userTask的行为类
        userTask.setBehavior(createUserTaskBehavior(userTask,processEngine));
        String targetActivityId = "step2";
        //设置连线信息
        SequenceFlow sequenceFlow = new SequenceFlow();
        sequenceFlow.setId("zcy");
        sequenceFlow.setName("新增连线");
        userTask.setOutgoingFlows(Arrays.asList(sequenceFlow));
        sequenceFlow.setTargetFlowElement(process.getFlowElement(targetActivityId));
        sequenceFlow.setTargetRef(targetActivityId);
        //将任务task和连线添加到process中
        process.addFlowElement(userTask);
        process.addFlowElement(sequenceFlow);
        ProcessDefinitionCacheEntry processDefinitionCacheEntry = managementService
                .executeCommand(new GetProcessDefinitionCacheEntryCmd(processDefinitionId));
        processDefinitionCacheEntry.setProcess(process);
        Process processCache = managementService
                .executeCommand(new GetProcessDefinitionCacheEntryCmd(processDefinitionId)).getProcess();
        System.out.println(processCache);
        managementService.executeCommand(new JumpTestCmd(taskId, "step1_2"));
    }

该方法要完成的事情主要包括如下几点:

1、构造UserTask对象,这个是动态新增的
2、为UserTask添加行为类
3、设置UserTask的出线和指向的新的目标节点
4、将UserTask和连线信息重新设置到process中
5、更新缓存中的process信息

于此同时,我们将该方法中用到的辅助工具类和方法贴出来,方便参考和学习,其实这些都是框架的相关API的应用,熟练了就容易掌握

	//创建任务节点的行为类
    private static UserTaskActivityBehavior createUserTaskBehavior(UserTask userTask,ProcessEngine processEngine) {
        ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl)processEngine.getProcessEngineConfiguration();
        ActivityBehaviorFactory activityBehaviorFactory = processEngineConfiguration.getActivityBehaviorFactory();
        UserTaskActivityBehavior userTaskActivityBehavior = activityBehaviorFactory.createUserTaskActivityBehavior(userTask);
        return userTaskActivityBehavior;
    }

动态获取Process 的类

public class ProcessGetCmd implements Command {

    private String processDefinitionId;
    public ProcessGetCmd(String processDefinitionId){
        this.processDefinitionId=processDefinitionId;
    }

    @Override
    public Process execute(CommandContext commandContext) {
        BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionId);
        Process process = bpmnModel.getProcesses().get(0);
        return process;
    }
}

动态获取ProcessDefinitionCacheEntry的类

public class GetProcessDefinitionCacheEntryCmd  implements Command{
	String processDefinitionId;
	
	public GetProcessDefinitionCacheEntryCmd(String processDefinitionId) {
		this.processDefinitionId = processDefinitionId;
	}

	@Override
	public ProcessDefinitionCacheEntry execute(CommandContext commandContext) {
		DeploymentManager deploymentManager = commandContext.getProcessEngineConfiguration().getDeploymentManager();
		ProcessDefinitionCacheEntry processDefinitionCacheEntry = deploymentManager.getProcessDefinitionCache().get(processDefinitionId);
		return processDefinitionCacheEntry;
	}

}

然后运行上面的main方法,我们观察一下数据库的task表的数据变化,可以发现,这时候,直接从节点1走到了我们新增的任务节点了
activity动态加签任意节点_第3张图片

3、完成新增节点任务的审批

public static void main(String[] args) {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        ManagementService managementService = processEngine.getManagementService();
        String taskId = "5002";
        // 获取当前的任务
        TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult();
        System.out.println(taskEntity);
        String processDefinitionId = taskEntity.getProcessDefinitionId();
        Process process = managementService.executeCommand(new ProcessGetCmd(processDefinitionId));
        System.out.println(process);
        UserTask userTask = new UserTask();
        userTask.setId("step1_2");
        userTask.setName("新增的任务节点D");
        userTask.setAssignee("zcy");
        userTask.setBehavior(createUserTaskBehavior(userTask,processEngine));
        String targetActivityId = "step2";
        SequenceFlow sequenceFlow = new SequenceFlow();
        sequenceFlow.setId("zcy");
        sequenceFlow.setName("新增连线");
        userTask.setOutgoingFlows(Arrays.asList(sequenceFlow));
        sequenceFlow.setTargetFlowElement(process.getFlowElement(targetActivityId));
        sequenceFlow.setTargetRef(targetActivityId);
        process.addFlowElement(userTask);
        process.addFlowElement(sequenceFlow);
        ProcessDefinitionCacheEntry processDefinitionCacheEntry = managementService
                .executeCommand(new GetProcessDefinitionCacheEntryCmd(processDefinitionId));
        processDefinitionCacheEntry.setProcess(process);
        //TODO ---------- 完成任务之前,上面的代码是为了重新更新一下缓存中的process数据,避免报空指针异常
        //TODO 为什么要这么做呢?其实就是确保在当前这个新增节点完成任务的时候强制activity使用的是最新的流程实例对象
        taskService.complete(taskId);
    }

其中有个注意点,在代码中有标注,可以重点关注,运行上面的代码,再次观察任务表的数据,可以看到,新增的节点完成了任务,来到原来的第二个审批节点了,继续向下走的话,可以尝试完成一下任务,这里就不再继续演示了;
在这里插入图片描述

本篇简单介绍了如何使用activity实现动态加签任务节点,其实只要理清了思路也不是很难,希望对看到的同学有用,最后感谢观看!

你可能感兴趣的:(activity)