之前的文章中,宋大哥也和小伙伴们一起使用过流程变量,但是并没有系统的梳理流程变量的具体玩法以及其对应的数据表的细节。今天我们就来看看Flowable中流程变量的详细玩法。1.为什么需要流程变量首先我们来看一下为什么需要流程变量。举个简单的例子,假设我们有如下流程:这是一个请假的流程,所以请假的人,多少天,开始时间,请假原因等等,都需要说明,不然领导认可的依据是什么?那么如何传递这些数据,我们就需要流程变量。2、流程变量的分类总体上,当前流程变量可以分为三种:全局流程变量:该流程变量在整个流程执行过程中有效。本地流程变量:这仅对流程中的特定任务有效。任务执行后,流程变量失效。临时过程变量:顾名思义,它是临时的,这个不会存入数据库。在接下来的内容中,我将一一介绍这些流程变量的用法。3、全局流程变量假设我们是上面的离开流程,我们来看看流程变量的设置和获取。3.1启动时设置第一个方法,即我们可以在进程启动时设置进程变量,如下:@Testvoidtest01(){Mapvariables=newHashMap<>();variables.put("天数",10);variables.put("原因","休息一下");variables.put("开始时间",newDate());ProcessInstancepi=runtimeService.startProcessInstanceByKey("demo01",变量);记录器。info("id:{},activityId:{}",pi.getId(),pi.getActivityId());}我们可以在启动的时候给进程设置变量。朋友注意到,流程变量的值也可以是一个对象(但是这个对象必须是可以序列化的,也就是实现了Serializable接口),然后在启动的时候传入这个变量。我们在进程启动日志中搜索四个词,可以找到与进程变量相关的SQL。一共有两个,分别是:insertintoACT_HI_VARINST(ID_,PROC_INST_ID_,EXECUTION_ID_,TASK_ID_,NAME_,REV_,VAR_TYPE_,SCOPE_ID_,SUB_SCOPE_ID_,SCOPE_TYPE_,BYTEARRAY_ID_,DOUBLE_,LONG_,TEXT_,TEXT2_,CREATE_UPDATED_,LAST)values_(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?),(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?),(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)插入ACT_RU_VARIABLE(ID_,REV_,TYPE_,NAME_,PROC_INST_ID_,EXECUTION_ID_,TASK_ID_,SCOPE_ID_,SUB_SCOPE_ID_,SCOPE_TYPE_,BYTEARRAY_ID_,DOUBLE_,LONG_,TEXT_,TEXT2_),?,VALUES1,(?,?,?,?,?,?,?,?,?,?,?,),(?,1,?,?,?,?,?,?,?,?,?,?,?,?,?),(?,1,?,?,?,?,?,?,?,?,?,?,?,?,?)从标签名可以看出ACT_HI_VARINST存放的是历史信息进程执行的信息,ACT_RU_VARIABLE存储进程运行时的信息。我们打开ACT_RU_VARIABLE表看一下:从表中可以看出,每个流程变量都有对应的流程实例ID,也就是说这些流程变量属于某个流程实例,所以我们可以查询如下流程变量:@Testvoidtest01(){Listlist=runtimeService.createExecutionQuery().list();for(Executionexecution:list){Objectreason=runtimeService.getVariable(execution.getId(),"reason");logger.info("原因:{}",原因);}}对应的查询SQL如下:==>Preparing:select*fromACT_RU_VARIABLEWHEREEXECUTION_ID_=?ANDTASK_ID_isnullANDNAME_=?:==>Parameters:6fdd2007-4c3a-11ed-aa7e-a??cde48001122(String),reason(String):<==Total:1如你所见,这是查询ACT_RU_VARIABLE表,查询条件包括变量名。当然我们也可以直接查询一个进程的所有变量,如下:@Testvoidtest02(){Listlist=runtimeService.createExecutionQuery().list();for(Executionexecution:list){Mapvariables=runtimeService.getVariables(execution.getId());logger.info("变量:{}",变量);}}对应的查询SQL如下:==>Preparing:select*fromACT_RU_VARIABLEWHEREEXECUTION_ID_=?ANDTASK_ID_isnull:==>Parameters:6fdd2007-4c3a-11ed-aa7e-a??cde48001122(String):<==Total:3如您所见,这与上面的类似,只是缺少条件NAME_。3.2通过Task设置,我们还可以在流程启动成功后设置流程变量。步骤如下:首先启动一个进程:@Testvoidtest01(){ProcessInstancepi=runtimeService.startProcessInstanceByKey("demo01");logger.info("id:{},activityId:{}",pi.getId(),pi.getActivityId());}然后设置流程变量:@Testvoidtest03(){tasktask=taskService.createTaskQuery().singleResult();taskService.setVariable(task.getId(),"days",10);Map变量=newHashMap<>();variables.put("原因","休息一下");variables.put("开始时间",newDate());taskService.setVariables(task.getId(),variables);}查询某个Task,然后设置流程变量。上面的代码和朋友们演示了两种设置方法:一一设置直接设置一个Map来设置流程变量的方法,本质上就是往ACT_HI_VARINST和ACT_RU_VARIABLE表中插入数据。具体的SQL和前面一样,就不贴了。3.3任务完成时设置也可以在任务完成时设置流程变量,如下:@Testvoidtest04(){Tasktask=taskService.createTaskQuery().singleResult();Map变量=newHashMap<>();variables.put("原因","休息一下");variables.put("开始时间",newDate());variables.put("天",10);taskService.complete(task.getId(),variables);}底层涉及的SQL同上,不再赘述。3.4通过流程设置由于是全局流程变量,我们也可以通过RuntimeService来设置,如下:@Testvoidtest05(){Executionexecution=runtimeService.createExecutionQuery().singleResult();runtimeService.setVariable(execution.getId(),"days",10);Map变量=newHashMap<>();variables.put("原因","休息一下");variables.put("开始时间",newDate());runtimeService.setVariables(execution.getId(),variables);}嗯,一共有四个方法。4.局部流程变量在第三节中,我们提到的全局流程变量是绑定到一个特定的流程,而局部流程变量则不同。本地流程变量绑定到某个任务。4.1Task设置假设我们启动流程后,我们通过Task设置一个本地流程变量如下:@Testvoidtest03(){Tasktask=taskService.createTaskQuery().singleResult();taskService.setVariableLocal(task.getId(),"days",10);Map变量=newHashMap<>();variables.put("原因","休息一下");variables.put("开始时间",newDate());taskService.setVariables(task.getId(),variables);}在上面的代码中,我设置了一个局部变量和两个全局变量。设置好后,我们去ACT_RU_VARIABLE表查看具体效果。如您所见,由于days是局部变量,因此它的TASK_ID_具有值。这很容易理解,说明可变天数与这个特定的任务有关。如果此时我们完成这个Task,代码如下:@Testvoidtest06(){Tasktask=taskService.createTaskQuery().singleResult();taskService.complete(task.getId());}完成后,再次查看ACT_RU_VARIABLE表,如下:我们发现局部变量days没有了。因为前面的Task已经执行完了,如果这时候你还用第三节介绍的方式查询变量,就找不到days了。这时候如果需要查询前几天的变量,就得去历史表中查询,如下:@Testvoidtest07(){ProcessInstancepi=runtimeService.createProcessInstanceQuery().singleResult();Listlist=historyService.createHistoricVariableInstanceQuery().processInstanceId(pi.getId()).list();对于(HistoricVariableInstancehvi:列表){logger.info(“名称:{},类型:{},值:{}”,hvi.getVariableName(),hvi.getVariableTypeName(),hvi.getValue());}}这是进程局部变量的特点。当然还有几个相关的方法,这里列出来供大家参考:org.flowable.engine.TaskService#complete(java.lang.String,java.util.Map,boolean):在完成一个Task的时候,如果传入一个变量,可以通过第三个参数来控制这个变量是全局的还是局部的,true表示这个变量是局部的。org.flowable.engine.RuntimeService#setVariableLocal:为执行实例设置局部变量。org.flowable.engine.RuntimeService#setVariablesLocal:同上,批量设置。好吧,这就是局部过程变量。5.临时过程变量临时过程变量不存储在数据库中。一般来说,我们可以在启动一个流程或完成一个任务时使用它们。用法如下:@Testvoidtest21(){Mapvariables=newHashMap<>();variables.put("原因","休息一下");variables.put("开始时间",newDate());ProcessInstancepi=runtimeService.createProcessInstanceBuilder().transientVariable("days",10).transientVariables(变量).processDefinitionKey("demo01").start();logger.info("id:{},activityId:{}",pi.getId(),pi.getActivityId());}上面代码涉及到获取到的流程变量是临时流程变量,不会存入数据库。也可以在完成任务时设置临时变量,如下:@Testvoidtest22(){Tasktask=taskService.createTaskQuery().singleResult();MaptransientVariables=newHashMap<>();瞬态变量。把(“天”,10);taskService.complete(task.getId(),null,transientVariables);}这个临时变量也不会存入数据库。