名词解释
转办:某个节点,候选人是好几人。其中一个人拾取了该任务,发现不应该办理,可以转给候选人中的其他人
会签:
1 bpmn
StartEvent | 开始事件(重要) |
EndEvent | 结束事件(重要) |
IntermediateEvent | 中间事件 |
UserTask | 用户任务:表示需要人参与的任务,可以配置候选人/组/代理人等。(重要) |
ServiceTask | 服务任务:调用外部服务或自动执行程序。 |
ManualTask | 手工任务:就是一个直接通过的任务。可以使用它来自动执行一些可以直接通过的任务 |
BusinessRuleTask | 规则任务: |
SubProcess | 子流程:子流程表示多个activity的组合。子流程内部的元件禁止和外部的元件直连,只能作为一个整体与父流程的元件相连接。 |
Lane | |
ExclusiveGateway | 排他网关 |
EventGateway | |
IntermediateCatchingEvent | |
Annotation | |
ScriptTask | 脚本任务:用于执行定义好的脚本程序,流程执行到这个结点自动执行脚本。 |
MailTask | |
ReceiveTask | |
CallActivityTask | |
Pool | |
ParallelGateway | 并行网关 |
InclusiveGateway | 包容性网关 |
BoundaryEvent | |
IntermediateThrowingEvent |
BPMN2.0之顺序流和网关_Richard678的博客-CSDN博客_bpmn顺序
https://www.jianshu.com/p/6f38a0275e98/
userTask属性:
documentation | 文档 |
asynchronous | 异步 |
exclusive | 独家专用的 |
multi instance | 多实例 |
assignee | 代理人,受让人 |
candidate users | 候选人 ; 申请人 |
candidate groups | 候选组 |
due date | 到期日 |
form key | 表单键 |
priority | 优先事项 |
task listeners | 任务监听器 |
execution listeners | 执行监听器 |
form | 表单 |
2 Activiti表
表分类 | 表名 | |
一般数据 | ||
act_ge_bytearray | 通用的流程定义和流程资源 | |
act_ge_property | 系统相关属性 | |
流程历史记录 | ||
act_hi_actinst | 历史的流程实例 (节点表,审批到哪个节点了,) | |
act_hi_attachment | 历史的流程附件 | |
act_hi_comment | 历史的流程说明性信息 | |
act_hi_detail | 历史的流程运行中的细节信息 | |
act_hi_identitylink | 历史的流程运行过程中用户关系 | |
act_hi_procinst | 历史的流程实例 | |
act_hi_taskinst | 历史的任务实例 | |
act_hi_varinst | 历史的流程运行中的变量信息 | |
流程定义表 | ||
act_re_deployment | 部署单元信息 | |
act_re_model | 模型信息 | |
act_re_procdef | 部署的流程定义 | |
运行实例表 | ||
act_ru_deadletter_job | 死信 | |
act_ru_event_subscr | 运行时事件 | |
act_ru_execution | 运行时流程执行实例 | |
act_ru_identitylink | 运行时用户关系信息,存储任务节点与参与者的相关信息 | |
act_ru_integration | 集成 | |
act_ru_job | 运行时作业 | |
act_ru_suspended_job | 暂停 | |
act_ru_task | 运行时任务 | |
act_ru_timer_job | ||
act_ru_variable | 运行时变量表 |
Activiti的后台是有数据库的支持,所有的表都以ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的API对应。
ACT_RE_*: 'RE'表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
ACT_RU_*: 'RU'表示runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
ACT_ID_*: 'ID'表示identity。 这些表包含身份信息,比如用户,组等等。
ACT_HI_*: 'HI'表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
ACT_GE_*: 通用数据, 用于不同场景下,如存放资源文件。
activiti7和activiti6的区别:
不同点:activiti6是28张数据表,activiti7是25张,少了用户和组的三张表。相应的服务接口也少了俩:IdentityService和FormService。另外activiti7中对activiti6的API再次进行了封装,新增加了分布式和云部署的功能,核心没变
RepositoryService:流程定义和部署对象
RuntimeService:执行管理,包括流程实例和执行对象(正在执行)
TaskService:执行任务相关的(正在执行)
HistoryService:历史管理
IdentityService:Activiti表的用户角色组
ManagementService:引擎管理服务
activiti开发工作流的一个基本开发模式
功能复用:对于像查询待办任务、已办任务、抄送我的、我发起的流程、流程部署、流程挂起与激活、生成流程图等这样的可以复用的功能,使用一套代码即可,提供统一的接口或service。
功能不复用:但是对于启动流程、完成任务这样的功能,因为每个流程的参数或流程变量不一样,并且任务完成之后做的回调事情也不一样,如果不能复用,则每一个流程都单独开发这样的功能。
目前采用的方式是:对于启动流程、完成任务抽象出一个interface,让不同的流程service实现各自不同的操作;创建一个简单工厂,根据流程类型实例化不同的流程service;对外只暴露出启动流程和完成任务两个接口,前端传递不同的流程类型,执行不同的service操作。
数据表扩展:如果activiti提供的数据表无法满足业务需求,可以建立关联表,辅助业务运行。
3 开发准备
idea插件actiBPM 和pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<!-- <version>8.0.30</version>-->
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- <dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
<version>6.0.0</version>
</dependency>-->
<!--
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>7.0.0.Betal</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>7.0.0.Betal</version>
</dependency>
<!– bpmn模型处理–>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
<version>7.0.0.Betal</version>
</dependency>
<!– bpmn转换–>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
<version>7.0.0.Betal</version>
</dependency>
<!– bpmn json数据转换–>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>7.0.0.Betal</version>
</dependency>
<!– bpmn 布局–>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-layout</artifactId>
<version>7.0.0.Betal</version>
</dependency>
<!– activiti 云支持–>
<dependency>
<groupId>org.activiti.cloud</groupId>
<artifactId>activiti-cloud-service-api</artifactId>
<version>7.0.0.Betal</version>
</dependency>
-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.0.0.Beta2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
yml
server:
port: 8080
spring:
application:
name: activiti
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=UTF-8&useTimezone=true&serverTimezone=GMT%2B8&allowMultiQueries=true&nullCatalogMeansCurrent=true
username: root
password: root
druid:
filter:
stat:
enabled: true
db-type: mysql
log-slow-sql: true
activiti:
# false:默认值。在activiti启动时,会对比数据库表中保存的版本,如果没有表或版本不匹配,将抛出异常。(生产环境常用)
# true:activiti会对数据库中所有表进行更新操作。如果表不存在,将会创建。(开发环境常用)
# create-drop:在activiti启动时创建表,在关闭时删除表,必须手动关闭引擎才会删除表。(单元测试用)
# drop-create:在activiti启动时删除旧表,然后创建新表,不需要关闭引擎。
database-schema-update: true
#检测历史表是否存在,activiti7默认没有开启数据库历史记录,true启动数据库历史记录
db-history-used: true
#记录历史等级,可配置的历史级别有:none,activity,audit,full
# none:不保存任何的历史数据,因此在流程执行过程中,这是最高效的
# activity:级别高于none,保存流程实例与流程行为,其他数据不保存
# audit:除保存activity保存的数据外,还会保存全部的流程任务及其属性。history-level的默认值
# full:保存历史数据的最高级别,会额外保存全部流程相关的细节数据。
history-level: full
#校验流程文件,默认校验resources下的process文件夹的流程文件
check-process-definitions: false
logging:
pattern:
console: "%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n"
level:
org.activiti.engine.impl.persistence.entity: trace
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
资源文件下加配置文件activiti.cfg.xml和log4j.properties文件
activiti.cfg.xml:springboot方式就不用了。
<?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">
<!--dbcp数据源-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/activiti"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--配置Activiti的ProcessEngineConfiguration对象,因为没有跟spring整合,所以这里使用单例的。-->
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
<!--指定数据表生成策略,该策略是,若数据表不存在则创建,存在则更新-->
<property name="databaseSchemaUpdate" value="true"/>
</bean>
</beans>
代码实战
Activiti学习——踩坑和经验_chuchui5713的博客-CSDN博客
分配个人任务的三种方式
1:直接给值,在Xxxx.bpmn文件中指定
2:流程变量${流程变量的名称}或者#{}
3:使用类 监听这个类(实现一个接口),指定任务的办理人(setAssgnee())
个人任务和组任务的查询一样吗?
* 不一样
* 都是用TaskService完成(TaskService.createTasQuery)
* 个人任务(taskAssgnee),组任务(taskCandidateUser)
* 数据库存放,个人任务(类型:参与),组任务(类型,参与,候选)
bpmn创建一个简单请假流程
张三提交申请单---> 李四经理审批--->王五总经理审批
生成图片流程:
1将travel.bpmn 改名为 travel.xml
2:右击 找到Diagrams --->show BPMN 2.0 Designer
3: 点击导出 image
4 将 travel.xml改为 travel.bpmn
结论:
act_re_deployment (流程部署 )和act_re_procdef(流程定义) 一对多的关系
procdef表中,可以有多条记录,每一条记录,对应一个流程的定义信息。
张三 走这个出差申请流程
李四 也走这个出差申请流程
简单的案例代码
package com.example.activiti;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.zip.ZipInputStream;
@SpringBootTest
class ActivitiApplicationTests {
static ProcessEngine processEngine = null;
@BeforeEach
void test() {
/**
* 初始化流程引擎对象,将会根据配置创建25数据表(创建了索引和外键)
*/
processEngine = ProcessEngines.getDefaultProcessEngine();
}
/**
* 部署流程 将流程保存到数据中
*/
@Test
void test1() {
RepositoryService repositoryService = processEngine.getRepositoryService();
//zip方式部署 (可以很多流程都压缩在一个zip下)
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("bpmn/travel.zip");
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
Deployment deploy = repositoryService.createDeployment().addZipInputStream(zipInputStream)
// .name("")
.deploy();
// 单个部署方式
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("bpmn/travel.bpmn")
.addClasspathResource("bpmn/travel.png")
// .name("请假流程测试")
// .category("办公类别") //设置部署的类别
.deploy();
System.out.println(deployment.getId());//流程部署id 6f2030ef-58ec-11ed-bbe8-fa89d281dc2b
System.out.println(deployment.getName());//流程部署名字 请假流程测试
System.out.println(deployment.getKey());//null
System.out.println(deployment.getCategory());//null
System.out.println(deployment.getDeploymentTime());
System.out.println(deployment.getTenantId());//null
/*
受影响的表:3个
act_re_deployment:流程部署表 : 添加一条流程部署记录 主键是贯穿这三个表
act_re_procdef::流程定义:添加一条流程定义记录,一个流程定义记录和一个流程图一一对应,流程定义记录的key就是流程图的id
act_ge_bytearray:blob形式保存部署的资源
*/
/*
流程部署意味着两件事:
1、将流程定义文件放到activiti引擎配置的持久化存储中,以便activiti引擎重启时能再次读取部署的流程。
2、解析bpmn文件并转化为activiti内存中的对象模型,然后就能使用acticiti提供的api对持久化的数据进行操作。
*/
}
/**
* 查询流程定义 act_re_procdef
*/
@Test
void tes2() {
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
List<ProcessDefinition> myTravel_1 = processDefinitionQuery.processDefinitionKey("myTravel_1")
.orderByProcessDefinitionVersion() //根据 Version 正序
.asc() //正序
.list();
for (ProcessDefinition processDefinition : myTravel_1) {
System.out.println("流程定义ID: "+processDefinition.getId());//IDmyTravel_1:1:6f3602e2-58ec-11ed-bbe8-fa89d281dc2b
System.out.println("流程定义名称: "+processDefinition.getName()); //出差申请流程
System.out.println("流程定义key: "+processDefinition.getKey()); //keymyTravel_1
System.out.println("流程定义版本: "+processDefinition.getVersion()); //1
System.out.println("流程定义部署id: "+processDefinition.getDeploymentId()); //710668f8-5904-11ed-b08d-fa89d281dc2b
}
}
/**
* 删除流程定义 act_re_procdef
*/
@Test
void tes3() {
RepositoryService repositoryService = processEngine.getRepositoryService();
//通过部署id删除流程部署信息 不会删除历史表的信息
repositoryService.deleteDeployment("54215d66-5903-11ed-a890-fa89d281dc2b");
//历史信息也会删除
repositoryService.deleteDeployment("54215d66-5903-11ed-a890-fa89d281dc2b",true);
/**
* delete from ACT_GE_BYTEARRAY where DEPLOYMENT_ID_ =
* delete from ACT_RE_DEPLOYMENT where ID_ =
* delete from ACT_RE_PROCDEF where DEPLOYMENT_ID_ =
* delete from ACT_RU_IDENTITYLINK where PROC_DEF_ID_ =
*/
}
/**
* 下载流程
*/
@Test
void tes4() throws IOException {
RepositoryService repositoryService = processEngine.getRepositoryService();
//查询流程定义信息
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myTravel_1").singleResult();
//获取流程部署id
String deploymentId = processDefinition.getDeploymentId();
//获取图片目录和名字
String pngName = processDefinition.getDiagramResourceName();
InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName);
//获取bpmn目录和名字
String bpmnName = processDefinition.getResourceName();
InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName);
File pngfile = new File("D:/travel.png");
File bpmnfile = new File("D:/travel.bpmn");
FileOutputStream pngOutputStream = new FileOutputStream(pngfile);
FileOutputStream bpmnOutputStream = new FileOutputStream(bpmnfile);
IOUtils.copy(pngInput, pngOutputStream);
IOUtils.copy(bpmnInput, bpmnOutputStream);
pngInput.close();
bpmnInput.close();
pngOutputStream.close();
bpmnOutputStream.close();
}
/**
* 运行工作流
*/
@Test
void test5() {
RuntimeService runtimeService = processEngine.getRuntimeService();
//act_re_procdef---拿来的参数
ProcessInstance processInstance = runtimeService.startProcessInstanceById("myTravel_1:1:6f3602e2-58ec-11ed-bbe8-fa89d281dc2b");
// runtimeService.startProcessInstanceByKey("myTravel_1");
System.out.println("流程定义ID"+processInstance.getProcessDefinitionId());//myTravel_1:1:6f3602e2-58ec-11ed-bbe8-fa89d281dc2b
System.out.println("流程实例ID"+processInstance.getId());//c96e78ef-58f7-11ed-9f8b-fa89d281dc2b
System.out.println("流程活动ID"+processInstance.getActivityId());//null
/* act_ru_task 任务信息
* act_ru_identitylink 标识链接 流程的参与用户信息
* act_ru_execution 处决 流程正在执行信息
* act_hi_taskinst 任务 流程任务历史信息
* act_hi_procinst 流程实例历史信息
* act_hi_identitylink 流程的参与用户信息历史
* act_hi_actinst 流程实例执行历史
*
* */
}
/**
* 查询张三正在执行任务查询
* 正在执行的任务会在这个表 ACT_RU_TASK ,一旦这个节点完成,会到历史表中,下一个节点到 ACT_RU_TASK 中
* https://blog.csdn.net/JHC23/article/details/97001687?ops_request_misc=&request_id=&biz_id=102&utm_term=activi&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-5-97001687.142^v62^pc_search_tree,201^v3^control_1,213^v1^control&spm=1018.2226.3001.4187
*/
@Test
void test6() {
TaskService taskService = processEngine.getTaskService();
//创建任务查询对象
TaskQuery taskQuery = taskService.createTaskQuery();
//查看办理人的任务列表
List<Task> list = taskQuery
.processDefinitionKey("myTravel_1") // 流程key
.taskAssignee("张三").list();//要查询的负责人
//select distinct RES.* from ACT_RU_TASK RES WHERE RES.ASSIGNEE_ ="张三"
// select distinct RES.* from ACT_RU_TASK RES inner join ACT_RE_PROCDEF D on RES.PROC_DEF_ID_ = D.ID_ WHERE RES.ASSIGNEE_ = '张三' and D.KEY_ = 'myTravel_1'
for (Task task : list) {
System.out.println("任务办理人:"+task.getAssignee());
System.out.println("任务id:" + task.getId());
System.out.println("任务名称:"+ task.getName());
System.out.println("流程实例id:"+ task.getProcessInstanceId());
}
}
/**
* 张三提交申请单 完成个人任务
*/
@Test
void test7() {
TaskService taskService = processEngine.getTaskService();
//根据任务id act_ru_task 表的 id 完成任务
// act_ru_task 目前节点是 提交申请单
taskService.complete("75b2666e-598d-11ed-951f-fa89d281dc2b");
// 执行后 act_ru_task 节点变成 经理审批 act_hi_taskinst 也会多一个经理审批
/*流程sql
select * from ACT_RU_TASK where ID_ = 'c972e5c3-58f7-11ed-9f8b-fa89d281dc2b'
* select * from ACT_RE_PROCDEF where ID_ = 'myTravel_1:1:6f3602e2-58ec-11ed-bbe8-fa89d281dc2b'
* select * from ACT_RE_DEPLOYMENT where ID_ ='6f2030ef-58ec-11ed-bbe8-fa89d281dc2b'
* select * from ACT_GE_BYTEARRAY where DEPLOYMENT_ID_ = '6f2030ef-58ec-11ed-bbe8-fa89d281dc2b' order by NAME_ asc
* insert into ACT_HI_TASKINST 经理审批的数据
* insert into ACT_HI_ACTINST 经理审批的数据
* insert into ACT_HI_IDENTITYLINK 李四人员数据
insert into ACT_RU_TASK 经理审批的数据
insert into ACT_RU_IDENTITYLINK 李四人员数据
* update ACT_HI_ACTINST 张三
update ACT_RU_EXECUTION update ACT_HI_TASKINST delete from ACT_RU_TASK 张三
*/
}
/**
* 查看历史信息 (审批节点) ACT_HI_ACTINST
*/
@Test
void test8() {
HistoryService historyService = processEngine.getHistoryService();
HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
//act_hi_actinst表 PROC_INST_ID_字段
//select RES.* from ACT_HI_ACTINST RES WHERE RES.PROC_INST_ID_ = ?
instanceQuery.processInstanceId("c96e78ef-58f7-11ed-9f8b-fa89d281dc2b");
//排序 开始
instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
List<HistoricActivityInstance> list = instanceQuery.list();
for (HistoricActivityInstance instance : list) {
System.out.println(instance.getActivityId());//_3
System.out.println(instance.getActivityName());// 经理审批
System.out.println(instance.getProcessDefinitionId()); //myTravel_1:1:6f3602e2-58ec-11ed-bbe8-fa89d281dc2b
System.out.println(instance.getProcessInstanceId());//c96e78ef-58f7-11ed-9f8b-fa89d281dc2b
}
}
@Test
void del() {
RepositoryService repositoryService = processEngine.getRepositoryService();
// repositoryService.deleteDeployment();
RuntimeService runtimeService = processEngine.getRuntimeService();
//act_re_procdef---拿来的参数
// ProcessInstance processInstance = runtimeService.startProcessInstanceById("myTravel_1:1:6f3602e2-58ec-11ed-bbe8-fa89d281dc2b");
runtimeService.deleteProcessInstance("51b423d0-5902-11ed-b595-fa89d281dc2b","");
}
}
晋级版
绑定其他业务表
占位符方式
UEL-value方式: ${submitName}
UEL-method方式: ${User.submitName}
结合版: ${userService.findUser(userBean)}
详解:userService是spring容器的类,调用接口 findUser 入参 userBean 是activiti流程变量
其他:${order.price>100 && order.price<200} 表达式支持解析基础类型,bean,list,array,map
static ProcessEngine processEngine = null;
@BeforeEach
void test() {
/**
* 初始化流程引擎对象,将会根据配置创建25数据表(创建了索引和外键)
*/
processEngine = ProcessEngines.getDefaultProcessEngine();
}
/**
* 分配任务负责人
* 1:固定方式
* 2 uel表达式方式 ( UEL-value 和 UEL-method)
* 3 监听器方式
*/
@Test
void test4() {
// 1:固定方式 就是我们用idea软件画图的时候直接给死了人员名称。创建申请单就是张三。
/* 注意一定变成xml方式看看是不是写的表达式,有的时候变不过来
2: UEL-value方式: ${submitName}
UEL-method方式: ${User.submitName}
结合版: ${userService.findUser(userBean)} userService是spring容器的类,调用接口 findUser 入参 userBean 是activiti流程变量
其他:${order.price>100 && order.price<200} 表达式支持解析基础类型,bean,list,array,map
*/
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("bpmn/travel3.bpmn")
.name("动态人员出差申请流程")
.deploy();
RuntimeService runtimeService = processEngine.getRuntimeService();
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("submitName","张三-动态");
hashMap.put("approval1","李四-动态");
hashMap.put("approval2","王五-动态");
runtimeService.startProcessInstanceByKey("myTravel_3",hashMap);
// act_ru_variable 会存 字段和人名 映射关系
// 删除 repositoryService.deleteDeployment("240b39a6-59c8-11ed-8bd7-fa89d281dc2b",true);
}
挂起
/**
* 挂起:当流程实例没有跑完,如果已经挂起,就不能继续处理了,只有当流程激活后,才能继续执行。
* 挂起后 完成任务 taskService.complete() 报错会
* act_ru_task:SUSPENSION_STATE_ 暂停_状态_ 1 未暂停 2 暂停
*/
@Test
void test3() {
/**
* 多实例流程的挂起
*/
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey("myTravel_1").singleResult();
//当前所有流程实例是否被挂起
boolean suspended = processDefinition.isSuspended();
if(suspended){
//激活方法 参数1:流程定义id 参数2:是否激活 参数3:激活时间
repositoryService.activateProcessDefinitionById(processDefinition.getId(),true,null);
}else {
//挂起方法 参数1:流程定义id 参数2:是否暂停 参数3:暂停时间
repositoryService.suspendProcessDefinitionById(processDefinition.getId(),true,null);
}
/**
* 单个流程实例的挂起
*/
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processDefinitionId("c96e78ef-58f7-11ed-9f8b-fa89d281dc2b").singleResult();
boolean suspended1 = processInstance.isSuspended();
if(suspended1){
//激活方法 参数1:流程定义id
runtimeService.activateProcessInstanceById(processInstance.getId());
}else {
//挂起方法
runtimeService.suspendProcessInstanceById(processInstance.getId());
}
}
监听器方式 动态分配人员 我的插件不好使了。始终出不来 算了
使用global变量控制流程
员工创建出差申请单,由经理审核,经理审核通过后出差3天一下直接由财务审批,3天以上由总经理审批,在财务审核。
static ProcessEngine processEngine = null;
@BeforeEach
void test() {
/**
* 初始化流程引擎对象,将会根据配置创建25数据表(创建了索引和外键)
*/
processEngine = ProcessEngines.getDefaultProcessEngine();
}
/**
* 使用global变量控制流程
*/
@Test
void test6() {
//保存到数据库
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("bpmn/evection-global.bpmn")
.name("global变量动态人员出差申请流程")
.deploy();
//开启流程
RuntimeService runtimeService = processEngine.getRuntimeService();
HashMap<String, Object> hashMap = new HashMap<>();
Evection evection = new Evection();
evection.setNum(2.0);
evection.setId(1L);
evection.setReason("项目出差原因");
hashMap.put("evection",evection);
hashMap.put("submitName","张三提交");
hashMap.put("approval1","李四经理审批");
hashMap.put("approval2","王五总经理-动态");
hashMap.put("approval3","李六财务-动态");
runtimeService.startProcessInstanceByKey("evection-global",hashMap);
}
组任务
就是给当前流程设置多个负责人。
多人审批该任务时候。不能立即审批。先看这个人是不是候选人之一,是的话,还要在拾取该任务,变成个人任务。才能办理。
如果不想办理,还要将任务还回去。
/**
* 组任务 74
*/
@Test
void test7() {
//保存到数据库
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("bpmn/travel-candidate.bpmn")
.name("组人员出差申请流程")
.deploy();
//流程定义的key
String key="travel-candidate";
//开启流程
RuntimeService runtimeService = processEngine.getRuntimeService();
runtimeService.startProcessInstanceByKey(key);
TaskService taskService = processEngine.getTaskService();
//创建申请单(张三) ----->经理审批(候选人 wangwu和lisi)-------等等
String userId="张三";
//创建申请单步骤
// 张三查询自己待办任务
Task task1 = taskService.createTaskQuery().processDefinitionKey(key).taskAssignee(userId).singleResult();
if(task1!=null){
//完成任务
taskService.complete(task1.getId());
}
//经理审批 (组任务模式 候选人 wangwu和lisi)
String candidateUserId="wangwu";
//查询这个候选人待办任务
Task task3 = taskService.createTaskQuery().processDefinitionKey(key)
.taskCandidateUser(candidateUserId) //候选人
//.list() 查询所有待办
.singleResult();
System.out.println("任务id"+task3.getId());
System.out.println("任务负责人"+task3.getAssignee()); //null 因为还没有人拾取任务
if(task3!=null){
//拾取该任务
taskService.claim(task3.getId(),candidateUserId);
}
//拾取完可以办理或归还任务
// taskService.complete(task3.getId()); 完成任务
//归还任务
taskService.setAssignee(task3.getId(),null); //归还任务就是把负责人设置为null
// 任务的转办(任务交接) :这个任务我做不了,想交给别人做。
// 候选人王五做不了,转给李四做
taskService.setAssignee(task3.getId(),"lisi"); //转办任务就是把负责人设置为目标人
}
网关
排他网关
排他网关exclusiveGateway: 排他网关只会选择一个为true去执行。都为true 选择id值较小的那条线去执行。 (global变量控制流程)连线上设置分支条件方式: 不符合任何一条条件时,会结束任务 排他网关方式: 不符合任何一条条件时,会抛异常。扔我们知道哪出问题了。
并行网关
拆分:拆分处,有几个分支就会走几个分支,不会因为连线处有条件而不执行。
聚合:等所有分支都执行完,才能继续往下走。