Activit 流程变量
Activit 流程变量
流程变量在 activiti 中是一个非常重要的角色,流程运转有时需要靠流程变量,业务系统和 activiti 结合时少不了流程变量
流程变量就是 activiti 在管理工作流时根据管理需要而设置的变量,比如:在出差申请流程流转时如果出差天数大于 3 天则由总经理审核,否则由人事直接审核, 出差天数就可以设置为流程变量,在流程流转时使用
动态分配任务负责人时,负责人变量就是流程变量
虽然流程变量中可以存储业务数据可以通过 activiti 的 api 查询流程变量从而实现查询业务数据,但是不建议这样使用,因为业务数据查询由业务系统负责,activiti设置流程变量是为了流程执行需要而创建
流程变量作用域
流程变量的作用域可以是一个流程实例(processInstance),或一个任务(task),或一个执行实例(execution)
流程实例是 global 变量,变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值
任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大, 称为 local 变量
local 变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响;Local 变量名也可以和 global 变量名相同,没有影响
流程变量的使用
-
在用户任务属性上使用,比如:通过 uel 表达式设置用户任务 Assignee 为 $
-
在连线属性上使用,比如:通过 uel 表达式设置连线的 Condition 为 $
代码实战
需求:员工创建出差申请单,由部门经理审核,部门经理审核通过后出差3天以下由人财务直接审批,3天及以上先由总经理审核,总经理审核通过再由财务审批
创建流程定义 evection-variable.bpmn20.xml,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" 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" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
<process id="evection-variable" name="evection-variable" isExecutable="true">
<startEvent id="sid-e9b611c5-f349-47c0-8e64-fce81ebcaef9" name="出差申请流程开始"/>
<userTask id="sid-a0892ee6-958b-4587-88f5-22ae84518d08" name="经理审批" activiti:assignee="${assignee1}"/>
<userTask id="sid-a0568e26-9f86-4bca-8884-34c9bf719478" name="申请出差" activiti:assignee="${assignee0}"/>
<userTask id="sid-ffbf825b-a0ec-4e99-b845-f056c40a5d3c" name="总经理审批" activiti:assignee="${assignee2}"/>
<endEvent id="sid-689662c6-57b7-4aeb-b45e-ab7e7b489bca" name="出差申请流程结束"/>
<sequenceFlow id="sid-02bcbc4c-4564-4e81-8cc2-75ababbdb550" sourceRef="sid-e9b611c5-f349-47c0-8e64-fce81ebcaef9" targetRef="sid-a0568e26-9f86-4bca-8884-34c9bf719478"/>
<sequenceFlow id="sid-a86c082f-5c19-4856-9546-153c26e28f8f" sourceRef="sid-a0568e26-9f86-4bca-8884-34c9bf719478" targetRef="sid-a0892ee6-958b-4587-88f5-22ae84518d08"/>
<sequenceFlow id="sid-a31d3331-c574-4449-a7e7-8f1d121dcdf5" sourceRef="sid-a0892ee6-958b-4587-88f5-22ae84518d08" targetRef="sid-ffbf825b-a0ec-4e99-b845-f056c40a5d3c">
<conditionExpression>${evection.day>=3}</conditionExpression>
</sequenceFlow>
<userTask id="sid-72e4fc1a-580f-4431-a099-8719b0914864" name="财务审批" activiti:assignee="${assignee3}"/>
<sequenceFlow id="sid-f98b37b3-9a6b-4792-b026-524610b5310c" sourceRef="sid-a0892ee6-958b-4587-88f5-22ae84518d08" targetRef="sid-72e4fc1a-580f-4431-a099-8719b0914864">
<conditionExpression>${evection.day<3}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="sid-c3382648-152a-4f21-99af-fc37b2f8e102" sourceRef="sid-ffbf825b-a0ec-4e99-b845-f056c40a5d3c" targetRef="sid-72e4fc1a-580f-4431-a099-8719b0914864"/>
<sequenceFlow id="sid-fe7c0db2-d94a-46b7-b28d-97fbb0ae1053" sourceRef="sid-72e4fc1a-580f-4431-a099-8719b0914864" targetRef="sid-689662c6-57b7-4aeb-b45e-ab7e7b489bca"/>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_evection-variable">
<bpmndi:BPMNPlane bpmnElement="evection-variable" id="BPMNPlane_evection-variable">
<bpmndi:BPMNShape id="shape-c3d1bdc6-6931-49e1-a012-cf95de2f2af7" bpmnElement="sid-e9b611c5-f349-47c0-8e64-fce81ebcaef9">
<omgdc:Bounds x="-440.0" y="-130.0" width="30.0" height="30.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape-bb326f08-b3d5-4837-bfe4-a26ec9955201" bpmnElement="sid-a0892ee6-958b-4587-88f5-22ae84518d08">
<omgdc:Bounds x="-124.17816" y="-155.0" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape-91190fa9-bd05-4c5f-b03b-bd660239c3cc" bpmnElement="sid-a0568e26-9f86-4bca-8884-34c9bf719478">
<omgdc:Bounds x="-317.0736" y="-155.0" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape-5a72cb0f-352b-406b-8997-5895455020af" bpmnElement="sid-ffbf825b-a0ec-4e99-b845-f056c40a5d3c">
<omgdc:Bounds x="65.0" y="-155.0" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape-d83dbd93-b2b7-4ec0-b048-5db66e26cad1" bpmnElement="sid-689662c6-57b7-4aeb-b45e-ab7e7b489bca">
<omgdc:Bounds x="-271.4048" y="51.5216" width="30.0" height="30.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-694c7c56-6880-4653-8249-4aa295561768" bpmnElement="sid-02bcbc4c-4564-4e81-8cc2-75ababbdb550">
<omgdi:waypoint x="-410.0" y="-115.0"/>
<omgdi:waypoint x="-317.0736" y="-115.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="edge-6bdd6ad6-c3a1-47a2-bd03-0b3be222df79" bpmnElement="sid-a86c082f-5c19-4856-9546-153c26e28f8f">
<omgdi:waypoint x="-217.07361" y="-115.0"/>
<omgdi:waypoint x="-124.17816" y="-115.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="edge-fc682d53-58b9-48c9-9906-16b97635abaf" bpmnElement="sid-a31d3331-c574-4449-a7e7-8f1d121dcdf5">
<omgdi:waypoint x="-24.178162" y="-115.0"/>
<omgdi:waypoint x="65.0" y="-115.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="shape-04890e4b-a95c-4bf9-bfed-0019bb53056d" bpmnElement="sid-72e4fc1a-580f-4431-a099-8719b0914864">
<omgdc:Bounds x="-125.0" y="20.0" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-9e053774-fa8f-4802-b1a1-6f6d79107bc6" bpmnElement="sid-f98b37b3-9a6b-4792-b026-524610b5310c">
<omgdi:waypoint x="-74.17816" y="-75.0"/>
<omgdi:waypoint x="-75.0" y="20.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="edge-9e7a651c-d874-4658-8988-5cc4a786d6f4" bpmnElement="sid-c3382648-152a-4f21-99af-fc37b2f8e102">
<omgdi:waypoint x="115.0" y="-75.00001"/>
<omgdi:waypoint x="115.0" y="60.0"/>
<omgdi:waypoint x="-25.000002" y="60.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="edge-42dca40d-66c1-469e-b2f4-953b5dd41872" bpmnElement="sid-fe7c0db2-d94a-46b7-b28d-97fbb0ae1053">
<omgdi:waypoint x="-125.0" y="60.0"/>
<omgdi:waypoint x="-241.40479" y="59.0216"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
设置连线属性 Condition|Condition expression 为 ${evection.day>=3} 控制出差3天及以上由总经理审批后再由财务审批
设置连线属性 Condition|Condition expression 为 ${evection.day<3} 控制出差3天以下由财务直接审批
流程图如下
创建实体类
package com.yl.entity;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import java.util.Date;
/**
* 出差申请
*
* @author Y-wee
*/
@Getter
@Setter
@ToString
public class Evection implements Serializable {
/**
* 主键id
*/
private Long id;
/**
* 出差申请单名称
*/
private String evectionName;
/**
* 出差天数
*/
private Double day;
/**
* 预计开始时间
*/
private Date beginDate;
/**
* 预计结束时间
*/
private Date endDate;
/**
* 目的地
*/
private String destination;
/**
* 出差事由
*/
private String reson;
}
如果将实体存储到流程变量中,必须实现序列化接口 serializable,为了防止由于新增字段无法反序列化,需要生成 serialVersionUID
将流程定义部署后,在启动流程时设置流程变量
/**
* 启动流程实例,设置流程变量的值
*/
@Test
public void startProcess(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
String key = "evection-variable";
// 存储流程变量,key的值要和流程变量保持一致
Map<String, Object> map = new HashMap<>(1);
Evection evection = new Evection();
evection.setDay(2d);
map.put("evection",evection);
// 任务负责人
map.put("assignee0","张三");
map.put("assignee1","李经理");
map.put("assignee2","王总经理");
map.put("assignee3","赵财务");
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey(key, map);
System.out.println("流程实例名称="+processInstance.getName());
System.out.println("流程定义id=="+processInstance.getProcessDefinitionId());
}
完成任务
/**
* 处理用户任务
*/
@Test
public void complete(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey("evection-variable")
.taskAssignee("李经理")
.singleResult();
if (!ObjectUtils.isEmpty(task)){
// 完成任务
taskService.complete(task.getId());
}
}
任务依次完成,当经理审批任务完成后 act_ru_task 表显示当前运行任务为财务审批;修改出差日期为大于3天,当经理审批任务完成后 act_ru_task 表显示当前运行任务为总经理审批
流程变量的设置方式
流程变量也可以在完成任务时设置
// 完成任务时设置流程变量
taskService.complete(task.getId(),map);
流程变量还可以通过流程实例设置
@Test
public void setGlobalVariableByExecutionId(){
// 当前流程实例执行id
String executionId="2601";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Evection evection = new Evection();
evection.setNum(3d);
// 通过流程实例设置流程变量(参数二:流程变量名,参数三:流程变量值),该方式只能设置单个流程变量值
runtimeService.setVariable(executionId, "evection", evection);
// 一次设置多个值
// runtimeService.setVariables(executionId, map)
}
通过流程实例id设置全局变量,该流程实例必须未执行完成,可以通 runtimeService.getVariable() 获取流程变量
流程变量还可以通过流程任务设置
@Test
public void setGlobalVariableByTaskId(){
// 当前待办任务id
String taskId="1404";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Evection evection = new Evection();
evection.setNum(3);
// 通过任务设置流程变量(参数二:流程变量名,参数三:流程变量值),该方式只能设置单个流程变量值
taskService.setVariable(taskId, "evection", evection);
// 一次设置多个值
//taskService.setVariables(taskId, map)
}
任务 id 必须是当前待办任务 id,act_ru_task 中存在,如果该任务已结束,会报错;可以通过 taskService.getVariable() 获取流程变量
注意事项
- 如果 UEL 表达式中流程变量名不存在则报错
- 如果 UEL 表达式中流程变量值为空(NULL),流程不按 UEL 表达式去执行,而流程结束
- 如果 UEL 表达式都不符合条件,流程结束
- 如果连线不设置条件,会走 flow 序号小的那条线
设置 Local 类型流程变量
处理任务时设置
/**
* 处理任务时设置local流程变量
*/
@Test
public void completTask() {
String taskId = "1404";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
// 存储流程变量
Map<String, Object> variables = new HashMap<String, Object>();
Evection evection = new Evection ();
evection.setNum(3d);
variables.put("evection", evection);
// 设置local变量(作用域为该任务)
taskService.setVariablesLocal(taskId, variables);
taskService.complete(taskId);
}
任务办理时设置 local 流程变量,当前运行的流程实例只能在该任务结束前使用,任务结束该变量无法在当前流程实例使用,可以通过查询历史任务查询
设置作用域为任务的 local 变量,每个任务可以设置同名的变量,互不影响
通过当前任务设置
@Test
public void setLocalVariableByTaskId(){
String taskId="1404";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Evection evection = new Evection ();
evection.setNum(3d);
// 通过任务设置流程变量(参数二:流程变量名,参数三:流程变量值),该方式只能设置单个流程变量值
taskService.setVariableLocal(taskId, "evection", evection);
// 一次设置多个值
//taskService.setVariablesLocal(taskId, map)
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通