版本信息:
idea:2021.3.1
java:17
mysql:8.0.36
maven:3.6.3
使用插件:
Activiti BPMN visualizer
JBoss jBPM
前提
需要安装如下插件
目录
- 创建数据库
- 创建 maven 工程
- 添加依赖
- 创建activiti.cfg.xml文件
- 创建工具类,生成数据库表
- 启动项目,生成数据表
- 使用 bpmn 画流程图
- 流程部署
- 启动流程实例
- 查询个人待执行任务
- 完成个人任务
- 查询流程定义
- 删除流程部署信息
- 下载资源文件
- 流程历史信息查看
- 流程添加业务key
- 流程实例的挂起和激活
- 通过uel格式动态地为每一个流程节点设置assignee
- 监听器分配
- 在启动流程的时候定义流程变量
- 在完成任务的时候定义流程变量
- 使用组任务办理流程
- 排他网关
- 并行网关
- 包含网关
- 代码demo
一、创建数据库
create database activity DEFAULT CHARACTER SET utf8mb4
二、创建 maven 工程
三、添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yuqn</groupId>
<artifactId>activityPro</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<activiti.version>7.0.0.Beta1</activiti.version>
</properties>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn模型处理-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn转换-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn json数据转换-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn布局-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-layout</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- activity 云支持-->
<dependency>
<groupId>org.activiti.cloud</groupId>
<artifactId>activiti-cloud-services-api</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- mysql驱动-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<!-- mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<!-- 连接池依赖-->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- log start-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
</project>
四、创建activiti.cfg.xml文件
需要在 resource 目录下创建 activiti.cfg.xml 文件,内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 在默认方式下,bean的id固定为processEngineConfiguration-->
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<!-- 配置数据库相关信息-->
<!-- 数据库驱动-->
<property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"/>
<!-- 数据库连接-->
<property name="jdbcUrl" value="jdbc:mysql://localhost:3307/activity-db?characterEncoding=utf-8"/>
<!-- 数据库用户-->
<property name="jdbcUsername" value="root"/>
<!-- 数据库密码-->
<property name="jdbcPassword" value="your_password"/>
<!-- activiti 数据库表生成的策略 true-如果数据库中已经存在相应的表,那么直接使用,如果不存在就会创建-->
<property name="databaseSchemaUpdate" value="true"/>
</bean>
</beans>
五、创建工具类,生成数据库表
/**
* @author: yuqn
* @Date: 2024/4/28 17:41
* @description:
* 使用activiti提供的默认方式来创建mysql的表
* @param: null
* @return: null
*/
@Test
public void testCreateDbTable(){
// 需要使用activiti提供的工具类ProcessEngines,使用getDefaultProcessEngine方法
// getDefaultProcessEngine方法会默认从resources下读取activiti.cfg.xml文件
// 创建processEngine时,就会创建mysql表
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
System.out.println(defaultProcessEngine);
}
六、启动项目,生成数据表
七、使用 bpmn 画流程图
1、创建 bpmn 文件
2、右击文件打开视图
3、画流程图
要指定每一个的name和assigne属性:
4、流程定义
4.1、将上述bpmn文件改为xml后缀,并且右键 dragrams 转为流程
4.2、导出png文件
4.3、转回bpmn文件
八、流程部署
将流程存到数据库,通过提供的接口,上传信息,代码如下:
@Test
public void testDeployment(){
// 1、创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取RepositoryServoie
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、使用service进行流程部署,定义一个流程的名字,把bpmn和png部署到数据中
Deployment deploy = repositoryService.createDeployment()
.name("出差信息")
.addClasspathResource("bpmn/evection.bpmn20.xml")
.addClasspathResource("bpmn/evection.png")
.deploy();
// 4、输出部署信息
System.out.println("流程部署id=" + deploy.getId());
System.out.println("流程部署名字=" + deploy.getName());
}
部署成功后,操作了四张表,分别是 act_ge_bytearray、act_ge_property、act_re_deployment、act_re_procdef 。
1、act_re_deployment:每次部署都会新增一条记录
2、act_re_procdef:流程定义表
3、act_ge_bytearray:流程资源表
8.1 通过zip模式上传资源
/**
* @author: yuqn
* @Date: 2024/4/29 23:52
* @description:
* 通过zip压缩包部署
* @param: null
* @return: null
*/
@Test
public void deployProcessByZip(){
// 1、创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取RepositoryServoie
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、流程部署
// 读取资源包文件,构成inputStream
InputStream inputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("bpmn/evection.zip");
// 用inputStream构成zipinputstream
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
// 使用压缩包流程进行流程的部署
Deployment deploy = repositoryService.createDeployment()
.addZipInputStream(zipInputStream)
.deploy();
System.out.println("流程部署id= " + deploy.getId());
System.out.println("流程部署名称= " + deploy.getName());
}
九、启动流程实例
/**
* @author: yuqn
* @Date: 2024/4/29 17:22
* @description:
* 启动流程实例
* act_hi_actinst 流程实例执行历史
* act_hi_identitylink 流程的参与用户历史信息
* act_hi_procinst 流程实例历史信息
* act_hi_taskinst 流程任务历史信息
* act_ru_execution 流程正在执行信息
* act_ru_identitylink 流程的参与用户信息
* act_ru_task 任务信息
* @param: null
* @return: null
*/
@Test
public void testStartProcess(){
// 1、创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取runtimeservice
RuntimeService runtimeService = processEngine.getRuntimeService();
// 3、根据流程定义的id启动流程
ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection");
// 4、输出内容
System.out.println("流程定义id:" + instance.getProcessDefinitionId());
System.out.println("流程实例id:" + instance.getId());
System.out.println("当前活动的id:" + instance.getActivityId());
}
十、查询个人待执行任务
/**
* @author: yuqn
* @Date: 2024/4/29 18:18
* @description:
* 查询个人待执行任务
* @param: null
* @return: null
*/
@Test
public void testFindPersonalTaskList(){
// 1、获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取taskService
TaskService taskService = processEngine.getTaskService();
// 3、根据 流程key 和 任务负责人 查询任务
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey("myEvection")
.taskAssignee("张三")
.list();
// 4、输出
for (Task task : taskList) {
System.out.println("流程实例id=" + task.getProcessInstanceId());
System.out.println("任务id=" + task.getId());
System.out.println("任务负责人=" + task.getAssignee());
System.out.println("任务名称=" + task.getName());
}
}
十一、完成个人任务
/**
* @author: yuqn
* @Date: 2024/4/29 22:54
* @description:
* 完成个人任务
*/
@Test
public void completTask(){
// 1、获取控制流引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取TaskService
TaskService taskService = processEngine.getTaskService();
// 3、根据任务id完成个人任务
// taskService.complete("2505");
// // 3、获取jerry-myevection对应任务
// Task task = taskService.createTaskQuery()
// .processDefinitionKey("myEvection")
// .taskAssignee("jerry")
// .singleResult();
// // 完成jerry的任务
// taskService.complete(task.getId());
// // 3、获取jack-myevection对应任务
// Task task = taskService.createTaskQuery()
// .processDefinitionKey("myEvection")
// .taskAssignee("jack")
// .singleResult();
// // 完成jerry的任务
// taskService.complete(task.getId());
// 3、获取rose-myevection对应任务
// Task task = taskService.createTaskQuery()
// .processDefinitionKey("myEvection")
// .taskAssignee("rose")
// .singleResult();
// // 完成jerry的任务
// taskService.complete(task.getId());
}
十二、查询流程定义
/**
* @author: yuqn
* @Date: 2024/5/5 23:41
* @description:
* 查询流程定义
* @param: null
* @return: null
*/
@Test
public void queryProcessDefinition(){
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取repositoryservice
RepositoryService repositoryService = processEngine.getRepositoryService();
// 获取processdifinitionquery对象
ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
//查询当前所有的流程定义,返回流程定义信息的集合
// processDefinitionKey(里路程定义的key)
// orderbyprocessdefinitionversion进行排序
// desc 倒序
// list 查询出所有内容
List<ProcessDefinition> definitionList = definitionQuery.processDefinitionKey("myEvection")
.orderByProcessDefinitionVersion()
.desc()
.list();
// 输出信息
for (ProcessDefinition processDefinition : definitionList) {
System.out.println("流程定义id = " + processDefinition.getId());
System.out.println("流程定义名称 = " + processDefinition.getName());
System.out.println("流程定义key = " + processDefinition.getKey());
System.out.println("流程定义版本 = " + processDefinition.getVersion());
System.out.println("流程部署的id = " + processDefinition.getDeploymentId());
}
}
十三、删除流程部署信息
/**
* @author: yuqn
* @Date: 2024/5/5 23:41
* @description:
* 删除流程部署信息
* @param: null
* @return: null
* 当前流程如果没有全部完成,想要删除的话需要使用特殊方式,原理就是 级联删除
*/
@Test
public void deleteDeployMent(){
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 通过引擎来获取 RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 通过部署id删除流程部署信息
String deploymentId = "15001";
// 非级联删除
//repositoryService.deleteDeployment(deploymentId);
// 级联删除,流程没有完全完成也能删除
repositoryService.deleteDeployment(deploymentId,true);
}
需要添加依赖,用于文件转换:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
十四、下载资源文件
/**
* @author: yuqn
* @Date: 2024/5/9 16:41
* @description:
* 下载资源文件
* 方案一:使用activiti提供的api下载资源文件,保存到文件目录
* 方案二:自己写代码从数据库中下载文件
* @param: null
* @return: null
*/
@Test
public void getDeployment() throws IOException {
// 1、得到引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取api、repositoryservice
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、获取查询对象 processdefinitionquery,查询流程定义信息
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myEvection")
.singleResult();
// 4、通过流程定义信息,获取部署id
String deploymentId = processDefinition.getDeploymentId();
// 5、通过repositoryservice,传递部署id参数,读取资源信息(png和bpmn)
// 5.1、获取png图片的流
String pngName = processDefinition.getDiagramResourceName();
InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName);
// 5.2、获取bpmn的流
String bpmnName = processDefinition.getResourceName();
InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName);
// 6、构造outputstream流
File pngFile = new File("E:\\myJavaProject/activityPro/evectionflow01.png");
File bpmnFile = new File("E:\\myJavaProject/activityPro/evectionflow01.bpmn");
FileOutputStream pngOutStream = new FileOutputStream(pngFile);
FileOutputStream bpmnOutStream = new FileOutputStream(bpmnFile);
// 7、输入流、输出流的转换
IOUtils.copy(pngInput,pngOutStream);
IOUtils.copy(bpmnInput,bpmnOutStream);
// 8、关闭流
pngOutStream.close();
bpmnOutStream.close();
pngInput.close();
bpmnInput.close();
}
十五、流程历史信息查看
/**
* @author: yuqn
* @Date: 2024/5/9 17:37
* @description:
* 流程历史信息查看
* @param: null
* @return: null
*/
@Test
public void findHistoryInfo(){
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取Historyservice
HistoryService historyService = processEngine.getHistoryService();
// 获取actinst表的查询对象
HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
// 查询actinst表
instanceQuery.processInstanceId("2501");
instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
// 查询所有内容
List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();
// 输出
for (HistoricActivityInstance hi : activityInstanceList) {
System.out.println(hi.getActivityId());
System.out.println(hi.getActivityName());
System.out.println(hi.getProcessDefinitionId());
System.out.println(hi.getProcessInstanceId());
System.out.println("<------------------------------->");
}
}
十六、流程添加业务key
给每一个流程实例关联一个业务key,该key为其他业务表的id,这样可以查看该实例除了activiti提供的信息外的其他信息。
/**
* @author: yuqn
* @Date: 2024/5/10 16:09
* @description:
* 添加业务key到activiti表
* @param: null
* @return: null
*/
@Test
public void addBusinessKey(){
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取runtimeservice
RuntimeService runtimeService = processEngine.getRuntimeService();
// 启动流程的过程中,添加businesskey
// 第一个参数:流程定义的key
// 第二个参数:业务表id
ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection", "1002");
// 输出
System.out.println("instance.getBusinessKey() = " + instance.getBusinessKey());
}
十七、流程实例的挂起和激活
17.1、全部流程实例的挂起和激活
/**
* @author: yuqn
* @Date: 2024/5/10 16:50
* @description:
* 全部流程实例的挂起和激活
* suspend暂停
* @param: null
* @return: null
*/
@Test
public void suspendAllProcessInstance(){
// 1、获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取repositoryservice
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、查询流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myEvection")
.singleResult();
// 4、获取读取流程定义的实力是否都是挂起状态
boolean suspended = processDefinition.isSuspended();
// 5、获取流程定义的id
String definitionId = processDefinition.getId();
if(suspended){
/*
* 6、如果是挂起状态,改为激活状态
* 参数一:流程定义id
* 参数二:是否激活
* 参数三:激活时间
* */
repositoryService.activateProcessDefinitionById(definitionId,true,null);
System.out.println("流程定义id:" + definitionId + "已激活");
}else{
/*
* 7、如果是激活状态,改为挂起状态
* 参数一:流程定义id
* 参数二:是否暂停
* 参数三:暂停时间
* */
repositoryService.suspendProcessDefinitionById(definitionId,true,null);
System.out.println("流程定义id:" + definitionId + "已挂起");
}
}
17.2、单个流程实例的挂起和激活
/**
* @author: yuqn
* @Date: 2024/5/10 16:50
* @description:
* 单个流程实例的挂起和激活
* suspend暂停
* @param: null
* @return: null
*/
@Test
public void suspendSingleProcessInstance(){
// 1、获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、runtimeservice
RuntimeService runtimeService = processEngine.getRuntimeService();
// 3、通过runtimeservice获取流程实例对象
ProcessInstance instance = runtimeService.createProcessInstanceQuery()
.processInstanceId("30001")
.singleResult();
// 4、得到当前流程实例的暂停状态
boolean suspended = instance.isSuspended();
// 5、获取流程实例id
String instanceId = instance.getId();
// 6、如果已经暂停,执行激活操作
if(suspended){
runtimeService.activateProcessInstanceById(instanceId);
System.out.println("流程实例id:" + instanceId + "已经激活");
}else{
// 7、如果已经激活,执行暂停操作
runtimeService.suspendProcessInstanceById(instanceId);
System.out.println("流程实例id:" + instanceId + "已经暂停");
}
}
十八、通过uel格式动态地为每一个流程节点设置assignee
1-17的例子所介绍的流程中,每一个节点的assignee都是固定的,如:张三、jerry 等等,在实际开发中,负责每一个工作流程的人并不是固定的,所以可以通过uel设置 Assignee 值为变量,使之更具有灵活性,用法如下:${变量值} ,该方法相当于将原本固定的负责人改为一个占位符。
18.1、部署流程
/**
* @author: yuqn
* @Date: 2024/5/11 15:47
* @description:
* 第四部分:基于assignee uel模式测试模块
* @version: 1.0
*/
public class TestAssigneeUel {
/**
* @author: yuqn
* @Date: 2024/4/29 23:52
* @description:
* 部署流程
* @param: null
* @return: null
*/
@Test
public void testDeployment(){
// 1、创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取RepositoryServoie
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、使用service进行流程部署,定义一个流程的名字,把bpmn和png部署到数据中
Deployment deploy = repositoryService.createDeployment()
.name("出差申请流程-uel")
.addClasspathResource("bpmn/evection-uel.bpmn20.xml")
.addClasspathResource("bpmn/evection-uel.png")
.deploy();
// 4、输出部署信息
System.out.println("流程部署id=" + deploy.getId());
System.out.println("流程部署名字=" + deploy.getName());
}
18.2、启动流程引擎
/**
* @author: yuqn
* @Date: 2024/5/11 15:52
* @description:
* 启动流程引擎
* @param: null
* @return: null
*/
@Test
public void startAssigneeUel(){
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取runtimeservice
RuntimeService runtimeService = processEngine.getRuntimeService();
// 设定assignee的值,用来替代uel表达式
Map<String,Object> assigneeMap = new HashMap<>();
assigneeMap.put("assignee0","张三");
assigneeMap.put("assignee1","李经理");
assigneeMap.put("assignee2","王总经理");
assigneeMap.put("assignee3","赵财务");
// 启动流程实例
ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection1",assigneeMap);
// 输出
System.out.println("流程定义id:" + instance.getProcessDefinitionId());
System.out.println("流程实例id:" + instance.getId());
System.out.println("当前活动的id:" + instance.getActivityId());
}
十九、监听器分配
监听器不可用,该插件目前没有提供监听器功能!!!!!!!!!!!!!
每一个流程节点可以有多个负责人,可以使用监听器分配,在流程设计时就不需要指定assignee值了,启动流程的时候通过监听器自动分配。
创建监听器,每次启动都会通过监听器执行
/**
* @author: yuqn
* @Date: 2024/5/11 16:42
* @description:
* 监听器
* @version: 1.0
*/
public class MyTaskListener implements TaskListener {
/**
* @author: yuqn
* @Date: 2024/5/11 16:43
* @description:
* 指定负责人
* @param: delegateTask
*/
@Override
public void notify(DelegateTask delegateTask) {
System.out.println("*****************");
System.out.println("delegateTask.getName() = " + delegateTask.getName());
System.out.println("delegateTask.getEventName() = " + delegateTask.getEventName());
// 如果当前是 创建申请 并且是 create 事件 ,则设置为张三
if ("创建申请".equals(delegateTask.getName()) &&
"start".equals(delegateTask.getEventName())){
delegateTask.setAssignee("张三");
}
}
}
部署和启动:
/**
* @author: yuqn
* @Date: 2024/4/29 23:52
* @description:
* 部署流程
* @param: null
* @return: null
*/
@Test
public void testDeployment(){
// 1、创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取RepositoryServoie
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、使用service进行流程部署,定义一个流程的名字,把bpmn和png部署到数据中
Deployment deploy = repositoryService.createDeployment()
.name("测试监听器")
.addClasspathResource("bpmn/evection-listen.bpmn20.xml")
.deploy();
// 4、输出部署信息
System.out.println("流程部署id=" + deploy.getId());
System.out.println("流程部署名字=" + deploy.getName());
}
@Test
public void startDemoListener(){
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取runtimeservice
RuntimeService runtimeService = processEngine.getRuntimeService();
// 启动流程实例
runtimeService.startProcessInstanceByKey("evection-listen");
}
二十、在启动流程的时候定义流程变量
场景:如果请假出差时间小于三天,则经理审批后直接由财务审批;如果请假出差时间大于三天,则经理审批后由总经理审批,最后再由财务审批。
以上场景中的三天就是流程变量,如下图:
20.1、画流程图,并且给每一个流程节点设置assignee值和定义流程变量(这里以 ${evection.num} 为例子)
20.2、创建 pojo 类
原理:在启动流程的时候,会将pojo对象一同作为参数,在完成任务时,就可以拿到 pojo.num 的值了,
该 pojo 需要实现 Serializable 接口完成序列化。
/**
* @author: yuqn
* @Date: 2024/5/12 0:49
* @description:
* 出差申请中的流程变量
* @version: 1.0
*/
public class Evection implements Serializable {
/**
* 主键id
*/
private Long id;
/**
* 出差单名字
*/
private String evectionName;
/**
* 出差天数
*/
private Double num;
/**
* 出差开始时间
*/
private Date beginDate;
/**
* 出差结束时间
*/
private Date endDate;
/**
* 出差目的地
*/
private String destination;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEvectionName() {
return evectionName;
}
public void setEvectionName(String evectionName) {
this.evectionName = evectionName;
}
public Double getNum() {
return num;
}
public void setNum(Double num) {
this.num = num;
}
public Date getBeginDate() {
return beginDate;
}
public void setBeginDate(Date beginDate) {
this.beginDate = beginDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
public String getDestination() {
return destination;
}
public void setDestination(String destination) {
this.destination = destination;
}
@Override
public String toString() {
return "Evection{" +
"id=" + id +
", evectionName='" + evectionName + '\'' +
", num=" + num +
", beginDate=" + beginDate +
", endDate=" + endDate +
", destination='" + destination + '\'' +
'}';
}
public Evection(Long id, String evectionName, Double num, Date beginDate, Date endDate, String destination) {
this.id = id;
this.evectionName = evectionName;
this.num = num;
this.beginDate = beginDate;
this.endDate = endDate;
this.destination = destination;
}
public Evection() {
}
}
20.3、部署流程
/**
* @author: yuqn
* @Date: 2024/4/29 23:52
* @description:
* 部署流程
* @param: null
* @return: null
*/
@Test
public void testDeployment(){
// 1、创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取RepositoryServoie
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、使用service进行流程部署,定义一个流程的名字,把bpmn和png部署到数据中
Deployment deploy = repositoryService.createDeployment()
.name("出差申请流程-variables")
.addClasspathResource("bpmn/evection-global.bpmn20.xml")
.deploy();
// 4、输出部署信息
System.out.println("流程部署id=" + deploy.getId());
System.out.println("流程部署名字=" + deploy.getName());
}
20.4、启动流程
这里结合 uel 的方式。
/**
* @author: yuqn
* @Date: 2024/5/12 1:03
* @description:
* 启动流程 启动的时候设置流程变量
* 设置流程变量num
* 设置任务负责人
* @param: null
* @return: null
*/
@Test
public void testStartProcess(){
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取runtimeservice
RuntimeService runtimeService = processEngine.getRuntimeService();
// 流程定义的key
String key = "evection-global";
// 流程变量的map
HashMap<String, Object> variables = new HashMap<>();
// 设置流程变量
Evection evection = new Evection();
// 设置出差日期
evection.setNum(3d);
// 把流程变量的pojo放入map
variables.put("evection",evection);
// 设定任务负责人
variables.put("assignee0","yuqn-lobal-0");
variables.put("assignee1","yuqn-lobal-1");
variables.put("assignee2","yuqn-lobal-2");
variables.put("assignee3","yuqn-lobal-3");
// 启动流程
runtimeService.startProcessInstanceByKey(key,variables);
}
20.5、完成任务
原理:当完成部门经理审批yuqn-lobal-1后,如果pojo对象中的num值小于3,则下一个审核流程为财务审批yuqn-lobal-3;否则为 yuqn-lobal-2 -> yuqn-lobal-3。
/**
* @author: yuqn
* @Date: 2024/5/12 1:04
* @description:
* 完成个人任务
* @param: null
* @return: null
*/
@Test
public void completTask(){
// 定义流程key
String key = "evection-global";
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskservice
TaskService taskService = processEngine.getTaskService();
// 完成任务,
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee("yuqn-lobal-2")
.singleResult();
if(task != null){
// 根据任务id,完成任务
taskService.complete(task.getId());
}
}
二十一、在完成任务的时候定义流程变量
该方法跟 步骤二十一 的区别在于: 步骤二十一是启动流程的时候就定义了变量,而这里是在完成某一个任务的时候,如果该任务后面有分支,那么完成该任务的时候就定义流程变量。
如上:在完成 创建出差申请 任务的时候不需要设置流程变量;而在完成 部门经理审批 任务的时候,就需要设置流程变量了;完成 部门经理审批 后,根据流程变量来判断下一步是走 总经理审批-> 财务审批 还是直接走 财务审批。
代码如下:
21.1、部署流程
/**
* @author: yuqn
* @Date: 2024/4/29 23:52
* @description:
* 部署流程
* @param: null
* @return: null
*/
@Test
public void testDeployment(){
// 1、创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取RepositoryServoie
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、使用service进行流程部署,定义一个流程的名字,把bpmn和png部署到数据中
Deployment deploy = repositoryService.createDeployment()
.name("出差申请流程-variables-complete")
.addClasspathResource("bpmn/evection-global.bpmn20.xml")
.deploy();
// 4、输出部署信息
System.out.println("流程部署id=" + deploy.getId());
System.out.println("流程部署名字=" + deploy.getName());
}
21.2、启动流程
这里将不再设置出差时间。
/**
* @author: yuqn
* @Date: 2024/5/12 1:03
* @description:
* 启动流程 启动的时候设置流程变量
* 设置流程变量num
* 设置任务负责人
* @param: null
* @return: null
*/
@Test
public void testStartProcess(){
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取runtimeservice
RuntimeService runtimeService = processEngine.getRuntimeService();
// 流程定义的key
String key = "evection-global";
// 流程变量的map
HashMap<String, Object> variables = new HashMap<>();
// 设定任务负责人
variables.put("assignee0","yuqn-lobal-complete-0");
variables.put("assignee1","yuqn-lobal-complete-1");
variables.put("assignee2","yuqn-lobal-complete-2");
variables.put("assignee3","yuqn-lobal-complete-3");
// 启动流程
runtimeService.startProcessInstanceByKey(key,variables);
}
21.3、完成任务
21.3.1、完成出差申请任务
/**
* @author: yuqn
* @Date: 2024/5/12 1:04
* @description:
* 完成个人任务
* @param: null
* @return: null
*/
@Test
public void completTask(){
// 定义流程key
String key = "evection-global";
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskservice
TaskService taskService = processEngine.getTaskService();
// 完成任务
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee("yuqn-lobal-complete-0")
.singleResult();
if(task != null){
// 根据任务id,完成任务,该方法用于没有流程变量的
taskService.complete(task.getId());
}
}
21.3.2、完成经理审批任务
/**
* @author: yuqn
* @Date: 2024/5/12 1:04
* @description:
* 完成个人任务
* @param: null
* @return: null
*/
@Test
public void completTask(){
// 定义流程key
String key = "evection-global";
// 设置流程变量,注:如果当前审批节点完成后,需要分支,则需要设置流程变量了
Evection evection = new Evection();
evection.setNum(2d);
HashMap<String, Object> map = new HashMap<>();
map.put("evection",evection);
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskservice
TaskService taskService = processEngine.getTaskService();
// 完成任务
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee("yuqn-lobal-complete-1")
.singleResult();
if(task != null){
// 根据任务id,完成任务,该方法用于有流程变量的
taskService.complete(task.getId(),map);
}
}
二十二、使用组任务办理流程
原理:某个任务可能不止只有一个审批者,通过设置组,用于保存所有可以审批的工作人员信息。
22.1、创建流程图
22.2、组任务办理
22.3、部署任务
/**
* @author: yuqn
* @Date: 2024/4/29 23:52
* @description:
* 部署流程
* @param: null
* @return: null
*/
@Test
public void testDeployment(){
// 1、创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取RepositoryServoie
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、使用service进行流程部署,定义一个流程的名字,把bpmn和png部署到数据中
Deployment deploy = repositoryService.createDeployment()
.name("出差申请流程-Candidate")
.addClasspathResource("bpmn/evection-candidate.bpmn20.xml")
.deploy();
// 4、输出部署信息
System.out.println("流程部署id=" + deploy.getId());
System.out.println("流程部署名字=" + deploy.getName());
}
22.4、启动任务
/**
* @author: yuqn
* @Date: 2024/5/14 22:53
* @description:
* 启动流程
* @param: null
* @return: null
*/
@Test
public void testStartProcess(){
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取runtimeservice
RuntimeService runtimeService = processEngine.getRuntimeService();
// 流程定义的key
String key = "evection-candidate";
// 启动流程
runtimeService.startProcessInstanceByKey(key);
}
22.5、完成个人任务
/**
* @author: yuqn
* @Date: 2024/5/12 1:04
* @description:
* 完成个人任务,因为这里的组任务是设置在第二个审批任务,所以先把第一个审批任务完成
* @param: null
* @return: null
*/
@Test
public void completTask(){
// 定义流程key
String key = "evection-candidate";
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskservice
TaskService taskService = processEngine.getTaskService();
// 完成任务
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee("yuqn-candidate-0")
.singleResult();
if(task != null){
// 根据任务id,完成任务
taskService.complete(task.getId());
}
}
22.6、组任务查询
/**
* @author: yuqn
* @Date: 2024/5/14 22:57
* @description:
* 查询组任务
* @param: null
* @return: null
*/
@Test
public void findGroupTaskList(){
// 获取key
String key = "evection-candidate";
// 选择任务候选人,组里面的一个
String candidateUser = "yuqn-candidate-1.0";
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskService
TaskService taskService = processEngine.getTaskService();
// 查询组任务
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskCandidateUser(candidateUser)
.list();
for (Task task : taskList) {
System.out.println("-------------------------------");
System.out.println("流程实例id = " + task.getProcessInstanceId());
System.out.println("任务id = " + task.getId());
System.out.println("任务负责人 = " + task.getAssignee());
}
}
22.7、拾取任务
/**
* @author: yuqn
* @Date: 2024/5/14 23:44
* @description:
* 拾取任务,执行后,指定的人就能变为当前审批任务的负责人
* @param: null
* @return: null
*/
@Test
public void claimTask(){
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskService
TaskService taskService = processEngine.getTaskService();
// 当前任务id,为act_ru_task的id值
String taskId = "162502";
// 任务候选人
String candidateUser = "yuqn-candidate-1.0";
// 查询任务
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskCandidateUser(candidateUser)
.singleResult();
if (task != null){
// 拾取任务
taskService.claim(taskId,candidateUser);
System.out.println( "taskId-" + taskId + "- 用户 -" + candidateUser + " - 任务拾取完成");
}
}
22.8、归还任务
/**
* @author: yuqn
* @Date: 2024/5/15 22:14
* @description:
* 任务归还
* @param: null
* @return: null
*/
@Test
public void testAssigneeToGroupTask(){
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskservice
TaskService taskService = processEngine.getTaskService();
// 获取当前任务id
String taskId = "162502";
// 任务负责人
String assignee = "yuqn-candidate-1.0";
// 根据key和负责人查询任务
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskAssignee(assignee)
.singleResult();
if(task!=null){
// 归还任务,就是把负责人设置为空
taskService.setAssignee(taskId,null);
System.out.println("taskid-" + taskId + "-归还任务完成");
}
}
22.9、交接任务
由原本的任务候选人改为另外一个。
/**
* @author: yuqn
* @Date: 2024/5/15 22:25
* @description:
* 任务交接,切换任务候选人
* @param: null
* @return: null
*/
@Test
public void testAssigneeToCandidateUser(){
// 获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskservice
TaskService taskService = processEngine.getTaskService();
// 当前任务id
String taskId = "162502";
// 任务负责人
String assignee = "yuqn-candidate-1.0";
// 任务候选人
String candidateUser = "yuqn-candidate-1.1";
// 根据key和负责人来查询任务
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskAssignee(assignee)
.singleResult();
if(task!=null){
// 交接,任务负责人由 yuqn-candidate-1.0 改为 yuqn-candidate-1.1
taskService.setAssignee(taskId,candidateUser);
System.out.println("taskid-" + taskId + "-交接任务完成");
}
}
二十三、排他网关
使用排他网关,只选择其中1条或0条链路执行,情况如下:
1、满足多个条件,选择id最小的路径
2、都不满足,抛出异常(跟定义流程变量的主要区别)
原理如下:
启动流程后,开始逐步完成任务,最先开始填写出差申请,然后进行部门经理审核,此次后面有网关,所以完成该任务的前提是有‘定义流程变量’,当完成该任务后,根据流程变量确定下一步审批任务是总经理审批还是财务审批。
23.1、画流程图
23.2、部署程图
/**
* @author: yuqn
* @Date: 2024/5/16 18:01
* @description:
* 部署流程
* @param: null
* @return: null
*/
@Test
public void testDeployment(){
// 创建processengine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取repositoryservice实例
RepositoryService repositoryService = processEngine.getRepositoryService();
// 使用repositoryservice部署
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("bpmn/evection-exclusive.bpmn20.xml")
.name("出差申请流程-排他网关")
.deploy();
// 输出部署信息
System.out.println("流程部署id" + deployment.getId());
System.out.println("流程部署名称" + deployment.getName());
}
23.3、启动程图
/**
* @author: yuqn
* @Date: 2024/5/12 1:03
* @description:
* 启动流程 启动的时候设置流程变量
* 设置流程变量num
* 设置任务负责人
* @param: null
* @return: null
*/
@Test
public void testStartProcess(){
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取runtimeservice
RuntimeService runtimeService = processEngine.getRuntimeService();
// 流程定义的key
String key = "evection-exclusive";
// 流程变量的map
HashMap<String, Object> variables = new HashMap<>();
// 设置流程变量
Evection evection = new Evection();
// 设置出差日期
evection.setNum(4d);
// 把流程变量的pojo放入map
variables.put("evection",evection);
// 启动流程
runtimeService.startProcessInstanceByKey(key,variables);
}
23.4、完成个人任务
/**
* @author: yuqn
* @Date: 2024/5/12 1:04
* @description:
* 完成个人任务
* @param: null
* @return: null
*/
@Test
public void completTask(){
// 定义流程key
String key = "evection-exclusive";
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskservice
TaskService taskService = processEngine.getTaskService();
// 完成任务
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee("yuqn-exclusive-04")
.singleResult();
if(task != null){
// 根据任务id,完成任务
taskService.complete(task.getId());
}
}
23.5、删除任务
/**
* @author: yuqn
* @Date: 2024/5/5 23:41
* @description:
* 删除流程部署信息
* @param: null
* @return: null
* 当前流程如果没有全部完成,想要删除的话需要使用特殊方式,原理就是 级联删除
*/
@Test
public void deleteDeployMent(){
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 通过引擎来获取 RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 通过部署id删除流程部署信息
String deploymentId = "172501";
// 非级联删除
//repositoryService.deleteDeployment(deploymentId);
// 级联删除,流程没有完全完成也能删除
repositoryService.deleteDeployment(deploymentId,true);
}
二十四、并行网关
使用并行网关,所有分支都会走一遍。如果有一个分支完成了,另一个分支还没完成,则需要等另外一个分支完成后,才后进入下一个任务。act_ru_task表会出现多条任务记录,只有全部完成,才能进入下一个任务。
24.1、画流程图
24.2、部署流程
/**
* @author: yuqn
* @Date: 2024/5/16 18:01
* @description:
* 部署流程
* @param: null
* @return: null
*/
@Test
public void testDeployment(){
// 创建processengine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取repositoryservice实例
RepositoryService repositoryService = processEngine.getRepositoryService();
// 使用repositoryservice部署
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("bpmn/evection-parallel.bpmn20.xml")
.name("出差申请流程-并行网关")
.deploy();
// 输出部署信息
System.out.println("流程部署id" + deployment.getId());
System.out.println("流程部署名称" + deployment.getName());
}
24.3、启动流程
/**
* @author: yuqn
* @Date: 2024/5/12 1:03
* @description:
* 启动流程 启动的时候设置流程变量
* 设置流程变量num
* 设置任务负责人
* @param: null
* @return: null
*/
@Test
public void testStartProcess(){
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取runtimeservice
RuntimeService runtimeService = processEngine.getRuntimeService();
// 流程定义的key
String key = "evection-parallel";
// 流程变量的map
HashMap<String, Object> variables = new HashMap<>();
// 设置流程变量
Evection evection = new Evection();
// 设置出差日期
evection.setNum(4d);
// 把流程变量的pojo放入map
variables.put("evection",evection);
// 启动流程
runtimeService.startProcessInstanceByKey(key,variables);
}
24.4、完成任务
/**
* @author: yuqn
* @Date: 2024/5/12 1:04
* @description:
* 完成个人任务
* @param: null
* @return: null
*/
@Test
public void completTask(){
// 定义流程key
String key = "evection-parallel";
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskservice
TaskService taskService = processEngine.getTaskService();
// 完成任务
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee("yuqn-parallel-03")
.singleResult();
if(task != null){
// 根据任务id,完成任务
taskService.complete(task.getId());
}
}
二十五、包含网关
包含网关:满足条件的所有分支都执行后,才能进入下一个任务。不设置条件的分支默认为满足条件。
25.1、画流程图
25.2、部署程图
/**
* @author: yuqn
* @Date: 2024/5/16 18:01
* @description:
* 部署流程
* @param: null
* @return: null
*/
@Test
public void testDeployment(){
// 创建processengine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取repositoryservice实例
RepositoryService repositoryService = processEngine.getRepositoryService();
// 使用repositoryservice部署
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("bpmn/evection-include.bpmn20.xml")
.name("出差申请流程-包含网关")
.deploy();
// 输出部署信息
System.out.println("流程部署id" + deployment.getId());
System.out.println("流程部署名称" + deployment.getName());
}
25.3、启动程图
/**
* @author: yuqn
* @Date: 2024/5/12 1:03
* @description:
* 启动流程 启动的时候设置流程变量
* 设置流程变量num
* 设置任务负责人
* @param: null
* @return: null
*/
@Test
public void testStartProcess(){
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取runtimeservice
RuntimeService runtimeService = processEngine.getRuntimeService();
// 流程定义的key
String key = "evection-include";
// 流程变量的map
HashMap<String, Object> variables = new HashMap<>();
// 设置流程变量
Evection evection = new Evection();
// 设置出差日期
evection.setNum(4d);
// 把流程变量的pojo放入map
variables.put("evection",evection);
// 启动流程
runtimeService.startProcessInstanceByKey(key,variables);
}
25.4、完成任务
/**
* @author: yuqn
* @Date: 2024/5/12 1:04
* @description:
* 完成个人任务
* @param: null
* @return: null
*/
@Test
public void completTask(){
// 定义流程key
String key = "evection-include";
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskservice
TaskService taskService = processEngine.getTaskService();
// 完成任务
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee("yuqn-include-02-2")
.singleResult();
if(task != null){
// 根据任务id,完成任务
taskService.complete(task.getId());
}
}
二十六、代码demo
github仓库地址: github.com/Yuqn/activi…