流程参与者(可以是用户也可以是程序)按照流程定义内容发起一个流程,这就是一个流程实例。是动态的。
流程定义和流程实例的图解:

====================================================
==========启动流程实例=============
====================================
流程定义部署在 activiti 后,就可以在系统中通过 activiti 去管理该流程的执行,执行流程表示流程的一次执行。比如部署系统请假流程后,如果某用户要申请请假这时就需要执行这个流程,如果另外一个用户也要申请请假则也需要执行该流程,每个执行互不影响,每个执行是单独的流程实例。执行流程首先需要启动流程实例。
@Test
public void
startProcessInstance() {
// 流程定义key
String processDefinitionKey = “”;
// 获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// 根据流程定义key启动流程
ProcessInstanceprocessInstance =runtimeService.startProcessInstanceByKey(processDefinitionKey);
System.
out
.println(“流 程 定 义 id:” +processInstance.getProcessDefinitionId());
System.
out
.println(“流程实例id:” +processInstance.getId());
System.
out
.println(“当前活动Id:” +processInstance.getActivityId());
}
===============================================================
==========BusinessKey(业务标识)=============
===========================================
启动流程实例时,指定的businesskey,就会在act_ru_execution#流程实例的执行表中存储businesskey。 Businesskey:业务标识,通常为业务表的主键,业务标识和流程实例一一对应。业务标识来源于业务系统。存储业务标识就是根据业务标识来关联查询业务系统的数据。
比如:请假流程启动一个流程实例,就可以将请假单的 id作为业务标识存储到 activiti 中,将来查询 activiti 的流程实例信息就可以获取请假单的 id 从而关联查询业务系统数据库得到请假单信息。
代码:
// 根据流程定义的key启动一个流程实例
ProcessInstance processInstance =runtimeService.startProcessInstanceByKey(processDefinitionKey,businessKey);
Activiti 中存储业务标识:

操作数据库表:
启动流程实例,操作如下数据库表:
SELECT * FROM act_ru_execution #流程实例执行表,记录当前流程实例的执行情况

说明:
流程实例执行,如果当前只有一个分支时,一个流程实例只有一条记录且执行表的主键 id 和流程实例id相同,如果当前有多个分支正在运行则该执行表中有多条记录,存在执行表的主键和流程实例id 不相同的记录。
不论当前有几个分支总会有一条记录的执行表的主键和流程实例 id 相同
一个流程实例运行完成,此表中与流程实例相关的记录删除。
SELECT * FROM act_ru_task #任务执行表,记录当前执行的任务

说明:启动流程实例,流程当前执行到第一个任务结点,此表会插入一条记录表示当前任务的执行情况,如果任务完成则记录删除。
SELECT * FROM act_ru_identitylink #任务参与者,记录当前参与任务的用户或组

SELECT * FROM act_hi_procinst #流程实例历史表

流程实例启动,会在此表插入一条记录,流程实例运行完成记录也不会删除。
SELECT * FROM act_hi_taskinst #任务历史表,记录所有任务

开始一个任务,不仅在 act_ru_task 表插入记录,也会在历史任务表插入一条记录,任务历史表的主
键就是任务 id,任务完成此表记录不删除。
SELECT * FROM act_hi_actinst #活动历史表,记录所有活动

活动包括任务,所以此表中不仅记录了任务,还记录了流程执行过程的其它活动,比如开始事件、结束事件。
===============================================================
==========查询流程实例=============
===========================================
流程在运行过程中可以查询流程实例的状态,当前运行结点等信息。
@Test
public void
queryProcessInstance() {
// 流程定义key
String processDefinitionKey = “holiday”;
// 获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
List<ProcessInstance> list = runtimeService
.createProcessInstanceQuery()
.processDefinitionKey(processDefinitionKey)//
.list();
for
(ProcessInstanceprocessInstance : list) {
System.
out
.println(“—————————-“);
System.
out
.println(“流程实例id:”+processInstance.getProcessInstanceId());
System.
out
.println(“所属流程定义id:”+processInstance.getProcessDefinitionId());
System.
out
.println(“是否执行完成:” + processInstance.isEnded());
System.
out
.println(“是否暂停:” + processInstance.isSuspended());
System.
out
.println(” 当 前 活 动标 识 : ” + processInstance.getActivityId());
}
}
===============================================================
============关联 businessKey=============
===============================================================
需求:
在 activiti 实际应用时,查询流程实例列表时可能要显示出业务系统的一些相关信息,比如:查询当前运行的请假流程列表需要将请假单名称、请假天数等信息显示出来,请假天数等信息在业务系统中存在,而并没有在activiti 数据库中存在,所以是无法通过 activiti的 api查询到请假天数等信息。
实现:
在查询流程实例时,通过 businessKey(业务标识 )关联查询业务系统的请假单表,查询出请假天数等信息。
通过下面的代码就可以获取 activiti 中所对应实例保存的业务 Key。而这个业务 Key一般都会保存相关联的业务操作表的主键,再通过主键 ID 去查询业务信息,比如通过请假单的ID,去查询更多的请假信息(请假人,请假时间,请假天数,请假事由等)
StringbusinessKey = processInstance.getBusinessKey();
在 activiti 的 act_ru_execution表,字段 BUSINESS_KEY就是存放业务 KEY 的。

===============================================================
============挂起与激活流程=============
===============================================================
某些情况可能由于流程变更需要将当前运行的流程暂停而不是直接删除,流程暂停后将不会继续执行。
=============================================
==========全部流程实例挂起=========
====================================
操作流程定义为挂起状态,该流程定义下边所有的流程实例全部暂停:流程定义为挂起状态该流程定义将不允许启动新的流程实例,同时该流程定义下所有的流程实例将
全部挂起暂停执行。
// 挂起激活流程定义
@Test
public void
suspendOrActivateProcessDefinition() {
// 流程定义id
String processDefinitionId = “”;
RepositoryService repositoryService = processEngine.getRepositoryService();
// 获得流程定义
ProcessDefinition processDefinition =
repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
//是否暂停
boolean
suspend= processDefinition.isSuspended();
if
(suspend){
//如果暂停则激活,这里将流程定义下的所有流程实例全部激活
repositoryService.activateProcessDefinitionById(processDefinitionId,
true
,
null
);
System.
out
.println(“流程定义:”+processDefinitionId+”激活”);
}
else
{
//如果激活则挂起,这里将流程定义下的所有流程实例全部挂起
repositoryService.suspendProcessDefinitionById(processDefinitionId,
true
,
null
);
System.
out
.println(“流程定义:”+processDefinitionId+”挂起”);
}
}
=============================================
==========单个流程实例挂起=========
====================================
操作流程实例对象,针对单个流程执行挂起操作,某个流程实例挂起则此流程不再继续执行,完成
该流程实例的当前任务将报异常。
@Test
public void
suspendOrActiveProcessInstance() {
// 流程实例id
String processInstanceId = “”;
// 获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//根据流程实例id查询流程实例
ProcessInstance processInstance =runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
boolean
suspend= processInstance.isSuspended();
if
(suspend){
//如果暂停则激活
runtimeService.activateProcessInstanceById(processInstanceId);
System.
out
.println(“流程实例:”+processInstanceId+”激活”);
}
else
{
//如果激活则挂起
runtimeService.suspendProcessInstanceById(processInstanceId);
System.
out
.println(“流程实例:”+processInstanceId+”挂起”);
}
}
=============================================
==========Activiti7:任务分配=========
====================================
第一种方式:在进行业务流程建模时指定固定的任务负责人。

在 properties 视图中,填写 Assignee项为任务负责人。
缺点:由于固定分配方式,任务只管一步一步执行任务,执行到每一个任务将按照 bpmn的配置去分配任务负责人
第二种方式:UEL表达式
Activiti 使用 UEL 表达式,UEL 是 java EE6 规范的一部分,UEL(
Unified Expression Language
)即 统一表达式语言,activiti 支持两个 UEL 表达式:UEL-value 和 UEL-method。
UEL-value 定义如下:

assignee 这个变量是 activiti 的一个流程变量。或:

user 也是 activiti 的一个流程变量,user.assignee 表示通过调用 user的 getter方法获取值。
UEL-method 方式如下:

userBean 是 spring 容器中的一个 bean,表示调用该 bean的 getUserId()方法。
UEL-method 与 UEL-value 结合
再比如: ${ldapService.findManagerForEmployee(emp)}ldapService 是 spring 容器的一个 bean,findManagerForEmployee是该 bean的一个方法,emp是 activiti流程变量,emp作为参数传到 ldapService.findManagerForEmployee 方法中。
其它
表达式支持解析基础类型、bean、list、array和 map,也可作为条件判断。
如下: ${order.price >100 && order.price < 250}
第三种方式:使用流程变量分配任务
定义任务分配流程变量

设置流程变量
在启动流程实例时设置流程变量,如下:
//启动流程实例时设计流程变量
//定义流程变量
Map<String, Object> variables =
new
HashMap<String,Object>();
//设置流程变量assignee
variables.put(“assignee”,”张三”);
ProcessInstance processInstance =runtimeService.startProcessInstanceByKey(processDefinitionKey, variables);
注意点:由于使用了表达式分配,必须保证在任务执行过程表达式执行成功,比如:某个任务使用了表达式${order.price> 100 && order.price < 250},当执行该任务时必须保证 order 在流程变量中存在,否则activiti 异常。
第四种方式:监听器分配
任务监听器是发生对应的任务相关事件时执行自定义 java逻辑 或表达式。
任务相当事件包括:

Create:任务创建后触发
Assignment:任务分配后触发
Delete:任务完成后触发
All:所有事件发生都触发
java 逻辑 或表达式:
表达式参考上边的介绍的 UEL 表达式,这里主要介绍监听类使用。
定义任务监听类,且类必须实现 org.activiti.engine.delegate.TaskListener接口
public class
MyTaskListener
implements
TaskListener {
@Override
public void
notify(DelegateTask delegateTask) {
//这里指定任务负责人
delegateTask.setAssignee(“张三”);
}
}
注意点:使用监听器分配方式,按照监听事件去执行监听类的 notify 方法,方法如果不能正常执行也会影响
任务的执行。
======================================================
===========Activit7:查询任务==========
======================================================
查询任务负责人的待办任务
// 查询当前个人待执行的任务
@Test
public void
findPersonalTaskList() {
// 流程定义key
String processDefinitionKey = “holiday”;
// 任务负责人
String assignee = “张三丰”;
// 创建TaskService
TaskService taskService = processEngine.getTaskService();
List<Task> list = taskService.createTaskQuery()//
.processDefinitionKey(processDefinitionKey)//
.includeProcessVariables().taskAssignee(assignee).list();
for
(Tasktask : list) {
System.
out
.println(“—————————-“);
System.
out
.println(“流程实例id:” +task.getProcessInstanceId());
System.
out
.println(“任务id:” +task.getId());
System.
out
.println(“任务负责人:”+ task.getAssignee());
System.
out
.println(“任务名称:”+ task.getName());
}
}
================================================================
===========Activit7:关联businessKey==========
================================================================
需求:
在 activiti 实际应用时,查询待办任务可能要显示出业务系统的一些相关信息,比如:查询待审批请假单任务列表需要将请假单的日期、请假天数等信息显示出来,请假天数等信息在业务系统中存在,而并没有在 activiti 数据库中存在,所以是无法通过 activiti的 api查询到请假天数等信息。
实现:
在查询待办任务时,通过 businessKey(业务标识 )关联查询业务系统的请假单表,查询出请假天数等信息。

================================================================
===========Activit7:办理任务==========
================================================================
指定任务 id,调用 TaskService 完成任务:
// 完成任务
@Test
public void
completTask() {
//任务id
String taskId = “10305”;
// 创建TaskService
TaskService taskService = processEngine.getTaskService();
taskService.complete(taskId);
System.
out
.println(“完成任务”);
}
注意:在实际应用中,完成任务前需要校验任务的负责人是否具有该任务的办理权限

================================================================
===========Activit7:流程变量==========
================================================================
流程变量是什么:在 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,要决定 流程执行走向
================================================
========使用Global变量控制流程========
================================================
需求:
员工创建请假申请单,由部门经理审核,部门经理审核通过后请假 3天及以下由人事经理直接
审核,3 天以上先由总经理审核,总经理审核通过再由人事经理存档。

=================================================
============流程定义==============
=================================================
请假天数大于等于 3 连线条件:

请假天数小于 3 连线条件:

设置 global流程变量
==================================================
======设置global流程变量===========
==================================================
在部门经理审核前设置流程变量,变量值为请假单信息(包括请假天数),部门经理审核后可以根据流程变量的值决定流程走向
启动流程时设置
在启动流程时设置流程变量,变量的作用域是整个流程实例。
通过 map<key,value>设置流程变量,map中可以设置多个变量,这个 key 就是流程变量的名字。
// 启动流程时设置流程变量
@Test
public void
startProcessInstance() {
// 流程定义key
String processDefinitionKey = “”;
Holiday holiday = new Holiday();
holiday.setNum(3);
// 定义流程变量
Map<String, Object> variables =
new
HashMap<String,Object>();
//变量名是num,变量值是holiday.getNum(),变量名也可以是一个对象
variables.put(“num”, holiday.getNum());
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance =runtimeService.startProcessInstanceByKey(processDefinitionKey, variables);
System.
out
.println(“流 程 实 例 id:” +processInstance.getProcessInstanceId());
}
说明:
startProcessInstanceByKey(processDefinitionKey, variables)流程变量作用域是一个流
程实例,流程变量使用 Map 存储,同一个流程实例设置变量 map中 key相同,后者覆盖前者。
任务办理时设置
在完成任务时设置流程变量,该流程变量只有在该任务完成后其它结点才可使用该变量,它的作用
域是整个流程实例,如果设置的流程变量的 key 在流程实例中已存在相同的名字则后设置的变量替
换前边设置的变量。
这里需要在创建请假单任务完成时设置流程变量
// 办理任务时设置流程变量
@Test
public void
completTask() {
//任务id
String taskId = “”;
TaskService taskService = processEngine.getTaskService();
Holiday holiday = new Holiday();
holiday.setNum(4);
// 定义流程变量
Map<String, Object> variables =
new
HashMap<String,Object>();
//变量名是holiday,变量值是holiday对象
variables.put(“holiday”, holiday);
taskService.complete(taskId, variables);
}
说明:
通过当前任务设置流程变量,需要指定当前任务 id,如果当前执行的任务 id不存在则抛出异常。
任务办理时也是通过 map<key,value>设置流程变量,一次可以设置多个变量。
通过当前流程实例设置
通过流程实例 id 设置全局变量,该流程实例必须未执行完成。
public void
setGlobalVariableByExecutionId(){
//当前流程实例执行 id,通常设置为当前执行的流程实例
String executionId=”2601″;
RuntimeService runtimeService = processEngine.getRuntimeService();
Holiday holiday = new Holiday();
holiday.setNum(3);
//通过流程实例 id设置流程变量
runtimeService.setVariable(executionId, “holiday”, holiday);
//一次设置多个值
//runtimeService.setVariables(executionId, variables)
}
注意:
executionId 必须当前未结束流程实例的执行 id,通常此 id设置流程实例 的 id。
也可以通过 runtimeService.getVariable()获取流程变量
通过当前任务设置
<<SaaS-IHRM项目-Activiti7讲义(进阶部分).pdf>>