设想这么一种场景,一个流程有3级审批,其中第一级审批完毕后本应该到达二级审批的,但是可能觉得这个流程模板设置的不尽合理,需要再在上面增加一级审批人,即变成4级审批,这个需求该怎么做呢?
按照我们初步的设想,解决办法大概有这么两种思路:
第一,修改流程模板
这是一种大家很容易想到的方法,即重新更新一下流程定义文件,更改审批节点的审批人,所谓直接修改模板。在模板中添加节点以及连线,并修改实例的走向。
第二,修改流程定义对应的缓存数据
即不修改模板,新增的节点与当前需要加签的实例挂钩,关于缓存数据,我们可以先这么理解,即每个流程模板一旦启动一个实例之后,相当于是说在缓存中添加了一个流程定义的副本,这个副本被当前启动的这个流程实例使用,很明显这样做的好处就是,不会影响其他正在运行中的流程实例
比如说,我们这里的审批存在step1和step2两个审批节点,这时需要新增一个step1_2的节点进来,按照上面的思路,我们无需修改原有的流程定义文件,而是需要动态的构造出一个这样的step1_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走到了我们新增的任务节点了
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实现动态加签任务节点,其实只要理清了思路也不是很难,希望对看到的同学有用,最后感谢观看!