1.流程变量
1.1、什么是流程变量
流程变量在 activiti 中是一个非常重要的角色,流程运转有时需要靠流程变量,业务系统和 activiti 结合时少不了流程变量,流程变量就是 activiti 在管理工作流时根据管理需要而设置的变量。 比如:在出差申请流程流转时如果出差天数大于 3 天则由总经理审核,否则由人事直接审核, 出差天 数就可以设置为流程变量,在流程流转时使用。
注意:虽然流程变量中可以存储业务数据可以通过activiti的api查询流程变量从而实现 查询业务数据,但是不建议这样使用,因为业务数据查询由业务系统负责,activiti设置流程变量是为了流程执行需要而创建。
1.2、流程变量类型
如果将 pojo 存储到流程变量中,必须实现序列化接口 serializable,为了防止由于新增字段无 法反序列化,需要生成 serialVersionUID。
1.3、流程变量作用域
流程变量的作用域可以是一个流程实例(processInstance),或一个任务(task),或一个执行实例 (execution)
1.3.1、globa变量
流程变量的默认作用域是流程实例。当一个流程变量的作用域为流程实例时,可以称为 global 变量
注意:
如: Global变量:userId(变量名)、zhangsan(变量值)
global 变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值。
3.3.2、local变量
任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大, 称为 local 变量。
Local 变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。Local 变量名也可以和 global 变量名相同,没有影响。
1.4、流程变量的使用方法
1.4.1、在属性上使用UEL表达式
可以在 assignee 处设置 UEL 表达式,表达式的值为任务的负责人,比如: ${assignee}, assignee 就是一个流程变量名称。
Activiti获取UEL表达式的值,即流程变量assignee的值 ,将assignee的值作为任务的负责人进行任务分配
1.4.2、在连线上使用UEL表达式
可以在连线上设置UEL表达式,决定流程走向。
比如:${price<10000} 。price就是一个流程变量名称,uel表达式结果类型为布尔类型。
如果UEL表达式是true,要决定 流程执行走向。
1.5 流程变量使用
1.5.1 需求
员工创建出差申请单,由部门经理审核,部门经理申请通过后3天以下由财务直接申批,3天以上先由总经理审批,总经理审批通过后再由财务审批。
1.5.2 流程定义
先通过UEL-value来设置负责人
然后在分支线上来设置条件
那么还可以通过对象参数命名,比如 evection.num:
另一根线对应的设置
然后可以将相关的资源文件拷贝到项目中,
15.3 使用Global变量
接下来使用Global变量控制流程
1.5.3.1 POJO创建
首先创建POJO对象
/** * 出差申请的POJO对象 */ @Data public class Evection { private long id; private String evectionName; /** * 出差的天数 */ private double num; private Date beginDate; private Date endDate; private String destination; private String reson; } 复制代码
1.5.3.2 流程的部署
/** * 部署流程 */ @Test public void test01(){ // 1.获取ProcessEngine对象 ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); // 2.获取RepositoryService进行部署操作 RepositoryService service = engine.getRepositoryService(); // 3.使用RepositoryService进行部署操作 Deployment deploy = service.createDeployment() .addClasspathResource("bpmn/evection-variable.bpmn") // 添加bpmn资源 .addClasspathResource("bpmn/evection-variable.png") // 添加png资源 .name("出差申请流程-流程变量") .deploy();// 部署流程 // 4.输出流程部署的信息 System.out.println("流程部署的id:" + deploy.getId()); System.out.println("流程部署的名称:" + deploy.getName()); } 复制代码
1.5.3.3 设置流程变量
a.启动时设置流程变量
在启动流程时设置流程变量,变量的作用域是整个流程实例。
/** * 启动流程实例,设置流程变量 */ @Test public void test02(){ ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = engine.getRuntimeService(); // 流程定义key String key = "evection-variable"; // 创建变量集合 Map<String,Object> variables = new HashMap<>(); // 创建出差对象 POJO Evection evection = new Evection(); // 设置出差天数 evection.setNum(4d); // 定义流程变量到集合中 variables.put("evection",evection); // 设置assignee的取值 variables.put("assignee0","张三1"); variables.put("assignee1","李四1"); variables.put("assignee2","王五1"); variables.put("assignee3","赵财务1"); ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key, variables); // 输出信息 System.out.println("获取流程实例名称:"+processInstance.getName()); System.out.println("流程定义ID:" + processInstance.getProcessDefinitionId()); } 复制代码
完成任务
/** * 完成任务 */ @Test public void test03(){ String key = "evection-variable"; String assignee = "李四1"; ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = engine.getTaskService(); Task task = taskService.createTaskQuery() .processDefinitionKey(key) .taskAssignee(assignee) .singleResult(); if(task != null){ taskService.complete(task.getId()); System.out.println("任务执行完成..."); } } 复制代码
通过startProcessInstanceByKey方法设置流程变量的作用域是一个流程实例,流程变量使用Map存储,同一个流程实例map中的key相同,后者会覆盖前者
b.任务办理时设置
在完成任务时设置流程变量,该流程变量只有在该任务完成后其它结点才可使用该变量,它的作用域是整个流程实例,如果设置的流程变量的key在流程实例中已存在相同的名字则后设置的变量替换前边设置的变量。
这里需要在创建出差单任务完成时设置流程变量
/** * 启动流程实例,设置流程变量 */ @Test public void test02(){ ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = engine.getRuntimeService(); // 流程定义key String key = "evection-variable"; // 创建变量集合 Map<String,Object> variables = new HashMap<>(); // 设置assignee的取值 variables.put("assignee0","张三1"); variables.put("assignee1","李四1"); variables.put("assignee2","王五1"); variables.put("assignee3","赵财务1"); ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key, variables); // 输出信息 System.out.println("获取流程实例名称:"+processInstance.getName()); System.out.println("流程定义ID:" + processInstance.getProcessDefinitionId()); } /** * 完成任务 */ @Test public void test03(){ String key = "evection-variable"; String assignee = "李四1"; ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = engine.getTaskService(); Task task = taskService.createTaskQuery() .processDefinitionKey(key) .taskAssignee(assignee) .singleResult(); Map<String,Object> variables = new HashMap<>(); // 创建出差对象 POJO Evection evection = new Evection(); // 设置出差天数 evection.setNum(4d); // 定义流程变量到集合中 variables.put("evection",evection); if(task != null){ taskService.complete(task.getId(),variables); System.out.println("任务执行完成..."); } } 复制代码
说明:
通过当前任务设置流程变量,需要指定当前任务id,如果当前执行的任务id不存在则抛出异常。
任务办理时也是通过map<key,value>设置流程变量,一次可以设置多个变量。
c.当前流程实例设置
通过流程实例id设置全局变量,该流程实例必须未执行完成。
@Test public void setGlobalVariableByExecutionId(){ // 当前流程实例执行 id,通常设置为当前执行的流程实例 String executionId="2601"; // 获取processEngine ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取RuntimeService RuntimeService runtimeService = processEngine.getRuntimeService(); // 创建出差pojo对象 Evection evection = new Evection(); // 设置天数 evection.setNum(3d); // 通过流程实例 id设置流程变量 runtimeService.setVariable(executionId, "evection", evection); // 一次设置多个值 // runtimeService.setVariables(executionId, variables) } 复制代码
注意:
executionId必须当前未结束 流程实例的执行id,通常此id设置流程实例 的id。也可以通runtimeService.getVariable()获取流程变量。
d.当前任务设置
@Test public void setGlobalVariableByTaskId(){ //当前待办任务id String taskId="1404"; // 获取processEngine ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); Evection evection = new Evection(); evection.setNum(3); //通过任务设置流程变量 taskService.setVariable(taskId, "evection", evection); //一次设置多个值 //taskService.setVariables(taskId, variables) } 复制代码
注意:
任务id必须是当前待办任务id,act_ru_task中存在。如果该任务已结束,会报错
也可以通过taskService.getVariable()获取流程变量。
1.5.4 设置local流程变量
1.5.4.1、任务办理时设置
任务办理时设置local流程变量,当前运行的流程实例只能在该任务结束前使用,任务结束该变量无法在当前流程实例使用,可以通过查询历史任务查询。
/* *处理任务时设置local流程变量 */ @Test public void completTask() { //任务id String taskId = "1404"; // 获取processEngine ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); // 定义流程变量 Map<String, Object> variables = new HashMap<String, Object>(); Evection evection = new Evection (); evection.setNum(3d); // 定义流程变量 Map<String, Object> variables = new HashMap<String, Object>(); // 变量名是holiday,变量值是holiday对象 variables.put("evection", evection); // 设置local变量,作用域为该任务 taskService.setVariablesLocal(taskId, variables); // 完成任务 taskService.complete(taskId); } 复制代码
说明:
设置作用域为任务的local变量,每个任务可以设置同名的变量,互不影响。
1.5.4.2、通过当前任务设置
@Test public void setLocalVariableByTaskId(){ // 当前待办任务id String taskId="1404"; // 获取processEngine ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); Evection evection = new Evection (); evection.setNum(3d); // 通过任务设置流程变量 taskService.setVariableLocal(taskId, "evection", evection); // 一次设置多个值 //taskService.setVariablesLocal(taskId, variables) } 复制代码
注意:
任务id必须是当前待办任务id,act_ru_task中存在。
1.5.4.3、 Local变量测试1
如果上边例子中设置global变量改为设置local变量是否可行?为什么?
Local变量在任务结束后无法在当前流程实例执行中使用,如果后续的流程执行需要用到此变量则会报错。
1.5.4.4、 Local变量测试2
在部门经理审核、总经理审核、财务审核时设置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()); }