一、工作流介绍
1. 什么是工作流
工作流起源于办公自动化,是对软件中业务流程的抽象。通过工作流将各个任务有序组织起来形成一个完整的业务闭环。比如:请假流程,网上购物流程,银行贷款流程等。
2. 工作流应用场景
- 传统办公自动化业务
- 微服务业务组装器
- 各种能力层(如图像识别、离线分析、指纹识别)组合业务
- 低代码平台,标准化输入输出,功能独立化的业务组件,可以通过拖拽改变流程组成新的业务
- 微服务状态机
3. 常用工作流对比
最常用业务的工作流组件包括jbpm Activity flowable camunda
功能最强大的属flowable camunda ,都从activity发展而来,性能,功能都比activity强大。
4. 性能对比
(来自flowable与camunda性能对比测试_camunda flowable对比-CSDN博客)
PC笔记本,8G内存,CPU两核i5-8250
压测工具:JMeter5.1
数据库:mysql5.7
Flowable版本:6.4.1
Camunda版本:7.10
并发数 | flowable | camunda | 性能对比(Camunda比flowable提升) |
---|---|---|---|
100并发 | 2269 ms | 1631 ms | +39% |
200并发 | 3907 ms | 3489 ms | +12% |
400并发 | 7250 ms | 6452 ms | +12% |
600并发 | 9943 ms | 8700 ms | +14% |
800并发 | 13700 ms | 12400 ms | +10% |
1000并发 | 18800 ms | 15700 ms | +20% |
2、camunda 工作流介绍
简介
camunda工作流源自activity5,是德国一家工作流程自动化软件开发商提供的,现在同时提供camunda7(组件方式)与camunda8(基于云原生)两种平台。
目标
为业务和IT提供基于标准、高度可伸缩和协作的方法,创新流程自动化
支持
- BPMN2(Business Process Model and Notation业务流程模型标记)
- CMMN ( Case Management Model and Notation.案例管理模型标记)
- DMN(Decision Model and Notation决策模型标记)
优势
- 高性能(乐观锁,缓存机制)
- 高扩展性
- 高稳定性
- 独有的外部任务模式
- 完善rest api
- 支持多租户
- 优秀的流程设计器
camunda现状
一年发形两个版本
五年内保证,camunda7 与camunda8并行开发与维护。
https://camunda.com/about/customers/ 官网在册企业
学习文档与社区
官方文档:http://docs.camunda.org/manual/7.17/
github社区:https://github.com/camunda-community-hub
github官方开源库:https://github.com/camunda
国内开源社区:https://www.oschina.net/informat/camunda
3、流程引擎下载安装与部署
camunda有多种使用方式,此处先使用独立平台的方式部署引擎,这种用法适合分布式,微服务化,多语言异构系统的使用方式。是官方推荐的使用方式。
camunda-platform-run支持的运行方式有多种,包括:
- Apache tomcat
- JBoss EAP/wildfly
- IBM WebShpere
- Oracle WebLogic
- Docker
- Spring boot启动
推荐安装一、docker方式安装
参考文档:https://github.com/camunda/docker-camunda-bpm-platform/tree/7.17
暂时先以docker运行7.17.0版本,其他版本可以在https://hub.docker.com/中查看镜像版。
1. 拉取镜像
docker pull camunda/camunda-bpm-platform:7.17.0
docker run -d --name camunda -p 8080:8080 camunda/camunda-bpm-platform:7.17.0
2. 访问地址
地址:http://192.168.18.139:8080/camunda
账号:demo
密码:demo
推荐安装二、springboot启动
参考文档:Spring Boot Integration | docs.camunda.org
前提条件:
- JDK1.8(建议JDK11)
- Maven3.6以上版本
1. 下载入口
Camunda Automation Platform 7 Initializr
2. 配置
3. 运行
4. 验证
访问:http://127.0.0.1:8080/
账号:demo
密码:demo
5. 自动部署
项目启动默认加载resources
目录下的.bpmn
文件
4、流程设计器安装与使用
下载地址
https://camunda.com/download/modeler/
https://github.com/camunda/camunda-modeler/releases
根据自己操作系统选择下载。
下载完,解压后直接运行。
简单使用
使用Camunda Modeler.exe
工具加上SpringBoot客户端Deploy
流程
5、快速入门
1、需求
快速入门,设计一个最简单购物流程, 开始==》加入购物车==》付款 》物流发货》结束。
假设这是一个大型异构分布式系统,加入购物车,物流发货是java系统,付款是nodejs系统。
2、BPMN流程设计
2.1 设计流程
打开modeler设计器依次单击_File > New File > BPMN Diagram (Camunda Platform)。
<?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_15h209i" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_shopping" name="购物流程" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0zqlwr1</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0zqlwr1" sourceRef="StartEvent_1" targetRef="Activity_0kws2so" />
<bpmn:serviceTask id="Activity_0kws2so" name="加入购物车" camunda:type="external" camunda:topic="shopping_cart">
<bpmn:incoming>Flow_0zqlwr1</bpmn:incoming>
<bpmn:outgoing>Flow_0j11kjd</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="Flow_0j11kjd" sourceRef="Activity_0kws2so" targetRef="Activity_1vcn0da" />
<bpmn:serviceTask id="Activity_1vcn0da" name="付款" camunda:type="external" camunda:topic="pay">
<bpmn:incoming>Flow_0j11kjd</bpmn:incoming>
<bpmn:outgoing>Flow_0pnceza</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="Flow_0pnceza" sourceRef="Activity_1vcn0da" targetRef="Activity_1ja2llu" />
<bpmn:serviceTask id="Activity_1ja2llu" name="物流发货" camunda:type="external" camunda:topic="logistic_delivery">
<bpmn:incoming>Flow_0pnceza</bpmn:incoming>
<bpmn:outgoing>Flow_1dvb438</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:endEvent id="Event_0pe4bew">
<bpmn:incoming>Flow_1dvb438</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1dvb438" sourceRef="Activity_1ja2llu" targetRef="Event_0pe4bew" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_shopping">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_00t6ldz_di" bpmnElement="Activity_0kws2so">
<dc:Bounds x="270" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1crgybk_di" bpmnElement="Activity_1vcn0da">
<dc:Bounds x="430" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1y8a32h_di" bpmnElement="Activity_1ja2llu">
<dc:Bounds x="590" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0pe4bew_di" bpmnElement="Event_0pe4bew">
<dc:Bounds x="752" y="99" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="759" y="142" width="22" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0zqlwr1_di" bpmnElement="Flow_0zqlwr1">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0j11kjd_di" bpmnElement="Flow_0j11kjd">
<di:waypoint x="370" y="117" />
<di:waypoint x="430" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0pnceza_di" bpmnElement="Flow_0pnceza">
<di:waypoint x="530" y="117" />
<di:waypoint x="590" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1dvb438_di" bpmnElement="Flow_1dvb438">
<di:waypoint x="690" y="117" />
<di:waypoint x="752" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
2.2 Deploy 流程
使用流程设计器+Springboot RestFul Deploy流程
3、搭建业务系统
1. 搭建Java工程
<!-- camunda 外部任务依赖 -->
<dependency>
<groupId>org.camunda.bpm</groupId>
<artifactId>camunda-external-task-client</artifactId>
<version>${camunda.version}</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
package com.lonewalker.snail.buss.shopping;
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.client.ExternalTaskClient;
import org.camunda.bpm.engine.variable.Variables;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Map;
@Slf4j
@Component
public class SubscribeTask {
private final static String CAMUNDA_BASE_URL = "http://localhost:8080/engine-rest";
private ExternalTaskClient client = null;
private ExternalTaskClient getClient() {
if (this.client == null) {
this.client = ExternalTaskClient.create()
.baseUrl(CAMUNDA_BASE_URL)
.asyncResponseTimeout(10000)
.build();
}
return this.client;
}
@PostConstruct
public void handleShoppingCart() {
getClient().subscribe("shopping_cart")
.processDefinitionKey("Process_shopping")
.lockDuration(2000)
.handler((externalTask, externalTaskService) -> {
log.info("订阅到加入购物车任务");
Map<String, Object> map = Variables.createVariables()
.putValue("size", "xl")
.putValue("count", 2);
externalTaskService.complete(externalTask, map);
}).open();
}
@PostConstruct
public void handleLogisticDelivery() {
getClient().subscribe("logistic_delivery")
.processDefinitionKey("Process_shopping")
.lockDuration(2000)
.handler((externalTask, externalTaskService) -> {
Object toWhere = externalTask.getVariable("toWhere");
log.info("收到发货任务,目的地:{}", toWhere);
externalTaskService.complete(externalTask);
}).open();
}
}
2. 搭建NodeJs工程
mkdir shopping-service-nodejs
cd .\shopping-service-nodejs\
npm init
npm install camunda-external-task-client-js
npm install -D open
subscribe.js
import { Client, logger ,Variables} from 'camunda-external-task-client-js'
const config = {baseUrl:"http://localhost:8080/engine-rest",use:logger,asyncResponseTimeout: 10000};
const client = new Client(config);
client.subscribe('pay', {processDefinitionKey: "Process_shopping"},
async function ({task, taskService}) {
const size = task.variables.get('size');
const count = task.variables.get('count');
console.log(`顾客下单尺寸:${size} 数量:'${count}'...`);
const processVariables = new Variables()
.set("toWhere", "nanjing");
try {
await taskService.complete(task, processVariables);
console.log('I complete my task successfully!');
} catch (e) {
console.error(`异常:${e}`);
}
});
node subscribe.js
报错处理package.json
:
"type": "module",
"devDependencies": {
"open": "^10.0.4"
}
3. 运行验证
6、camunda的几种使用方式
1. 引擎嵌入用法
将camunda引擎与业务系统整合到一起,适合java单体小型项目,流程引擎的生命周期与应用程序相同,可以使用引擎的所有内部API直接调用。
优点:使用方便,不用单独部署和维护。
缺点:与业务深度耦合,不方便扩容,只能本项目使用。
接下来的技术点讲解采用此用法。
2. 组件式用法
组件式用法流程引擎在运行时容器(Servlet容器、应用程序服务器……)中启动。流程引擎作为容器服务提供,可以由部署在容器内的所有应用程序共享。这个概念可以与运行时提供的JMS消息队列进行比较,它可以被所有应用程序使用。流程部署和应用程序之间存在一对一的映射:流程引擎跟踪由应用程序部署的流程定义,并将执行委托给相关应用程序。
不常用
3. 中间件用法
将流程引擎单独部署成平台模式,是一种单实例SAAS模式,支持多项目共用,最常用的是通过Rest api方式来通信。前面快速入门用的就是此种用法。
优点:与业务完全解耦,方便扩容,同时支持多项目,支持多租户用法; 缺点:存在单点风险,远程调用有一定性能损耗。
4. 集群用法
5. camunda8云原生用法
7、可视化控制台的介绍
1、添加正式管理员账号
初始安装的流程引擎平台,控制台管理员用户名密码默认为 demo/demo,这肯定是不符合生产环境要求的。按如步骤添加用户名为admin,密码为camunda_admin。 ** 进入管理员窗口**
2、任务列表
3、驾驶舱
4、详细的流程
8、BPMN介绍
1、什么是BPMN
BPMN(Business Process Modeling Notation)指业务流程建模与标记,由BPMI Notation Working Group超过2年的努力于2004年5月对外发布了BPMN 1.0 规范,后BPMI并入到OMG组织,OMG于2011年推出BPMN2.0标准
BPMN定义了业务流程图,其基于流程图技术,同时为创建业务流程操作的图形化模型进行了裁减。业务流程的模型就是图形化对象的网图,包括活动(也可以说工作)和定义操作顺序的流控制。
BPMN官网:https://www.bpmn.org/
2、BPMN2主要元素
2.1 基本分类
一张全景图概述了BPMN元素的关系与作用。
9、用户任务(user task)
描述
用户任务是指:需要人工处理后才能流转任务的任务类型。
需求
假设员工小明请假,并备注,请假人名,请假原因和请假天数,直接上级王兵审批通过即可。
设计流程图
设置任务启动人为申请人
设置申请人表单
设置审批人
设置审批人表单
保存流程图到resources/bpmn下
<?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_1j3klwy" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_06o8fn7" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1" camunda:initiator="starter">
<bpmn:outgoing>Flow_0kvlstb</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0kvlstb" sourceRef="StartEvent_1" targetRef="Activity_0768qxw" />
<bpmn:userTask id="Activity_0768qxw" name="员工请假" camunda:assignee="${starter}">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="name" label="姓名" type="string" />
<camunda:formField id="reason" label="原因" type="string" />
<camunda:formField id="leaveday" label="请假天数" type="long" defaultValue="1" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0kvlstb</bpmn:incoming>
<bpmn:outgoing>Flow_1xj8x9o</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_1xj8x9o" sourceRef="Activity_0768qxw" targetRef="Activity_1d3btal" />
<bpmn:userTask id="Activity_1d3btal" name="直接领导审批" camunda:assignee="wangbing">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="审批结果" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1xj8x9o</bpmn:incoming>
<bpmn:outgoing>Flow_0wrymd2</bpmn:outgoing>
</bpmn:userTask>
<bpmn:endEvent id="Event_0vkilb3">
<bpmn:incoming>Flow_0wrymd2</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0wrymd2" sourceRef="Activity_1d3btal" targetRef="Event_0vkilb3" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_06o8fn7">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_076ixzh_di" bpmnElement="Activity_0768qxw">
<dc:Bounds x="270" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1fbzk2c_di" bpmnElement="Activity_1d3btal">
<dc:Bounds x="430" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0vkilb3_di" bpmnElement="Event_0vkilb3">
<dc:Bounds x="592" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0kvlstb_di" bpmnElement="Flow_0kvlstb">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1xj8x9o_di" bpmnElement="Flow_1xj8x9o">
<di:waypoint x="370" y="117" />
<di:waypoint x="430" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0wrymd2_di" bpmnElement="Flow_0wrymd2">
<di:waypoint x="530" y="117" />
<di:waypoint x="592" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Java业务代码
package com.example.workflow;
import org.camunda.bpm.engine.IdentityService;
import org.camunda.bpm.engine.RuntimeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserTaskController {
@Autowired
private IdentityService identityService;
@Autowired
private RuntimeService runtimeService;
@GetMapping("/start/{processKey}")
public void start(@PathVariable(value = "processKey") String processKey) {
this.identityService.setAuthenticatedUserId("xiaoming");
this.runtimeService.startProcessInstanceByKey(processKey);
}
}
需要在camunda控制台添加用户
- xiaoming
- wangbing
10、业务任务(service task)
描述
业务任务通常是用来调用业务系统,camunda中可以调用JAVA代码或者rest api调用。
任务
在camunda中,业务任务实现方式有5种,本节先用一个小例子显示前三种,External 外部任务,Connector连接器后面分别讲解。
- Java Class
- Expression
- Delegate expression
- External
- Connector
需求
假设用户预约电器公司上门维修家电,然后师傅上门维修,完成后公司回访客户对师傅服务打分,师傅查询自己的评分。
流程设计
1.预约维修
使用java class 模式实现业务任务。
com.example.workflow.servicetask.ReserveRepair
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:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0eq22qp" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_yuyueweixiu" name="预约维修" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0n469eu</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0n469eu" sourceRef="StartEvent_1" targetRef="Activity_09x0iac" />
<bpmn:serviceTask id="Activity_09x0iac" name="预约修理家电" camunda:class="com.example.workflow.servicetask.ReserveRepair">
<bpmn:incoming>Flow_0n469eu</bpmn:incoming>
<bpmn:outgoing>Flow_14zkkbk</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="Flow_14zkkbk" sourceRef="Activity_09x0iac" targetRef="Activity_02ns1og" />
<bpmn:serviceTask id="Activity_02ns1og" name="师傅上门修理" camunda:delegateExpression="${doRepair}">
<bpmn:incoming>Flow_14zkkbk</bpmn:incoming>
<bpmn:outgoing>Flow_1i6wubb</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="Flow_1i6wubb" sourceRef="Activity_02ns1og" targetRef="Activity_1tsbcvy" />
<bpmn:serviceTask id="Activity_1tsbcvy" name="公司电话回访" camunda:expression="${telcall.doCall(execution)}" camunda:resultVariable="score">
<bpmn:incoming>Flow_1i6wubb</bpmn:incoming>
<bpmn:outgoing>Flow_1iin4mj</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="Flow_1iin4mj" sourceRef="Activity_1tsbcvy" targetRef="Activity_1l7c1nd" />
<bpmn:serviceTask id="Activity_1l7c1nd" name="查看评分" camunda:expression="${telcall.getScore(execution)}">
<bpmn:incoming>Flow_1iin4mj</bpmn:incoming>
<bpmn:outgoing>Flow_1lcfnyo</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:endEvent id="Event_1q7swj6">
<bpmn:incoming>Flow_1lcfnyo</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1lcfnyo" sourceRef="Activity_1l7c1nd" targetRef="Event_1q7swj6" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_yuyueweixiu">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0q4cmgo_di" bpmnElement="Activity_09x0iac">
<dc:Bounds x="270" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1l7sw1w_di" bpmnElement="Activity_02ns1og">
<dc:Bounds x="430" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1wzdr65_di" bpmnElement="Activity_1tsbcvy">
<dc:Bounds x="590" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_19v1gmd_di" bpmnElement="Activity_1l7c1nd">
<dc:Bounds x="750" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1q7swj6_di" bpmnElement="Event_1q7swj6">
<dc:Bounds x="912" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0n469eu_di" bpmnElement="Flow_0n469eu">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_14zkkbk_di" bpmnElement="Flow_14zkkbk">
<di:waypoint x="370" y="117" />
<di:waypoint x="430" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1i6wubb_di" bpmnElement="Flow_1i6wubb">
<di:waypoint x="530" y="117" />
<di:waypoint x="590" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1iin4mj_di" bpmnElement="Flow_1iin4mj">
<di:waypoint x="690" y="117" />
<di:waypoint x="750" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1lcfnyo_di" bpmnElement="Flow_1lcfnyo">
<di:waypoint x="850" y="117" />
<di:waypoint x="912" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
3. 业务代码
-
ReserveRepair
package com.example.workflow.servicetask; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.camunda.bpm.engine.delegate.JavaDelegate; public class ReserveRepair implements JavaDelegate { @Override public void execute(DelegateExecution delegateExecution) throws Exception { System.out.println("delegateExecution.getCurrentActivityName() = " + delegateExecution.getCurrentActivityName()); System.out.println("delegateExecution.getProcessDefinitionId() = " + delegateExecution.getProcessDefinitionId()); } }
-
DoingRepair
package com.example.workflow.servicetask; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.camunda.bpm.engine.delegate.JavaDelegate; import org.springframework.stereotype.Service; @Service("doRepair") public class DoingRepair implements JavaDelegate { @Override public void execute(DelegateExecution delegateExecution) throws Exception { System.out.println("delegateExecution.getCurrentActivityName() = " + delegateExecution.getCurrentActivityName()); System.out.println("delegateExecution.getProcessDefinitionId() = " + delegateExecution.getProcessDefinitionId()); delegateExecution.setVariable("repairName","王小二"); } }
-
TelCall
package com.example.workflow.servicetask; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.springframework.stereotype.Service; @Service("telcall") public class TelCall { public Long doCall(DelegateExecution delegateExecution) { System.out.println("开始电话回访"); String repairName = String.valueOf(delegateExecution.getVariable("repairName")); System.out.println("您对"+repairName+"的服务打几分"); return 10L; } public void getScore(DelegateExecution delegateExecution) { String score = String.valueOf(delegateExecution.getVariable("score")); System.out.println("score = " + score); } }
11、外部任务(external task)
描述
外部任务(external task)是属于业务任务(service task)的一个分支,外部任务需要实现方明确告知其complete任务了,才会流转任务。camunda工作流特有的类型,非常有用。
外部任务指的是任务实现在引擎服务的外面,camunda以下优势都是通过外部任务提供的:
- 多语言异构系统,常用语言支持SDK;
- 对微服务较好的支持,与业务解耦;
- 作为SAAS平台使用,并支持多租户;
这一节在企业应用中非常实用,会讲得很详细,在工作流技术选型时,特有的外部任务基本上是camunda打败竞争对手最有力的武器。
外部任务执行流程
基于REST API实现,官方与社区提供常用语言的SDK。
外部任务的执行大体分三步:
- Process Engine: Creation of an external task instance
- External Worker: Fetch and lock external tasks(根据TOPIC订阅拉取)
- External Worker & Process Engine: Complete ext.
第三步当处理业务失败时,还可以上报异常给引擎,可以从控制台可视化准确确定位到流程实例失败的原因,当然,上报异常时,在异常没消失之前会永远卡在失败节点,重试成功后异常会消失,流程往下走。
长轮训(Long Polling)
需求
流程设计
<?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_0eq22qp" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_yuyueweixiu_External" name="预约维修-External" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0n469eu</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0n469eu" sourceRef="StartEvent_1" targetRef="Activity_09x0iac" />
<bpmn:serviceTask id="Activity_09x0iac" name="预约修理家电" camunda:class="com.example.workflow.servicetask.ReserveRepair">
<bpmn:incoming>Flow_0n469eu</bpmn:incoming>
<bpmn:outgoing>Flow_0dxuwri</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:serviceTask id="Activity_02ns1og" name="师傅上门修理" camunda:delegateExpression="${doRepair}">
<bpmn:incoming>Flow_0jq6sjg</bpmn:incoming>
<bpmn:outgoing>Flow_1i6wubb</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="Flow_1i6wubb" sourceRef="Activity_02ns1og" targetRef="Activity_1tsbcvy" />
<bpmn:serviceTask id="Activity_1tsbcvy" name="公司电话回访" camunda:expression="${telcall.doCall(execution)}" camunda:resultVariable="score">
<bpmn:incoming>Flow_1i6wubb</bpmn:incoming>
<bpmn:outgoing>Flow_1iin4mj</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="Flow_1iin4mj" sourceRef="Activity_1tsbcvy" targetRef="Activity_1l7c1nd" />
<bpmn:serviceTask id="Activity_1l7c1nd" name="查看评分" camunda:expression="${telcall.getScore(execution)}">
<bpmn:incoming>Flow_1iin4mj</bpmn:incoming>
<bpmn:outgoing>Flow_1lcfnyo</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:endEvent id="Event_1q7swj6">
<bpmn:incoming>Flow_1lcfnyo</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1lcfnyo" sourceRef="Activity_1l7c1nd" targetRef="Event_1q7swj6" />
<bpmn:sequenceFlow id="Flow_0dxuwri" sourceRef="Activity_09x0iac" targetRef="Activity_0eblueo" />
<bpmn:serviceTask id="Activity_0eblueo" name="尝试自修" camunda:type="external" camunda:topic="try_self_repair">
<bpmn:incoming>Flow_0dxuwri</bpmn:incoming>
<bpmn:outgoing>Flow_0jq6sjg</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="Flow_0jq6sjg" sourceRef="Activity_0eblueo" targetRef="Activity_02ns1og" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_yuyueweixiu_External">
<bpmndi:BPMNShape id="Activity_1l7sw1w_di" bpmnElement="Activity_02ns1og">
<dc:Bounds x="580" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1wzdr65_di" bpmnElement="Activity_1tsbcvy">
<dc:Bounds x="740" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_19v1gmd_di" bpmnElement="Activity_1l7c1nd">
<dc:Bounds x="900" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1q7swj6_di" bpmnElement="Event_1q7swj6">
<dc:Bounds x="1062" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="159" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0q4cmgo_di" bpmnElement="Activity_09x0iac">
<dc:Bounds x="250" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0oruj5t_di" bpmnElement="Activity_0eblueo">
<dc:Bounds x="410" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0jq6sjg_di" bpmnElement="Flow_0jq6sjg">
<di:waypoint x="510" y="117" />
<di:waypoint x="580" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1i6wubb_di" bpmnElement="Flow_1i6wubb">
<di:waypoint x="680" y="117" />
<di:waypoint x="740" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1iin4mj_di" bpmnElement="Flow_1iin4mj">
<di:waypoint x="840" y="117" />
<di:waypoint x="900" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1lcfnyo_di" bpmnElement="Flow_1lcfnyo">
<di:waypoint x="1000" y="117" />
<di:waypoint x="1062" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0n469eu_di" bpmnElement="Flow_0n469eu">
<di:waypoint x="195" y="117" />
<di:waypoint x="250" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0dxuwri_di" bpmnElement="Flow_0dxuwri">
<di:waypoint x="350" y="117" />
<di:waypoint x="410" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Java代码
Pom依赖
<!-- camunda-springboot 外部任务依赖 -->
<dependency>
<groupId>org.camunda.bpm.springboot</groupId>
<artifactId>camunda-bpm-spring-boot-starter-external-task-client</artifactId>
<version>${camunda.version}</version>
</dependency>
配置
# 引擎根路径
camunda.bpm.client.base-url=http://localhost:8088/engine-rest
# 长轮训时间间隔
camunda.bpm.client.async-response-timeout=20000
# 一次最多拉取的任务数量
camunda.bpm.client.max-tasks=1
# 全局订阅Topic上锁时间,单位毫秒,锁住期间,其他订阅者拉取不了任务
camunda.bpm.client.lock-duration=10000
# 指定工作节点ID
camunda.bpm.client.worker-id=java-client
Java代码
package com.lonewalker.snail.buss.externaltask;
import org.camunda.bpm.client.spring.annotation.ExternalTaskSubscription;
import org.camunda.bpm.client.task.ExternalTaskHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
@Configuration
public class SelfRepairService {
@Bean
@ExternalTaskSubscription(topicName = "try_self_repair", processDefinitionIdIn = {"Process_yuyueweixiu_External"}, lockDuration = 500000)
public ExternalTaskHandler doSelfRepair() {
return (externalTask, externalTaskService) -> {
System.out.println("外部任务进入尝试自修");
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
throw new RuntimeException(e);
}
Boolean isFree = externalTask.getVariable("isFree");
if (isFree) {
System.out.println("免费维修");
externalTaskService.handleFailure(externalTask, "维修是免费的,我不想自修了", "可以打印异常", 0, 5000);
} else {
System.out.println("收费维修");
externalTaskService.complete(externalTask);
}
};
}
}
外部任务超时时间设置经验
任务监听器
开启鉴权
同时在客户端增加如下配置,否则会报错401
camunda.bpm.client.basic-auth.username=xxx
camunda.bpm.client.basic-auth.password=xxx
12、外部任务2(external task)
省略…
13、多实例任务(multi instance)
介绍
多实例任务,是指一个类型的任务需要循环执行多次,包括串行多实例任务和并行多实例任务。
需求(串行)
假设前面用户任务示例中的请假的流程中,请假审批由领导组组长442346754441461760,经理 demo 按顺序审批才能完成请假。
修改流程BPMN
操作步骤:
1、点任务 - 设置(点小扳手) - 点 三个竖线或者横线。
2、在右侧的属性面板填写:
Collection :它表示一个集合
Element Variable:写一个变量名,它表示遍历上面的集合元素使用的标识。
然后就可以使用变量 ${ 变量名 } 了。
3、在 Assignee (分配到任务的人)填写 ${ 变量名 }。
4、Loop Cardinality当没有设置Collection的时候,可以通过此变量设置循环的次数。
5、修改后的XML
<?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_1j3klwy" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_06o8fn7_multitask" name="请假流程-多实例" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1" camunda:initiator="starter">
<bpmn:outgoing>Flow_0kvlstb</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0kvlstb" sourceRef="StartEvent_1" targetRef="Activity_0768qxw" />
<bpmn:userTask id="Activity_0768qxw" name="员工请假" camunda:assignee="${starter}">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="name" label="姓名" type="string" />
<camunda:formField id="reason" label="原因" type="string" />
<camunda:formField id="leaveday" label="请假天数" type="long" defaultValue="1" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0kvlstb</bpmn:incoming>
<bpmn:outgoing>Flow_1xj8x9o</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_1xj8x9o" sourceRef="Activity_0768qxw" targetRef="Activity_1d3btal" />
<bpmn:userTask id="Activity_1d3btal" name="领导审批" camunda:assignee="${leader}">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="审批结果" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1xj8x9o</bpmn:incoming>
<bpmn:outgoing>Flow_0wrymd2</bpmn:outgoing>
<bpmn:multiInstanceLoopCharacteristics isSequential="true" camunda:collection="${leaders}" camunda:elementVariable="leader" />
</bpmn:userTask>
<bpmn:endEvent id="Event_0vkilb3">
<bpmn:incoming>Flow_0wrymd2</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0wrymd2" sourceRef="Activity_1d3btal" targetRef="Event_0vkilb3" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_06o8fn7_multitask">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_076ixzh_di" bpmnElement="Activity_0768qxw">
<dc:Bounds x="270" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1fbzk2c_di" bpmnElement="Activity_1d3btal">
<dc:Bounds x="430" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0vkilb3_di" bpmnElement="Event_0vkilb3">
<dc:Bounds x="592" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0kvlstb_di" bpmnElement="Flow_0kvlstb">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1xj8x9o_di" bpmnElement="Flow_1xj8x9o">
<di:waypoint x="370" y="117" />
<di:waypoint x="430" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0wrymd2_di" bpmnElement="Flow_0wrymd2">
<di:waypoint x="530" y="117" />
<di:waypoint x="592" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Java代码
/**
* 多实例-创建流程
* @param processKey
*/
@GetMapping("/startMultiTask/{processKey}")
public void startMultiTask(@PathVariable(value = "processKey") String processKey) {
this.identityService.setAuthenticatedUserId("xiaoming");
VariableMap variables = Variables.createVariables();
LinkedList<String> leaders = new LinkedList<>();
leaders.add("442346754441461760");
leaders.add("demo");
variables.putValue("leaders",leaders);
this.runtimeService.startProcessInstanceByKey(processKey,variables);
}
需求(并行)
假设审批人中,任意一个审批通过即可完成请假。任意一个就不能是串行。
- nrOfActiveInstances
- loopCounter
- nrOfInstances
- nrOfCompletedInstances
修改流程BPMN
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_1j3klwy" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_06o8fn7_multitask" name="请假流程-多实例" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1" camunda:initiator="starter">
<bpmn:outgoing>Flow_0kvlstb</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0kvlstb" sourceRef="StartEvent_1" targetRef="Activity_0768qxw" />
<bpmn:userTask id="Activity_0768qxw" name="员工请假" camunda:assignee="${starter}">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="name" label="姓名" type="string" />
<camunda:formField id="reason" label="原因" type="string" />
<camunda:formField id="leaveday" label="请假天数" type="long" defaultValue="1" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0kvlstb</bpmn:incoming>
<bpmn:outgoing>Flow_1xj8x9o</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_1xj8x9o" sourceRef="Activity_0768qxw" targetRef="Activity_1d3btal" />
<bpmn:userTask id="Activity_1d3btal" name="领导审批" camunda:assignee="${leader}">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="审批结果" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1xj8x9o</bpmn:incoming>
<bpmn:outgoing>Flow_0wrymd2</bpmn:outgoing>
<bpmn:multiInstanceLoopCharacteristics camunda:collection="${leaders}" camunda:elementVariable="leader">
<bpmn:completionCondition xsi:type="bpmn:tFormalExpression">${nrOfCompletedInstances==1}</bpmn:completionCondition>
</bpmn:multiInstanceLoopCharacteristics>
</bpmn:userTask>
<bpmn:endEvent id="Event_0vkilb3">
<bpmn:incoming>Flow_0wrymd2</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0wrymd2" sourceRef="Activity_1d3btal" targetRef="Event_0vkilb3" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_06o8fn7_multitask">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_076ixzh_di" bpmnElement="Activity_0768qxw">
<dc:Bounds x="270" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1fbzk2c_di" bpmnElement="Activity_1d3btal">
<dc:Bounds x="430" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0vkilb3_di" bpmnElement="Event_0vkilb3">
<dc:Bounds x="592" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0kvlstb_di" bpmnElement="Flow_0kvlstb">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1xj8x9o_di" bpmnElement="Flow_1xj8x9o">
<di:waypoint x="370" y="117" />
<di:waypoint x="430" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0wrymd2_di" bpmnElement="Flow_0wrymd2">
<di:waypoint x="530" y="117" />
<di:waypoint x="592" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
14、脚本任务(script task)
描述
在Camunda中,脚本任务是一个自动活动,当流程执行到脚本任务时,相关的脚本自动执行。camunda支持大多是兼容JSR-223的脚本引擎实现,比如Groovy, JavaScript, JRuby and Jython,要使用脚本功能,需要在classpath中添加对应的脚本引擎,Javascript, Groovy两种脚本引擎已在发布中包含。
相关参考文档:
https://docs.camunda.org/manual/7.17/reference/bpmn20/tasks/script-task/
https://docs.camunda.org/manual/7.17/user-guide/process-engine/scripting/#script-source
https://docs.camunda.org/manual/7.17/user-guide/process-engine/scripting/
除了脚本任务中可以使用脚本,以下元素也可以支持脚本:
修改脚本(内部)
var name= execution.getVariable("name");
var leaveday = execution.getVariable("leaveday");
leftAnnualDays=10-leaveday
<?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_1j3klwy" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_06o8fn7_script" name="请假流程-脚本" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1" camunda:initiator="starter">
<bpmn:outgoing>Flow_0kvlstb</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0kvlstb" sourceRef="StartEvent_1" targetRef="Activity_0768qxw" />
<bpmn:userTask id="Activity_0768qxw" name="员工请假" camunda:assignee="${starter}">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="name" label="姓名" type="string" />
<camunda:formField id="reason" label="原因" type="string" />
<camunda:formField id="leaveday" label="请假天数" type="long" defaultValue="1" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0kvlstb</bpmn:incoming>
<bpmn:outgoing>Flow_1xj8x9o</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_1xj8x9o" sourceRef="Activity_0768qxw" targetRef="Activity_1d3btal" />
<bpmn:userTask id="Activity_1d3btal" name="直接领导审批" camunda:assignee="wangbing">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="审批结果" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1xj8x9o</bpmn:incoming>
<bpmn:outgoing>Flow_0wrymd2</bpmn:outgoing>
</bpmn:userTask>
<bpmn:endEvent id="Event_0vkilb3">
<bpmn:incoming>Flow_19zlgiy</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0wrymd2" sourceRef="Activity_1d3btal" targetRef="Activity_1tjennd" />
<bpmn:sequenceFlow id="Flow_1jlm2uj" sourceRef="Activity_1tjennd" targetRef="Activity_1m7kky3" />
<bpmn:scriptTask id="Activity_1tjennd" name="年假扣减" scriptFormat="JavaScript" camunda:resultVariable="leftAnnualDays">
<bpmn:incoming>Flow_0wrymd2</bpmn:incoming>
<bpmn:outgoing>Flow_1jlm2uj</bpmn:outgoing>
<bpmn:script>var name= execution.getVariable("name");
var leaveday = execution.getVariable("leaveday");
leftAnnualDays=10-leaveday </bpmn:script>
</bpmn:scriptTask>
<bpmn:sequenceFlow id="Flow_19zlgiy" sourceRef="Activity_1m7kky3" targetRef="Event_0vkilb3" />
<bpmn:serviceTask id="Activity_1m7kky3" name="查询剩余年假" camunda:delegateExpression="${queryAnnualLeave}">
<bpmn:incoming>Flow_1jlm2uj</bpmn:incoming>
<bpmn:outgoing>Flow_19zlgiy</bpmn:outgoing>
</bpmn:serviceTask>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_06o8fn7_script">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_076ixzh_di" bpmnElement="Activity_0768qxw">
<dc:Bounds x="270" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1fbzk2c_di" bpmnElement="Activity_1d3btal">
<dc:Bounds x="430" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_08cf4s9_di" bpmnElement="Activity_1tjennd">
<dc:Bounds x="600" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0vkilb3_di" bpmnElement="Event_0vkilb3">
<dc:Bounds x="952" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1ev4ork_di" bpmnElement="Activity_1m7kky3">
<dc:Bounds x="770" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0kvlstb_di" bpmnElement="Flow_0kvlstb">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1xj8x9o_di" bpmnElement="Flow_1xj8x9o">
<di:waypoint x="370" y="117" />
<di:waypoint x="430" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0wrymd2_di" bpmnElement="Flow_0wrymd2">
<di:waypoint x="530" y="117" />
<di:waypoint x="600" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1jlm2uj_di" bpmnElement="Flow_1jlm2uj">
<di:waypoint x="700" y="117" />
<di:waypoint x="770" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_19zlgiy_di" bpmnElement="Flow_19zlgiy">
<di:waypoint x="870" y="117" />
<di:waypoint x="952" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Java代码
package com.lonewalker.snail.buss.scripttask;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.springframework.stereotype.Service;
@Service("queryAnnualLeave")
public class QueryAnnualLeave implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) throws Exception {
Object leftAnnualDays = execution.getVariable("leftAnnualDays");
System.out.println("剩余年假天数 = " + leftAnnualDays);
}
}
修改脚本(外部)
<?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_1j3klwy" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_06o8fn7_script" name="请假流程-脚本" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1" camunda:initiator="starter">
<bpmn:outgoing>Flow_0kvlstb</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0kvlstb" sourceRef="StartEvent_1" targetRef="Activity_0768qxw" />
<bpmn:userTask id="Activity_0768qxw" name="员工请假" camunda:assignee="${starter}">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="name" label="姓名" type="string" />
<camunda:formField id="reason" label="原因" type="string" />
<camunda:formField id="leaveday" label="请假天数" type="long" defaultValue="1" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0kvlstb</bpmn:incoming>
<bpmn:outgoing>Flow_1xj8x9o</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_1xj8x9o" sourceRef="Activity_0768qxw" targetRef="Activity_1d3btal" />
<bpmn:userTask id="Activity_1d3btal" name="直接领导审批" camunda:assignee="wangbing">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="审批结果" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1xj8x9o</bpmn:incoming>
<bpmn:outgoing>Flow_0wrymd2</bpmn:outgoing>
</bpmn:userTask>
<bpmn:endEvent id="Event_0vkilb3">
<bpmn:incoming>Flow_19zlgiy</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0wrymd2" sourceRef="Activity_1d3btal" targetRef="Activity_1tjennd" />
<bpmn:sequenceFlow id="Flow_1jlm2uj" sourceRef="Activity_1tjennd" targetRef="Activity_1m7kky3" />
<bpmn:scriptTask id="Activity_1tjennd" name="年假扣减" scriptFormat="JavaScript" camunda:resultVariable="leftAnnualDays" camunda:resource="classpath://js/script.js">
<bpmn:incoming>Flow_0wrymd2</bpmn:incoming>
<bpmn:outgoing>Flow_1jlm2uj</bpmn:outgoing>
</bpmn:scriptTask>
<bpmn:sequenceFlow id="Flow_19zlgiy" sourceRef="Activity_1m7kky3" targetRef="Event_0vkilb3" />
<bpmn:serviceTask id="Activity_1m7kky3" name="查询剩余年假" camunda:delegateExpression="${queryAnnualLeave}">
<bpmn:incoming>Flow_1jlm2uj</bpmn:incoming>
<bpmn:outgoing>Flow_19zlgiy</bpmn:outgoing>
</bpmn:serviceTask>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_06o8fn7_script">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_076ixzh_di" bpmnElement="Activity_0768qxw">
<dc:Bounds x="270" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1fbzk2c_di" bpmnElement="Activity_1d3btal">
<dc:Bounds x="430" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0vkilb3_di" bpmnElement="Event_0vkilb3">
<dc:Bounds x="952" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_08cf4s9_di" bpmnElement="Activity_1tjennd">
<dc:Bounds x="600" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1ev4ork_di" bpmnElement="Activity_1m7kky3">
<dc:Bounds x="770" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0kvlstb_di" bpmnElement="Flow_0kvlstb">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1xj8x9o_di" bpmnElement="Flow_1xj8x9o">
<di:waypoint x="370" y="117" />
<di:waypoint x="430" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0wrymd2_di" bpmnElement="Flow_0wrymd2">
<di:waypoint x="530" y="117" />
<di:waypoint x="600" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1jlm2uj_di" bpmnElement="Flow_1jlm2uj">
<di:waypoint x="700" y="117" />
<di:waypoint x="770" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_19zlgiy_di" bpmnElement="Flow_19zlgiy">
<di:waypoint x="870" y="117" />
<di:waypoint x="952" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
外部脚本排错处理
org.camunda.bpm.engine.impl.scripting.ResourceExecutableScript#loadScriptSource
15、发送任务(send task)& 接收任务(received task)
描述
发送任务是一个非常简单的任务,一般只用来发送一个消息;
接收任务用来等待发送任务的消息,仅仅用来等待作用。
发送任务和接收任务一般成对配合使用。
需求
有简单的一个发送任务根据接收任务的消息ID和业务KEY(businessKey)来绑定一个消息发送,接收任务收到发送任务的消息后才往下流转。
设计BPMN
发送任务
<?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_1v1m7ms" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_0ll4ffk_send_task" name="发送任务" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1wa8gmm</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_1wa8gmm" sourceRef="StartEvent_1" targetRef="Activity_1bh9puc" />
<bpmn:sendTask id="Activity_1bh9puc" name="发送任务" camunda:delegateExpression="${sendTask}">
<bpmn:incoming>Flow_1wa8gmm</bpmn:incoming>
<bpmn:outgoing>Flow_1l3jy3z</bpmn:outgoing>
</bpmn:sendTask>
<bpmn:endEvent id="Event_1ybfkim">
<bpmn:incoming>Flow_1l3jy3z</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1l3jy3z" sourceRef="Activity_1bh9puc" targetRef="Event_1ybfkim" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_0ll4ffk_send_task">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1le813g_di" bpmnElement="Activity_1bh9puc">
<dc:Bounds x="270" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1ybfkim_di" bpmnElement="Event_1ybfkim">
<dc:Bounds x="432" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1wa8gmm_di" bpmnElement="Flow_1wa8gmm">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1l3jy3z_di" bpmnElement="Flow_1l3jy3z">
<di:waypoint x="370" y="117" />
<di:waypoint x="432" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
接收任务
<?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_0e1jsf1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_0muzhnk_receive_task" name="接收任务" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1koqmxd</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_1koqmxd" sourceRef="StartEvent_1" targetRef="Activity_16s4bhc" />
<bpmn:receiveTask id="Activity_16s4bhc" name="接收任务" messageRef="Message_01bg3t7">
<bpmn:incoming>Flow_1koqmxd</bpmn:incoming>
<bpmn:outgoing>Flow_1rlt12j</bpmn:outgoing>
</bpmn:receiveTask>
<bpmn:endEvent id="Event_0js2lpu">
<bpmn:incoming>Flow_1rlt12j</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1rlt12j" sourceRef="Activity_16s4bhc" targetRef="Event_0js2lpu" />
</bpmn:process>
<bpmn:message id="Message_01bg3t7" name="Message_01bg3t7" />
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_0muzhnk_receive_task">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1bfllrn_di" bpmnElement="Activity_16s4bhc">
<dc:Bounds x="270" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0js2lpu_di" bpmnElement="Event_0js2lpu">
<dc:Bounds x="432" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1koqmxd_di" bpmnElement="Flow_1koqmxd">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1rlt12j_di" bpmnElement="Flow_1rlt12j">
<di:waypoint x="370" y="117" />
<di:waypoint x="432" y="117" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
发送任务代码
发送任务需要根据接收任务的消息名称(接收任务中的message name),及业务businessKey,businesskey后面会专门讲,一般与单次流程实例一一对应,常规做法会与业务侧业务ID相关联。这里使用businessKey作用就是为防止所有流程实例都收到消息。
package com.lonewalker.snail.buss.sendtask;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.springframework.stereotype.Service;
@Service("sendTask")
public class SendTaskService implements JavaDelegate {
@Override
public void execute(DelegateExecution delegateExecution) throws Exception {
RuntimeService runtimeService = delegateExecution.getProcessEngineServices().getRuntimeService();
runtimeService.createMessageCorrelation("Message_01bg3t7")
.processInstanceBusinessKey("message_bussinessKey")
.correlate();
}
}
16、排他网关(exlusive gateway)
描述
排他网关是指在多条执行路径时,根据条件判断选择其中一条路径执行的网关,相当于程序中条件控制,if … elseif… else…。
需求
假设员工小明(xiaoming)请假天数小于等于3天直接上级(wangbing)审批即可,大于3天小于等于5天需要直接上级(wangbing)和部门经理(zhangsan)都要审批,大于5天需要直接上级(wangbing),部门经理(zhangsan)和总经理(wangwu)三者审批。
设计BPMN
1.开始事件中设置start initiator
2.员工请假任务
指定任务请假人就是启动的人,添加请假表单两个属性变量reason(请假原因),day(请假天数)
3.排他网关与条件
4. XML
<?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_1k2u4cy" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_1rcixk0" name="排他网关" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1" camunda:initiator="starter">
<bpmn:outgoing>Flow_14apr32</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_14apr32" sourceRef="StartEvent_1" targetRef="Activity_17jf4ew" />
<bpmn:exclusiveGateway id="Gateway_16g54fw">
<bpmn:incoming>Flow_1u762fi</bpmn:incoming>
<bpmn:outgoing>Flow_0p1ao8b</bpmn:outgoing>
<bpmn:outgoing>Flow_1jui8fx</bpmn:outgoing>
<bpmn:outgoing>Flow_05yz9dh</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_1u762fi" sourceRef="Activity_17jf4ew" targetRef="Gateway_16g54fw" />
<bpmn:sequenceFlow id="Flow_0p1ao8b" name="小于等于3天" sourceRef="Gateway_16g54fw" targetRef="Activity_1f1jgcj">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${day <= 3}</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:userTask id="Activity_17jf4ew" name="员工请假" camunda:assignee="${starter}">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="name" label="姓名" type="string" />
<camunda:formField id="day" label="请假天数" type="long" />
<camunda:formField id="reason" label="请假原因" type="string" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_14apr32</bpmn:incoming>
<bpmn:outgoing>Flow_1u762fi</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_1jui8fx" name="大于3天小于等于5天" sourceRef="Gateway_16g54fw" targetRef="Activity_18tpm8b">
<bpmn:extensionElements>
<camunda:executionListener delegateExpression="${addLeaders}" event="take" />
</bpmn:extensionElements>
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${day > 3 && day <= 5}</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_05yz9dh" name="大于5天" sourceRef="Gateway_16g54fw" targetRef="Activity_0r0xmml">
<bpmn:extensionElements>
<camunda:executionListener delegateExpression="${addLeaders}" event="take" />
</bpmn:extensionElements>
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${day > 5}</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:endEvent id="Event_0vbsagg">
<bpmn:incoming>Flow_1qmj3we</bpmn:incoming>
<bpmn:incoming>Flow_19o7fao</bpmn:incoming>
<bpmn:incoming>Flow_0rlhskj</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1qmj3we" sourceRef="Activity_18tpm8b" targetRef="Event_0vbsagg" />
<bpmn:sequenceFlow id="Flow_19o7fao" sourceRef="Activity_1f1jgcj" targetRef="Event_0vbsagg" />
<bpmn:sequenceFlow id="Flow_0rlhskj" sourceRef="Activity_0r0xmml" targetRef="Event_0vbsagg" />
<bpmn:userTask id="Activity_1f1jgcj" name="直接领导审批" camunda:assignee="wangbing">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="评论" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0p1ao8b</bpmn:incoming>
<bpmn:outgoing>Flow_19o7fao</bpmn:outgoing>
</bpmn:userTask>
<bpmn:userTask id="Activity_18tpm8b" name="直接领导和部门经理审批" camunda:assignee="${leader}">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="评论" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1jui8fx</bpmn:incoming>
<bpmn:outgoing>Flow_1qmj3we</bpmn:outgoing>
<bpmn:multiInstanceLoopCharacteristics isSequential="true" camunda:collection="${leaders}" camunda:elementVariable="leader" />
</bpmn:userTask>
<bpmn:userTask id="Activity_0r0xmml" name="直接领导和部门经理和总经理审批" camunda:assignee="${leader}">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="评论" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_05yz9dh</bpmn:incoming>
<bpmn:outgoing>Flow_0rlhskj</bpmn:outgoing>
<bpmn:multiInstanceLoopCharacteristics isSequential="true" camunda:collection="${leaders}" camunda:elementVariable="leader" />
</bpmn:userTask>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1rcixk0">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="229" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="175" y="272" width="44" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_16g54fw_di" bpmnElement="Gateway_16g54fw" isMarkerVisible="true">
<dc:Bounds x="425" y="222" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0amkuf6_di" bpmnElement="Activity_17jf4ew">
<dc:Bounds x="270" y="207" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0vbsagg_di" bpmnElement="Event_0vbsagg">
<dc:Bounds x="892" y="229" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0o45zp4_di" bpmnElement="Activity_1f1jgcj">
<dc:Bounds x="630" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_11n2h3w_di" bpmnElement="Activity_18tpm8b">
<dc:Bounds x="630" y="207" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0xpuevc_di" bpmnElement="Activity_0r0xmml">
<dc:Bounds x="630" y="330" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_14apr32_di" bpmnElement="Flow_14apr32">
<di:waypoint x="215" y="247" />
<di:waypoint x="270" y="247" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1u762fi_di" bpmnElement="Flow_1u762fi">
<di:waypoint x="370" y="247" />
<di:waypoint x="425" y="247" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0p1ao8b_di" bpmnElement="Flow_0p1ao8b">
<di:waypoint x="450" y="222" />
<di:waypoint x="450" y="120" />
<di:waypoint x="630" y="120" />
<bpmndi:BPMNLabel>
<dc:Bounds x="509" y="103" width="62" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1jui8fx_di" bpmnElement="Flow_1jui8fx">
<di:waypoint x="475" y="247" />
<di:waypoint x="630" y="247" />
<bpmndi:BPMNLabel>
<dc:Bounds x="512" y="229" width="84" height="27" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_05yz9dh_di" bpmnElement="Flow_05yz9dh">
<di:waypoint x="450" y="272" />
<di:waypoint x="450" y="370" />
<di:waypoint x="630" y="370" />
<bpmndi:BPMNLabel>
<dc:Bounds x="520" y="343" width="40" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1qmj3we_di" bpmnElement="Flow_1qmj3we">
<di:waypoint x="730" y="247" />
<di:waypoint x="892" y="247" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_19o7fao_di" bpmnElement="Flow_19o7fao">
<di:waypoint x="730" y="120" />
<di:waypoint x="811" y="120" />
<di:waypoint x="811" y="247" />
<di:waypoint x="892" y="247" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0rlhskj_di" bpmnElement="Flow_0rlhskj">
<di:waypoint x="730" y="370" />
<di:waypoint x="811" y="370" />
<di:waypoint x="811" y="247" />
<di:waypoint x="892" y="247" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
5. Java代码
package com.lonewalker.snail.buss.gateway;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.camunda.bpm.engine.variable.VariableMap;
import org.camunda.bpm.engine.variable.Variables;
import org.springframework.stereotype.Service;
import java.util.LinkedList;
/**
* 排他网关.
*/
@Service("addLeaders")
public class ExlusiveGateway implements JavaDelegate {
@Override
public void execute(DelegateExecution delegateExecution) throws Exception {
Long day = (Long) delegateExecution.getVariable("day");
LinkedList<String> leaders = new LinkedList<>();
if (day > 3 && day <= 5){
leaders.add("wangbing");
leaders.add("zhangsan");
} else if (day > 5){
leaders.add("wangbing");
leaders.add("zhangsan");
leaders.add("wangwu");
}
delegateExecution.setVariable("leaders",leaders);
}
}
17、并行网关(parallel gateway)
描述
并行网关(parallel gateway)是指可以同时执行所有输出路径,并且需要所有输入路径执行完毕汇总到网关后流程才往下流转的元素。
并行网关上的序列流即使有条件判断也会忽略。
并行网关分两部分:
叉子(fork):用于并行任务开始
汇总(join):用于并行任务汇总。
需求
假设社交平台中有个需求是,对用户自上传的视频并行处理几个任务,所有任务全正常达到要求才能上传到系统中。
视频格式的校验(service task);
内容涉黄鉴别(user task人工处理);
内容涉暴处理(user task 人工处理);
内容负面影响判断(external task);
设计BPMN
1.以assignee为xiaoming,设计一个user task,增加视频名称videoName表单字段。
2.增加fork并行网关
3.XML
<?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_0woopvd" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_1s2ftvg" name="并行网关" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1y67dx8</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_1y67dx8" sourceRef="StartEvent_1" targetRef="Activity_13xe75o" />
<bpmn:userTask id="Activity_13xe75o" name="用户上传视频" camunda:assignee="xiaoming">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="videoName" label="视频名称" type="string" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1y67dx8</bpmn:incoming>
<bpmn:outgoing>Flow_0glyu1z</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_0glyu1z" sourceRef="Activity_13xe75o" targetRef="Gateway_01tkydk" />
<bpmn:parallelGateway id="Gateway_01tkydk">
<bpmn:incoming>Flow_0glyu1z</bpmn:incoming>
<bpmn:outgoing>Flow_0uk1u98</bpmn:outgoing>
<bpmn:outgoing>Flow_1syku1i</bpmn:outgoing>
<bpmn:outgoing>Flow_1qvfhhv</bpmn:outgoing>
<bpmn:outgoing>Flow_0xdabmi</bpmn:outgoing>
</bpmn:parallelGateway>
<bpmn:sequenceFlow id="Flow_0uk1u98" sourceRef="Gateway_01tkydk" targetRef="Activity_0i7p9i9" />
<bpmn:serviceTask id="Activity_0i7p9i9" name="视频格式校验" camunda:delegateExpression="${checkVideoFormat}">
<bpmn:incoming>Flow_0uk1u98</bpmn:incoming>
<bpmn:outgoing>Flow_0g7s9k1</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="Flow_1syku1i" sourceRef="Gateway_01tkydk" targetRef="Activity_1tntphb" />
<bpmn:userTask id="Activity_1tntphb" name="涉黄鉴别" camunda:assignee="wangbing">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="isYellow" label="是否涉黄" type="boolean" defaultValue="false" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1syku1i</bpmn:incoming>
<bpmn:outgoing>Flow_0uongoh</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_1qvfhhv" sourceRef="Gateway_01tkydk" targetRef="Activity_1jjo31h" />
<bpmn:userTask id="Activity_1jjo31h" name="涉暴处理" camunda:assignee="zhangsan">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="isViolence" label="是否涉暴" type="boolean" defaultValue="false" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1qvfhhv</bpmn:incoming>
<bpmn:outgoing>Flow_0yj1vyl</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_0xdabmi" sourceRef="Gateway_01tkydk" targetRef="Activity_1l6e3fu" />
<bpmn:serviceTask id="Activity_1l6e3fu" name="负面影响判断" camunda:type="external" camunda:topic="checkNegtive">
<bpmn:incoming>Flow_0xdabmi</bpmn:incoming>
<bpmn:outgoing>Flow_0ps2cut</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="Flow_0g7s9k1" sourceRef="Activity_0i7p9i9" targetRef="Gateway_1xr8a3v" />
<bpmn:parallelGateway id="Gateway_1xr8a3v">
<bpmn:incoming>Flow_0g7s9k1</bpmn:incoming>
<bpmn:incoming>Flow_0uongoh</bpmn:incoming>
<bpmn:incoming>Flow_0yj1vyl</bpmn:incoming>
<bpmn:incoming>Flow_0ps2cut</bpmn:incoming>
<bpmn:outgoing>Flow_0k0a88u</bpmn:outgoing>
</bpmn:parallelGateway>
<bpmn:sequenceFlow id="Flow_0uongoh" sourceRef="Activity_1tntphb" targetRef="Gateway_1xr8a3v" />
<bpmn:sequenceFlow id="Flow_0yj1vyl" sourceRef="Activity_1jjo31h" targetRef="Gateway_1xr8a3v" />
<bpmn:sequenceFlow id="Flow_0ps2cut" sourceRef="Activity_1l6e3fu" targetRef="Gateway_1xr8a3v" />
<bpmn:sequenceFlow id="Flow_0k0a88u" sourceRef="Gateway_1xr8a3v" targetRef="Activity_1e6lwj0" />
<bpmn:userTask id="Activity_1e6lwj0" name="确定上传" camunda:assignee="wangwu">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="isUpload" label="是否上传" type="boolean" defaultValue="true" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0k0a88u</bpmn:incoming>
<bpmn:outgoing>Flow_0moftkc</bpmn:outgoing>
</bpmn:userTask>
<bpmn:endEvent id="Event_05wgy65">
<bpmn:incoming>Flow_0moftkc</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0moftkc" sourceRef="Activity_1e6lwj0" targetRef="Event_05wgy65" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1s2ftvg">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="159" y="282" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0flepn4_di" bpmnElement="Activity_13xe75o">
<dc:Bounds x="250" y="260" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_1jsdisz_di" bpmnElement="Gateway_01tkydk">
<dc:Bounds x="405" y="275" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0bpn50p_di" bpmnElement="Activity_0i7p9i9">
<dc:Bounds x="510" y="80" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_12qiubo_di" bpmnElement="Activity_1tntphb">
<dc:Bounds x="510" y="200" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0bmqfq6_di" bpmnElement="Activity_1jjo31h">
<dc:Bounds x="510" y="310" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1uagnj9_di" bpmnElement="Activity_1l6e3fu">
<dc:Bounds x="510" y="420" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_0rsiubf_di" bpmnElement="Gateway_1xr8a3v">
<dc:Bounds x="685" y="275" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1tva6wt_di" bpmnElement="Activity_1e6lwj0">
<dc:Bounds x="810" y="260" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_05wgy65_di" bpmnElement="Event_05wgy65">
<dc:Bounds x="982" y="282" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1y67dx8_di" bpmnElement="Flow_1y67dx8">
<di:waypoint x="195" y="300" />
<di:waypoint x="250" y="300" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0glyu1z_di" bpmnElement="Flow_0glyu1z">
<di:waypoint x="350" y="300" />
<di:waypoint x="405" y="300" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0uk1u98_di" bpmnElement="Flow_0uk1u98">
<di:waypoint x="430" y="275" />
<di:waypoint x="430" y="120" />
<di:waypoint x="510" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1syku1i_di" bpmnElement="Flow_1syku1i">
<di:waypoint x="430" y="275" />
<di:waypoint x="430" y="240" />
<di:waypoint x="510" y="240" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1qvfhhv_di" bpmnElement="Flow_1qvfhhv">
<di:waypoint x="430" y="325" />
<di:waypoint x="430" y="350" />
<di:waypoint x="510" y="350" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0xdabmi_di" bpmnElement="Flow_0xdabmi">
<di:waypoint x="430" y="325" />
<di:waypoint x="430" y="460" />
<di:waypoint x="510" y="460" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0g7s9k1_di" bpmnElement="Flow_0g7s9k1">
<di:waypoint x="610" y="120" />
<di:waypoint x="710" y="120" />
<di:waypoint x="710" y="275" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0uongoh_di" bpmnElement="Flow_0uongoh">
<di:waypoint x="610" y="240" />
<di:waypoint x="710" y="240" />
<di:waypoint x="710" y="275" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0yj1vyl_di" bpmnElement="Flow_0yj1vyl">
<di:waypoint x="610" y="350" />
<di:waypoint x="710" y="350" />
<di:waypoint x="710" y="325" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0ps2cut_di" bpmnElement="Flow_0ps2cut">
<di:waypoint x="610" y="460" />
<di:waypoint x="710" y="460" />
<di:waypoint x="710" y="325" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0k0a88u_di" bpmnElement="Flow_0k0a88u">
<di:waypoint x="735" y="300" />
<di:waypoint x="810" y="300" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0moftkc_di" bpmnElement="Flow_0moftkc">
<di:waypoint x="910" y="300" />
<di:waypoint x="982" y="300" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
4.Java代码
package com.lonewalker.snail.buss.gateway.parallel;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.springframework.stereotype.Service;
/**
* 视频格式校验.
*
* @author Li Zemin
* @since 2024/3/6 9:08
*/
@Service("checkVideoFormat")
public class CheckVideoFormatService implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) throws Exception {
System.out.println("开始视频格式校验");
Object videoName = execution.getVariable("videoName");
System.out.println("视频名称:" + videoName);
}
}
package com.lonewalker.snail.buss.gateway.parallel;
import java.util.concurrent.TimeUnit;
import org.camunda.bpm.client.spring.annotation.ExternalTaskSubscription;
import org.camunda.bpm.client.task.ExternalTaskHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 负面影响判断.
*
* @author Li Zemin
* @since 2024/3/6 9:13
*/
@Configuration
public class ExternalCheckNegtive {
@Bean
@ExternalTaskSubscription(topicName = "checkNegtive", processDefinitionKeyIn = {"Process_1s2ftvg"}, lockDuration = 500000)
public ExternalTaskHandler doSelfRepair() {
return (externalTask, externalTaskService) -> {
System.out.println("外部任务进入负面影响判断");
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
throw new RuntimeException(e);
}
Object videoName = externalTask.getVariable("videoName");
System.out.println("视频名称:" + videoName + " 不包含负面影响");
externalTaskService.complete(externalTask);
};
}
}
18、包含网关(Inclusive Gateway)
描述
包含网关(inclusive gateway)结合了排他网关与并行网关的特点,即可以根据条件判断,也可以同时多个并行执行。
包含网关的使用也需要用到两部分。
叉子(fork): 用于并行任务开始
汇总(join):用于并行任务汇总。
需求
假设排他网关中的需求中增加一条,请假天数大于3天,需要增加人事经理审批,人事经理(renyingying)审批与领导审批可并行。
BPMN设计
1.排他网关改成包含网关
用小扳手切换排他网关为包含网关,fork部分。
2.xml
<?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_1k2u4cy" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_1rcixk0_baohan" name="包含网关" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1" camunda:initiator="starter">
<bpmn:outgoing>Flow_14apr32</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_14apr32" sourceRef="StartEvent_1" targetRef="Activity_17jf4ew" />
<bpmn:sequenceFlow id="Flow_1u762fi" sourceRef="Activity_17jf4ew" targetRef="Gateway_16g54fw" />
<bpmn:sequenceFlow id="Flow_0p1ao8b" name="小于等于3天" sourceRef="Gateway_16g54fw" targetRef="Activity_1f1jgcj">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${day <= 3}</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:userTask id="Activity_17jf4ew" name="员工请假" camunda:assignee="${starter}">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="name" label="姓名" type="string" />
<camunda:formField id="day" label="请假天数" type="long" />
<camunda:formField id="reason" label="请假原因" type="string" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_14apr32</bpmn:incoming>
<bpmn:outgoing>Flow_1u762fi</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_1jui8fx" name="大于3天小于等于5天" sourceRef="Gateway_16g54fw" targetRef="Activity_18tpm8b">
<bpmn:extensionElements>
<camunda:executionListener delegateExpression="${addLeaders}" event="take" />
</bpmn:extensionElements>
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${day > 3 && day <= 5}</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_05yz9dh" name="大于5天" sourceRef="Gateway_16g54fw" targetRef="Activity_0r0xmml">
<bpmn:extensionElements>
<camunda:executionListener delegateExpression="${addLeaders}" event="take" />
</bpmn:extensionElements>
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${day > 5}</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:userTask id="Activity_1f1jgcj" name="直接领导审批" camunda:assignee="wangbing">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="评论" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0p1ao8b</bpmn:incoming>
<bpmn:outgoing>Flow_0m0n34x</bpmn:outgoing>
</bpmn:userTask>
<bpmn:userTask id="Activity_18tpm8b" name="直接领导和部门经理审批" camunda:assignee="${leader}">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="评论" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1jui8fx</bpmn:incoming>
<bpmn:outgoing>Flow_0hs4ead</bpmn:outgoing>
<bpmn:multiInstanceLoopCharacteristics isSequential="true" camunda:collection="${leaders}" camunda:elementVariable="leader" />
</bpmn:userTask>
<bpmn:userTask id="Activity_0r0xmml" name="直接领导和部门经理和总经理审批" camunda:assignee="${leader}">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="评论" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_05yz9dh</bpmn:incoming>
<bpmn:outgoing>Flow_09jz26f</bpmn:outgoing>
<bpmn:multiInstanceLoopCharacteristics isSequential="true" camunda:collection="${leaders}" camunda:elementVariable="leader" />
</bpmn:userTask>
<bpmn:inclusiveGateway id="Gateway_16g54fw">
<bpmn:incoming>Flow_1u762fi</bpmn:incoming>
<bpmn:outgoing>Flow_0p1ao8b</bpmn:outgoing>
<bpmn:outgoing>Flow_1jui8fx</bpmn:outgoing>
<bpmn:outgoing>Flow_05yz9dh</bpmn:outgoing>
<bpmn:outgoing>Flow_1y98kim</bpmn:outgoing>
</bpmn:inclusiveGateway>
<bpmn:sequenceFlow id="Flow_0m0n34x" sourceRef="Activity_1f1jgcj" targetRef="Gateway_1oseax7" />
<bpmn:inclusiveGateway id="Gateway_1oseax7">
<bpmn:incoming>Flow_0m0n34x</bpmn:incoming>
<bpmn:incoming>Flow_0hs4ead</bpmn:incoming>
<bpmn:incoming>Flow_09jz26f</bpmn:incoming>
<bpmn:incoming>Flow_1kk4i16</bpmn:incoming>
<bpmn:outgoing>Flow_0wrta3v</bpmn:outgoing>
</bpmn:inclusiveGateway>
<bpmn:sequenceFlow id="Flow_0hs4ead" sourceRef="Activity_18tpm8b" targetRef="Gateway_1oseax7" />
<bpmn:sequenceFlow id="Flow_09jz26f" sourceRef="Activity_0r0xmml" targetRef="Gateway_1oseax7" />
<bpmn:endEvent id="Event_0msblfe">
<bpmn:incoming>Flow_0wrta3v</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0wrta3v" sourceRef="Gateway_1oseax7" targetRef="Event_0msblfe" />
<bpmn:sequenceFlow id="Flow_1y98kim" name="大于3天" sourceRef="Gateway_16g54fw" targetRef="Activity_1nwb0df">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${day > 3}</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:userTask id="Activity_1nwb0df" name="人事经理审批" camunda:assignee="renyingying">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="评论" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1y98kim</bpmn:incoming>
<bpmn:outgoing>Flow_1kk4i16</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_1kk4i16" sourceRef="Activity_1nwb0df" targetRef="Gateway_1oseax7" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1rcixk0_baohan">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="229" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="175" y="272" width="44" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0amkuf6_di" bpmnElement="Activity_17jf4ew">
<dc:Bounds x="270" y="207" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0o45zp4_di" bpmnElement="Activity_1f1jgcj">
<dc:Bounds x="630" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_11n2h3w_di" bpmnElement="Activity_18tpm8b">
<dc:Bounds x="630" y="207" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0xpuevc_di" bpmnElement="Activity_0r0xmml">
<dc:Bounds x="630" y="330" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_01h16tf_di" bpmnElement="Gateway_16g54fw">
<dc:Bounds x="425" y="222" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_04i6hjq_di" bpmnElement="Gateway_1oseax7">
<dc:Bounds x="885" y="222" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0msblfe_di" bpmnElement="Event_0msblfe">
<dc:Bounds x="1032" y="229" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0jrlpki_di" bpmnElement="Activity_1nwb0df">
<dc:Bounds x="630" y="440" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_14apr32_di" bpmnElement="Flow_14apr32">
<di:waypoint x="215" y="247" />
<di:waypoint x="270" y="247" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1u762fi_di" bpmnElement="Flow_1u762fi">
<di:waypoint x="370" y="247" />
<di:waypoint x="425" y="247" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0p1ao8b_di" bpmnElement="Flow_0p1ao8b">
<di:waypoint x="450" y="222" />
<di:waypoint x="450" y="120" />
<di:waypoint x="630" y="120" />
<bpmndi:BPMNLabel>
<dc:Bounds x="509" y="103" width="62" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1jui8fx_di" bpmnElement="Flow_1jui8fx">
<di:waypoint x="475" y="247" />
<di:waypoint x="630" y="247" />
<bpmndi:BPMNLabel>
<dc:Bounds x="512" y="229" width="84" height="27" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_05yz9dh_di" bpmnElement="Flow_05yz9dh">
<di:waypoint x="450" y="272" />
<di:waypoint x="450" y="370" />
<di:waypoint x="630" y="370" />
<bpmndi:BPMNLabel>
<dc:Bounds x="520" y="343" width="40" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0m0n34x_di" bpmnElement="Flow_0m0n34x">
<di:waypoint x="730" y="120" />
<di:waypoint x="910" y="120" />
<di:waypoint x="910" y="222" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0hs4ead_di" bpmnElement="Flow_0hs4ead">
<di:waypoint x="730" y="247" />
<di:waypoint x="885" y="247" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_09jz26f_di" bpmnElement="Flow_09jz26f">
<di:waypoint x="730" y="370" />
<di:waypoint x="910" y="370" />
<di:waypoint x="910" y="272" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0wrta3v_di" bpmnElement="Flow_0wrta3v">
<di:waypoint x="935" y="247" />
<di:waypoint x="1032" y="247" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1y98kim_di" bpmnElement="Flow_1y98kim">
<di:waypoint x="450" y="272" />
<di:waypoint x="450" y="480" />
<di:waypoint x="630" y="480" />
<bpmndi:BPMNLabel>
<dc:Bounds x="520" y="463" width="40" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1kk4i16_di" bpmnElement="Flow_1kk4i16">
<di:waypoint x="730" y="480" />
<di:waypoint x="910" y="480" />
<di:waypoint x="910" y="272" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
19、基于事件网关(Event-based Gateway)
描述
基于事件的网关最少有两条可执行路径,根据事件做出执行路径的选择决定,当执行到达事件网关时,流程进入等待状态。每个传出序列流后面只能是中间捕获事件的元素。
且中间捕获事件的元素只能有一个输入序列流。
需求
假设员工xiaoming请假后,3分钟内直接领导wangbing收到了审批提醒,就是直接领导wangbing审批,超过3分钟直接领导没收到信号,就让部门经理zhangsan审批,最后总经理wangwu审批。
BPMN设计
XML
<?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_1aggmfi" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_1ykaiwf" name="基于事件网关" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_10g8p1l</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_10g8p1l" sourceRef="StartEvent_1" targetRef="Activity_0tg5dnd" />
<bpmn:userTask id="Activity_0tg5dnd" name="员工请假" camunda:assignee="xiaoming">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="day" label="请假天数" type="long" defaultValue="1" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_10g8p1l</bpmn:incoming>
<bpmn:outgoing>Flow_0lfmd36</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_0lfmd36" sourceRef="Activity_0tg5dnd" targetRef="Gateway_1oq3am6" />
<bpmn:eventBasedGateway id="Gateway_1oq3am6">
<bpmn:incoming>Flow_0lfmd36</bpmn:incoming>
<bpmn:outgoing>Flow_1md212o</bpmn:outgoing>
<bpmn:outgoing>Flow_0u86uqo</bpmn:outgoing>
</bpmn:eventBasedGateway>
<bpmn:intermediateCatchEvent id="Event_1c0yjiv">
<bpmn:incoming>Flow_1md212o</bpmn:incoming>
<bpmn:outgoing>Flow_1txed2k</bpmn:outgoing>
<bpmn:timerEventDefinition id="TimerEventDefinition_18z2fd4">
<bpmn:timeDuration xsi:type="bpmn:tFormalExpression">PT3M</bpmn:timeDuration>
</bpmn:timerEventDefinition>
</bpmn:intermediateCatchEvent>
<bpmn:sequenceFlow id="Flow_1md212o" sourceRef="Gateway_1oq3am6" targetRef="Event_1c0yjiv" />
<bpmn:sequenceFlow id="Flow_1txed2k" sourceRef="Event_1c0yjiv" targetRef="Activity_0m95cgw" />
<bpmn:userTask id="Activity_0m95cgw" name="部门经理审批" camunda:assignee="zhangsan">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="评论" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1txed2k</bpmn:incoming>
<bpmn:outgoing>Flow_0vebupd</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_0vebupd" sourceRef="Activity_0m95cgw" targetRef="Activity_0ghk285" />
<bpmn:userTask id="Activity_0ghk285" name="总经理审批" camunda:assignee="wangwu">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id=" comment" label="评论" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0vebupd</bpmn:incoming>
<bpmn:incoming>Flow_0jrc4ll</bpmn:incoming>
<bpmn:outgoing>Flow_1xfjrkf</bpmn:outgoing>
</bpmn:userTask>
<bpmn:endEvent id="Event_0m9mkvl">
<bpmn:incoming>Flow_1xfjrkf</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1xfjrkf" sourceRef="Activity_0ghk285" targetRef="Event_0m9mkvl" />
<bpmn:intermediateCatchEvent id="Event_1j75b5r">
<bpmn:incoming>Flow_0u86uqo</bpmn:incoming>
<bpmn:outgoing>Flow_0f4hti7</bpmn:outgoing>
<bpmn:signalEventDefinition id="SignalEventDefinition_1fipr02" signalRef="Signal_2bp1a63" />
</bpmn:intermediateCatchEvent>
<bpmn:sequenceFlow id="Flow_0u86uqo" sourceRef="Gateway_1oq3am6" targetRef="Event_1j75b5r" />
<bpmn:sequenceFlow id="Flow_0f4hti7" sourceRef="Event_1j75b5r" targetRef="Activity_1oc5h9k" />
<bpmn:userTask id="Activity_1oc5h9k" name="直接领导审批" camunda:assignee="wangbing">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="评论" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0f4hti7</bpmn:incoming>
<bpmn:outgoing>Flow_0jrc4ll</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_0jrc4ll" sourceRef="Activity_1oc5h9k" targetRef="Activity_0ghk285" />
</bpmn:process>
<bpmn:signal id="Signal_38gons5" name="Signal_38gons5" />
<bpmn:signal id="Signal_1kkgc4f" name="Signal_1kkgc4f" />
<bpmn:signal id="Signal_2bp1a63" name="Signal_direct_leader" />
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1ykaiwf">
<bpmndi:BPMNShape id="Event_1c0yjiv_di" bpmnElement="Event_1c0yjiv">
<dc:Bounds x="532" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1lyug10_di" bpmnElement="Activity_0m95cgw">
<dc:Bounds x="630" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1j75b5r_di" bpmnElement="Event_1j75b5r">
<dc:Bounds x="532" y="212" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_04gtoo4_di" bpmnElement="Activity_0ghk285">
<dc:Bounds x="830" y="130" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_04orr60_di" bpmnElement="Activity_1oc5h9k">
<dc:Bounds x="630" y="190" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0m9mkvl_di" bpmnElement="Event_0m9mkvl">
<dc:Bounds x="992" y="152" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_09ze404_di" bpmnElement="Gateway_1oq3am6">
<dc:Bounds x="425" y="145" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="152" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_12i0ai8_di" bpmnElement="Activity_0tg5dnd">
<dc:Bounds x="270" y="130" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0lfmd36_di" bpmnElement="Flow_0lfmd36">
<di:waypoint x="370" y="170" />
<di:waypoint x="425" y="170" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1md212o_di" bpmnElement="Flow_1md212o">
<di:waypoint x="450" y="145" />
<di:waypoint x="450" y="117" />
<di:waypoint x="532" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1txed2k_di" bpmnElement="Flow_1txed2k">
<di:waypoint x="568" y="117" />
<di:waypoint x="630" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0vebupd_di" bpmnElement="Flow_0vebupd">
<di:waypoint x="730" y="117" />
<di:waypoint x="780" y="117" />
<di:waypoint x="780" y="170" />
<di:waypoint x="830" y="170" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1xfjrkf_di" bpmnElement="Flow_1xfjrkf">
<di:waypoint x="930" y="170" />
<di:waypoint x="992" y="170" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0u86uqo_di" bpmnElement="Flow_0u86uqo">
<di:waypoint x="450" y="195" />
<di:waypoint x="450" y="230" />
<di:waypoint x="532" y="230" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0f4hti7_di" bpmnElement="Flow_0f4hti7">
<di:waypoint x="568" y="230" />
<di:waypoint x="630" y="230" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0jrc4ll_di" bpmnElement="Flow_0jrc4ll">
<di:waypoint x="730" y="230" />
<di:waypoint x="780" y="230" />
<di:waypoint x="780" y="170" />
<di:waypoint x="830" y="170" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_10g8p1l_di" bpmnElement="Flow_10g8p1l">
<di:waypoint x="215" y="170" />
<di:waypoint x="270" y="170" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Java代码
package com.lonewalker.snail.buss.gateway.eventbased;
import org.camunda.bpm.engine.RuntimeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SendSignalController {
@Autowired
private RuntimeService runtimeService;
@GetMapping("/sendSignal")
public boolean sendSignal(){
this.runtimeService.createSignalEvent("Signal_direct_leader").send();
return true;
}
}
20、定时事件(Timer Event)
描述
定时事件(Timer Events)指定时器触发的事件,可以用作启动事件、中间事件或边界事件。用作边界事件时,任务执行到节点时,定时器开始计时,这个功能用作任务超时处理挺有用。
https://docs.camunda.org/manual/latest/reference/bpmn20/events/timer-events/#time-date
Time Date: 指定的时间执行,如2022-08-29T12:13:14Z 2022-08-29T12:13:14+08:00(东八区)
Time Duration: 过多长时间后任务开始执行,如PT1H3M 表示过1小时3分钟就开始执行。
Time Cycle: 循环执行的时间间隔,如R3/PT10H 表示每十个小时执行一次,一共三次。
需求
假设员工请假流程,在直接领导(wangbing)的时候有时间约束,超过3分钟没有审批,直接把任务流转到部门经理(zhangsan)审批.
设计BPMN
<?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_1hjcdr9" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_0z7jcwg" name="定时事件" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_06a5hg3</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_06a5hg3" sourceRef="StartEvent_1" targetRef="Activity_1pwwfxg" />
<bpmn:userTask id="Activity_1pwwfxg" name="员工请假" camunda:assignee="xiaoming">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="day" label="请假天数" type="long" defaultValue="1" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_06a5hg3</bpmn:incoming>
<bpmn:outgoing>Flow_1jwfjvt</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_1jwfjvt" sourceRef="Activity_1pwwfxg" targetRef="Activity_1by7wwc" />
<bpmn:userTask id="Activity_1by7wwc" name="直接领导审批" camunda:assignee="wangbing">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="评论" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1jwfjvt</bpmn:incoming>
<bpmn:outgoing>Flow_0d0neqr</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_0d0neqr" sourceRef="Activity_1by7wwc" targetRef="Activity_0yxn2tu" />
<bpmn:userTask id="Activity_0yxn2tu" name="部门经理审批" camunda:assignee="zhangsan">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="comment" label="评论" type="string" defaultValue="同意" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0d0neqr</bpmn:incoming>
<bpmn:incoming>Flow_04q7ank</bpmn:incoming>
<bpmn:outgoing>Flow_0a3m7oi</bpmn:outgoing>
</bpmn:userTask>
<bpmn:endEvent id="Event_08op59n">
<bpmn:incoming>Flow_0a3m7oi</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0a3m7oi" sourceRef="Activity_0yxn2tu" targetRef="Event_08op59n" />
<bpmn:sequenceFlow id="Flow_04q7ank" name="超过1分钟" sourceRef="Event_09pw7bi" targetRef="Activity_0yxn2tu">
<bpmn:extensionElements />
</bpmn:sequenceFlow>
<bpmn:boundaryEvent id="Event_09pw7bi" attachedToRef="Activity_1by7wwc">
<bpmn:outgoing>Flow_04q7ank</bpmn:outgoing>
<bpmn:timerEventDefinition id="TimerEventDefinition_1rstsod">
<bpmn:timeDuration xsi:type="bpmn:tFormalExpression">PT1M</bpmn:timeDuration>
</bpmn:timerEventDefinition>
</bpmn:boundaryEvent>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_0z7jcwg">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_10j3ma0_di" bpmnElement="Activity_1pwwfxg">
<dc:Bounds x="270" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1kfe7bc_di" bpmnElement="Activity_1by7wwc">
<dc:Bounds x="430" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_17p9bq8_di" bpmnElement="Activity_0yxn2tu">
<dc:Bounds x="590" y="77" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_08op59n_di" bpmnElement="Event_08op59n">
<dc:Bounds x="752" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1xx3u3s_di" bpmnElement="Event_09pw7bi">
<dc:Bounds x="482" y="139" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_06a5hg3_di" bpmnElement="Flow_06a5hg3">
<di:waypoint x="215" y="117" />
<di:waypoint x="270" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1jwfjvt_di" bpmnElement="Flow_1jwfjvt">
<di:waypoint x="370" y="117" />
<di:waypoint x="430" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0d0neqr_di" bpmnElement="Flow_0d0neqr">
<di:waypoint x="530" y="117" />
<di:waypoint x="590" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0a3m7oi_di" bpmnElement="Flow_0a3m7oi">
<di:waypoint x="690" y="117" />
<di:waypoint x="752" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_04q7ank_di" bpmnElement="Flow_04q7ank">
<di:waypoint x="500" y="175" />
<di:waypoint x="500" y="195" />
<di:waypoint x="640" y="195" />
<di:waypoint x="640" y="157" />
<bpmndi:BPMNLabel>
<dc:Bounds x="545" y="177" width="50" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
21、消息事件(Message Event)
描述
消息事件(Message events)是引用已命名消息的事件。一条消息有一个名称和一个有效负载。与信号不同,消息事件总是指向单个收件人。消息事件定义是通过使用messageEventDefinition元素声明的。
- Camunda消息事件包括:Message Start Event(消息启动事件);
- Message Intermediate Catching Event(消息中间捕获事件);
- Message Boundary Event(消息边界事件);
- Message Intermediate Throwing Event(消息中断抛出事件);
- Message End Event(消息结束事件)
需求
假设在线订餐平台分为微信小程序订餐,支付宝小程序订餐,微信订餐支持微信支付,支付宝订餐支持支付宝支付。付款流程设置两个信号事件,在处理订单任务中根据订餐端的类型启动不同支付流程。
BPMN设计
XML
<?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_1ydzq3q" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_1efquuw" name="消息事件" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0lgt4mm</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0lgt4mm" sourceRef="StartEvent_1" targetRef="Activity_0ixf8ri" />
<bpmn:userTask id="Activity_0ixf8ri" name="用户下订单" camunda:assignee="xiaoming">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="endpoint" label="使用终端" type="enum" defaultValue="wechat">
<camunda:value id="wechat" name="微信小程序" />
<camunda:value id="alipay" name="支付宝小程序" />
</camunda:formField>
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0lgt4mm</bpmn:incoming>
<bpmn:outgoing>Flow_02rl081</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_02rl081" sourceRef="Activity_0ixf8ri" targetRef="Activity_0fml37y" />
<bpmn:serviceTask id="Activity_0fml37y" name="处理订单" camunda:delegateExpression="${handleOrder}">
<bpmn:incoming>Flow_02rl081</bpmn:incoming>
<bpmn:outgoing>Flow_08gbi8s</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:endEvent id="Event_0teeyqq">
<bpmn:incoming>Flow_08gbi8s</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_08gbi8s" sourceRef="Activity_0fml37y" targetRef="Event_0teeyqq" />
<bpmn:startEvent id="Event_12gfp0q" name="微信订餐">
<bpmn:outgoing>Flow_0h9ce8w</bpmn:outgoing>
<bpmn:messageEventDefinition id="MessageEventDefinition_0oxjqds" messageRef="Message_2o62p2a" />
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0h9ce8w" sourceRef="Event_12gfp0q" targetRef="Activity_1sgali6" />
<bpmn:serviceTask id="Activity_1sgali6" name="微信支付" camunda:type="external" camunda:topic="weChatPay">
<bpmn:incoming>Flow_0h9ce8w</bpmn:incoming>
<bpmn:outgoing>Flow_068rz4q</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="Flow_068rz4q" sourceRef="Activity_1sgali6" targetRef="Activity_03zqi8j" />
<bpmn:serviceTask id="Activity_03zqi8j" name="支付成功" camunda:type="external" camunda:topic="pay_success">
<bpmn:incoming>Flow_068rz4q</bpmn:incoming>
<bpmn:incoming>Flow_0nwx9dc</bpmn:incoming>
<bpmn:outgoing>Flow_1kzfqdo</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:startEvent id="Event_1ers7o5" name="支付宝订餐">
<bpmn:outgoing>Flow_0geeo29</bpmn:outgoing>
<bpmn:messageEventDefinition id="MessageEventDefinition_0mgekkn" messageRef="Message_3dqeof3" />
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0geeo29" sourceRef="Event_1ers7o5" targetRef="Activity_1alzjs2" />
<bpmn:serviceTask id="Activity_1alzjs2" name="支付宝支付" camunda:type="external" camunda:topic="alipay">
<bpmn:incoming>Flow_0geeo29</bpmn:incoming>
<bpmn:outgoing>Flow_0nwx9dc</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:endEvent id="Event_045qyu6">
<bpmn:incoming>Flow_1kzfqdo</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1kzfqdo" sourceRef="Activity_03zqi8j" targetRef="Event_045qyu6" />
<bpmn:sequenceFlow id="Flow_0nwx9dc" sourceRef="Activity_1alzjs2" targetRef="Activity_03zqi8j" />
</bpmn:process>
<bpmn:message id="Message_2o62p2a" name="Message_wechat" />
<bpmn:message id="Message_3dqeof3" name="Message_alipay" />
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1efquuw">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="152" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_02x2sl5_di" bpmnElement="Activity_0ixf8ri">
<dc:Bounds x="240" y="80" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1hfwn8u_di" bpmnElement="Activity_0fml37y">
<dc:Bounds x="400" y="80" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0teeyqq_di" bpmnElement="Event_0teeyqq">
<dc:Bounds x="562" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0ytbisa_di" bpmnElement="Event_12gfp0q">
<dc:Bounds x="152" y="282" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="149" y="325" width="44" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1slui5i_di" bpmnElement="Activity_1sgali6">
<dc:Bounds x="240" y="260" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1j1yl3g_di" bpmnElement="Event_1ers7o5">
<dc:Bounds x="152" y="402" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="143" y="445" width="55" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1mqta9v_di" bpmnElement="Activity_1alzjs2">
<dc:Bounds x="240" y="380" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1te6p9r_di" bpmnElement="Activity_03zqi8j">
<dc:Bounds x="430" y="320" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_045qyu6_di" bpmnElement="Event_045qyu6">
<dc:Bounds x="592" y="342" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0lgt4mm_di" bpmnElement="Flow_0lgt4mm">
<di:waypoint x="188" y="120" />
<di:waypoint x="240" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_02rl081_di" bpmnElement="Flow_02rl081">
<di:waypoint x="340" y="120" />
<di:waypoint x="400" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_08gbi8s_di" bpmnElement="Flow_08gbi8s">
<di:waypoint x="500" y="120" />
<di:waypoint x="562" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0h9ce8w_di" bpmnElement="Flow_0h9ce8w">
<di:waypoint x="188" y="300" />
<di:waypoint x="240" y="300" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_068rz4q_di" bpmnElement="Flow_068rz4q">
<di:waypoint x="340" y="300" />
<di:waypoint x="385" y="300" />
<di:waypoint x="385" y="360" />
<di:waypoint x="430" y="360" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0geeo29_di" bpmnElement="Flow_0geeo29">
<di:waypoint x="188" y="420" />
<di:waypoint x="240" y="420" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1kzfqdo_di" bpmnElement="Flow_1kzfqdo">
<di:waypoint x="530" y="360" />
<di:waypoint x="592" y="360" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0nwx9dc_di" bpmnElement="Flow_0nwx9dc">
<di:waypoint x="340" y="420" />
<di:waypoint x="385" y="420" />
<di:waypoint x="385" y="360" />
<di:waypoint x="430" y="360" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Java代码
package com.lonewalker.snail.buss.event;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.springframework.stereotype.Service;
/**
* 消息事件.
*
* @author Li Zemin
* @since 2024/3/7 8:38
*/
@Service("handleOrder")
public class HandleOrderService implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) throws Exception {
System.out.println("处理订餐订单");
Object endpoint = execution.getVariable("endpoint");
RuntimeService runtimeService = execution.getProcessEngineServices().getRuntimeService();
if ("alipay".equals(endpoint)) {
runtimeService.startProcessInstanceByMessage("Message_alipay");
} else if ("wechat".equals(endpoint)) {
runtimeService.startProcessInstanceByMessage("Message_wechat");
}
}
}
package com.lonewalker.snail.buss.event;
import org.camunda.bpm.client.spring.annotation.ExternalTaskSubscription;
import org.camunda.bpm.client.task.ExternalTaskHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 支付.
*
* @author Li Zemin
* @since 2024/3/7 8:43
*/
@Configuration
public class PayExternal {
@Bean
@ExternalTaskSubscription(topicName = "weChatPay", processDefinitionKeyIn = {"Process_1efquuw"}, lockDuration = 5000)
public ExternalTaskHandler weChatPay() {
return (externalTask, externalTaskService) -> {
System.out.println("外部任务进入weChatPay");
externalTaskService.complete(externalTask);
};
}
@Bean
@ExternalTaskSubscription(topicName = "alipay", processDefinitionKeyIn = {"Process_1efquuw"}, lockDuration = 5000)
public ExternalTaskHandler alipay() {
return (externalTask, externalTaskService) -> {
System.out.println("外部任务进入alipay");
externalTaskService.complete(externalTask);
};
}
@Bean
@ExternalTaskSubscription(topicName = "pay_success", processDefinitionKeyIn = {"Process_1efquuw"}, lockDuration = 5000)
public ExternalTaskHandler paySuccess() {
return (externalTask, externalTaskService) -> {
System.out.println("外部任务进入paySuccess");
externalTaskService.complete(externalTask);
};
}
}
22、嵌套子流程(embedded Subprocess)
描述
子流程是包含其他活动、网关、事件等的活动, 嵌套子流程是指其本身形成的流程是更大流程的一部分,元素为一个大方框,方框内部是一个完整的流程。
嵌套子流程分可以是并行多实例(parallel multi instance subprocess),串行多实例(Sequential multi instance subprocess)
子流程运行时,主流程会等待。子流程结束,主流程继续。
子流程用处:
- 1.分层建模
- 2.控制变量作用范围
需求
假设并行网关章节的上传视频是批量上传,对每个视频进行的格式校验、涉黄鉴别、涉暴鉴别、负面判断都是一个子流程完成。
以并行子流程演示一下,串行的操作逻辑是一样的。
BPMN设计
XML
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0woopvd" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_1s2ffff" name="嵌套子流程" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1y67dx8</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_1y67dx8" sourceRef="StartEvent_1" targetRef="Activity_13xe75o" />
<bpmn:userTask id="Activity_13xe75o" name="用户上传视频" camunda:assignee="xiaoming">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="numbers" label="批量上传视频数" type="long" defaultValue="1" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1y67dx8</bpmn:incoming>
<bpmn:outgoing>Flow_0ay41n4</bpmn:outgoing>
</bpmn:userTask>
<bpmn:userTask id="Activity_1e6lwj0" name="确定上传" camunda:assignee="wangwu">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="isUpload" label="是否上传" type="boolean" defaultValue="true" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_035z70a</bpmn:incoming>
<bpmn:outgoing>Flow_0moftkc</bpmn:outgoing>
</bpmn:userTask>
<bpmn:endEvent id="Event_05wgy65">
<bpmn:incoming>Flow_0moftkc</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0moftkc" sourceRef="Activity_1e6lwj0" targetRef="Event_05wgy65" />
<bpmn:subProcess id="Activity_0pf1w6o">
<bpmn:incoming>Flow_0ay41n4</bpmn:incoming>
<bpmn:outgoing>Flow_035z70a</bpmn:outgoing>
<bpmn:multiInstanceLoopCharacteristics>
<bpmn:loopCardinality xsi:type="bpmn:tFormalExpression">${numbers}</bpmn:loopCardinality>
</bpmn:multiInstanceLoopCharacteristics>
<bpmn:startEvent id="Event_1pdp8f3">
<bpmn:outgoing>Flow_0op672m</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:parallelGateway id="Gateway_01tkydk">
<bpmn:incoming>Flow_0op672m</bpmn:incoming>
<bpmn:outgoing>Flow_0xdabmi</bpmn:outgoing>
<bpmn:outgoing>Flow_1qvfhhv</bpmn:outgoing>
<bpmn:outgoing>Flow_1syku1i</bpmn:outgoing>
<bpmn:outgoing>Flow_0uk1u98</bpmn:outgoing>
</bpmn:parallelGateway>
<bpmn:serviceTask id="Activity_0i7p9i9" name="视频格式校验" camunda:delegateExpression="${checkVideoFormat}">
<bpmn:incoming>Flow_0uk1u98</bpmn:incoming>
<bpmn:outgoing>Flow_0g7s9k1</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:userTask id="Activity_1tntphb" name="涉黄鉴别" camunda:assignee="wangbing">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="isYellow" label="是否涉黄" type="boolean" defaultValue="false" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1syku1i</bpmn:incoming>
<bpmn:outgoing>Flow_0uongoh</bpmn:outgoing>
</bpmn:userTask>
<bpmn:userTask id="Activity_1jjo31h" name="涉暴处理" camunda:assignee="zhangsan">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="isViolence" label="是否涉暴" type="boolean" defaultValue="false" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1qvfhhv</bpmn:incoming>
<bpmn:outgoing>Flow_0yj1vyl</bpmn:outgoing>
</bpmn:userTask>
<bpmn:serviceTask id="Activity_1l6e3fu" name="负面影响判断" camunda:type="external" camunda:topic="checkNegtive">
<bpmn:incoming>Flow_0xdabmi</bpmn:incoming>
<bpmn:outgoing>Flow_0ps2cut</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:parallelGateway id="Gateway_1xr8a3v">
<bpmn:incoming>Flow_0g7s9k1</bpmn:incoming>
<bpmn:incoming>Flow_0uongoh</bpmn:incoming>
<bpmn:incoming>Flow_0yj1vyl</bpmn:incoming>
<bpmn:incoming>Flow_0ps2cut</bpmn:incoming>
<bpmn:outgoing>Flow_0dpf03d</bpmn:outgoing>
</bpmn:parallelGateway>
<bpmn:sequenceFlow id="Flow_0xdabmi" sourceRef="Gateway_01tkydk" targetRef="Activity_1l6e3fu" />
<bpmn:sequenceFlow id="Flow_1qvfhhv" sourceRef="Gateway_01tkydk" targetRef="Activity_1jjo31h" />
<bpmn:sequenceFlow id="Flow_1syku1i" sourceRef="Gateway_01tkydk" targetRef="Activity_1tntphb" />
<bpmn:sequenceFlow id="Flow_0uk1u98" sourceRef="Gateway_01tkydk" targetRef="Activity_0i7p9i9" />
<bpmn:sequenceFlow id="Flow_0g7s9k1" sourceRef="Activity_0i7p9i9" targetRef="Gateway_1xr8a3v" />
<bpmn:sequenceFlow id="Flow_0uongoh" sourceRef="Activity_1tntphb" targetRef="Gateway_1xr8a3v" />
<bpmn:sequenceFlow id="Flow_0yj1vyl" sourceRef="Activity_1jjo31h" targetRef="Gateway_1xr8a3v" />
<bpmn:sequenceFlow id="Flow_0ps2cut" sourceRef="Activity_1l6e3fu" targetRef="Gateway_1xr8a3v" />
<bpmn:sequenceFlow id="Flow_0op672m" sourceRef="Event_1pdp8f3" targetRef="Gateway_01tkydk" />
<bpmn:endEvent id="Event_041661o">
<bpmn:incoming>Flow_0dpf03d</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0dpf03d" sourceRef="Gateway_1xr8a3v" targetRef="Event_041661o" />
</bpmn:subProcess>
<bpmn:sequenceFlow id="Flow_0ay41n4" sourceRef="Activity_13xe75o" targetRef="Activity_0pf1w6o" />
<bpmn:sequenceFlow id="Flow_035z70a" sourceRef="Activity_0pf1w6o" targetRef="Activity_1e6lwj0" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1s2ffff">
<bpmndi:BPMNShape id="Activity_0flepn4_di" bpmnElement="Activity_13xe75o">
<dc:Bounds x="240" y="260" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="152" y="282" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1tva6wt_di" bpmnElement="Activity_1e6lwj0">
<dc:Bounds x="1030" y="260" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_05wgy65_di" bpmnElement="Event_05wgy65">
<dc:Bounds x="1202" y="282" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0pf1w6o_di" bpmnElement="Activity_0pf1w6o" isExpanded="true">
<dc:Bounds x="420" y="50" width="540" height="480" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_1jsdisz_di" bpmnElement="Gateway_01tkydk">
<dc:Bounds x="535" y="275" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0bpn50p_di" bpmnElement="Activity_0i7p9i9">
<dc:Bounds x="640" y="80" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_12qiubo_di" bpmnElement="Activity_1tntphb">
<dc:Bounds x="640" y="200" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0bmqfq6_di" bpmnElement="Activity_1jjo31h">
<dc:Bounds x="640" y="310" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1uagnj9_di" bpmnElement="Activity_1l6e3fu">
<dc:Bounds x="640" y="420" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_0rsiubf_di" bpmnElement="Gateway_1xr8a3v">
<dc:Bounds x="795" y="275" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_041661o_di" bpmnElement="Event_041661o">
<dc:Bounds x="902" y="282" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1pdp8f3_di" bpmnElement="Event_1pdp8f3">
<dc:Bounds x="442" y="282" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0xdabmi_di" bpmnElement="Flow_0xdabmi">
<di:waypoint x="560" y="325" />
<di:waypoint x="560" y="460" />
<di:waypoint x="640" y="460" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1qvfhhv_di" bpmnElement="Flow_1qvfhhv">
<di:waypoint x="560" y="325" />
<di:waypoint x="560" y="350" />
<di:waypoint x="640" y="350" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1syku1i_di" bpmnElement="Flow_1syku1i">
<di:waypoint x="560" y="275" />
<di:waypoint x="560" y="240" />
<di:waypoint x="640" y="240" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0uk1u98_di" bpmnElement="Flow_0uk1u98">
<di:waypoint x="560" y="275" />
<di:waypoint x="560" y="120" />
<di:waypoint x="640" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0g7s9k1_di" bpmnElement="Flow_0g7s9k1">
<di:waypoint x="740" y="120" />
<di:waypoint x="820" y="120" />
<di:waypoint x="820" y="275" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0uongoh_di" bpmnElement="Flow_0uongoh">
<di:waypoint x="740" y="240" />
<di:waypoint x="820" y="240" />
<di:waypoint x="820" y="275" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0yj1vyl_di" bpmnElement="Flow_0yj1vyl">
<di:waypoint x="740" y="350" />
<di:waypoint x="820" y="350" />
<di:waypoint x="820" y="325" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0ps2cut_di" bpmnElement="Flow_0ps2cut">
<di:waypoint x="740" y="460" />
<di:waypoint x="820" y="460" />
<di:waypoint x="820" y="325" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0op672m_di" bpmnElement="Flow_0op672m">
<di:waypoint x="478" y="300" />
<di:waypoint x="535" y="300" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0dpf03d_di" bpmnElement="Flow_0dpf03d">
<di:waypoint x="845" y="300" />
<di:waypoint x="902" y="300" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1y67dx8_di" bpmnElement="Flow_1y67dx8">
<di:waypoint x="188" y="300" />
<di:waypoint x="240" y="300" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0moftkc_di" bpmnElement="Flow_0moftkc">
<di:waypoint x="1130" y="300" />
<di:waypoint x="1202" y="300" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0ay41n4_di" bpmnElement="Flow_0ay41n4">
<di:waypoint x="340" y="300" />
<di:waypoint x="420" y="300" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_035z70a_di" bpmnElement="Flow_035z70a">
<di:waypoint x="960" y="300" />
<di:waypoint x="1030" y="300" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Java代码
package com.lonewalker.snail.buss.gateway.parallel;
import java.util.concurrent.TimeUnit;
import org.camunda.bpm.client.spring.annotation.ExternalTaskSubscription;
import org.camunda.bpm.client.task.ExternalTaskHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 负面影响判断.
*
* @author Li Zemin
* @since 2024/3/6 9:13
*/
@Configuration
public class ExternalCheckNegtive {
@Bean
@ExternalTaskSubscription(topicName = "checkNegtive", processDefinitionKeyIn = {"Process_1s2ftvg", "Process_1s2ffff"},
lockDuration = 5000)
public ExternalTaskHandler checkNegtive() {
return (externalTask, externalTaskService) -> {
System.out.println("外部任务进入负面影响判断");
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
throw new RuntimeException(e);
}
Object videoName = externalTask.getVariable("videoName");
System.out.println("视频名称:" + videoName + " 不包含负面影响");
externalTaskService.complete(externalTask);
};
}
}
23、调用子流程(Call Activity)
描述
调用子流程是指子流程在主流程的外面。子流程一般是多个流程可重用的流程,也可以独立调用子流程。
可以对比编程中的方法抽取。子流程运行时,主流程也是等待状态。子流程结束,主流程继续
需求
将嵌套子流程改成调用子流程实现一遍。
BPMN设计
主流程
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_0woopvd" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_1s2fccc" name="调用主流程" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1y67dx8</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_1y67dx8" sourceRef="StartEvent_1" targetRef="Activity_13xe75o" />
<bpmn:userTask id="Activity_13xe75o" name="用户上传视频" camunda:assignee="xiaoming">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="numbers" label="批量上传视频数" type="long" defaultValue="1" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1y67dx8</bpmn:incoming>
<bpmn:outgoing>Flow_1l930x0</bpmn:outgoing>
</bpmn:userTask>
<bpmn:userTask id="Activity_1e6lwj0" name="确定上传" camunda:assignee="wangwu">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="isUpload" label="是否上传" type="boolean" defaultValue="true" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0zd6lrm</bpmn:incoming>
<bpmn:outgoing>Flow_0moftkc</bpmn:outgoing>
</bpmn:userTask>
<bpmn:endEvent id="Event_05wgy65">
<bpmn:incoming>Flow_0moftkc</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0moftkc" sourceRef="Activity_1e6lwj0" targetRef="Event_05wgy65" />
<bpmn:callActivity id="Activity_1lliuod" name="处理单个视频" calledElement="Process_052uvlb">
<bpmn:extensionElements>
<camunda:in sourceExpression="${videoName}" target="videoName" />
<camunda:out sourceExpression="${targetResult}" target="result" />
</bpmn:extensionElements>
<bpmn:incoming>Flow_1l930x0</bpmn:incoming>
<bpmn:outgoing>Flow_0zd6lrm</bpmn:outgoing>
<bpmn:multiInstanceLoopCharacteristics camunda:collection="${videoNames}" camunda:elementVariable="videoName" />
</bpmn:callActivity>
<bpmn:sequenceFlow id="Flow_1l930x0" sourceRef="Activity_13xe75o" targetRef="Activity_1lliuod" />
<bpmn:sequenceFlow id="Flow_0zd6lrm" sourceRef="Activity_1lliuod" targetRef="Activity_1e6lwj0" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1s2fccc">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="152" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0flepn4_di" bpmnElement="Activity_13xe75o">
<dc:Bounds x="240" y="80" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0q8zjtn_di" bpmnElement="Activity_1lliuod">
<dc:Bounds x="440" y="80" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1tva6wt_di" bpmnElement="Activity_1e6lwj0">
<dc:Bounds x="640" y="80" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_05wgy65_di" bpmnElement="Event_05wgy65">
<dc:Bounds x="822" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1y67dx8_di" bpmnElement="Flow_1y67dx8">
<di:waypoint x="188" y="120" />
<di:waypoint x="240" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1l930x0_di" bpmnElement="Flow_1l930x0">
<di:waypoint x="340" y="120" />
<di:waypoint x="440" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0moftkc_di" bpmnElement="Flow_0moftkc">
<di:waypoint x="740" y="120" />
<di:waypoint x="822" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0zd6lrm_di" bpmnElement="Flow_0zd6lrm">
<di:waypoint x="540" y="120" />
<di:waypoint x="640" y="120" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
子流程
<?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_0gtpyem" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_052uvlb" name="调用子流程" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="Event_1pdp8f3">
<bpmn:outgoing>Flow_13but3z</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:parallelGateway id="Gateway_01tkydk">
<bpmn:incoming>Flow_13but3z</bpmn:incoming>
<bpmn:outgoing>Flow_0uk1u98</bpmn:outgoing>
<bpmn:outgoing>Flow_1syku1i</bpmn:outgoing>
<bpmn:outgoing>Flow_1qvfhhv</bpmn:outgoing>
<bpmn:outgoing>Flow_0xdabmi</bpmn:outgoing>
</bpmn:parallelGateway>
<bpmn:serviceTask id="Activity_0i7p9i9" name="视频格式校验" camunda:delegateExpression="${checkVideoFormat}">
<bpmn:incoming>Flow_0uk1u98</bpmn:incoming>
<bpmn:outgoing>Flow_0g7s9k1</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:userTask id="Activity_1tntphb" name="涉黄鉴别" camunda:assignee="wangbing">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="isYellow" label="是否涉黄" type="boolean" defaultValue="false" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1syku1i</bpmn:incoming>
<bpmn:outgoing>Flow_0uongoh</bpmn:outgoing>
</bpmn:userTask>
<bpmn:userTask id="Activity_1jjo31h" name="涉暴处理" camunda:assignee="zhangsan">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="isViolence" label="是否涉暴" type="boolean" defaultValue="false" />
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_1qvfhhv</bpmn:incoming>
<bpmn:outgoing>Flow_0yj1vyl</bpmn:outgoing>
</bpmn:userTask>
<bpmn:serviceTask id="Activity_1l6e3fu" name="负面影响判断" camunda:type="external" camunda:topic="checkNegtive">
<bpmn:incoming>Flow_0xdabmi</bpmn:incoming>
<bpmn:outgoing>Flow_0ps2cut</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:parallelGateway id="Gateway_1xr8a3v">
<bpmn:incoming>Flow_0g7s9k1</bpmn:incoming>
<bpmn:incoming>Flow_0uongoh</bpmn:incoming>
<bpmn:incoming>Flow_0yj1vyl</bpmn:incoming>
<bpmn:incoming>Flow_0ps2cut</bpmn:incoming>
<bpmn:outgoing>Flow_0rgd92n</bpmn:outgoing>
</bpmn:parallelGateway>
<bpmn:sequenceFlow id="Flow_0uk1u98" sourceRef="Gateway_01tkydk" targetRef="Activity_0i7p9i9" />
<bpmn:sequenceFlow id="Flow_1syku1i" sourceRef="Gateway_01tkydk" targetRef="Activity_1tntphb" />
<bpmn:sequenceFlow id="Flow_1qvfhhv" sourceRef="Gateway_01tkydk" targetRef="Activity_1jjo31h" />
<bpmn:sequenceFlow id="Flow_0xdabmi" sourceRef="Gateway_01tkydk" targetRef="Activity_1l6e3fu" />
<bpmn:sequenceFlow id="Flow_0g7s9k1" sourceRef="Activity_0i7p9i9" targetRef="Gateway_1xr8a3v" />
<bpmn:sequenceFlow id="Flow_0uongoh" sourceRef="Activity_1tntphb" targetRef="Gateway_1xr8a3v" />
<bpmn:sequenceFlow id="Flow_0yj1vyl" sourceRef="Activity_1jjo31h" targetRef="Gateway_1xr8a3v" />
<bpmn:sequenceFlow id="Flow_0ps2cut" sourceRef="Activity_1l6e3fu" targetRef="Gateway_1xr8a3v" />
<bpmn:endEvent id="Event_041661o">
<bpmn:incoming>Flow_0rgd92n</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_13but3z" sourceRef="Event_1pdp8f3" targetRef="Gateway_01tkydk" />
<bpmn:sequenceFlow id="Flow_0rgd92n" sourceRef="Gateway_1xr8a3v" targetRef="Event_041661o">
<bpmn:extensionElements>
<camunda:executionListener event="take">
<camunda:script scriptFormat="groovy">def result='正常';
execution.setVariable("targetResult",result);</camunda:script>
</camunda:executionListener>
</bpmn:extensionElements>
</bpmn:sequenceFlow>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_052uvlb">
<bpmndi:BPMNShape id="Event_1pdp8f3_di" bpmnElement="Event_1pdp8f3">
<dc:Bounds x="152" y="282" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_1jsdisz_di" bpmnElement="Gateway_01tkydk">
<dc:Bounds x="255" y="275" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0bpn50p_di" bpmnElement="Activity_0i7p9i9">
<dc:Bounds x="360" y="80" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_12qiubo_di" bpmnElement="Activity_1tntphb">
<dc:Bounds x="360" y="200" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0bmqfq6_di" bpmnElement="Activity_1jjo31h">
<dc:Bounds x="360" y="310" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1uagnj9_di" bpmnElement="Activity_1l6e3fu">
<dc:Bounds x="360" y="420" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_0rsiubf_di" bpmnElement="Gateway_1xr8a3v">
<dc:Bounds x="515" y="275" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_041661o_di" bpmnElement="Event_041661o">
<dc:Bounds x="652" y="282" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_13but3z_di" bpmnElement="Flow_13but3z">
<di:waypoint x="188" y="300" />
<di:waypoint x="255" y="300" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0uk1u98_di" bpmnElement="Flow_0uk1u98">
<di:waypoint x="280" y="275" />
<di:waypoint x="280" y="120" />
<di:waypoint x="360" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1syku1i_di" bpmnElement="Flow_1syku1i">
<di:waypoint x="280" y="275" />
<di:waypoint x="280" y="240" />
<di:waypoint x="360" y="240" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1qvfhhv_di" bpmnElement="Flow_1qvfhhv">
<di:waypoint x="280" y="325" />
<di:waypoint x="280" y="350" />
<di:waypoint x="360" y="350" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0xdabmi_di" bpmnElement="Flow_0xdabmi">
<di:waypoint x="280" y="325" />
<di:waypoint x="280" y="460" />
<di:waypoint x="360" y="460" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0g7s9k1_di" bpmnElement="Flow_0g7s9k1">
<di:waypoint x="460" y="120" />
<di:waypoint x="540" y="120" />
<di:waypoint x="540" y="275" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0uongoh_di" bpmnElement="Flow_0uongoh">
<di:waypoint x="460" y="240" />
<di:waypoint x="540" y="240" />
<di:waypoint x="540" y="275" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0yj1vyl_di" bpmnElement="Flow_0yj1vyl">
<di:waypoint x="460" y="350" />
<di:waypoint x="540" y="350" />
<di:waypoint x="540" y="325" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0ps2cut_di" bpmnElement="Flow_0ps2cut">
<di:waypoint x="460" y="460" />
<di:waypoint x="540" y="460" />
<di:waypoint x="540" y="325" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0rgd92n_di" bpmnElement="Flow_0rgd92n">
<di:waypoint x="565" y="300" />
<di:waypoint x="652" y="300" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Java代码
<!-- groovy 依赖 -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.21</version>
</dependency>
<!-- groovy发送http请求,底层是对HttpClient封装 HttpBuilder -->
<dependency>
<groupId>org.codehaus.groovy.modules.http-builder</groupId>
<artifactId>http-builder</artifactId>
<version>0.7.1</version>
</dependency>
package com.lonewalker.snail.buss.gateway.parallel;
import java.util.concurrent.TimeUnit;
import org.camunda.bpm.client.spring.annotation.ExternalTaskSubscription;
import org.camunda.bpm.client.task.ExternalTaskHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 负面影响判断.
*
* @author Li Zemin
* @since 2024/3/6 9:13
*/
@Configuration
public class ExternalCheckNegtive {
@Bean
@ExternalTaskSubscription(topicName = "checkNegtive", processDefinitionKeyIn = {"Process_1s2ftvg",
"Process_1s2ffff","Process_052uvlb"},
lockDuration = 5000)
public ExternalTaskHandler checkNegtive() {
return (externalTask, externalTaskService) -> {
System.out.println("外部任务进入负面影响判断");
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
throw new RuntimeException(e);
}
Object videoName = externalTask.getVariable("videoName");
System.out.println("视频名称:" + videoName + " 不包含负面影响");
externalTaskService.complete(externalTask);
};
}
}
/**
* 多实例-创建流程
* @param processKey
*/
@GetMapping("/startMultiTask/{processKey}")
public void startMultiTask(@PathVariable(value = "processKey") String processKey) {
this.identityService.setAuthenticatedUserId("xiaoming");
VariableMap variables = Variables.createVariables();
// 请假审批使用
LinkedList<String> leaders = new LinkedList<>();
leaders.add("442346754441461760");
leaders.add("demo");
variables.putValue("leaders",leaders);
// 主流程调用子流程使用
LinkedList<String> videoNames = new LinkedList<>();
videoNames.add("这个男人来自地球 The Man from Earth (2007)");
videoNames.add("第六感");
videoNames.add("调音师");
videoNames.add("彗星来的那一夜 Coherence (2013)");
videoNames.add("蝴蝶效应 The Butterfly Effect (2004)");
variables.putValue("videoNames",videoNames);
this.runtimeService.startProcessInstanceByKey(processKey,variables);
}
24、参与者/泳池泳道(participant/pool&lane)
描述
BPMN规范中将参与者(participant)进行分类分组,泳池(pool)一般用来表示相对更大范围的分类,泳道(lane)一般位于泳池内部或其他泳道内部。泳道一般用来对相对较小的范围进行分类。
需求
假设对消息事件中的示例订餐流程存在于订餐系统中,支付相关是支付系统中的业务。使用泳池泳道进行分类。
BPMN修改
XML
<?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_1ydzq3q" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:message id="Message_2o62p2a" name="Message_wechat_lane" />
<bpmn:message id="Message_3dqeof3" name="Message_alipay_lane" />
<bpmn:collaboration id="Collaboration_1vp8uyi">
<bpmn:participant id="Participant_181lgt4" name="在线订单系统" processRef="Process_osdf854a" />
</bpmn:collaboration>
<bpmn:process id="Process_osdf854a" name="泳池泳道" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:laneSet id="LaneSet_1so1b2q">
<bpmn:lane id="Lane_1q5f5ut" name="订单系统">
<bpmn:flowNodeRef>StartEvent_1</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_0ixf8ri</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_0fml37y</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Event_0teeyqq</bpmn:flowNodeRef>
</bpmn:lane>
<bpmn:lane id="Lane_00mamao" name="支付系统">
<bpmn:flowNodeRef>Event_12gfp0q</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_1sgali6</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_03zqi8j</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Event_1ers7o5</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Activity_1alzjs2</bpmn:flowNodeRef>
<bpmn:flowNodeRef>Event_045qyu6</bpmn:flowNodeRef>
</bpmn:lane>
</bpmn:laneSet>
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0lgt4mm</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:userTask id="Activity_0ixf8ri" name="用户下订单" camunda:assignee="xiaoming">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="endpoint" label="使用终端" type="enum" defaultValue="wechat">
<camunda:value id="wechat" name="微信小程序" />
<camunda:value id="alipay" name="支付宝小程序" />
</camunda:formField>
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0lgt4mm</bpmn:incoming>
<bpmn:outgoing>Flow_02rl081</bpmn:outgoing>
</bpmn:userTask>
<bpmn:serviceTask id="Activity_0fml37y" name="处理订单" camunda:delegateExpression="${handleOrder}">
<bpmn:incoming>Flow_02rl081</bpmn:incoming>
<bpmn:outgoing>Flow_08gbi8s</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:endEvent id="Event_0teeyqq">
<bpmn:incoming>Flow_08gbi8s</bpmn:incoming>
</bpmn:endEvent>
<bpmn:startEvent id="Event_12gfp0q" name="微信订餐">
<bpmn:outgoing>Flow_0h9ce8w</bpmn:outgoing>
<bpmn:messageEventDefinition id="MessageEventDefinition_0oxjqds" messageRef="Message_2o62p2a" />
</bpmn:startEvent>
<bpmn:serviceTask id="Activity_1sgali6" name="微信支付" camunda:type="external" camunda:topic="weChatPay">
<bpmn:incoming>Flow_0h9ce8w</bpmn:incoming>
<bpmn:outgoing>Flow_068rz4q</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:serviceTask id="Activity_03zqi8j" name="支付成功" camunda:type="external" camunda:topic="pay_success">
<bpmn:incoming>Flow_068rz4q</bpmn:incoming>
<bpmn:incoming>Flow_0nwx9dc</bpmn:incoming>
<bpmn:outgoing>Flow_1kzfqdo</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:startEvent id="Event_1ers7o5" name="支付宝订餐">
<bpmn:outgoing>Flow_0geeo29</bpmn:outgoing>
<bpmn:messageEventDefinition id="MessageEventDefinition_0mgekkn" messageRef="Message_3dqeof3" />
</bpmn:startEvent>
<bpmn:serviceTask id="Activity_1alzjs2" name="支付宝支付" camunda:type="external" camunda:topic="alipay">
<bpmn:incoming>Flow_0geeo29</bpmn:incoming>
<bpmn:outgoing>Flow_0nwx9dc</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:endEvent id="Event_045qyu6">
<bpmn:incoming>Flow_1kzfqdo</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0lgt4mm" sourceRef="StartEvent_1" targetRef="Activity_0ixf8ri" />
<bpmn:sequenceFlow id="Flow_02rl081" sourceRef="Activity_0ixf8ri" targetRef="Activity_0fml37y" />
<bpmn:sequenceFlow id="Flow_08gbi8s" sourceRef="Activity_0fml37y" targetRef="Event_0teeyqq" />
<bpmn:sequenceFlow id="Flow_0h9ce8w" sourceRef="Event_12gfp0q" targetRef="Activity_1sgali6" />
<bpmn:sequenceFlow id="Flow_068rz4q" sourceRef="Activity_1sgali6" targetRef="Activity_03zqi8j" />
<bpmn:sequenceFlow id="Flow_0nwx9dc" sourceRef="Activity_1alzjs2" targetRef="Activity_03zqi8j" />
<bpmn:sequenceFlow id="Flow_1kzfqdo" sourceRef="Activity_03zqi8j" targetRef="Event_045qyu6" />
<bpmn:sequenceFlow id="Flow_0geeo29" sourceRef="Event_1ers7o5" targetRef="Activity_1alzjs2" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Collaboration_1vp8uyi">
<bpmndi:BPMNShape id="Participant_181lgt4_di" bpmnElement="Participant_181lgt4" isHorizontal="true">
<dc:Bounds x="160" y="60" width="600" height="420" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_1q5f5ut_di" bpmnElement="Lane_1q5f5ut" isHorizontal="true">
<dc:Bounds x="190" y="60" width="570" height="180" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Lane_00mamao_di" bpmnElement="Lane_00mamao" isHorizontal="true">
<dc:Bounds x="190" y="240" width="570" height="240" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="262" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_02x2sl5_di" bpmnElement="Activity_0ixf8ri">
<dc:Bounds x="350" y="80" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1hfwn8u_di" bpmnElement="Activity_0fml37y">
<dc:Bounds x="510" y="80" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0teeyqq_di" bpmnElement="Event_0teeyqq">
<dc:Bounds x="672" y="102" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0ytbisa_di" bpmnElement="Event_12gfp0q">
<dc:Bounds x="262" y="282" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="259" y="325" width="44" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1slui5i_di" bpmnElement="Activity_1sgali6">
<dc:Bounds x="350" y="260" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1te6p9r_di" bpmnElement="Activity_03zqi8j">
<dc:Bounds x="540" y="320" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1j1yl3g_di" bpmnElement="Event_1ers7o5">
<dc:Bounds x="262" y="402" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="253" y="445" width="55" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1mqta9v_di" bpmnElement="Activity_1alzjs2">
<dc:Bounds x="350" y="380" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_045qyu6_di" bpmnElement="Event_045qyu6">
<dc:Bounds x="702" y="342" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_0lgt4mm_di" bpmnElement="Flow_0lgt4mm">
<di:waypoint x="298" y="120" />
<di:waypoint x="350" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_02rl081_di" bpmnElement="Flow_02rl081">
<di:waypoint x="450" y="120" />
<di:waypoint x="510" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_08gbi8s_di" bpmnElement="Flow_08gbi8s">
<di:waypoint x="610" y="120" />
<di:waypoint x="672" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0h9ce8w_di" bpmnElement="Flow_0h9ce8w">
<di:waypoint x="298" y="300" />
<di:waypoint x="350" y="300" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_068rz4q_di" bpmnElement="Flow_068rz4q">
<di:waypoint x="450" y="300" />
<di:waypoint x="495" y="300" />
<di:waypoint x="495" y="360" />
<di:waypoint x="540" y="360" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0nwx9dc_di" bpmnElement="Flow_0nwx9dc">
<di:waypoint x="450" y="420" />
<di:waypoint x="495" y="420" />
<di:waypoint x="495" y="360" />
<di:waypoint x="540" y="360" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1kzfqdo_di" bpmnElement="Flow_1kzfqdo">
<di:waypoint x="640" y="360" />
<di:waypoint x="702" y="360" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0geeo29_di" bpmnElement="Flow_0geeo29">
<di:waypoint x="298" y="420" />
<di:waypoint x="350" y="420" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Java
package com.lonewalker.snail.buss.event;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.springframework.stereotype.Service;
/**
* 消息事件.
*
* @author Li Zemin
* @since 2024/3/7 8:38
*/
@Service("handleOrder")
public class HandleOrderService implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) throws Exception {
System.out.println("处理订餐订单");
Object endpoint = execution.getVariable("endpoint");
RuntimeService runtimeService = execution.getProcessEngineServices().getRuntimeService();
if ("alipay".equals(endpoint)) {
// runtimeService.startProcessInstanceByMessage("Message_alipay");
runtimeService.startProcessInstanceByMessage("Message_alipay_lane");
} else if ("wechat".equals(endpoint)) {
// runtimeService.startProcessInstanceByMessage("Message_wechat");
runtimeService.startProcessInstanceByMessage("Message_wechat_lane");
}
}
}
package com.lonewalker.snail.buss.event;
import org.camunda.bpm.client.spring.annotation.ExternalTaskSubscription;
import org.camunda.bpm.client.task.ExternalTaskHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 支付.
*
* @author Li Zemin
* @since 2024/3/7 8:43
*/
@Configuration
public class PayExternal {
@Bean
@ExternalTaskSubscription(topicName = "weChatPay", processDefinitionKeyIn = {"Process_1efquuw","Process_osdf854a"}, lockDuration = 5000)
public ExternalTaskHandler weChatPay() {
return (externalTask, externalTaskService) -> {
System.out.println("外部任务进入weChatPay");
externalTaskService.complete(externalTask);
};
}
@Bean
@ExternalTaskSubscription(topicName = "alipay", processDefinitionKeyIn = {"Process_1efquuw","Process_osdf854a"}, lockDuration = 5000)
public ExternalTaskHandler alipay() {
return (externalTask, externalTaskService) -> {
System.out.println("外部任务进入alipay");
externalTaskService.complete(externalTask);
};
}
@Bean
@ExternalTaskSubscription(topicName = "pay_success", processDefinitionKeyIn = {"Process_1efquuw","Process_osdf854a"}, lockDuration = 5000)
public ExternalTaskHandler paySuccess() {
return (externalTask, externalTaskService) -> {
System.out.println("外部任务进入paySuccess");
externalTaskService.complete(externalTask);
};
}
}
25、流程引擎设计理念
前面演示了许多例子,对camunda流程引擎的基本使用已经基本掌握。可以了解一下camunda流程引擎的设计风格与理念,这对使用camunda工作流与定位异常很有帮助。流程引擎(ProcessEngine)是整个camunda工作流的大心脏。
流程引擎名词解释
流程定义(Process Definition):确定了流程的结构,设计的流程信息保存在xml文件中,部署到流程引擎中,引擎将xml信息解析成数据保存在数据库中,就是流程定义。
每次部署流程时,只要流程有变动,都会自动更新一个版本(version),一个流程定义有一个definitionKey,就是流程BPMN xml中全局的ID,
每个version有一个definition ID ,由definitionKey:UUID
26、流程引擎API
API层次关系
流程引擎(ProcessEngine)是整个camunda工作流的大心脏,初始化好流程引擎,就可以通过它获取各种API的操作。提供的所有API都是线程安全的。结构如下:
参考:camunda流程引擎 API 接口介绍 - 知乎 (zhihu.com)
27、引擎端有用的配置
历史信息存储级别
camunda工作流的数据都存储在数据库中,历史数据会非常大,可以根据需要,选择存储历史数据的级别,camunda支持的级别如下:
- full级别:所有历史数据都被保存,包括变量的更新。
- audit级别:只有历史的流程实例,活动实例,表单数据等会被保存。
- auto级别: 数据之前配置的是什么级别就是用什么级别,如果没配置则是audit级别。
- none级别:不存储历史数据。
实际验证发现只能是没有数据的时候可以设置,不能有数据后随意改级别。这点设计得有点奇怪。
springboot配置中可以加入:
camunda.bpm.history-level=audit
生产环境中建议使用audit级别,开发测试环境可以使用full级别,方便调试查找问题。
BPMN自动部署开关
流程引擎中默认会自动对resources/bpmn目录下的bpmn进行部署。如果采用rest api或者model直接部署,可以添加配置进行关闭。
引擎端同时支持多个项目在使用时,不可能因为某个项目部署流程重启引擎,一般会通过rest api进行部署。
springboot配置中可以加入:
camunda.bpm.auto-deployment-enabled=true
28、完美的RestApi
什么是RestApi
RestApi是指restful api的简写,restful是一种接口设计风格,一句话就是对接口的定义提出一组标准.
- 每个URL代表一种资源,独一无二;
- 无状态,访问不同的实例结果一致;
- 遵守GET POST PUT PATCH DELETE对应相应的操作;
- 支持路径参数;
- 不用代码开发,直接就可以通过URL获取到数据;
设计完善的RestApi 最大的好处就是与语言无关。
Camunda RestApi
camunda提供了非常完整的API,文档也非常齐全。
参考文档:https://docs.camunda.org/manual/7.17/reference/rest/
如果camunda提供的RestApi不满足业务要求,还可以通过使用springboot引擎端借助流程引擎API自己提供额外的rest api。
如果流程引擎API也不能满足要求,还可以通过直接通过SQL查询提供额外的Rest Api。
RestApi 调用
Postman 或 Swagger-ui测试
29、spin支持的json数据
描述
camunda引擎是用java语言开发的,当使用java语言开发业务系统,并且采用camunda引擎嵌入到业务系统中的使用方式时,可以采用纯java数据类型。如果数据通过rest api通信不不方便了,更多的是采用json,xmlt等数据类型。
https://docs.camunda.org/manual/7.17/user-guide/data-formats/
https://docs.camunda.org/manual/7.17/reference/spin/
Camunda Spin Dataformat 默认支持xml json,现在互联网项目中使用的最多的 是json类型。
30、流程变量及作用域
描述
前面已经很多地方使用过流程变量(variable),camunda中的变量主要有全局变量(variable)和局部变量(Local Variable).
前面我们使用的都是全局变量,就是整个流程实例中都可以访问的变量,作用域是整个流程实例。
现实开发中,有时候变量只希望变量部分范围可见,多实例任务时同一变量名会有多份不同数据,为了保持数据的并发安全,控制变量的作用域特别重要。
1.限制
流程变量主要是用来方便流程流转的数据传递,大量的业务数据不要使用流程变量。最好只传一些状态数据,影响流程路径的业务数据。流程引擎默认是给变量的内存空间是4M左右,这还包含了流程引擎内因变量,业务使用的在3M以内可以考虑是安全的。
2.作用域
全局变量
在整个流程实例中可见,任何地方设置新值会覆盖旧值。高作用域设置的
- a和b在根作用域上定义,任务A、任务B和任务C可以看到它们。
- c定义在子流程范围内,任务A和任务B可以看到它。
- b在任务A的活动范围内被再次定义,并且只能被任务A看到。它覆盖了根范围内的变量b。
全局变量传播
- 当变量合并到流程实例中时(例如,关于任务完成、消息关联等),每个变量都从活动的范围传播到更高的范围。
- 当作用域包含具有相同名称的变量时,传播结束。在这种情况下,变量值被更新。
- 如果没有作用域包含这个变量,它将作为根作用域中的一个新变量被创建。
局部变量
局部变量只在设置的当前范围可见,如果需要阻止变量范围自动传播,而是需要精准范围内的传播,可以使用局部变量,再通过指定范围设置范围。
需求
假设用户上传一批图片数据,并行对所有图片进行处理,采用并行子流程,每个图片内部采用并行网关分两条路径并行处理,第一条路径,先处理图片去水印,再去日期,第二条路径,先对图片提取人脸数据,再提取车辆数据。再上传单张图片,所有图片处理完后再下载所有图片。通过这个任务,看一下各种环节的流程变量以及,如何准备控制变量范围,防止数据并发安全。
BPMN设计
XML
<?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_0yirz2q" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_19e0lp8" name="流程变量及作用域" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_0akcbro</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0akcbro" sourceRef="StartEvent_1" targetRef="Activity_0neprwe" />
<bpmn:serviceTask id="Activity_0neprwe" name="上传一批图片" camunda:type="external" camunda:topic="dispatch_task">
<bpmn:incoming>Flow_0akcbro</bpmn:incoming>
<bpmn:outgoing>Flow_1othlu9</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="Flow_1othlu9" sourceRef="Activity_0neprwe" targetRef="Activity_0uj15xe" />
<bpmn:subProcess id="Activity_0uj15xe" name="处理单张图片任务">
<bpmn:incoming>Flow_1othlu9</bpmn:incoming>
<bpmn:outgoing>Flow_06o8qm3</bpmn:outgoing>
<bpmn:multiInstanceLoopCharacteristics camunda:collection="${pics}" camunda:elementVariable="pic" />
<bpmn:startEvent id="Event_1sp4j5g">
<bpmn:outgoing>Flow_08zti3a</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_08zti3a" sourceRef="Event_1sp4j5g" targetRef="Activity_1vlfbim" />
<bpmn:serviceTask id="Activity_1vlfbim" name="添加单张图片" camunda:type="external" camunda:topic="add_pic_name">
<bpmn:incoming>Flow_08zti3a</bpmn:incoming>
<bpmn:outgoing>Flow_1lkcr62</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="Flow_1lkcr62" sourceRef="Activity_1vlfbim" targetRef="Gateway_1ek2m2j" />
<bpmn:parallelGateway id="Gateway_1ek2m2j">
<bpmn:incoming>Flow_1lkcr62</bpmn:incoming>
<bpmn:outgoing>Flow_0nl1y3j</bpmn:outgoing>
<bpmn:outgoing>Flow_1tip5ew</bpmn:outgoing>
</bpmn:parallelGateway>
<bpmn:sequenceFlow id="Flow_0nl1y3j" sourceRef="Gateway_1ek2m2j" targetRef="Activity_1g71s7y" />
<bpmn:sequenceFlow id="Flow_138mytg" sourceRef="Activity_1g71s7y" targetRef="Activity_04r2tyh" />
<bpmn:sequenceFlow id="Flow_1tip5ew" sourceRef="Gateway_1ek2m2j" targetRef="Activity_0k08w90" />
<bpmn:sequenceFlow id="Flow_1byegdc" sourceRef="Activity_0k08w90" targetRef="Activity_1y9vbyy" />
<bpmn:sequenceFlow id="Flow_1japz9v" sourceRef="Activity_1y9vbyy" targetRef="Gateway_14kyniy" />
<bpmn:parallelGateway id="Gateway_14kyniy">
<bpmn:incoming>Flow_1japz9v</bpmn:incoming>
<bpmn:incoming>Flow_1djx22y</bpmn:incoming>
<bpmn:outgoing>Flow_0b3g08k</bpmn:outgoing>
</bpmn:parallelGateway>
<bpmn:sequenceFlow id="Flow_1djx22y" sourceRef="Activity_04r2tyh" targetRef="Gateway_14kyniy" />
<bpmn:sequenceFlow id="Flow_0b3g08k" sourceRef="Gateway_14kyniy" targetRef="Activity_1q63ves" />
<bpmn:endEvent id="Event_09owdvn">
<bpmn:incoming>Flow_077yqhi</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_077yqhi" sourceRef="Activity_1q63ves" targetRef="Event_09owdvn" />
<bpmn:serviceTask id="Activity_1g71s7y" name="图片去水印" camunda:type="external" camunda:topic="water_print_delete">
<bpmn:extensionElements>
<camunda:executionListener event="end">
<camunda:script scriptFormat="JavaScript">var picDate = execution.getVariableLocal("picDate")
var parentId=execution.getParentId()
execution.getProcessEngineServices().getRuntimeService().setVariableLocal(parentId,"picData",picData)</camunda:script>
</camunda:executionListener>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0nl1y3j</bpmn:incoming>
<bpmn:outgoing>Flow_138mytg</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:serviceTask id="Activity_04r2tyh" name="图片去日期" camunda:type="external" camunda:topic="date_delete">
<bpmn:incoming>Flow_138mytg</bpmn:incoming>
<bpmn:outgoing>Flow_1djx22y</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:serviceTask id="Activity_0k08w90" name="人脸提取" camunda:type="external" camunda:topic="get_face">
<bpmn:incoming>Flow_1tip5ew</bpmn:incoming>
<bpmn:outgoing>Flow_1byegdc</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:serviceTask id="Activity_1y9vbyy" name="车辆提取" camunda:type="external" camunda:topic="get_car">
<bpmn:incoming>Flow_1byegdc</bpmn:incoming>
<bpmn:outgoing>Flow_1japz9v</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:serviceTask id="Activity_1q63ves" name="上传单张图片" camunda:type="external" camunda:topic="upload_pic">
<bpmn:incoming>Flow_0b3g08k</bpmn:incoming>
<bpmn:outgoing>Flow_077yqhi</bpmn:outgoing>
</bpmn:serviceTask>
</bpmn:subProcess>
<bpmn:sequenceFlow id="Flow_06o8qm3" sourceRef="Activity_0uj15xe" targetRef="Activity_0qh8de1" />
<bpmn:serviceTask id="Activity_0qh8de1" name="批量下载图片" camunda:type="external" camunda:topic="batch_download_pic">
<bpmn:incoming>Flow_06o8qm3</bpmn:incoming>
<bpmn:outgoing>Flow_045glpu</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:endEvent id="Event_0ujc99o">
<bpmn:incoming>Flow_045glpu</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_045glpu" sourceRef="Activity_0qh8de1" targetRef="Event_0ujc99o" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_19e0lp8">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="122" y="292" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_100wjcc_di" bpmnElement="Activity_0neprwe">
<dc:Bounds x="210" y="270" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_06k47z3_di" bpmnElement="Activity_0qh8de1">
<dc:Bounds x="1450" y="270" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0ujc99o_di" bpmnElement="Event_0ujc99o">
<dc:Bounds x="1632" y="292" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0vjazcl_di" bpmnElement="Activity_0uj15xe" isExpanded="true">
<dc:Bounds x="390" y="80" width="980" height="460" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1sp4j5g_di" bpmnElement="Event_1sp4j5g">
<dc:Bounds x="420.3333333333333" y="292" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0rgys5c_di" bpmnElement="Activity_1vlfbim">
<dc:Bounds x="510" y="270" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_1ezcqul_di" bpmnElement="Gateway_1ek2m2j">
<dc:Bounds x="665" y="285" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_1ul8fen_di" bpmnElement="Gateway_14kyniy">
<dc:Bounds x="1055" y="285" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_09owdvn_di" bpmnElement="Event_09owdvn">
<dc:Bounds x="1302" y="292" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1kjnq8c_di" bpmnElement="Activity_1g71s7y">
<dc:Bounds x="760" y="190" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_100ml55_di" bpmnElement="Activity_04r2tyh">
<dc:Bounds x="910" y="190" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_072k3eo_di" bpmnElement="Activity_0k08w90">
<dc:Bounds x="760" y="380" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0m1h4z6_di" bpmnElement="Activity_1y9vbyy">
<dc:Bounds x="910" y="380" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1be5f8s_di" bpmnElement="Activity_1q63ves">
<dc:Bounds x="1150" y="270" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_08zti3a_di" bpmnElement="Flow_08zti3a">
<di:waypoint x="456" y="310" />
<di:waypoint x="510" y="310" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1lkcr62_di" bpmnElement="Flow_1lkcr62">
<di:waypoint x="610" y="310" />
<di:waypoint x="665" y="310" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0nl1y3j_di" bpmnElement="Flow_0nl1y3j">
<di:waypoint x="690" y="285" />
<di:waypoint x="690" y="230" />
<di:waypoint x="760" y="230" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_138mytg_di" bpmnElement="Flow_138mytg">
<di:waypoint x="860" y="230" />
<di:waypoint x="910" y="230" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1tip5ew_di" bpmnElement="Flow_1tip5ew">
<di:waypoint x="690" y="335" />
<di:waypoint x="690" y="420" />
<di:waypoint x="760" y="420" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1byegdc_di" bpmnElement="Flow_1byegdc">
<di:waypoint x="860" y="420" />
<di:waypoint x="910" y="420" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1japz9v_di" bpmnElement="Flow_1japz9v">
<di:waypoint x="1010" y="420" />
<di:waypoint x="1080" y="420" />
<di:waypoint x="1080" y="335" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1djx22y_di" bpmnElement="Flow_1djx22y">
<di:waypoint x="1010" y="230" />
<di:waypoint x="1080" y="230" />
<di:waypoint x="1080" y="285" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0b3g08k_di" bpmnElement="Flow_0b3g08k">
<di:waypoint x="1105" y="310" />
<di:waypoint x="1150" y="310" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_077yqhi_di" bpmnElement="Flow_077yqhi">
<di:waypoint x="1250" y="310" />
<di:waypoint x="1302" y="310" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0akcbro_di" bpmnElement="Flow_0akcbro">
<di:waypoint x="158" y="310" />
<di:waypoint x="210" y="310" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1othlu9_di" bpmnElement="Flow_1othlu9">
<di:waypoint x="310" y="310" />
<di:waypoint x="390" y="310" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_06o8qm3_di" bpmnElement="Flow_06o8qm3">
<di:waypoint x="1370" y="310" />
<di:waypoint x="1450" y="310" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_045glpu_di" bpmnElement="Flow_045glpu">
<di:waypoint x="1550" y="310" />
<di:waypoint x="1632" y="310" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Java
package com.lonewalker.snail.buss.variable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.time.DateUtils;
import org.camunda.bpm.client.spring.annotation.ExternalTaskSubscription;
import org.camunda.bpm.client.task.ExternalTaskHandler;
import org.camunda.bpm.engine.variable.VariableMap;
import org.camunda.bpm.engine.variable.Variables;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import cn.hutool.core.date.DateUtil;
/**
* @author Li Zemin
* @since 2024/3/12 8:41
*/
@Configuration
public class VariableScopeExternalTaskService {
@Bean
@ExternalTaskSubscription(topicName = "dispatch_task", processDefinitionKeyIn = {"Process_19e0lp8"},
lockDuration = 5000)
public ExternalTaskHandler dispatchTask() {
return (externalTask, externalTaskService) -> {
System.out.println("上传一批图片");
VariableMap variables = Variables.createVariables();
List<Integer> pics = new ArrayList<>();
for (int i = 0; i < 50; i++) {
pics.add(i);
}
variables.put("pics", pics);
externalTaskService.complete(externalTask, variables);
};
}
@Bean
@ExternalTaskSubscription(topicName = "add_pic_name", processDefinitionKeyIn = {"Process_19e0lp8"},
lockDuration = 5000)
public ExternalTaskHandler addPicName() {
return (externalTask, externalTaskService) -> {
System.out.println("添加单张图片");
Integer pic = externalTask.getVariable("pic");
VariableMap variables = Variables.createVariables();
variables.put("picName", "pic_" + pic + ".jpg");
System.out.println("picId = " + pic + ",picName=" + "pic_" + pic + ".jpg");
externalTaskService.complete(externalTask, null, variables);
};
}
@Bean
@ExternalTaskSubscription(topicName = "water_print_delete", processDefinitionKeyIn = {"Process_19e0lp8"},
lockDuration = 5000)
public ExternalTaskHandler waterPrintDelete() {
return (externalTask, externalTaskService) -> {
System.out.println("图片去水印");
Integer pic = externalTask.getVariable("pic");
String picName = externalTask.getVariable("picName");
String dateStr = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
VariableMap variables = Variables.createVariables();
variables.put("picDate", dateStr);
System.out.println("picId = " + pic + "picName = " + picName + ",dateStr=" + dateStr);
externalTaskService.complete(externalTask, null, variables);
};
}
@Bean
@ExternalTaskSubscription(topicName = "date_delete", processDefinitionKeyIn = {"Process_19e0lp8"},
lockDuration = 5000)
public ExternalTaskHandler dateDelete() {
return (externalTask, externalTaskService) -> {
System.out.println("图片去日期");
externalTaskService.complete(externalTask);
};
}
@Bean
@ExternalTaskSubscription(topicName = "get_face", processDefinitionKeyIn = {"Process_19e0lp8"},
lockDuration = 5000)
public ExternalTaskHandler getFace() {
return (externalTask, externalTaskService) -> {
System.out.println("人脸提取");
externalTaskService.complete(externalTask);
};
}
@Bean
@ExternalTaskSubscription(topicName = "get_car", processDefinitionKeyIn = {"Process_19e0lp8"},
lockDuration = 5000)
public ExternalTaskHandler getCar() {
return (externalTask, externalTaskService) -> {
System.out.println("车辆提取");
externalTaskService.complete(externalTask);
};
}
@Bean
@ExternalTaskSubscription(topicName = "upload_pic", processDefinitionKeyIn = {"Process_19e0lp8"},
lockDuration = 5000)
public ExternalTaskHandler uploadPic() {
return (externalTask, externalTaskService) -> {
System.out.println("上传单张图片");
externalTaskService.complete(externalTask);
};
}
@Bean
@ExternalTaskSubscription(topicName = "batch_download_pic", processDefinitionKeyIn = {"Process_19e0lp8"},
lockDuration = 5000)
public ExternalTaskHandler batchDownloadPic() {
return (externalTask, externalTaskService) -> {
System.out.println("批量下载图片");
externalTaskService.complete(externalTask);
};
}
}
31、BusinessKey的使用
描述
BusinessKey业务键,从名称上可以看出可能与业务强相关,是的,businessKey设计的目的就是为了将流程引擎数据与业务数据关联上。
比如线上订餐采用了涉及到订单系统,支付系统,用户下一次订单会启动两个流程,流程引擎中的数据可以通过将订单Id作为BusinessKey进行关联。这样业务在查询此订单的流程数据时,可以通过businessKey查到所有相关流程实例。
与流程变量的区别
与业务数据关联的方法除了BusinessKey外,还可能使用流程变量。但为什么有了流程变量还要设计BusinessKey?理由有如下两点:
- 性能:按业务键查询通常比按变量值查询更有效。例如,它不需要与变量表连接。
- 可见性:在像Camunda Cockpit这样的应用程序中,业务键显示在显著位置**。**
32、多租户(multi-tenancy)
描述
多租户指的是一个camunda引擎服务于一个以上的租户。对于每个租户,都应该做出一定的隔离保证。例如,一个租户的流程实例不应该干扰另一个租户的流程实例。
https://docs.camunda.org/manual/7.17/user-guide/process-engine/multi-tenancy/
实现方式:
- 每个租户使用一个流程引擎,数据库每个租户一个,数据库级别的隔离,这种用法忽略不讲了,很简单,数据完全不在一起,租户标识只是提示引擎去哪个数据库查数据;
- 只使用一个流程引擎,并将数据与租户标识符关联起来,SAAS用法;
这两种方法在数据隔离级别、维护工作量和可伸缩性方面各不相同。这两种方法的组合也是可能的。
需求
设计一个流程,测试多租户下的数据隔离是否正常。
BPMN设计
<?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_1nit0ik" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.20.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
<bpmn:process id="Process_0dvkl5v" name="多租户" isExecutable="true" camunda:historyTimeToLive="180">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_10pys2i</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_10pys2i" sourceRef="StartEvent_1" targetRef="Activity_0ek1hkx" />
<bpmn:endEvent id="Event_0tqh0kn">
<bpmn:incoming>Flow_0fuynii</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0fuynii" sourceRef="Activity_0ek1hkx" targetRef="Event_0tqh0kn" />
<bpmn:userTask id="Activity_0ek1hkx" name="多租户" camunda:assignee="xiaoming">
<bpmn:incoming>Flow_10pys2i</bpmn:incoming>
<bpmn:outgoing>Flow_0fuynii</bpmn:outgoing>
</bpmn:userTask>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_0dvkl5v">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="82" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0tqh0kn_di" bpmnElement="Event_0tqh0kn">
<dc:Bounds x="432" y="82" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0k18b4b_di" bpmnElement="Activity_0ek1hkx">
<dc:Bounds x="270" y="60" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_10pys2i_di" bpmnElement="Flow_10pys2i">
<di:waypoint x="215" y="100" />
<di:waypoint x="270" y="100" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0fuynii_di" bpmnElement="Flow_0fuynii">
<di:waypoint x="370" y="100" />
<di:waypoint x="432" y="100" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
租户ID用法(SAAS用法)
- 所有租户数据存在同一个数据库,流程引擎服务共用;
- 所有数据都必须与租户唯一TENANT_ID进行关联;
- 流程引擎一般独立于业务系统使用。
Tenant_id一般在部署流程的时候就开始关联,同一个流程定义可以同时给多个租户部署,没有关联Tenant_id的流程定义属于所有租户。
33、连接器(connector)
描述
camunda工作流设计的与外部信息沟通的方法有外部任务(external task),业务任务(service task),执行监听器(execution listener), 以上都是当外部业务较复杂的时候使用,如果外部调用很简单,仅是调用远程直接获取一些状态数据,可以使用camunda提供的连接器connector实现。
默认支援的connector类型:
1.http connector:用于请求协议的接口。
-
引擎内部存在一个Conectors类会自动探测Classpath下的所有connector,根据ConnectorID生成实例;
-
默认情况下使用Apache 默认配置的 http client调用;
-
返回数据使用spin json读取;
-
自定义http client;
34、camunda架构
- modeler:模型设计器,独立工具
- File Repository: 存放模型的仓库
- Engine: 核心引擎,将模型文件解释成对象数据,并提供相关管理;
- API: 提供java API,与rest api进行操作
- DataBase: 数据存储,支持常用的关系型数据库
- Tasklist:任务列表,可以从管理界面查看
- Cockpit: 流程控制台,可以从管理界面操作
- Admin: 租户,用户,用户组,权限等管理操作,可以从管理界面操作
- Job executor:处理定时任务与异步任务相关
流程引擎架构图
database: camunda7目前支持大多 数关系型数据库,camunda8云原生版本支持elasticsearch分布式存储,
public Api: 提供JAVA API对部署,任务,流程实例等一系列操作;
Job Executor: 提供对定时任务与异步任务的操作;
**persistence Layer: ** 数据持久化,采用mybatis框架;
**BPMN2核心引擎:**加载BPMN流程
35、数据表介绍
描述
了解了这些理论对使用camunda API有非常大的帮助,丰富完善camunda API已基本可以满足大多数业务场景,然而有些时候复杂的业务中,难免有些操作只靠现在的API无法满足需求。这时我们可以通过扩展引擎API,直接使用SQL操作引擎数据库表数据。了解表结构对操作表数据很关键。
表名规则
Camunda bpm流程引擎的数据库由多个表组成,表名都以ACT开头,第二部分是说明表用途的两字符标识。笔者在工作中用的Camunda7.11版本共47张表。
- ACT_RE_*: 'RE’表示流程资源存储,这个前缀的表包含了流程定义和流程静态资源(图片,规则等),共5张表。_
- ACT_RU_*: 'RU’表示流程运行时。 这些运行时的表,包含流程实例,任务,变量,Job等运行中的数据。 Camunda只在流程实例执行过程中保存这些数据,在流程结束时就会删除这些记录, 这样运行时表的数据量最小,可以最快运行。共15张表。
- ACT_ID_*: 'ID’表示组织用户信息,比如用户,组等,共6张表。
- ACT_HI_*: 'HI’表示流程历史记录。 这些表包含历史数据,比如历史流程实例,变量,任务等,共18张表。_
- ACT_GE_*: ‘GE’表示流程通用数据, 用于不同场景下,共3张表。
数据表清单
分类 表名称 描述
流程资源存储 act_re_case_def CMMN案例管理模型定义表
流程资源存储 act_re_decision_def DMN决策模型定义表
流程资源存储 act_re_decision_req_def 待确定
流程资源存储 act_re_deployment 流程部署表
流程资源存储 act_re_procdef BPMN流程模型定义表
流程运行时 act_ru_authorization 流程运行时收取表
流程运行时 act_ru_batch 流程执行批处理表
流程运行时 act_ru_case_execution CMMN案例运行执行表
流程运行时 act_ru_case_sentry_part 待确定
流程运行时 act_ru_event_subscr 流程事件订阅表
流程运行时 act_ru_execution BPMN流程运行时记录表
流程运行时 act_ru_ext_task 流程任务消息执行表
流程运行时 act_ru_filter 流程定义查询配置表
流程运行时 act_ru_identitylink 运行时流程人员表
流程运行时 act_ru_incident 运行时异常事件表
流程运行时 act_ru_job 流程运行时作业表
流程运行时 act_ru_jobdef 流程作业定义表
流程运行时 act_ru_meter_log 流程运行时度量日志表
流程运行时 act_ru_task 流程运行时任务表
流程运行时 act_ru_variable 流程运行时变量表
组织用户信息 act_id_group 群组信息表
组织用户信息 act_id_info 用户扩展信息表
组织用户信息 act_id_membership 用户群组关系表
组织用户信息 act_id_tenant 租户信息表
组织用户信息 act_id_tenant_member 用户租户关系表
组织用户信息 act_id_user 用户信息表
流程历史记录 act_hi_actinst 历史的活动实例表
流程历史记录 act_hi_attachment 历史的流程附件表
流程历史记录 act_hi_batch 历史的批处理记录表
流程历史记录 act_hi_caseactinst 历史的CMMN活动实例表
流程历史记录 act_hi_caseinst 历史的CMMN实例表
流程历史记录 act_hi_comment 历史的流程审批意见表
流程历史记录 act_hi_dec_in 历史的DMN变量输入表
流程历史记录 act_hi_dec_out 历史的DMN变量输出表
流程历史记录 act_hi_decinst 历史的DMN实例表
流程历史记录 act_hi_detail 历史的流程运行时变量详情记录表
流程历史记录 act_hi_ext_task_log 历史的流程任务消息执行表
流程历史记录 act_hi_identitylink 历史的流程运行过程中用户关系
流程历史记录 act_hi_incident 历史的流程异常事件记录表
流程历史记录 act_hi_job_log 历史的流程作业记录表
流程历史记录 act_hi_op_log 待确定
流程历史记录 act_hi_procinst 历史的流程实例
流程历史记录 act_hi_taskinst 历史的任务实例
流程历史记录 act_hi_varinst 历史的流程变量记录表
流程通用数据 act_ge_bytearray 流程引擎二进制数据表
流程通用数据 act_ge_property 流程引擎属性配置表
流程通用数据 act_ge_schema_log 数据库脚本执行日志表
36、流程事务(transaction)
camunda事务描述
camunda事务与关系型数据库中的事务有点区别,但是通过关系型数据库事务实现的,camunda一个事务是两个wait state之间的部分。
camunda流程引擎是被动触发的,如启动流程实例、complete一次task, 发送一次执行信号,引擎内部的job executor触发等,
一次事务没结束时,数据没有被持久化到DB,相关数据表会加乐观锁。此时如果在事务中断点停止,其他访问(如访问cockpit)会被挂起,
一个事务间的所有活动要么同时成功, 要么同时失败。
等待状态(wait states)
wait state是camunda事务的边界。位于等待状态的任务时,状态已经提交到数据库 。
以下元素,通常是处于wait state状态。
37、引擎高可用方案
描述
实际生产环境中流程引擎一般处理整个业务流程的核心地位,引擎服务一量不能正常使用,整个系统将会不能正常提供服务。为此,引擎高可用方案在生产环境是必不可少的一个环节,特别是SAAS模式。嵌入使用模式,引擎生命周期与业务系统一致。
camunda7目前支持到共享数据库。性能一般可以得到保证
1.因为数据库数据不会太大,运行时的数据存储与历史数据分开存储,运行时数据ACT_RU_*开头的表数据量大,但结束就删除了;
2.只有历史数据ACT_HI_开头的表,会有大量数据,可以设置保存时间与保存级别。况且历史数据不会影响到执行速度。
评论区