当前位置:网站首页>【activiti】流程变量
【activiti】流程变量
2022-07-24 05:19:00 【你怎么不笑了】
activiti流程变量
1. 什么是流程变量
流程变量在activiti中是一个非常重要的角色,流程运转有时就需要流程变量,流程变量就是activiti在管理工作流时根据管理需要而设置的变量。
前面我们用到的使用${assignee0}的方式分配负责人,就是流程变量
也可以设置别的流程变量,比如:出差申请流程如果出差天数大于3天由总经理审核,否则由财务审核,这里出差天数就可以设置一个流程变量进行管理。
注意:虽然流程变量中可以存储业务数据,通过activiti查询流程变量实现查询业务数据,但是不建议这么操作,因为业务数据是由业务系统提供的,activiti工作流流程变量只是负责流程执行而创建的。太多的业务数据当做流程变量容易造成数据紊乱。
2. 流程变量类型
如果是pojo对象存储到流程变量中,必须实现序列化接口Serializable,为防止由于新增字段无法发序列化,需要生成serialVersionUID

3. 流程变量的作用域
流程变量的作用域可以是一个流程实例(ProcessInstance),也可以是一个任务(Task)或者是一个执行实例(execution)
3.1 global变量
流程变量的默认作用域是流程实例。当一个流程变量的作用域为流程实例时,可以称为global变量。
注意:global变量中变量名不允许重复,设置相同的变量名,后设置的值会覆盖之前设置的值。
3.2 local变量
任务和执行实例仅仅针对一个任务和一个执行实例范围,范围没有流程实例大,称为local变量。
local变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同不会互相影响。local也可以和global变量名相同。
4. 流程变量的使用方法
4.1 在属性上使用UEL表达式
可以在向assignee这样的属性上使用UEL表达式,该表达式的值为任务的负责人,比如:${assignee},assignee就是一个流程变量名称。
activiti获取UEL表达式的值,即流程变量assignee的值,将该值作为任务负责人进行任务分配。
4.2 在连线上使用UEL表达式
可以在连线上使用UEL表达式,决定流程的走向。
比如:${price < 100},price就是一个流程变量的值,uel表达式的结果为布尔值,根据uel表达式的值true,来确定流程的走向。
5. 设置global流程变量
不同的工具设计流程不太一样,请自己选择,本文使用的是Camunda Modeler
5.1 需求
员工创建出差申请单,由部门经理审核,部门经理审核通过后出差3天及以下由财务直接审批,出差3天以上由总经理审批,总经理审批后再由财务审批。

5.2 流程定义
**1)出差天数大于3连线条件 **
选中连线,然后设计流程变量条件${num>3},当然也可以设计成${evection.num>3},evection是一个对象且该对象必须要进行序列化。

注意这里的连线是:Conditional Flow,切换成这个连线再设计流程变量

2)出差天数小于等于3连线条件
选中连线,然后设计流程变量条件${num<=3},同样也可以设计成${evection.num<=3},evection是一个对象且该对象必须要进行序列化。

5.3 设计global流程变量
在部门经理审核前设计流程变量,变量值为出差天数,部门经理审核后可以根据流程变量的值来决定流程的走向。
在设计流程变量时,可以在启动的时候设置,也可以在任务办理时设置。
5.4 启动流程时设置流程变量
测试为了方便数据查询,删除数据库,重新部署新的流程。
在启动流程时设置流程变量,变量的作用域是整个流程实例,具体操作是,通过Map设置键值对的方式去设置流程变量,key是流程变量的名称,value是流程变量的值。
注意:这里有个问题,使用Camunda Modeler工具设计的流程配置的负责人assignee变量值,在代码中通过map传入不生效,是由于assignee 的前缀为camunda,activity解析不到该标签。

解决办法:将camunda 替换为 activiti,命名空间改为activity的命名空间
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" targetNamespace="http://www.activiti.org/processdef" exporter="Camunda Modeler" exporterVersion="3.0.0">

/** * 启动流程实例 */
@Test
public void startProcess() {
//获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//流程定义key
String key = "evection-variable";
//定义流程变量map
Map<String, Object> map = new HashMap<>();
//设置出差天数,key值就是我们在流程图设计时添加的流程变量名称
//这里设置出差天数为3,按流程设计,经理审批完是由财务直接审核
map.put("num", 3);
//设置负责人流程变量的值
map.put("assignee0", "张三");
map.put("assignee1", "李经理");
map.put("assignee2", "王总经理");
map.put("assignee3", "赵财务");
//启动流程实例,将流程变量通过map传入
//该流程变量的作用域是一个流程实例
ProcessInstance instance = runtimeService.startProcessInstanceByKey(key, map);
//输出
System.out.println("流程定义id:" + instance.getProcessDefinitionId());
System.out.println("流程实例名称:" + instance.getName());
System.out.println("流程实例id:" + instance.getProcessInstanceId());
}
流程实例启动完成后,进行完成个人任务
/** * 完成个人任务 */
@Test
public void completePersonalTask() {
//流程定义key
String key = "evection-variable";
//任务负责人:先完成张三,再完成李经理的,然后根据配置的出差天数流程变量,最后应该是直接有财务直接审批
//String assignee = "张三";
String assignee = "李经理";
//获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取TaskService
TaskService taskService = processEngine.getTaskService();
//根据流程定义key和任务负责人查询任务
Task task = taskService.createTaskQuery()
//查询可能有多个,这里测试只有一条数据可以这么直接查询,建议实际业务根据别的条件进行查询
.processDefinitionKey(key)
.taskAssignee(assignee)
.singleResult();
if (task != null) {
taskService.complete(task.getId());
System.out.println("任务已完成");
}
}
任务由李经理执行完成后,根据配置条件,出差天数3天,应该直接有财务直接进行审核,查看act_run_task任务表:

5.5 完成任务时设置流程变量
在完成任务时设置流程变量,该流程变量只有在该任务完成后其他节点才可以使用该变量,作用域是整个流程实例。如果设置的流程变量key在流程实例中已存在,则后设置的会替换之前已设置的流程变量。
这里在完成创建出差申请单任务时设置流程变量,即完成张三的任务
为了演示,删库之后重新部署测试,注意部署完后启动实例,不用给num变量设置值了
启动流程实例后,查询act_ru_variable表只有四个流程变量

/** * 任务办理时设置流程变量 * 这里测试出差天数num流程变量,所以在启动流程实例的时候不用设置num,只设置任务负责人即可 */
@Test
public void completeTask() {
//流程定义key
String key = "evection-variable";
//任务id
String taskId = "7501";
//任务负责人
String assignee = "张三";
//获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取TaskService
TaskService taskService = processEngine.getTaskService();
// 创建变量集合
Map<String, Object> map = new HashMap<>();
/** * 可以使用对象的方式设置 * Evection evection = new Evection(); * evection.setNum(2d); * map.put("evection",evection); */
map.put("num", 3);
//查询任务
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskId(taskId)
.taskAssignee(assignee)
.singleResult();
if (task != null) {
//完成任务并设置流程变量
taskService.complete(task.getId(), map);
System.out.println(task.getId() + "任务已完成");
}
}
执行上面的代码完成个人任务,并给出差天数num流程变量设置值。
查询act_ru_variable表可以看到出差天数流程变量值正常设置

根据流程图或者act_ru_task表的数据可以看到当前任务由李经理审核完成,用之前完成个人任务的代码执行流程任务
/** * 完成个人任务 */
@Test
public void completePersonalTask() {
//流程定义key
String key = "evection-variable";
//任务负责人:先完成张三,再完成李经理的,然后根据配置的出差天数流程变量,最后应该是直接有财务直接审批
//String assignee = "张三";
String assignee = "李经理";
//获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取TaskService
TaskService taskService = processEngine.getTaskService();
//根据流程定义key和任务负责人查询任务
Task task = taskService.createTaskQuery()
//查询可能有多个,这里测试只有一条数据可以这么直接查询,建议实际业务根据别的条件进行查询
.processDefinitionKey(key)
.taskAssignee(assignee)
.singleResult();
if (task != null) {
taskService.complete(task.getId());
System.out.println("任务已完成");
}
}
任务完成后刷新act_ru_task表可以看到流程走到财务了,因为num=3直接由财务审核

5.6 通过当前执行流程实例设置流程变量
通过流程实例执行id设置流程变量,该流程实例必须未执行完成。
/** * 通过当前执行的流程实例执行id设置变量 * 这里测试出差天数num流程变量,所以在启动流程实例的时候不用设置num,只设置任务负责人即可 */
@Test
public void setGlobalVariableByExecutionId() {
//获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//当前流程实例执行id,通常为当前执行的流程实例
String executionId = "";
//获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// 创建变量集合
Map<String, Object> map = new HashMap<>();
/** * 可以使用对象的方式设置 * Evection evection = new Evection(); * evection.setNum(2d); * runtimeService.setVariable(executionId, "evection", evection); */
map.put("num", 3);
runtimeService.setVariables(executionId, map);
/** * 可以通过getVariables获取到已设置的流程变量 */
Map<String, Object> variables = runtimeService.getVariables(executionId);
variables.forEach((k,v) -> {
System.out.println(k +" "+ v);
});
}
为了方便测试数据查看,清空数据库,重新部署,然后启动流程实例,在act_ru_task表拿到EXECUTION_ID的值,该值就是当前流程实例执行ID

执行完成后,再去查看act_ru_variable表可查询到流程变量num的数据。
注意:EXECUTION_ID必须是当前未结束的流程实例的执行id
5.7 通过当前任务设置流程变量
任务id必须是当前待办任务id,在act_ru_task表中存在,如果任务结束,则会报错。
/** * 通过当前任务设置流程变量 * 这里测试出差天数num流程变量,所以在启动流程实例的时候不用设置num,只设置任务负责人即可 */
@Test
public void setGlobalVariableByTask() {
//获取流程引起
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//当前任务id
String taskId = "2509";
//获取TaskService
TaskService taskService = processEngine.getTaskService();
//设置流程变量
Map<String, Object> map = new HashMap<>();
map.put("num", 5);
taskService.setVariables(taskId, map);
Map<String, Object> variables = taskService.getVariables(taskId);
variables.forEach((k, v) -> {
System.out.println(k + ":" + v);
});
}
可以直接通过上面的数据进行测试,不用重新部署创建流程实例了。执行完成后,会发现变量表的num值更新成了5。
5.8 数据库表说明
设置流程变量会在当前执行流程变量表插入记录,同时也会在历史流程变量表也插入记录。
//当前流程变量表
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变量
字段意义参考当前流程变量表。
6. 设置local流程变量
6.1 任务办理时设置
任务办理时设置local流程变量,当前运行的流程实例只能在该任务结束前使用,任务结束后无法在当前流程实例使用,可以通过历史任务查询。
/** * 处理任务时设置local流程变量 */
@Test
public void setLocalVariableByComplete() {
//任务id
String taskId = "7503";
//获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取TaskService
TaskService taskService = processEngine.getTaskService();
//定义local流程变量
Map<String, Object> map = new HashMap<>();
map.put("num", 10);
taskService.setVariablesLocal(taskId, map);
taskService.complete(taskId);
}
6.2 通过当前任务设置
/** * 处理任务时设置local流程变量 */
@Test
public void setLocalVariableByComplete() {
//任务id
String taskId = "7503";
//获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取TaskService
TaskService taskService = processEngine.getTaskService();
//定义local流程变量
Map<String, Object> map = new HashMap<>();
map.put("num", 10);
taskService.setVariablesLocal(taskId, map);
//taskService.complete(taskId);
}
任务id必须是当前待办任务,act_ru_task表中存在
Local变量在任务结束后无法在当前流程实例执行中使用,如果后续的流程执行需要用到此变量则会报错。
6.3 查询历史local流程变量
/** * 查询历史local变量 */
@Test
public void queryHistoricLocalVariable() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//查询local流程变量
HistoryService historyService = processEngine.getHistoryService();
List<HistoricTaskInstance> list = historyService
.createHistoricTaskInstanceQuery()
.includeTaskLocalVariables()
.list();
for (HistoricTaskInstance taskInstance : list) {
System.out.println("任务id:" + taskInstance.getId());
System.out.println("任务local变量:" + taskInstance.getTaskLocalVariables());
}
}
注意:查询历史流程变量,特别是查询pojo变量需要经过反序列化,不推荐使用。
边栏推荐
- spark 广播变量和累加器使用和原理
- Open Web3, once unpopular decentralized identity (did)
- Polkadot | 一文解读颠覆传统社媒的Liberty计划如何在波卡落地
- Analysis of logic development principle of quantitative contract clip arbitrage robot system
- Canvas - round
- jsp标签
- How can the multiple-choice and single choice results of PHP be displayed in the foreground?
- Function Closure
- 达梦数据库_支持的表类型,用法,特性
- Flink state使用
猜你喜欢
随机推荐
【虚拟化】如何将虚拟机从workstation转换到esxi
关于DAO流动性双币质押挖矿开发原理分析
仿某网站百度地图页面 百度API
Flink state使用
ODS、数据集市、数据仓库的异同点
LP双币流动性质押挖矿系统逻辑开发分析
【奖励发放】OneOS专区首届征文活动评奖结果公布
Canvas - round
Web3 Foundation grant program empowers developers to review four successful projects
Hex to RGB
Vulnhub solidstate: 1 target penetration test
Review the whole process of the 5th Polkadot Hackathon entrepreneurship competition, and uncover the secrets of the winning projects!
Why is music NFT popular? Polkadot may become the best choice for developing music NFT
Collection = = academic waste
利用流媒体将RSTP流转成WEB端播放(二)[可回看]
波卡创始人 Gavin Wood:波卡治理 v2 会有哪些变化?
The repetition detection function of PHP multi line text content and count the number of repetitions
spark 广播变量和累加器使用和原理
达梦数据库_常用命令
波卡生态发展不设限的奥义——多维解读平行链









