💖专栏简介
✔️本专栏将从Camunda(卡蒙达) 7中的关键概念到实现中国式工作流相关功能。
✔️文章中只包含演示核心代码及测试数据,完整代码可查看作者的开源项目snail-camunda
✔️请给snail-camunda 点颗星吧😘
💖排他网关
流程定义中需要用到排他网关时需要注意两点:
1是必须要有一条默认路线,当其他条件均不满足时走该路线。
2是条件表达式要设置正确
表单定义如下
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0lyy3jm" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.19.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.15.0">
<bpmn:process id="Process_1celx74" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0a6p958</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0a6p958" sourceRef="StartEvent_1" targetRef="root" />
<bpmn:userTask id="root" name="提交人" camunda:assignee="${initiator}">
<bpmn:incoming>Flow_0a6p958</bpmn:incoming>
<bpmn:outgoing>Flow_0i294hl</bpmn:outgoing>
</bpmn:userTask>
<bpmn:exclusiveGateway id="Gateway_1e17vip" default="Flow_19gtn2c">
<bpmn:incoming>Flow_0i294hl</bpmn:incoming>
<bpmn:outgoing>Flow_07vd7cq</bpmn:outgoing>
<bpmn:outgoing>Flow_19gtn2c</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_0i294hl" sourceRef="root" targetRef="Gateway_1e17vip" />
<bpmn:sequenceFlow id="Flow_07vd7cq" name="大于3天" sourceRef="Gateway_1e17vip" targetRef="Activity_1fw9lpo">
<bpmn:extensionElements />
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${day > 3}</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_19gtn2c" sourceRef="Gateway_1e17vip" targetRef="Activity_17k9da9">
<bpmn:extensionElements />
</bpmn:sequenceFlow>
<bpmn:endEvent id="Event_1673c3w">
<bpmn:incoming>Flow_1cxwd4c</bpmn:incoming>
<bpmn:incoming>Flow_0gnj3ll</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1cxwd4c" sourceRef="Activity_1fw9lpo" targetRef="Event_1673c3w" />
<bpmn:sequenceFlow id="Flow_0gnj3ll" sourceRef="Activity_17k9da9" targetRef="Event_1673c3w" />
<bpmn:userTask id="Activity_1fw9lpo" name="部长" camunda:assignee="${head}">
<bpmn:incoming>Flow_07vd7cq</bpmn:incoming>
<bpmn:outgoing>Flow_1cxwd4c</bpmn:outgoing>
</bpmn:userTask>
<bpmn:userTask id="Activity_17k9da9" name="经理" camunda:assignee="${manager}">
<bpmn:incoming>Flow_19gtn2c</bpmn:incoming>
<bpmn:outgoing>Flow_0gnj3ll</bpmn:outgoing>
</bpmn:userTask>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1celx74">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="209" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_07adzvd_di" bpmnElement="root">
<dc:Bounds x="270" y="187" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_1e17vip_di" bpmnElement="Gateway_1e17vip" isMarkerVisible="true">
<dc:Bounds x="425" y="202" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1673c3w_di" bpmnElement="Event_1673c3w">
<dc:Bounds x="752" y="209" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1rofeex_di" bpmnElement="Activity_1fw9lpo">
<dc:Bounds x="520" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_01iu09y_di" bpmnElement="Activity_17k9da9">
<dc:Bounds x="520" y="290" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0a6p958_di" bpmnElement="Flow_0a6p958">
<di:waypoint x="215" y="227" />
<di:waypoint x="270" y="227" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0i294hl_di" bpmnElement="Flow_0i294hl">
<di:waypoint x="370" y="227" />
<di:waypoint x="425" y="227" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_07vd7cq_di" bpmnElement="Flow_07vd7cq">
<di:waypoint x="450" y="202" />
<di:waypoint x="450" y="120" />
<di:waypoint x="520" y="120" />
<bpmndi:BPMNLabel>
<dc:Bounds x="445" y="158" width="40" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_19gtn2c_di" bpmnElement="Flow_19gtn2c">
<di:waypoint x="450" y="252" />
<di:waypoint x="450" y="330" />
<di:waypoint x="520" y="330" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1cxwd4c_di" bpmnElement="Flow_1cxwd4c">
<di:waypoint x="620" y="120" />
<di:waypoint x="700" y="120" />
<di:waypoint x="700" y="227" />
<di:waypoint x="752" y="227" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0gnj3ll_di" bpmnElement="Flow_0gnj3ll">
<di:waypoint x="620" y="330" />
<di:waypoint x="700" y="330" />
<di:waypoint x="700" y="227" />
<di:waypoint x="752" y="227" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
发起实例的接口,参数类和之前文章中提到的都一样,不重复贴了
/**
* 根据流程定义key发起流程实例
*
* @param requestParam 请求参数
* @return 流程实例id
*/
@PostMapping("/startProcessInstanceByKey")
public String startProcessInstanceByKey(@RequestBody StartProcessRequest requestParam) {
Map<String, Object> paramMap = new HashMap<>(8);
paramMap.put("initiator", requestParam.getInitiator());
paramMap.put("day", 4);
paramMap.put("manager","10087");
paramMap.put("head", "10088");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(requestParam.getProcessDefinitionKey(), requestParam.getBusinessKey(), paramMap);
return processInstance.getProcessInstanceId();
}
发起后,满足预期来到【部长】节点
💖统一表达式语言
Camunda支持统一表达式语言,使用开源的JUEL来实现的。需要掌握更多可访问如下链接
Unified Expression Language
💖并行网关
在之前的《认识BPMN2.0》中我们知道并行网关的功能是基于传入和传出序列流:
- Fork:所有传出序列流并行执行,为每个序列流创建一个并发执行。
- Join:到达并行网关的所有并发执行在网关等待,直到每个传入序列流的执行到达为止。
流程定义设计如下:
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0x5ifr3" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.19.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.15.0">
<bpmn:process id="Process_17ri3bi" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0woj0jt</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0woj0jt" sourceRef="StartEvent_1" targetRef="root" />
<bpmn:userTask id="root" name="发起人" camunda:assignee="${initiator}">
<bpmn:incoming>Flow_0woj0jt</bpmn:incoming>
<bpmn:outgoing>Flow_0istezk</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_0istezk" sourceRef="root" targetRef="Gateway_0j97tkc" />
<bpmn:parallelGateway id="Gateway_0j97tkc">
<bpmn:incoming>Flow_0istezk</bpmn:incoming>
<bpmn:outgoing>Flow_1ucnqdb</bpmn:outgoing>
<bpmn:outgoing>Flow_0nvwxww</bpmn:outgoing>
<bpmn:outgoing>Flow_06j90pb</bpmn:outgoing>
</bpmn:parallelGateway>
<bpmn:sequenceFlow id="Flow_1ucnqdb" sourceRef="Gateway_0j97tkc" targetRef="Activity_16bwr8x" />
<bpmn:sequenceFlow id="Flow_0nvwxww" sourceRef="Gateway_0j97tkc" targetRef="Activity_0qtaspo" />
<bpmn:userTask id="Activity_16bwr8x" name="审批人1号" camunda:assignee="${userOne}">
<bpmn:incoming>Flow_1ucnqdb</bpmn:incoming>
<bpmn:outgoing>Flow_11upvwe</bpmn:outgoing>
</bpmn:userTask>
<bpmn:userTask id="Activity_0qtaspo" name="审批人3号" camunda:assignee="${userThree}">
<bpmn:incoming>Flow_0nvwxww</bpmn:incoming>
<bpmn:outgoing>Flow_1qfv4jz</bpmn:outgoing>
</bpmn:userTask>
<bpmn:endEvent id="Event_01ck26r">
<bpmn:incoming>Flow_0rzniwk</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_06j90pb" sourceRef="Gateway_0j97tkc" targetRef="Activity_0bczswl" />
<bpmn:userTask id="Activity_0bczswl" name="审批人2号" camunda:assignee="${userTwo}">
<bpmn:incoming>Flow_06j90pb</bpmn:incoming>
<bpmn:outgoing>Flow_1mymqa7</bpmn:outgoing>
</bpmn:userTask>
<bpmn:parallelGateway id="Gateway_1gholo6">
<bpmn:incoming>Flow_1mymqa7</bpmn:incoming>
<bpmn:incoming>Flow_11upvwe</bpmn:incoming>
<bpmn:outgoing>Flow_0luwvad</bpmn:outgoing>
</bpmn:parallelGateway>
<bpmn:sequenceFlow id="Flow_1mymqa7" sourceRef="Activity_0bczswl" targetRef="Gateway_1gholo6" />
<bpmn:sequenceFlow id="Flow_0luwvad" sourceRef="Gateway_1gholo6" targetRef="Activity_10re8z2" />
<bpmn:userTask id="Activity_10re8z2" name="审批人4号" camunda:assignee="${userFour}">
<bpmn:incoming>Flow_0luwvad</bpmn:incoming>
<bpmn:outgoing>Flow_05npw3q</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_05npw3q" sourceRef="Activity_10re8z2" targetRef="Gateway_1u3oe8c" />
<bpmn:parallelGateway id="Gateway_1u3oe8c">
<bpmn:incoming>Flow_05npw3q</bpmn:incoming>
<bpmn:incoming>Flow_1qfv4jz</bpmn:incoming>
<bpmn:outgoing>Flow_0rzniwk</bpmn:outgoing>
</bpmn:parallelGateway>
<bpmn:sequenceFlow id="Flow_0rzniwk" sourceRef="Gateway_1u3oe8c" targetRef="Event_01ck26r" />
<bpmn:sequenceFlow id="Flow_1qfv4jz" sourceRef="Activity_0qtaspo" targetRef="Gateway_1u3oe8c" />
<bpmn:sequenceFlow id="Flow_11upvwe" sourceRef="Activity_16bwr8x" targetRef="Gateway_1gholo6" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_17ri3bi">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_04cwdxu_di" bpmnElement="root">
<dc:Bounds x="270" y="137" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_0wqcqy3_di" bpmnElement="Gateway_0j97tkc">
<dc:Bounds x="425" y="152" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1978o8o_di" bpmnElement="Activity_16bwr8x">
<dc:Bounds x="520" y="60" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1jr9acr_di" bpmnElement="Activity_0bczswl">
<dc:Bounds x="520" y="200" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1opqr0v_di" bpmnElement="Activity_0qtaspo">
<dc:Bounds x="510" y="360" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_1iutlje_di" bpmnElement="Gateway_1gholo6">
<dc:Bounds x="675" y="115" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1ne89o0_di" bpmnElement="Activity_10re8z2">
<dc:Bounds x="770" y="100" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_0an4f7j_di" bpmnElement="Gateway_1u3oe8c">
<dc:Bounds x="915" y="215" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_01ck26r_di" bpmnElement="Event_01ck26r">
<dc:Bounds x="1042" y="222" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0woj0jt_di" bpmnElement="Flow_0woj0jt">
<di:waypoint x="215" y="177" />
<di:waypoint x="270" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0istezk_di" bpmnElement="Flow_0istezk">
<di:waypoint x="370" y="177" />
<di:waypoint x="425" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1ucnqdb_di" bpmnElement="Flow_1ucnqdb">
<di:waypoint x="450" y="152" />
<di:waypoint x="450" y="100" />
<di:waypoint x="520" y="100" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0nvwxww_di" bpmnElement="Flow_0nvwxww">
<di:waypoint x="450" y="202" />
<di:waypoint x="450" y="400" />
<di:waypoint x="510" y="400" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_06j90pb_di" bpmnElement="Flow_06j90pb">
<di:waypoint x="450" y="202" />
<di:waypoint x="450" y="240" />
<di:waypoint x="520" y="240" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1mymqa7_di" bpmnElement="Flow_1mymqa7">
<di:waypoint x="620" y="240" />
<di:waypoint x="700" y="240" />
<di:waypoint x="700" y="165" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0luwvad_di" bpmnElement="Flow_0luwvad">
<di:waypoint x="725" y="140" />
<di:waypoint x="770" y="140" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_05npw3q_di" bpmnElement="Flow_05npw3q">
<di:waypoint x="870" y="140" />
<di:waypoint x="940" y="140" />
<di:waypoint x="940" y="215" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0rzniwk_di" bpmnElement="Flow_0rzniwk">
<di:waypoint x="965" y="240" />
<di:waypoint x="1042" y="240" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1qfv4jz_di" bpmnElement="Flow_1qfv4jz">
<di:waypoint x="610" y="400" />
<di:waypoint x="940" y="400" />
<di:waypoint x="940" y="265" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_11upvwe_di" bpmnElement="Flow_11upvwe">
<di:waypoint x="620" y="100" />
<di:waypoint x="648" y="100" />
<di:waypoint x="648" y="140" />
<di:waypoint x="675" y="140" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
发起实例接口:
/**
* 根据流程定义key发起流程实例
*
* @param requestParam 请求参数
* @return 流程实例id
*/
@PostMapping("/startProcessInstanceByKey")
public String startProcessInstanceByKey(@RequestBody StartProcessRequest requestParam) {
Map<String, Object> paramMap = new HashMap<>(8);
paramMap.put("initiator", requestParam.getInitiator());
paramMap.put("userOne","10087");
paramMap.put("userTwo","10088");
paramMap.put("userThree","10089");
paramMap.put("userFour","10090");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(requestParam.getProcessDefinitionKey(), requestParam.getBusinessKey(), paramMap);
return processInstance.getProcessInstanceId();
}
从下图可见,经过第一个并行网关后三个节点的审批人会同时收到待办任务。
所以3号完成后执行会在最后的并行网关等待