Activiti中提供了多实例任务,多实例实在任务节点上添加额外的属性,使任务可以变成多实例,以下节点都可以添加:
- User Task
- Script Task
- Java Service Task
- Web Service Task
- Business Rule Task
- Email Task
- Manual Task
- Receive Task
- (Embedded) Sub-Process
- Call Activity
多实例内置变量
- nrOfInstances:实例总数
- nrOfActiveInstances:当前活动的实例数,对于顺序执行的多实例,值一直为1。
- nrOfCompletedInstances:已经完成实例的数目。
*后台服务基于Springboot2 + Activiti6,整合文章请参考:https://blog.csdn.net/yy756127197/article/details/101211510 不需要流程设计器就排除3,4步骤 *
流程图
流程文件bpmn
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
<process id="multiInstance" name="多实例测试" isExecutable="true">
<startEvent id="startEvent1">startEvent>
<userTask id="task1" name="发起会议" activiti:assignee="admin">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler">modeler:initiator-can-complete>
extensionElements>
userTask>
<sequenceFlow id="sid-AB72BCEE-4568-4240-A4A8-23A79506CAC1" sourceRef="startEvent1" targetRef="task1">sequenceFlow>
<userTask id="task2" name="会议签到" activiti:assignee="${user}">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler">modeler:initiator-can-complete>
extensionElements>
<multiInstanceLoopCharacteristics isSequential="false" activiti:collection="users" activiti:elementVariable="user">
<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.5}completionCondition>
multiInstanceLoopCharacteristics>
userTask>
<sequenceFlow id="sid-98BE643F-B247-46B2-94BA-EA9E06EBD9AC" sourceRef="task1" targetRef="task2">sequenceFlow>
<endEvent id="sid-EA4EA283-C5CF-43C5-8401-E0BF40132529">endEvent>
<sequenceFlow id="sid-BFD094C8-66EC-4ED2-8A35-0100E0B4E8B2" sourceRef="task2" targetRef="sid-EA4EA283-C5CF-43C5-8401-E0BF40132529">sequenceFlow>
process>
<bpmndi:BPMNDiagram id="BPMNDiagram_multiInstance">
<bpmndi:BPMNPlane bpmnElement="multiInstance" id="BPMNPlane_multiInstance">
<bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
<omgdc:Bounds height="30.0" width="30.0" x="210.0" y="195.0">omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task1" id="BPMNShape_task1">
<omgdc:Bounds height="80.0" width="100.0" x="375.0" y="170.0">omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task2" id="BPMNShape_task2">
<omgdc:Bounds height="80.0" width="100.0" x="600.0" y="170.0">omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-EA4EA283-C5CF-43C5-8401-E0BF40132529" id="BPMNShape_sid-EA4EA283-C5CF-43C5-8401-E0BF40132529">
<omgdc:Bounds height="28.0" width="28.0" x="795.0" y="196.0">omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sid-AB72BCEE-4568-4240-A4A8-23A79506CAC1" id="BPMNEdge_sid-AB72BCEE-4568-4240-A4A8-23A79506CAC1">
<omgdi:waypoint x="240.0" y="210.0">omgdi:waypoint>
<omgdi:waypoint x="375.0" y="210.0">omgdi:waypoint>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-98BE643F-B247-46B2-94BA-EA9E06EBD9AC" id="BPMNEdge_sid-98BE643F-B247-46B2-94BA-EA9E06EBD9AC">
<omgdi:waypoint x="475.0" y="210.0">omgdi:waypoint>
<omgdi:waypoint x="600.0" y="210.0">omgdi:waypoint>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-BFD094C8-66EC-4ED2-8A35-0100E0B4E8B2" id="BPMNEdge_sid-BFD094C8-66EC-4ED2-8A35-0100E0B4E8B2">
<omgdi:waypoint x="700.0" y="210.0">omgdi:waypoint>
<omgdi:waypoint x="795.0" y="210.0">omgdi:waypoint>
bpmndi:BPMNEdge>
bpmndi:BPMNPlane>
bpmndi:BPMNDiagram>
definitions>
MultiInstanceTaskTest.java
import com.it.cloud.modules.activiti.service.IActReModelService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 多实例测试
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class MultiInstanceTaskTest {
@Autowired
private IActReModelService actReModelService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
/**
* 部署流程定义
*/
@Test
public void deploy() {
Deployment deployment = repositoryService.createDeployment() // 创建部署
.addClasspathResource("diagrams/multiInstance.bpmn20.xml") // 加载流程资源文件
.name("multiInstance流程") // 流程名称
.deploy(); // 部署
System.out.println("流程部署ID:" + deployment.getId());
System.out.println("流程部署Name:" + deployment.getName());
}
/**
* 启动流程实例
*/
@Test
public void start() {
ProcessInstance pi = runtimeService.startProcessInstanceByKey("multiInstance"); // 流程定义表的KEY字段值
System.out.println("流程实例ID:" + pi.getId());
System.out.println("流程定义ID:" + pi.getProcessDefinitionId());
}
/**
* 查看任务
*/
@Test
public void queryTask() {
List<Task> taskList = taskService.createTaskQuery() // 创建任务查询
.taskAssignee("admin") // 指定某个人
.list();
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());
}
}
/**
* 完成任务
*/
@Test
public void completeTask() {
taskService.complete("42536");
}
/**
* 完成任务2
*/
@Test
public void completeTask2() {
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("users", Arrays.asList("test1,test2,test3,test4".split(",")));
taskService.complete("40005", variables);
}
}
运行deploy(),start()
运行queryTask(),流程运行完服务任务,直接结束
运行completeTask2(),设置变量users
运行completeTask()
运行completeTask(),到达完成条件,流程结束
节点设置
说明:
跟前一个不同的地方在于完成条件,${nrOfCompletedInstances/nrOfInstances >= 0.5 || flag==false}
如果flag变量为false 就直接结束当前节点
流程图
流程文件bpmn
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
<process id="multiInstance-reject" name="多实例一票否决测试" isExecutable="true">
<startEvent id="startEvent1">startEvent>
<userTask id="task1" name="发起会议" activiti:assignee="admin">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler">modeler:initiator-can-complete>
extensionElements>
userTask>
<sequenceFlow id="sid-AB72BCEE-4568-4240-A4A8-23A79506CAC1" sourceRef="startEvent1" targetRef="task1">sequenceFlow>
<userTask id="task2" name="会议签到" activiti:assignee="${user}">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler">modeler:initiator-can-complete>
extensionElements>
<multiInstanceLoopCharacteristics isSequential="false" activiti:collection="users" activiti:elementVariable="user">
<completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.5 || flag==false}completionCondition>
multiInstanceLoopCharacteristics>
userTask>
<sequenceFlow id="sid-98BE643F-B247-46B2-94BA-EA9E06EBD9AC" sourceRef="task1" targetRef="task2">sequenceFlow>
<endEvent id="sid-EA4EA283-C5CF-43C5-8401-E0BF40132529">endEvent>
<sequenceFlow id="sid-BFD094C8-66EC-4ED2-8A35-0100E0B4E8B2" sourceRef="task2" targetRef="sid-EA4EA283-C5CF-43C5-8401-E0BF40132529">sequenceFlow>
process>
<bpmndi:BPMNDiagram id="BPMNDiagram_multiInstance-reject">
<bpmndi:BPMNPlane bpmnElement="multiInstance-reject" id="BPMNPlane_multiInstance-reject">
<bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
<omgdc:Bounds height="30.0" width="30.0" x="210.0" y="195.0">omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task1" id="BPMNShape_task1">
<omgdc:Bounds height="80.0" width="100.0" x="375.0" y="170.0">omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task2" id="BPMNShape_task2">
<omgdc:Bounds height="80.0" width="100.0" x="600.0" y="170.0">omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-EA4EA283-C5CF-43C5-8401-E0BF40132529" id="BPMNShape_sid-EA4EA283-C5CF-43C5-8401-E0BF40132529">
<omgdc:Bounds height="28.0" width="28.0" x="795.0" y="196.0">omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sid-AB72BCEE-4568-4240-A4A8-23A79506CAC1" id="BPMNEdge_sid-AB72BCEE-4568-4240-A4A8-23A79506CAC1">
<omgdi:waypoint x="240.0" y="210.0">omgdi:waypoint>
<omgdi:waypoint x="375.0" y="210.0">omgdi:waypoint>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-98BE643F-B247-46B2-94BA-EA9E06EBD9AC" id="BPMNEdge_sid-98BE643F-B247-46B2-94BA-EA9E06EBD9AC">
<omgdi:waypoint x="475.0" y="210.0">omgdi:waypoint>
<omgdi:waypoint x="600.0" y="210.0">omgdi:waypoint>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-BFD094C8-66EC-4ED2-8A35-0100E0B4E8B2" id="BPMNEdge_sid-BFD094C8-66EC-4ED2-8A35-0100E0B4E8B2">
<omgdi:waypoint x="700.0" y="210.0">omgdi:waypoint>
<omgdi:waypoint x="795.0" y="210.0">omgdi:waypoint>
bpmndi:BPMNEdge>
bpmndi:BPMNPlane>
bpmndi:BPMNDiagram>
definitions>
MultiInstanceRejectTaskTest.java
import com.it.cloud.modules.activiti.service.IActReModelService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 多实例测试
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class MultiInstanceTaskTest {
@Autowired
private IActReModelService actReModelService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
/**
* 部署流程定义
*/
@Test
public void deploy() {
Deployment deployment = repositoryService.createDeployment() // 创建部署
.addClasspathResource("diagrams/multiInstance.bpmn20.xml") // 加载流程资源文件
.name("multiInstance流程") // 流程名称
.deploy(); // 部署
System.out.println("流程部署ID:" + deployment.getId());
System.out.println("流程部署Name:" + deployment.getName());
}
/**
* 启动流程实例
*/
@Test
public void start() {
ProcessInstance pi = runtimeService.startProcessInstanceByKey("multiInstance"); // 流程定义表的KEY字段值
System.out.println("流程实例ID:" + pi.getId());
System.out.println("流程定义ID:" + pi.getProcessDefinitionId());
}
/**
* 查看任务
*/
@Test
public void queryTask() {
List<Task> taskList = taskService.createTaskQuery() // 创建任务查询
.taskAssignee("admin") // 指定某个人
.list();
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());
}
}
/**
* 完成任务
*/
@Test
public void completeTask() {
taskService.complete("42536");
}
/**
* 完成任务2
*/
@Test
public void completeTask2() {
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("users", Arrays.asList("test1,test2,test3,test4".split(",")));
taskService.complete("40005", variables);
}
}
运行deploy(),start()
运行queryTask(),流程运行完服务任务,直接结束
运行completeTask2(),设置变量users
运行completeTask3(), 设置flag=dalse, 到达完成条件,流程结束
效果:
数据表 ACT_RU_TASK
这就实现了一票否决的效果,更多效果,可以设置完成条件来实现
IT-CLOUD-ACTIVITI6
开源项目,持续更新中,喜欢请 Star~
IT-CLOUD :IT服务管理平台,集成基础服务,中间件服务,监控告警服务等。
开源项目,持续更新中,喜欢请 Star~