环境
- Activiti 5.22.0
- SpringBoot 2.3.5.RELEASE
- Mysql 5.7.37
概念
- 委托:即初始任务处理人交给他人处理,处理完成后返回初始任务处理人
- 转办:即初始任务处理人交给他人处理,处理完成后不返回初始任务处理人
- 串行:当任务交给多人处理时,多个人按照顺序依次执行
- 并行:当任务交给多人处理时,多个人同时执行
- 会签:当任务交给多人处理时,所有人都必须处理完,才能结束当前节点
- 抢占:当任务交给多人处理时,任务必须已有N个人完成,才可以结束当前节点,一般情况下,N为1
- 监听器:当流程执行到某些步骤时,进行业务处理,常用于自动分配任务处理人、消息推送、更新业务状态等操作
代码实现
// 委托他人
// 委托会修改act_ru_task表,OWNER_为初始任务处理人,ASSIGNEE_为当前任务处理人。如果任务未执行委托操作,则OWNER_为空。
taskService.delegateTask(taskId, userId);
// 完成委托
// 完成委托会修改act_ru_task表,将ASSIGNEE_为OWNER_,即使发生多次委托操作,也会直接修改为初始任务处理人
taskService.resolveTask(taskId);
// 转办
// 实质就是修改act_ru_task表的ASSIGNEE_字段
taskService.setAssignee(taskId, userId);
// 并行和串行
// 流程配置xml文件中,多实例节点multiInstanceLoopCharacteristics有可选isSequential属性。如果没有该属性,则默认为并行。
// isSequential="true" 表示串行
// completionCondition 表示节点完成条件,相关参数如下
// nrOfActiveInstances 当前进行的实例数量,如果时串行,为1,如果并行,则为处理任务的人数
// nrOfInstances 总的实例数量,即处理任务的人数
// nrOfCompletedInstances 已完成的实例数量
// 会签:${nrOfCompletedInstances/nrOfInstances == 1},意思表示:已完成的实例数量 等于 总的实例数量。即所有人都已处理。
// 抢占:${nrOfCompletedInstances == 1},意思表示:已完成的实例数量 等于 1。即已有1个人完成,就算该节点已处理。
// !!!重点!!!:
// 开始和中间环节的任务必须直接使用taskService.complete(taskId)进行处理,否则会报错。
// 但是最后一个处理人,必须带参处理
Map<String, Object> map = new HashMap<>();
map.put("assigneeList", Arrays.asList(userIdA, userIdB));
taskService.complete(taskId, map);
// 如果最后一个处理人不带参处理,则会把上次处理人的集合继续传给下一个节点
// 那么,如何判断是否为最后一个人呢?
taskService.getVariables(taskId);
// 以上即可返回任务处理信息,若nrOfCompletedInstances 等于 nrOfInstances - 1,则表示当前为最后一个处理人
// 监听器
// 在监听器内部如果需要进行人员分配,必须使用delegateExecution.setVariable("assigneeList", Arrays.asList("0202", "0101", "0303"));
@Slf4j
@Component
public class StartExecutionListener implements ExecutionListener {
@Override
@Transactional
public void notify(DelegateExecution delegateExecution) throws Exception {
log.info("StartExecutionListener------start");
delegateExecution.setVariable("assigneeList", Arrays.asList("0202", "0101", "0303"));
log.info("StartExecutionListener---{}---end");
}
}
// delegateExecution.setVariableLocal会导致很多奇奇怪怪的问题,比如Variable assigneeList is not found,又比如处理人和传值不一致等问题
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:activiti="http://activiti.org/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" targetNamespace="http://bpmn.io/schema/bpmn" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
<bpmn2:process id="contract_order_apply" name="contract_order_apply">
<bpmn2:documentation>null</bpmn2:documentation>
<bpmn2:startEvent id="StartEvent_01ydzqe">
<bpmn2:outgoing>Flow_1vfva23</bpmn2:outgoing>
</bpmn2:startEvent>
<bpmn2:userTask id="Activity_1u5vv78" name="营销经理" activiti:assignee="${assignee}" activiti:status="1" activiti:selectedRole="1638731586205618177">
<bpmn2:extensionElements>
<activiti:executionListener expression="" class="fun.gudu.modules.listener.StartExecutionListener" delegateExpression="" event="start" />
<activiti:formProperty id="status" type="string" name="1" />
<activiti:formProperty id="selectedRole" type="string" name="1638731586205618177" />
</bpmn2:extensionElements>
<bpmn2:incoming>Flow_1vfva23</bpmn2:incoming>
<bpmn2:outgoing>Flow_0v1zao7</bpmn2:outgoing>
<bpmn2:multiInstanceLoopCharacteristics isSequential="true" activiti:collection="assigneeList" activiti:elementVariable="assignee">
<bpmn2:completionCondition>${nrOfCompletedInstances == 1}</bpmn2:completionCondition>
</bpmn2:multiInstanceLoopCharacteristics>
</bpmn2:userTask>
<bpmn2:sequenceFlow id="Flow_1vfva23" sourceRef="StartEvent_01ydzqe" targetRef="Activity_1u5vv78" />
<bpmn2:userTask id="Activity_0rgq1wm" name="项目总监" activiti:assignee="${assignee}" activiti:status="2" activiti:selectedRole="1638732409782374401">
<bpmn2:extensionElements>
<activiti:formProperty id="status" type="string" name="2" />
<activiti:formProperty id="selectedRole" type="string" name="1638732409782374401" />
</bpmn2:extensionElements>
<bpmn2:incoming>Flow_0v1zao7</bpmn2:incoming>
<bpmn2:outgoing>Flow_1615yky</bpmn2:outgoing>
<bpmn2:multiInstanceLoopCharacteristics activiti:collection="assigneeList" activiti:elementVariable="assignee">
<bpmn2:completionCondition>${nrOfCompletedInstances/nrOfInstances == 1}</bpmn2:completionCondition>
</bpmn2:multiInstanceLoopCharacteristics>
</bpmn2:userTask>
<bpmn2:sequenceFlow id="Flow_0v1zao7" sourceRef="Activity_1u5vv78" targetRef="Activity_0rgq1wm" />
<bpmn2:userTask id="Activity_0jggib6" name="项目经理" activiti:assignee="${assignee}" activiti:status="3">
<bpmn2:extensionElements>
<activiti:executionListener expression="" class="fun.gudu.modules.listener.SetStatusExecutionListener" delegateExpression="" event="start" />
<activiti:formProperty id="status" type="string" name="3" />
</bpmn2:extensionElements>
<bpmn2:incoming>Flow_1615yky</bpmn2:incoming>
<bpmn2:outgoing>Flow_09rzzh1</bpmn2:outgoing>
<bpmn2:multiInstanceLoopCharacteristics activiti:collection="assigneeList" activiti:elementVariable="assignee">
<bpmn2:completionCondition>${nrOfCompletedInstances/nrOfInstances == 1}</bpmn2:completionCondition>
</bpmn2:multiInstanceLoopCharacteristics>
</bpmn2:userTask>
<bpmn2:sequenceFlow id="Flow_1615yky" sourceRef="Activity_0rgq1wm" targetRef="Activity_0jggib6" />
<bpmn2:endEvent id="Event_0nr2t8s">
<bpmn2:incoming>Flow_09rzzh1</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:sequenceFlow id="Flow_09rzzh1" sourceRef="Activity_0jggib6" targetRef="Event_0nr2t8s" />
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="contract_order_apply">
<bpmndi:BPMNEdge id="Flow_09rzzh1_di" bpmnElement="Flow_09rzzh1">
<di:waypoint x="750" y="230" />
<di:waypoint x="812" y="230" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1615yky_di" bpmnElement="Flow_1615yky">
<di:waypoint x="590" y="230" />
<di:waypoint x="650" y="230" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0v1zao7_di" bpmnElement="Flow_0v1zao7">
<di:waypoint x="430" y="230" />
<di:waypoint x="490" y="230" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1vfva23_di" bpmnElement="Flow_1vfva23">
<di:waypoint x="278" y="230" />
<di:waypoint x="330" y="230" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="StartEvent_01ydzqe_di" bpmnElement="StartEvent_01ydzqe">
<dc:Bounds x="242" y="212" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="247" y="263" width="25" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1u5vv78_di" bpmnElement="Activity_1u5vv78">
<dc:Bounds x="330" y="190" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0rgq1wm_di" bpmnElement="Activity_0rgq1wm">
<dc:Bounds x="490" y="190" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0jggib6_di" bpmnElement="Activity_0jggib6">
<dc:Bounds x="650" y="190" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0nr2t8s_di" bpmnElement="Event_0nr2t8s">
<dc:Bounds x="812" y="212" width="36" height="36" />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>