一、Activiti是什么
Alfresco 软件在 2010 年 5 月17 日宣布 Activiti业务流程管理(BPM)开源项目的正式启动,其 首席架构师由业务流程管理 BPM的专家 Tom Baeyens 担任,Tom Baeyens 就是原来 jbpm的架构师, 而 jbpm 是一个非常有名的工作流引擎,当然 activiti也是一个工作流引擎。 Activiti 是一个工作流引擎, activiti 可以将业务系统中复杂的业务流程抽取出来,使用专门的 建模语言(BPMN2.0)进行定义,业务系统按照预先定义的流程进行执行,实现了业务系统的业务 流程由 activiti进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的 健壮性,同时也减少了系统开发维护成本。
官方网站:https://www.activiti.org/
BPM(Business Process Management),即业务流程管理,是一种以规范化的构造端到端的卓越 业务流程为中心,以持续的提高组织业务绩效为目的系统化方法,常见商业管理教育如EMBA、MBA 等均将 BPM 包含在内。
BPMN(Business Process Model And Notation)- 业务流程模型和符号 是由 BPMI(Business Process Management Initiative)开发的一套标准的业务流程建模符。BPMN 是目前被各 BPM 厂商广泛接受的 BPM 标准。Activiti 就是使用 BPMN 2.0 进行流程建 模、流程执行管理,它包括很多的建模符。
二、Activiti使用流程
1、流程定义 :列如定义一个请假业务流程模型。
2、流程定义部署:只有部署以后才能创建流程实列。
3、启动一个流程实列:启动一个流程实例表示开始一次业务流程的运行,比如员工请假流程部署完成,如果张三要请 假就可以启动一个流程实例,如果李四要请假也启动一个流程实例,两个流程的执行互相不影 响,就好比定义一个 java类,实例化两个对象一样,部署的流程就好比 java 类,启动一个流程 实例就好比 new 一个 java 对象。
4、用户查询代办任务(Task):因为现在系统的业务流程已经交给 activiti管理,通过activiti就可以查询当前流程执行到哪了, 当前用户需要办理什么任务了,这些activiti帮我们管理了,而不像上边需要我们在sql语句中的where 条件中指定当前查询的状态值是多少。
5、用户办理任务:用户查询待办任务后,就可以办理某个任务。
6、流程结束:当任务办理完成没有下一个任务/结点了,这个流程实例就完成了。
三、环境准备
1、JAVA环境:jdk1.8或者以上版本。
2、数据库:Mysql5及以上。
3、Activiti版本:7.0
4、Spring Boot版本:2.0.3.RELEAS。
四、数据库命名规则
Activiti 的表都以ACT开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的 API 对 应。
ACT_RE*: 'RE'表示 repository。 这个前缀的表包含了流程定义和流程静态资源 (图片, 规则,等等)。
ACT_RU*: 'RU'表示 runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务, 等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删 除这些记录。 这样运行时表可以一直很小速度很快。
ACT_HI*: 'HI'表示 history。 这些表包含历史数据,比如历史流程实例, 变量,任务等 等。
ACT_GE_*: GE表示 general。通用数据, 用于不同场景下。
五、Activiti服务架构图
RepositoryService | activiti的资源管理类 |
---|---|
RuntimeService | activiti的流程运行管理类 |
TaskService | activiti的任务管理类 |
HistoryService | activiti的历史管理类 |
ManagerService | activiti的引擎管理类 |
RepositoryService:是 activiti的资源管理类,提供了管理和控制流程发布包和流程定义的操作。使用工作流建模工 具设计的业务流程图需要使用此 service 将流程定义文件的内容部署到计算机。 除了部署流程定义以外还可以 查询引擎中的发布包、 以及暂停或激活该发布包,暂停意味着它们不能再执行任何操作了,激活 是对应的反向操作。
RuntimeService :它是 activiti的流程运行管理类。可以从这个服务类中获取很多关于流程执行相关的信息。
TaskService :是 activiti的任务管理类。可以从这个类中获取任务的信息。
HistoryService :是 activiti 的历史管理类,可以查询历史信息,执行流程时,引擎会保存很多数据(根据配置),比 如流程实例启动时间,任务的参与者, 完成任务的时间,每个流程实例的执行路径,等等。 这个 服务主要通过查询功能来获得这些数据。
ManagementService :是 activiti的引擎管理类,提供了对 Activiti 流程引擎的管理和维护功能,这些功能不在工作流驱动 的应用程序中使用,主要用于 Activiti 系统的日常维护。
-
六、Activiti流程与表之间的关系
-
1、部署流程定义
/**
* 部署流程定义
* activiti表有哪些?
* act_ge_property 系统相关属性
* act_ge_bytearray 流程定义的bpmn文件
* act_re_deployment 部署信息
* act_re_procdef 流程定义的一些信息
*/
@Test
public void createDeployment(){
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("holiday.bpmn")
.name("请假申请流程")
.deploy();
System.out.println(deployment.getName());
}
-
1.1表名:ACT_GE_PROPERTY(系统相关属性)
字段名 | 字段描述 |
---|---|
NAME_ | 属性名称(主键) |
VALUE_ | 属性值 |
REV_ | 版本号 |
-
1.2表名:ACT_GE_BYTEARRAY(通用的流程定义和流程资源)
用来保存部署文件的大文本数据。
保存流程定义图片和xml、Serializable(序列化)的变量,即保存所有二进制数据,特别注意类路径部署时候,不要把svn等隐藏文件或者其他与流程无关的文件也一起部署到该表中,会造成一些错误(可能导致流程定义无法删除)。
字段名 | 字段描述 |
---|---|
ID_ | 主键ID,资源文件编号,自增长 |
REV_ | 版本号 |
NAME_ | 部署文件名称 |
DEPLOYMENT_ID_ | 部署ID(来自于父表act_re_deployment的主键) |
BYTES_ | 大文本类型,存储文本字节流 |
GENERATED_ | 是否是引擎生成(0为用户生成,1为Activiti生成) |
1.3表名:ACT_RE_DEPLOYMENT(部署信息表)
字段名称 | 字段描述 |
---|---|
ID_ | 部署编号,自增ID |
NAME_ | 部署包的名称 |
CATEGORY_ | 类型 |
TENANT_ID_ | 租户 |
DEPLOY_TIME_ | 部署时间 |
-
1.4表名:ACT_RE_PROCDEF(流程定义:解析表)
注:此表和ACT_RE_DEPLOYMENT是多对一的关系,即,一个部署的bar包里可能包含多个流程定义文件,每个流程定义文件都会有一条记录在ACT_RE_PROCDEF表内,每个流程定义的数据,都会对于ACT_GE_BYTEARRAY表内的一个资源文件和PNG图片文件。和ACT_GE_BYTEARRAY的关联是通过程序用ACT_GE_BYTEARRAY.NAME与ACT_RE_PROCDEF.NAME_完成的,在数据库表结构中没有体现。
字段名称 | 字段描述 |
---|---|
ID_ | 流程ID,由“流程编号:流程版本号:自增长ID”组成 |
REV_ | 版本号 |
CATEGORY_ | 流程命名空间(该编号就是流程文件targetNamespace的属性值) |
NAME_ | 流程名称(该编号就是流程文件process元素的name属性值) |
KEY_ | 流程编号(该编号就是流程文件process元素的id属性值) |
VERSION_ | 流程版本号(由程序控制,新增即为1,修改后依次加1来完成的) |
DEPLOYMENT_ID_ | 部署编号 |
RESOURCE_NAME_ | 资源文件名称 |
DGRM_RESOURCE_NAME_ | 图片资源文件名称 |
DESCRIPTION_ | 描述信息 |
HAS_START_FORM_KEY | 是否从key启动 |
SUSPENSION_STATE_ | 是否挂起 |
-
2、启动流程实例
/**
* 启动流程实例:
* 前提是先已经完成流程定义的部署工作
* 背后影响的表:
* act_hi_actinst 已完成的活动信息
* act_hi_identitylink 参与者信息
* act_hi_procinst 流程实例
* act_hi_taskinst 任务实例
* act_ru_execution 执行表
* act_ru_identitylink 参与者信息
* act_ru_task 任务
*/
@Test
public void instanceActiviti(){
// 流程定义key
String processDefinitionKey = "myProcess_1";
RuntimeService runtimeService = processEngine.getRuntimeService();
// 根据流程定义key启动流程
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey);
System.out.println("流 程 定 义 id : " + processInstance.getProcessDefinitionId());
System.out.println("流程实例id:" + processInstance.getId());
System.out.println("当前活动Id:" + processInstance.getActivityId());
}
-
2.1表名:ACT_HI_ACTINST(历史节点表)
历史活动信息。这里记录流程流转过的所有节点,与HI_TASKINST不同的是,taskinst只记录usertask内容。
字段名称 | 字段描述 |
---|---|
ID_ | ID(主键自增) |
PROC_DEF_ID_ | 流程定义ID |
PROC_INST_ID_ | 流程实列ID |
EXECUTION_ID_ | l流程执行ID |
ACT_ID_ | 活动ID |
TASK_ID_ | 任务ID |
CALL_PROC_INST_ID_ | 请求流程实列ID |
ACT_NAME_ | 活动名称 |
ACT_TYPE_ | 活动类型(startEvent,userTask) |
ASSIGNEE_ | 代理人员 |
START_TIME_ | 开始时间 |
END_TIME_ | 结束时间 |
DURATION_ | 时长,耗时(毫秒值) |
-
2.2表名:ACT_HI_IDENTITYLINK (历史流程人员表)
任务参与者数据表。主要存储历史节点参与者的信息。
字段名称 | 字段描述 |
---|---|
ID_ | 主键自增ID |
GROUP_ID_ | 组ID |
TYPE_ | 类型(assignee,candidate,owner,starter,participant) |
USER_ID_ | 用户ID |
TASK_ID_ | 任务ID |
PROC_INST_ID_ | 流程实列ID |
-
2.3表名:ACT_HI_PROCINST(历史流程实例信息)核心表
字段名称 | 字段描述 |
---|---|
ID_ | 自增ID |
PROC_INST_ID_ | 流程实列ID |
BUSINESS_KEY_ | 业务key |
PROC_DEF_ID_ | 流程定义ID |
START_TIME_ | 开始时间 |
END_TIME_ | 结束时间 |
DURATION_ | 时长 |
START_USER_ID_ | 发起人员Id |
START_ACT_ID_ | 开始节点 |
END_ACT_ID_ | 结束节点 |
SUPER_PROCESS_INSTANCE_ID_ | 超级流程实列ID |
DELETE_REASON_ | 删除理由 |
-
2.4表名:ACT_HI_TASKINST(历史任务流程实例信息)核心表
字段名称 | 字段描述 |
---|---|
ID_ | 自增主键 |
PROC_DEF_ID_ | 任务定义ID |
TASK_DEF_KEY_ | 任务定义key |
PROC_INST_ID_ | 流程实列ID |
EXECUTION_ID_ | 执行ID |
NAME_ | 名称 |
PARENT_TASK_ID_ | 父任务ID |
DESCRIPTION_ | 描述 |
OWNER_ | 实际签收人 任务的拥有者 |
ASSIGNEE_ | 代理人 |
START_TIME_ | 开始时间 |
CLAIM_TIME_ | 提醒时间 |
END_TIME_ | 结束时间 |
DURATION_ | 时长 |
DELETE_REASON_ | 删除原因 |
PRIORITY_ | 优先级别 |
DUE_DATE_ | 过期时间,表示任务应该多长时间内完成 |
FORM_KEY_ | 表单key(desinger节点定义的) |
-
2.5表名:ACT_RU_EXECUTION(运行时流程执行实例)
核心,我的代办任务查询表
字段名称 | 字段描述 |
---|---|
ID_ | 自增ID |
REV_ | 版本号 |
PROC_INST_ID_ | 流程实例编号 |
BUSINESS_KEY_ | 业务编号 |
PARENT_ID_ | 父执行流程 |
PROC_DEF_ID_ | 流程定义ID |
SUPER_EXEC_ | |
ACT_ID_ | 实列ID |
IS_ACTIVE_ | 激活状态 |
IS_CONCURRENT_ | 并发状态 |
IS_SCOPE_ | |
IS_EVENT_SCOPE_ | |
SUSPENSION_STATE_ | 暂停状态(1激活,2挂起) |
CACHED_ENT_STATE_ | 缓存结束状态 |
-
2.6表名:ACT_RU_IDENTITYLINK(身份联系)
主要存储当前节点参与者的信息,任务参与者数据表。
字段名称 | 字段描述 |
---|---|
ID_ | 自增ID |
REV_ | 版本号 |
GROUP_ID_ | 用户组ID |
TYPE_ | 主要分为以下几种:assignee、candidate、owner、starter、participant。即:受让人,候选人,所有者、起动器、参与者 |
USER_ID_ | 用户ID |
TASK_ID_ | 任务Id |
PROC_INST_ID_ | 流程实例ID |
PROC_DEF_ID_ | 流程定义Id |
-
2.7表名:ACT_RU_TASK(运行时任务数据表)
(执行中实时任务)代办任务查询表
字段名称 | 字段描述 |
---|---|
ID_ | 自增主键 |
REV_ | 版本号 |
EXECUTION_ID_ | 执行实例ID |
PROC_INST_ID_ | 流程实例ID |
PROC_DEF_ID_ | 流程定义ID |
NAME_ | 节点定义名称 |
PARENT_TASK_ID_ | 父节点实例ID |
DESCRIPTION_ | 节点定义描述 |
TASK_DEF_KEY_ | 任务定义的key |
OWNER_ | 拥有者(一般情况下为空,只有在委托时才有值) |
ASSIGNEE_ | 代理人员 |
DELEGATION_ | 代理团委DelegationState分为两种:PENDING,RESOLVED。如无委托则为空 |
PRIORITY_ | 优先权 |
CREATE_TIME_ | 创建时间 |
DUE_DATE_ | 执行时间 |
SUSPENSION_STATE_ | 挂起状态(1代表激活 2代表挂起) |
-
3、执行任务
/**
* 通过流程定义的key和执行人
* 处理当前用户的任务
* 背后操作的表:
* act_hi_actinst
* act_hi_identitylink
* act_hi_taskinst
* act_ru_identitylink
* act_ru_task
*/
@Test
public void queryTaskAndExc() {
String assignee = "wangwu";
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().processDefinitionKey(PRO_DEF_KEY)
.taskAssignee(assignee)
.singleResult();
String id = task.getId();
taskService.complete(id);
}
-
4、任务结束
-
七、流程变量以及网关结束
-
1、分配任务负责人
类型 | 描述 |
---|---|
固定分配 | 在进行业务流程建模时(Assignee)指定固定任务负责人(不推荐) |
表达式分配 | UEL(Unified Expression Language)统一表达式语言,${assignee}。表达式支持解析基础类型、bean、list、array 和 map,也可作为条件判断。 |
监听器分配 | Create:任务创建后触发 Assignment:任务分配后触发 Delete:任务完成后触发 All:所有事件发生都触发 |
/**
* 使用UEL表达式
* 填充占位的变量
*/
@Test
public void variable(){
//2.得到RuntimeService对象
RuntimeService runtimeService = processEngine.getRuntimeService();
//3.设置assignee的取值 用户可以在界面上设置流程的执行人
Map<String,Object> map = new HashMap<>();
map.put("assignee0","zhangsan");
map.put("assignee1","lishi");
map.put("assignee2","wangwu");
//4.启动流程实例,同时还要设置流程定义的assignee的值
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(PRO_DEF_KEY, map);
//5.输出
System.out.println(processEngine.getName());
}
-
2、流程变量
流程变量在 activiti中是一个非常重要的角色,流程运转有时需要靠流程变量,业务系统和 activiti 结合时少不了流程变量,流程变量就是 activiti在管理工作流时根据管理需要而设置的变量。 比如在请假流程流转时如果请假天数大于 3 天则由总经理审核,否则由人事直接审核,请假天 数就可以设置为流程变量,在流程流转时使用。
注意:虽然流程变量中可以存储业务数据可以通过 activiti 的 api 查询流程变量从而实现 查询业务 数据,但是不建议这样使用,因为业务数据查询由业务系统负责,activiti设置流程变量是为了流程执行需要而创建。
如果将 pojo 存储到流程变量中,必须实现序列化接口 serializable,为了防止由于新增字段无 法反序列化,需要生成 serialVersionUID。
流程变量的作用域默认是一个流程实例(processInstance),也可以是一个任务(task)或一个执行实例 (execution),这三个作用域流程实例的范围最大,可以称为 global变量,任务和执行实例仅仅是针对 一个任务和一个执行实例范围,范围没有流程实例大,称为 local变量。
global变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值。
Local变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。
Local变量名也可以和 global变量名相同,没有影响。
第一步:设置流程变量
第二步:通过 UEL表达式使用流程变量 1> 可以在 assignee 处设置 UEL表达式,表达式的值为任务的负责人 比如:${assignee},assignee 就是一个流程变量名称
Activiti获取 UEL 表达式的值 ,即流程变量 assignee 的值 ,将 assignee 的值作为任务的负责人 进行任务分配
2> 可以在连线上设置 UEL表达式,决定流程走向 比如:${price>=10000}和${price<10000}: price 就是一个流程变量名称,uel 表达式结果类型为 布尔类型
如果 UEL表达式是 true,要决定 流程执行走向
1、 如果 UEL表达式中流程变量名不存在则报错。
2、 如果 UEL表达式中流程变量值为空NULL,流程不按 UEL 表达式去执行,而流程结束 。
3、 如果 UEL表达式都不符合条件,流程结束
4、 如果连线不设置条件,会走 flow 序号小的那条线
-
3、网关
网关分类 | 描述 |
---|---|
排他网关 | 任务执行之后的分支,经过排他网关分支只有一条有效。 |
并行网关 | 任务执行后,可以多条分支,多条分支总会汇聚,汇聚完成,并行网关结束。 |
包含网关 | 是排他网关和并行网关结合体。 |