引言
用户在发起流程后,如遇到用户任务节点。 即需要用户手动完成审批操作。 这时就会出现一个需求。如何将流程变量存储。 以方便用户在审批时拿到相应数据。
很多人第一想法就是将数据存表。但是该如何考虑将不同的表单(各种不同类型的数据)进行存储呢?
流程变量是什么?
举个例子: 假设我们有一个流程。
这是一个请假流程,那么谁请假、请几天、起始时间、请假理由等等,这些都需要说明,不然领导审批的依据是啥?
那么如何传递这些数据,我们就需要流程变量。
@Test
void test01() {
Map<String, Object> variables = new HashMap<>();
variables.put("days", 10);
variables.put("reason", "休息一下");
variables.put("startTime", new Date());
ProcessInstance pi = runtimeService.startProcessInstanceByKey("demo01", variables);
logger.info("id:{},activityId:{}", pi.getId(), pi.getActivityId());
}
流程变量如何存储
流程实例在挂起后,如何保存持有的流程变量。主要就是act_ru_variable。
select * from act_ru_variable where PROC_INST_ID_ = "03895336-3efe-11ed-9968-c689ce830b50";
流程变量类型
流程实例可以持有变量,称作流程变量(process variables)。
为了使用效率,Flowable将变量分为两种:运行时变量、历史变量。
运行时变量
流程实例运行时的变量,存入act_ru_variable表中。在流程实例运行结束时,此实例的变量在表中删除。
在流程实例创建及启动时,可设置流程变量。所有的startProcessInstanceXXX方法都有一个可选参数用于设置变量。例如,在RuntimeService中:
ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables);
也可以在流程执行中加入变量。例如,(RuntimeService):
void setVariable(String executionId, String variableName, Object value);
void setVariableLocal(String executionId, String variableName, Object value);
void setVariables(String executionId, Map<String, ? extends Object> variables);
void setVariablesLocal(String executionId, Map<String, ? extends Object> variables);
读取变量方法(请注意TaskService中有类似的方法。这意味着任务与执行一样,可以持有局部变量,其生存期为任务持续的时间。)
Map<String, Object> getVariables(String executionId);
Map<String, Object> getVariablesLocal(String executionId);
Map<String, Object> getVariables(String executionId, Collection<String> variableNames);
Map<String, Object> getVariablesLocal(String executionId, Collection<String> variableNames);
Object getVariable(String executionId, String variableName);
<T> T getVariable(String executionId, String variableName, Class<T> variableClass);
注意:由于流程实例结束时,对应在运行时表的数据跟着被删除。所以,查询一个已经完结流程实例的变量,只能在历史变量表中查找。
全局变量
在整个流程执行期间,这个流程变量都是有效的。
@Test
void test01() {
Map<String, Object> variables = new HashMap<>();
variables.put("days", 10);
variables.put("reason", "休息一下");
variables.put("startTime", new Date());
ProcessInstance pi = runtimeService.startProcessInstanceByKey("demo01", variables);
logger.info("id:{},activityId:{}", pi.getId(), pi.getActivityId());
}
我们可以在启动的时候为流程设置变量,小伙伴们注意到,流程变量的 value 也可以是一个对象
(不过这个对象要能够序列化,即实现了 Serializable 接口),然后在启动的时候传入这个变量即可。
我们在流程启动日志中搜索 休息一下 四个字,可以找到和流程变量相关的 SQL,一共有两条,如下:
insert into ACT_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_TIME_, LAST_UPDATED_TIME_) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) , ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) , ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
INSERT INTO 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_) VALUES ( ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) , ( ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) , ( ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
从标名称上大概就能看出来,ACT_HI_VARINST 是存储流程执行的历史信息的,ACT_RU_VARIABLE 则是保存流程运行时候的信息的。
临时变量
个只针对流程中某一个具体的 Task(任务)有效,这个任务执行完毕后,这个流程变量就失效了。
- 启动一个流程
@Test
void test01() {
ProcessInstance pi = runtimeService.startProcessInstanceByKey("demo01");
logger.info("id:{},activityId:{}", pi.getId(), pi.getActivityId());
}
- 设置本地变量
@Test
void test03() {
Task task = taskService.createTaskQuery().singleResult();
taskService.setVariable(task.getId(), "days", 10);
Map<String, Object> variables = new HashMap<>();
variables.put("reason", "休息一下");
variables.put("startTime", new Date());
taskService.setVariables(task.getId(),variables);
}
- 执行情况
查询到某一个 Task,然后设置流程变量,上面这段代码和小伙伴们演示了两种设置方式:
- 逐个设置
- 直接设置一个 Map
上面这个设置流程变量的方式,本质上还是往 ACT_HI_VARINST 和 ACT_RU_VARIABLE 表中插入数据。具体的 SQL 也和前面的一样,我就不贴出来了。
本地变量
顾名思义就是临时的,这个不会存入到数据库中。
假设我们启动流程之后,通过 Task 来设置一个本地流程变量,方式如下:
@Test
void test03() {
Task task = taskService.createTaskQuery().singleResult();
taskService.setVariableLocal(task.getId(), "days", 10);
Map<String, Object> variables = new HashMap<>();
variables.put("reason", "休息一下");
variables.put("startTime", new Date());
taskService.setVariables(task.getId(),variables);
}
上面这段代码中,我设置了一个本地变量,两个全局变量,设置完成后,我们去 ACT_RU_VARIABLE 表中来查看一下具体的效果。
大家看到,由于 days 是本地变量,所以它的 TASK_ID_ 有值,这个好理解,说明 days 这个变量和这个具体的 Task 是有关的。
此时如果我们完成这个 Task,代码如下:
@Test
void test06() {
Task task = taskService.createTaskQuery().singleResult();
taskService.complete(task.getId());
}
执行查询ACT_RU_VARIABLE, 我们发现本地变量 days 已经没有了.
历史变量
历史变量,存入act_hi_varinst表中。在流程启动时,流程变量会同时存入历史变量表中;在流程结束时,历史表中的变量仍然存在。可理解为“永久代”的流程变量。
获取已完成的、id为’XXX’的流程实例中,所有的HistoricVariableInstances(历史变量实例),并以变量名排序。
historyService.createHistoricVariableInstanceQuery()
.processInstanceId("XXX")
.orderByVariableName.desc()
.list();