【Activiti工作流】11.并行网关

上一节我们讲解了排他网关,本节我们来讲解与排他网关类似的模式的一种网关---并行网关。

通过上一篇我们了解,排他网关是对一个事件流向线的分支决策节点,决定着任务的流向。而并行网关除了有分支以外,还有聚合。下面是一个排他网关的图示:

在该流程图中,流程任务首先通过一个节点,进行决策后,分别同时执行两个流程线,然后再归到另一个节点上统一走向结束节点,其中扮演分支和聚合工作的那两个节点,都属于并行网关。

并行网关的特点就是在一个决策点将任务分支,然后同时执行多条任务线,最后再将多条任务线聚合在一起。

下面我们编写一个购物的例子,来对并行网关进行实现。
我们在原来的测试工程中并行网关的实例,首先创建一个名为“parallelGateWay”的Activiti Diagram流程图:


然后进行流程图的绘制,该图模拟了一个网上购物的流程:

这里包括了“开始”、“流程线”、“并行网关”、“用户任务”和“结束节点”。
每个节点的详情如下:








点击空白处,设置整个流程信息:

发现生成了图片信息:


然后我们新建一个测试类“ParallelGateWayTest”对流程进行测试:


首先编写部署流程的测试方法:

package cn.com.parallelGateWay;
import java.io.InputStream;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.junit.Test;

public class ParallelGateWayTest {
	//getDefaultProcessEngine方法内部会自动读取名为activiti.cfg.xml文件的配置信息
	ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
	
	/**部署流程定义*/
	@Test
	public void deploymentProcessDefinition_inputStream(){
		//获得上传文件的输入流
		InputStream inputStreamBpmn=this.getClass().getResourceAsStream("parallelGateWay.bpmn");
		InputStream inputStreamPng=this.getClass().getResourceAsStream("parallelGateWay.png");
		//获取仓库服务,从类路径下完成部署
		RepositoryService repositoryService=processEngine.getRepositoryService();
		DeploymentBuilder deploymentBuilder=repositoryService.createDeployment();//创建一个部署对象
		deploymentBuilder.name("并行网关");//添加部署的名称
		deploymentBuilder.addInputStream("parallelGateWay.bpmn", inputStreamBpmn);
		deploymentBuilder.addInputStream("parallelGateWay.png", inputStreamPng);
		Deployment deployment=deploymentBuilder.deploy();//完成部署
		
		//打印我们的流程信息
		System.out.println("部署Id:"+deployment.getId());
		System.out.println("部署名称Name:"+deployment.getName());
	}
}
部署之后结果:


然后我们编写启动流程的方法:
/**启动流程引擎*/
@Test
public void startProcessInstance(){
	//获取流程启动Service
	RuntimeService runtimeService=processEngine.getRuntimeService();
	//使用流程定义的key,key对应bpmn文件对应的id,
	//(也是act_re_procdef表中对应的KEY_字段),默认是按照最新版本启动
	String processDefinitionkey="parallelGateWayProcess";//流程定义的key就是parallelGateWayProcess
	//获取流程实例对象
	ProcessInstance processInstance=runtimeService.startProcessInstanceByKey(processDefinitionkey);
	System.out.println("流程实例ID:"+processInstance.getId());//流程实例ID
	System.out.println("流程定义ID:"+processInstance.getProcessDefinitionId());//流程定义ID
}
执行流程的启动:

现在重点来了,按照上面的那张流程图,我们此时数据库中流程表中的各表数据情况如何呢?
下面将数据库中有关刚刚启动的“parallelGateWayProcess”流程的信息展示如下:
act_ru_execution(正在执行的执行对象表):

此时有一个流程实例,两个流程对象

act_hi_procinst(流程实例的历史表):

此时有一个开始节点的流程实例为历史

act_ru_task(正在执行的任务表(只有节点式UserTask的时候,该表存在数据)):

此时正在执行的有两个UserTask任务,受理人分别为买家和卖家。

act_hi_taskinst(任务历史表):

此时有4个任务历史,分别是开始节点任务(已经执行完毕),并行网关任务(已经执行完毕),
userTask1(有开始时间,没有确定结束时间),userTask2(有开始时间,没有确定结束时间)。

act_hi_actinst(所有活动节点的历史表):

目前有两个历史节点,分别是userTask1和userTask2,只有开始时间,还没有确定结束时间。

下面我们开始查看买家和卖家的待办任务:
@Test
public void findMyPersonalTask(){
	findTask("买家");
	findTask("卖家");
}
/**查询当前的个人任务(实际就是查询act_ru_task表)*/
public void findTask(String assignee){
	//获取事务Service
	TaskService taskService=processEngine.getTaskService();
	List taskList=taskService.createTaskQuery()//创建任务查询对象
			   .taskAssignee(assignee)//指定个人任务查询,指定办理人
			   .list();//获取该办理人下的事务列表
	
	if(taskList!=null&&taskList.size()>0){
		for(Task task:taskList){
			System.out.println("任务ID:"+task.getId());
			System.out.println("任务名称:"+task.getName());
			System.out.println("任务的创建时间:"+task.getCreateTime());
			System.out.println("任务办理人:"+task.getAssignee());
			System.out.println("流程实例ID:"+task.getProcessInstanceId());
			System.out.println("执行对象ID:"+task.getExecutionId());
			System.out.println("流程定义ID:"+task.getProcessDefinitionId());
			System.out.println("#############################################");
		}
	}
}
查询结果:


首先执行买家的任务:
@Test
public void completeMyPersonalTask(){
	completeTask("3407");//执行买家的任务
}
/**完成我的任务  taskId为执行任务的ID*/
public void completeTask(String taskId){
	TaskService taskService=processEngine.getTaskService();
	taskService.complete(taskId);//完成taskId对应的任务
	System.out.println("完成ID为"+taskId+"的任务");
}

现在act_ru_execution发生了变化,执行对象userTask1被执行完了,开始执行userTask2

而act_hi_procinst记录的是整个流程的情况,目前尚未有变化。

act_ru_task正在执行的任务表中,目前正在执行的是发货和收款的活动,办理人都是卖家

act_hi_taskinst任务历史表中,有一个买家已经办理完毕(有结束时间)的付款任务,和两个卖家还没有执行的(没有结束时间)发货和收款任务:


act_hi_actinst所有活动节点的历史表中记录了三个已经办理完毕的任务,和两个办理中的任务历史:

然后执行卖家的任务:
@Test
public void completeMyPersonalTask(){
	completeTask("3410");//执行卖家的任务
}


/**完成我的任务  taskId为执行任务的ID*/
public void completeTask(String taskId){
	TaskService taskService=processEngine.getTaskService();
	taskService.complete(taskId);//完成taskId对应的任务
	System.out.println("完成ID为"+taskId+"的任务");
}


此时任务节点到这里:


然后分别再次查询买家和卖家的待办任务:
@Test
public void findMyPersonalTask(){
	findTask("买家");
	findTask("卖家");
}


然后我们同时先后执行买家(收货)和卖家(收款)的任务:
@Test
public void completeMyPersonalTask(){
	completeTask("3602");//执行买家收货的任务
	completeTask("3502");//执行卖家收款的任务
}


此时观察act_hi_procinst记录的是整个流程的情况,已经有结束时间,说明流程结束:


然后查看act_hi_actinst所有活动节点的历史表,可以看到该流程一共的历史节点有9个:

但是流程图上只有8个节点,这里怎么会有9个呢?那是因为当两个任务走向第二个并行网关时,由于执行时间上的先后,两个任务各自执行了一个并行网关进行聚合操作。

以上就是并行网关的介绍和实例。有关并行网关的特点如下:
(1)一个流程示例只有一个,执行对象有多个

(2)并行网关的功能是基于进入和外出的顺序流的:
    分支(fork):并行后的所有外出顺序流。为每个顺序流都创建一个并发分支。
    聚合(join):所有到达并行网关,在此等待的进入分支,直到所有进入顺序流的分支都到达之后,流程就会通过汇聚网关。

(3)并行网关的进入和外出都是使用相同节点的标识。

(4)如果同一个并行网关有多个进入和多个外出顺序流,它就同时具有分支和汇聚功能。这时网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支。

(5)并行网关不会解析条件,即使顺序流中定义了条件,也会被忽略。

转载请注明出处:https://blog.csdn.net/acmman/article/details/79681730

你可能感兴趣的:(Activiti工作流)