流程变量
流程变量在 activiti
中是一个非常重要的角色,流程运转有时需要靠流程变量,业务系统和 activiti
结合时少不了流程变量,流程变量就是 activiti
在管理工作流时根据管理需要而设置的变量。
比如在请假流程流转时如果请假天数大于 3 天则由总经理审核,否则由人事直接审核,请假天数就可以设置为流程变量,在流程流转时使用。
注意:虽然流程变量中可以存储业务数据可以通过 activiti
的 api
查询流程变量从而实现查询业务数据,但是不建议这样使用,因为业务数据查询由业务系统负责,activiti
设置流程变量是为了流程执行需要而创建。
流程变量类型
注意:如果将pojo
存储到流程变量中,必须实现序列化接口 serializable
,为了防止由于新增字段无
法反序列化,需要生成 serialVersionUID
。
流程变量作用域
流程变量的作用域默认是一个流程实例(processInstance
),也可以是一个任务(task
)或一个执行实例(execution
)
- 流程实例的范围最大,可以称为
global 变量
- global 变量中变量名不允许重复
- 设置相同名称的变量,后设置的值会覆盖前设置的变量值。
- 任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大,称为
local 变量
Local 变量
由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。Local 变量名
也可以和global 变量名
相同,没有影响。
流程变量的使用方法
- 第一步:设置流程变量
- 第二步:通过 UEL 表达式使用流程变量
-
可以在
assignee
处设置UEL 表达式
,表达式的值为任务的负责人
比如:${assignee}
,assignee
就是一个流程变量名称
-
可以在连线上设置
UEL 表达式
,决定流程走向
比如:${price>=10000}
和${price<10000}
:price
就是一个流程变量名称,uel
表达式结果类型为布尔类型
如果UEL 表达式
是true
,要决定 流程执行走向
-
使用 Global
变量控制流程
需求:
员工创建请假申请单,由部门经理审核,部门经理审核通过后请假 3 天及以下由人事经理直接审核,3 天以上先由总经理审核,总经理审核通过再由人事经理存档。
流程定义
请假天数大于等于 3 连线条件:
请假天数小于 3 连线条件:
Condition
也可以设置为${holiday.num}
设置 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()
获取流程变量
通过当前任务设置
public void setGlobalVariableByTaskId(){
//当前待办任务id
String taskId="1404";
TaskService taskService = processEngine.getTaskService();
Holiday holiday = new Holiday();
holiday.setNum(3);
//通过任务设置流程变量
taskService.setVariable(taskId, "holiday", holiday);
//一次设置多个值
//taskService.setVariables(taskId, variables)
}
注意:
任务id
必须是当前待办任务id
,act_ru_task
中存在。如果该任务已结束,报错:
也可以通过 taskService.getVariable()
获取流程变量。
测试
正常测试:
- 设置流程变量的值大于等于 3 天
- 设计流程变量的值小于 3 天
异常测试:
- 流程变量不存在
- 流程变量的值为空
NULL
,price
属性为空 UEL
表达式都不符合条件- 不设置连线的条件
注意事项
- 如果
UEL
表达式中流程变量名不存在则报错。 - 如果
UEL
表达式中流程变量值为空NULL
,流程不按UEL
表达式去执行,而流程结束 。 - 如果
UEL
表达式都不符合条件,流程结束 - 如果连线不设置条件,会走
flow
序号小的那条线
操作数据库表
设置流程变量会在当前执行流程变量表插入记录,同时也会在历史流程变量表也插入记录。
当前流程变量表
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
变量
字段意义参考当前流程变量表。
代码
启动时设置流程变量
/**
* com.lxf.activiti.processInstance
* 请假实体类:
* 注意POJO类型,一定要实现Serializable接口,否则在存储这个pojo时就会报异常
* @author lxf
* @version 1.0
* @date 2020/4/27 7:09
*/
public class Holiday implements Serializable {
private Integer id;
private String holidayName;//申请人的名字
private Date beginDate;//开始时间
private Date endDate;//结束日期
private Float num;//请假天数
private String reason;//事由
private String type;//请假类型
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getHolidayName() {
return holidayName;
}
public void setHolidayName(String holidayName) {
this.holidayName = holidayName;
}
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 Float getNum() {
return num;
}
public void setNum(Float num) {
this.num = num;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
测试
/**
* com.lxf.activiti.processInstance
* 流程变量的测试
* @author lxf
* @version 1.0
* @date 2020/4/27 7:10
*/
public class VariableTest {
public static void main(String[] args) {
VariableTest variableTest = new VariableTest();
variableTest.processDeploy();
}
/**
* 1. 新的请假流程定义的部署
*/
public void processDeploy(){
//1.得到ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RepositoryService对象
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.部署
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("diagram/holiday4.bpmn")
.addClasspathResource("diagram/holiday4.png")
.name("请假流程-流程变量")
.deploy();
System.out.println(deploy.getId());
System.out.println(deploy.getName());
}
/**
* 2. 启动流程实例,同时还要设置流程变量的值
* act_ge_bytearray
* act_ru_variable
*/
public void startProcessInstance(){
//1.得到ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3.流程定义的key问题 myProcess_1
String key = "myProcess_1";
Map<String ,Object> map = new HashMap<>();
Holiday holiday = new Holiday();
holiday.setNum(5F);
map.put("holiday",holiday);
//4.启动流程实例,并且设置流程变量的值
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key, map);
//5.输出实例信息
System.out.println(processInstance.getName());
System.out.println(processInstance.getProcessDefinitionId());
//6.通过实例id,来设置流程变量
//第一个参数:流程实例的id
//第二个参数:流程变量名
//第三个变量:流程变量名,所对应的值
// runtimeService.setVariable(processInstance.getId(),"holiday",map);
}
/**
* 完成任务 zhangsan -----lishi----判断流程变量的请假天数,1天----分支:人事经理存档(zhaoliu)
*/
public void complete(){
//1.得到ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到TaskService
TaskService taskService = processEngine.getTaskService();
//3.查询当前用户是否有任务
String key = "myProcess_1";
Task task = taskService.createTaskQuery().processDefinitionKey(key)
.taskAssignee("zhaoliu").singleResult();
//4.判断task!=null,说明当前用户有任务
if(task!=null){
taskService.complete(task.getId());
// 可以设置流程变量的值
// taskService.complete(task.getId(),map);
System.out.println("任务执行完毕");
}
}
}
设置 local
流程变量
任务办理时设置
任务办理时设置local
流程变量,当前运行的流程实例只能在该任务结束前使用,任务结束该变量无法在当前流程实例使用,可以通过查询历史任务查询。
// 办理任务时设置local流程变量
@Test
public void completTask() {
//任务id
String taskId = "";
TaskService taskService = processEngine.getTaskService();
// 定义流程变量
Map<String, Object> variables = new HashMap<String, Object>();
Holiday holiday = new Holiday ();
holiday.setNum(3);
// 定义流程变量
Map<String, Object> variables = new HashMap<String, Object>();
//变量名是holiday,变量值是holiday对象
variables.put("holiday", holiday);
// 设置local变量,作用域为该任务
taskService.setVariablesLocal(tasked, variables);
taskService.complete(taskId);
}
说明:
设置作用域为任务的 local
变量,每个任务可以设置同名的变量,互不影响。
与全局变量的区别为setVariablesLocal
,全局变量为setVariables
通过当前任务设置
@Test
public void setLocalVariableByTaskId(){
//当前待办任务id
String taskId="1404";
TaskService taskService = processEngine.getTaskService();
Holiday holiday = new Holiday ();
holiday.setNum(3);
//通过任务设置流程变量
taskService.setVariableLocal(taskId, "holiday", holiday);
//一次设置多个值
//taskService.setVariablesLocal(taskId, variables)
}
注意:
任务 id
必须是当前待办任务id
,act_ru_task
中存在。
Local
变量测试
Local
变量在任务结束后无法在当前流程实例执行中使用,如果后续的流程执行需要用到此变量则会报错
在部门经理审核、总经理审核、人事经理审核时设置 local
变量,可通过 historyService
查询每个历史任务时将流程变量的值也查询出来。
// 创建历史任务查询对象
HistoricTaskInstanceQuery historicTaskInstanceQuery =
historyService
.createHistoricTaskInstanceQuery();
// 查询结果包括 local变量
historicTaskInstanceQuery.includeTaskLocalVariables();
for (HistoricTaskInstance historicTaskInstance : list) {
System.out.println("==============================");
System.out.println(" 任 务 id : " +
historicTaskInstance.getId());
System.out.println(" 任 务 名 称 : " +
historicTaskInstance.getName());
System.out.println(" 任 务 负 责 人 : " +
historicTaskInstance.getAssignee());
System.out.println(" 任 务 local 变 量 : "+
historicTaskInstance.getTaskLocalVariables());
}
注意:查询历史流程变量,特别是查询 pojo 变量需要经过反序列化,不推荐使用。