三、流程变量
3.1、什么是流程变量
流程变量在
activiti
中是一个非常重要的角色,流程运转有时需要靠流程变量,业务系统和
activiti
结合时少不了流程变量,流程变量就是 activiti
在管理工作流时根据管理需要而设置的变量。 比如:在出差申请流程流转时如果出差天数大于 3
天则由总经理审核,否则由人事直接审核, 出差天数就可以设置为流程变量,在流程流转时使用。
注意:虽然流程变量中可以存储业务数据可以通过
activiti
的
api
查询流程变量从而实现查询业务数据,但是不建议这
样使用,因为业务数据查询由业务系统负责,
activiti
设置流程变量是为了流程执行需要而创建。
3.2、流程变量类型
如果将
pojo
存储到流程变量中,必须实现序列化接口
serializable
,为了防止由于新增字段无法反序列化,需要生成serialVersionUID。
3.3、流程变量作用域
流程变量的作用域可以是一个流程实例
(processInstance)
,或一个任务
(task)
,或一个执行实例
(execution)
3.3.1、globa变量
流程变量的默认作用域是流程实例。当一个流程变量的作用域为流程实例时,可以称为
global
变量
注意:
如:Global变量:
userId
(变量名)、
zhangsan
(变量值)
global
变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值。
3.3.2、local变量
任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大, 称为
local
变量。
Local
变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。
Local
变量名也可以和 global
变量名相同,没有影响。
3.4、流程变量的使用方法
3.4.1、在属性上使用UEL表达式
可以在
assignee
处设置
UEL
表达式,表达式的值为任务的负责人,比如:
${assignee}
,
assignee
就是一个流程变量名称。
Activiti
获取
UEL
表达式的值,即流程变量
assignee
的值 ,将
assignee
的值作为任务的负责人进行任务分配
3.4.2、在连线上使用UEL表达式
可以在连线上设置
UEL
表达式,决定流程走向。
比如:
${price<10000}
。
price
就是一个流程变量名称,
uel
表达式结果类型为布尔类型。
如果
UEL
表达式是
true
,要决定 流程执行走向。
3.5、使用Global变量控制流程
3.5.1、需求
员工创建出差申请单,由部门经理审核,部门经理审核通过后出差
3
天及以下由人财务直接审批,
3
天以上先由总经理
审核,总经理审核通过再由财务审批。
3.5.2
、流程定义
1
)、出差天数大于等于
3
连线条件
也可以使用对象参数命名,如evection.num:
2)、出差天数小于3连线条件
也可以使用对象参数命名,如:
3.5.3、设置global流程变量
在部门经理审核前设置流程变量,变量值为出差单信息(包括出差天数),部门经理审核后可以根据流程变量的值决定流程走向。
在设置流程变量时,可以在启动流程时设置,也可以在任务办理时设置
3.5.3.1
、创建
POJO
对象
创建出差申请
pojo
对象
package com.activiti.demo.pojo;
import java.io.Serializable;
import java.util.Date;
/**
* 出差申请中的流程变量对象
*/
public class Evection implements Serializable {
/**
* 主键Id
*/
private Long id;
/**
* 出差单的名字
*/
private String evectionName;
/**
* 出差天数
*/
private Double num;
/**
* 开始时间
*/
private Date beginDate;
/**
* 出差结束时间
*/
private Date endDate;
/**
* 目的地
*/
private String destination;
/**
* 出差原因
*/
private String reson;
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;
}
public String getReson() {
return reson;
}
public void setReson(String reson) {
this.reson = reson;
}
}
3.5.3.2
、启动流程时设置变量
在启动流程时设置流程变量,变量的作用域是整个流程实例。
通过
Map<key,value>
设置流程变量,
map
中可以设置多个变量,这个
key
就是流程变量的名字。
/**
* 启动流程 的时候设置流程变量
* 设置流程变量num
* 设置任务负责人
*/
@Test
public void testStartProcess(){
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// 流程定义的Key
String key = "myEvection2";
// 流程变量的map
Map<String,Object> variables = new HashMap<>();
// 设置流程变量
Evection evection = new Evection();
// 设置出差日期
evection.setNum(2d);
// 把流程变量的pojo放入map
variables.put("evection",evection);
// 设定任务的负责人
variables.put("assignee0","李四");
variables.put("assignee1","王经理");
variables.put("assignee2","杨总经理");
variables.put("assignee3","张财务");
// 启动流程
runtimeService.startProcessInstanceByKey(key,variables);
}
/**
* 完成个人任务
*/
@Test
public void completTask(){
// 流程定义的Key
String key = "myEvection2";
// 任务负责人
// String assingee = "李四";
String assingee = "张财务";
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskservice
TaskService taskService = processEngine.getTaskService();
// 查询任务
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee(assingee)
.singleResult();
if(task != null){
// 根据任务id来 完成任务
taskService.complete(task.getId());
}
}
说明:
startProcessInstanceByKey(processDefinitionKey, variables)
流程变量作用域是一个流程实例,流程变量使用
Map
存储,同一个流程实例设置变量
map
中
key
相同,后者覆盖前者。
3.5.3.2
、任务办理时设置变量
在完成任务时设置流程变量,该流程变量只有在该任务完成后其它结点才可使用该变量,它的作用域是整个流程实例,如果设置的流程变量的key
在流程实例中已存在相同的名字则后设置的变量替换前边设置的变量。
这里需要在创建出差单任务完成时设置流程变量
/**
* 完成个人任务
*/
@Test
public void completTask(){
// 流程定义的Key
String key = "myEvection2";
// 任务负责人
// String assingee = "李四3";
String assingee = "王经理3";
// String assingee = "杨总经理1";
// String assingee = "张财务1";
// 设置流程变量
Evection evection = new Evection();
// 设置出差时间
evection.setNum(2d);
Map<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(assingee)
.singleResult();
if(task != null){
// 根据任务id 完成任务,并传递流程变量
taskService.complete(task.getId(),map);
System.out.println(task.getId()+"----任务已完成");
}
}
说明:
通过当前任务设置流程变量,需要指定当前任务
id
,如果当前执行的任务
id
不存在则抛出异常。
任务办理时也是通过
map<key,value>
设置流程变量,一次可以设置多个变量。
3.5.3.3
、通过当前流程实例设置
通过流程实例
id
设置全局变量,该流程实例必须未执行完成。
注意:
executionId
必须当前未结束 流程实例的执行
id
,通常此
id
设置流程实例 的
id
。也可以通
runtimeService.getVariable()
获取流程变量。
3.5.3.4
、通过当前任务设置
注意:
任务
id
必须是当前待办任务
id
,
act_ru_task
中存在。如果该任务已结束,会报错
也可以通过
taskService.getVariable()
获取流程变量。
3.5.4、测试
正常测试:
设置流程变量的值大于等于
3
天
设计流程变量的值小于
3
天
异常测试:
流程变量不存在
流程变量的值为空
NULL
,
price
属性为空
UEL
表达式都不符合条件
不设置连线的条件
3.5.5、注意事项
1
、 如果
UEL
表达式中流程变量名不存在则报错。
2
、 如果
UEL
表达式中流程变量值为空
NULL
,流程不按
UEL
表达式去执行,而流程结束 。
3
、 如果
UEL
表达式都不符合条件,流程结束
4
、 如果连线不设置条件,会走
flow
序号小的那条线
3.5.6、操作数据库表
设置流程变量会在当前执行流程变量表插入记录,同时也会在历史流程变量表也插入记录。
//当前流程变量表
SELECT * FROM act_ru_variable
记录当前运行流程实例可使用的流程变量,包括
global
和
local
变量
Id_
:主键
Type_
:变量类型
Name_
:变量名称
Execution_id_
:所属流程实例执行
id
,
global
和
local
变量都存储
Proc_inst_id_
:所属流程实例
id
,
global
和
local
变量都存储
Task_id_
:所属任务
id
,
local
变量存储
Bytearray_
:
serializable
类型变量存储对应
act_ge_bytearray
表的
id
Double_
:
double
类型变量值
Long_
:
long
类型变量值
Text_
:
text
类型变量值
#历史流程变量表
SELECT * FROM act_hi_varinst
记录所有已创建的流程变量,包括
global
和
local
变量
字段意义参考当前流程变量表。
3.6、设置local流程变量
3.6.1、任务办理时设置
任务办理时设置
local
流程变量,当前运行的流程实例只能在该任务结束前使用,任务结束该变量无法在当前流程实例使用,可以通过查询历史任务查询。
说明:
设置作用域为任务的
local
变量,每个任务可以设置同名的变量,互不影响。
3.6.2、通过当前任务设置
注意:
任务
id
必须是当前待办任务
id
,
act_ru_task
中存在。
3.6.3、 Local变量测试1
如果上边例子中设置
global
变量改为设置
local
变量是否可行?为什么?
Local
变量在任务结束后无法在当前流程实例执行中使用,如果后续的流程执行需要用到此变量则会报错。
3.6.4、 Local变量测试2
在部门经理审核、总经理审核、财务审核时设置
local
变量,可通过
historyService
查询每个历史任务时将流程变量的值也查询出来。
代码如下:
注意:查询历史流程变量,特别是查询pojo变量需要经过反序列化,不推荐使用。