1. 流程实例
什么是流程实例
参与者(可以是用户也可以是程序)按照流程定义内容发起-一个流程,这就是-一个流程实例。是动态的。
流程定义和流程实例的图解:
启动流程实例
/**
* 部署流程
*/
@Test
public void testDeployProcess() {
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("processes/test.bpmn")
.addClasspathResource("processes/test.png")
.name("测试获取流程图-1")
.deploy();
System.out.println("流程部署ID:"+deploy.getId());
System.out.println("流程部署名称:"+deploy.getName());
}
/**
* 启动流程
*/
@Test
public void testStartProcess(){
securityUtil.logInAs("salaboy");
//启动流程实例,同时还要指定业务标识businessKey
//第一个参数:是指流程定义key
//第二个参数:业务标识businessKey
ProcessInstance test = runtimeService.startProcessInstanceByKey("test","1001");
System.out.println("流程实例id:"+test.getId());
System.out.println("流程部署id:"+test.getProcessDefinitionId());
}
2. Businesskey(业务标识)
Businesskey:业务标识,通常为业务表的主键,业务标识和流程实例一-对应。业务标识来源于业务系统。存储业务标识就是根据业务标识来关联查询业务系统的数据。比如:请假流程启动一个流程实例,就可以将请假单的id作为业务标识存储到activiti中, 将来查询activiti的流程实例信息就可以获取请假单的id从而关联查询业务系统数据库得到请假单信息。
- //根据流程定义的key启动- -个流程实例
- ProcessInstanceprocessInstance=runtimeService.startProcessInstanceByKey(processDefinitionKey,
businessKey);
3. 操作数据库表
启动流程实例,操作如下数据库表:
SELECT * FROM act_ru_execution #流程实例执行表,记录当前流程实例的执行情况
说明:
流程实例执行,如果当前只有一一个分支时,-一个流程实例只有一.条记录且执行表的主键id和流程实例id相同,如果当前有多个分支正在运行则该执行表中有多条记录,存在执行表的主键和流程实例id不相同的记录。不论当前有几个分支总会有-条记录的执行表的主键和流程实例id相同-一个流程实例运行完成,此表中与流程实例相关的记录删除。
SELECT * FROM act_ru_task #任务执行表,记录当前执行的任务
说明:
启动流程实例,流程当前执行到第一个任务节点,此表会插入一条记录表示当前任务的执行情况,如果任务完成则该记录删除。
SELECT * FROM act _hi _procinst #流程实例历史表
SELECT * FROM act_hi_taskinst #任务历史表,记录所有任务
开始一个任务,不仅在act_ru_task表插入记录,也会在历史任务表插入一条记录,任务历史表的主键就是任务id,任务完成此表记录不删除。
SELECT * FROM act_hi_actinst #活动历史表,记录所有活动。
活动包括任务,所以此表中不仅记录了任务,还记录了流程执行过程的其它活动,比如开始事件、结束事件。
流程在运行过程中可以查询流程实例的状态,当前运行结点等信息:
/**
* 查询流程实例
*/
@Test
public void getProcessInstance(){
List<ProcessInstance> list = runtimeService.createProcessInstanceQuery()
.processInstanceId("6fa76f62-e5d5-11ea-958c-68ecc5dbc2f7")
.list();
for (ProcessInstance processInstance : list) {
System.out.println(processInstance.getId());
}
}
4. 关联BusinnessKey
需求:
在activiti实际应用时,查询流程实例列表时可能要显示出业务系统的一些相关信息,比如:查询当
前运行的请假流程列表需要将请假单名称、请假天数等信息显示出来,请假天数等信息在业务系统
中存在,而并没有在activiti数据库中存在,所以是无法通过activiti的api查询到请假天数等信息。
实现:
在查询流程实例时,通过businessKey (业务标识)关联查询业务系统的请假单表,查询出请假天
数等信息。通过下面的代码就可以获取actiti中所对应实例保存的业务Keyo而这个业务Key一般都会保存相
关联的业务操作表的主键,再通过主键ID去查询业务信息,比如通过请假单的ID,去查询更多的
请假信息(请假人,请假时间,请假天数,请假事由等)
这个表是工作流程的核心表,流程的驱动都和合格表有密切的关系。
一般来讲一个流程实例都有一条主线。如果流程为直线流程,那么流程实例在这个表中只有一条记录对应。
- ID_:EXECUTION主键,这个主键有可能和PROC_INST_ID_相同,相同的情况表示这条记录为主实例记录。
- REV_:表示数据库表更新次数。
- PROC_INST_ID_:一个流程实例不管有多少条分支实例,这个ID都是一致的。
- BUSINESS_KEY_:这个为业务主键,主流程才会使用业务主键,另外这个业务主键字段在表中有唯一约束。
- PARENT_ID_:这个记录表示父实例ID,如上图,同步节点会产生两条执行记录,这两条记录的父ID为主线的ID。
- PROC_DEF_ID_ :流程定义ID
- SUPER_EXEC : 这个如果存在表示这个实例记录为一个外部子流程记录,对应主流程的主键ID。
- ACT_ID_:表示流程运行到的节点
- IS_ACTIVE_ : 是否活动流程实例,比如上图,主流程为非活动实例,下面两个为活动实例,如果UserTask2完成,那么这个值将变为0即非活动。
- IS_CONCURRENT_:是否并发。
- IS_SCOPE_: 这个字段我跟踪了一下不同的流程实例,如会签,子流程,同步等情况,发现主实例的情况这个字段为1,子实例这个字段为0。
- TENANT_ID_ : 这个字段表示租户ID。可以应对多租户的设计。
- IS_EVENT_SCOPE: 没有使用到事件的情况下,一般都为0。
- SUSPENSION_STATE_: 这个表示是否暂停。
- CACHE_ENT_STATE :这个暂时还不明白有什么作用。
查询业务id
/**
* 查询BusinnessKey
*/
@Test
public void testQueryProcessDefinition() {
securityUtil.logInAs("salaboy");
String businessKey = processRuntime.processInstance("6fa76f62-e5d5-11ea-958c-68ecc5dbc2f7")
.getBusinessKey();
System.out.println(businessKey);
}
挂起和激活实例
某些情况可能由于流程变更需要将当前运行的流程暂停而不是直接删除,流程暂停后将不会继续执行
全部挂起和激活
操作流程定义为挂起状态,该流程定义下边所有的流程实例全部暂停:流程定义为挂起状态该流程定义将不允许启动新的流程实例,同时该流程定义下所有的流程实例将全部挂起暂停执行。
/**
* 全部挂起和激活实例
*/
@Test
public void PendingActivation(){
//查询流程定义的对象
ProcessDefinition test = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("test")
.singleResult();
//得到当前流程定义的实例是否都为暂停状态
boolean suspended = test.isSuspended();
String id = test.getId();
if(suspended){
//暂停,就可以激活操作
repositoryService.activateProcessDefinitionById(id,true,null);
System.out.println("流程定义:"+id+"激活");
}else {
//激活,就可以挂起操作
repositoryService.suspendProcessDefinitionById(id,true,null);
System.out.println("流程定义:"+id+"挂起");
}
}
说明:流程挂起时上面红色框的字段值为2,激活时值为1,当前为激活状态
单个挂起和激活
/**
* 单个挂起和激活
*/
@Test
public void singlePendingActivation(){
//查询流程定义的对象
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId("cf8ab090-e5dc-11ea-a288-68ecc5dbc2f7")
.singleResult();
//得到当前流程定义的实例是否都为暂停状态
boolean suspended = processInstance.isSuspended();
String id = processInstance.getId();
//判断
if(suspended){
//暂停,就可以激活操作
runtimeService.activateProcessInstanceById(id);
System.out.println("流程定义:"+id+"激活");
}else {
//激活,就可以挂起操作
runtimeService.suspendProcessInstanceById(id);
System.out.println("流程定义:"+id+"挂起");
}
}
数据库:
可以看出单个实例挂起,红色框内的实例,SUSPENSION_STATE_字段值为1,表示实例激活,上面的那个实例值为2,表示实例挂起。
注意:实例挂起时,当前实例的任务无法完成,如果强行执行任务提交则会报错
org.activiti.engine.ActivitiException: Cannot complete a suspended task(org.activiti.engine网站.ActivityException:无法完成挂起的任务)
5. 流程变量
什么是流程变量
流程变量在activiti中是-一个非常重要的角色,流程运转有时需要靠流程变量,业务系统和ativiti结合时少不了流程变量,流程变量就是activiti在管理工作流时根据管理需要而设置的变量。比如在请假流程流转时如果请假天数大于3天则由总经理审核,否则由人事直接审核,请假天数就可以设置为流程变量,在流程流转时使用。
注意:虽然流程变t中可以存储业务数据可以通过activiti 的api查询流程变册t从而实现查询业务数据,但是不建议这样使用,因为业务数据查询由业务系统负责, activiti 设流程变t是为了流程执行而需要创建的
流程变量类型
注意:如果将pojo存储到流程变量中,必须实现序列化接口serializable, 为了防止由于新增字段无法反序列化,需要生成serialVersionUID.
global变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值。
Local变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响
Local变量名也可以和global 变量名相同,没有影响。
流程变量的使用方法
第一步:设置流程变量
第二步:通过UEL表达式使用流程变量
- 可以在assignee处设置UEL表达式,表达式的值为任务的负责人比如: ${assignee}, assignee
就是-个流程变量名称Activiti获取UEL表达式的值,即流程变量assignee的值,将assignee的值作为任务的负责人进行任务分配 - 可以在连线上设置UEL表达式,决定流程走向比如: ${price>=10000} 和S {ric10000: price 就是- t
个流程变量名称,uel 表达式结果类型为布尔类型
如果UEL表达式是true,要决定流程执行走向。
使用global变量控制流程
员工创建请假申请单,由部门经理审核,部门经理审核通过后请假3天及以下由人事经理直接审核,3天以上先由总经理审核,总经理审核通过再由人事经理存档。
设置global流程变量
在部广经理审核前设置流程变量,变量值为请假单信息(包括请假天数),部门经理审核后可以根据流程变量的值决定流程走向。
启动时设置流程变量
在启动流程时设置流程变量,变量的作用域是整个流程实例。通过map<key,value>设置流程变量,map 中可以设置多个变量,这个key就是流程变量的名字。
说明:
startProcessInstanceByKey( processDefinitionkey, variables )流程变量作用域是-一个流程实例,流程变量使用Map存储,同-一个流程实例设置变量map中key相同,后者覆盖前者。
任务办理时设置流程变量
在完成任务时设置流程变量,该流程变量只有在该任务完成后其它节点才可使用该变量,它的作用域是整个流程实例,如果设置的流程变量的key在流程实例中已存在相同的名字则后设置的变量替换前边设置的变量。这需要在创建请假单任务完成时设置流程变量。
说明:
通过当前任务设置流程变量,需要指定当前任务id,如果当前执行的任务id不存在则抛出异常。任务办理时也是通过map<key,value>设置流程变量,- -次可以设置多个变量。
通过当前实例来设置流程变量
//新加入的:通过流程实例id,来测试流程变量
public static void main(String[] args) {
//1.得到ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3.流程定义的key问题 myProcess_1
//Map<String ,Object> map = new HashMap<>();
Holiday holiday = new Holiday();
holiday.setNum(5F);
// map.put("holiday",holiday);
//4.通过实例id,来设置流程变量
//第一个参数:流程实例的id
//第二个参数:流程变量名
//第三个变量:流程变量名,所对应的值
runtimeService.setVariable("2501","holiday",holiday);
}
注意:
executionld必须当前未结束流程实例的执行id,通常此id设置流程实例的id.也可以通过runtimeService getVariable()获取流程变量
通过当前任务来设置流程变量
String taskId = "1404";
TaskService taskService = processEngine.getTaskService();
Holiday holiday = new Holiday();
holiday.setNum(5F);
taskService.setVariable(taskId,"holiday",holiday);
6. Activiti7总结
什么是工作流?
就是通过计算机对业务流程进行自动化管理,实现多个参与者按照预定义的流程去自动执行业务流
什么activiti?
Activiti是一个工作流的引擎,开源的架构,基本bpmn2.0标准进行流程定义,它的是前身是jbpm.
Activiti通过是要嵌入到业务系统开发使用。
如何使用activiti开发?
●第一步: 部署activiti 的环境。
环境包括: jar 包和数据库(25 张表)业务系统通过spring和activiti 整合进行开发。
●第二步: 使用activiti提供流程设计器(和idea或eclipse集成的designer)工具进行流程定义
流程定义生成两个文件: .bpmn 和.png (不是必须的)。
●第三步: 将流程定义文件部署到activiti的数据库
SELECT * FROM act re_ deployment #流程定义部署表-次部署插入一条记录,记录流程定义的部署信息SELECT * FROM act re procdef #流程定义表-次部署流程定义信息,如果一-次部署两个流程定义,插入两条记录建议: -次部署只部署一一个流程定义,这样act re_ deployment 和act_ re_ procdef- -对- -关系常用两个方法:单个文件部署和zip文件部署.建议单个文件部署。
●第四步: 启动一个流程实例
业务系统就可以按照流程定义去执行业务流程,执行前需要启动-个流程实例根据流程定义来启动一个流程实例。指定-一个流程定义的key启动-个流程实例,activiti根据key找最新版本的流程定义。指定一个流程定义的id启动一个流程实例。启动一个实例需要指定businesskey (业务标识),businessKey 是activiti 和业务系统整合时桥梁。比如:请假流程,businessKey 就是请假单id.启动一个实例还可以指定流程变量,流程变量是全局变量(生命期是整个流程实例,流程实例结束,变量就消失)
●第五步: 查询待办任务
查询个人任务:使用taskService,根据assignee查询该用户当前的待办任务。
查询组任务:使用taskService,根据andidateuser查询候选用户当前的待办组任务。
●第六步: 办理任务
办理个人任务:调用taskService的complete方法完成任务。
如果是组任务,需要先拾取任务,调用taskService 的claim方法拾取任务,拾取任务之后组任务就
变成了个人任务(该任务就有负责人)。
网关:
排他网关:任务执行之后的分支,经过排他网关分支只有一条有效。
并行网关:任务执行后,可以多条分支,多条分支总会汇聚,汇聚完成,并行网关结束。
包含网关:是排他网关和并行网关结合体。
本文借用爱学习的老王的很多知识点,学到了很多。