Flowable 設(shè)置流程變量的四種方式詳解
引言
在之前的文章中,松哥也有和小伙伴們使用過(guò)流程變量,然而沒(méi)有和大家系統(tǒng)的梳理過(guò)流程變量的具體玩法以及它對(duì)應(yīng)的數(shù)據(jù)表詳情,今天我們就來(lái)看看 Flowable 中流程變量的詳細(xì)玩法。
1. 為什么需要流程變量
首先我們來(lái)看看為什么需要流程變量。
舉一個(gè)簡(jiǎn)單的例子,假設(shè)我們有如下一個(gè)流程:

這是一個(gè)請(qǐng)假流程,那么誰(shuí)請(qǐng)假、請(qǐng)幾天、起始時(shí)間、請(qǐng)假理由等等,這些都需要說(shuō)明,不然領(lǐng)導(dǎo)審批的依據(jù)是啥?那么如何傳遞這些數(shù)據(jù),我們就需要流程變量。
2. 流程變量的分類(lèi)
整體上來(lái)說(shuō),目前流程變量可以分為三種類(lèi)型:
- 全局流程變量:在整個(gè)流程執(zhí)行期間,這個(gè)流程變量都是有效的。
- 本地流程變量:這個(gè)只針對(duì)流程中某一個(gè)具體的 Task(任務(wù))有效,這個(gè)任務(wù)執(zhí)行完畢后,這個(gè)流程變量就失效了。
- 臨時(shí)流程變量:顧名思義就是臨時(shí)的,這個(gè)不會(huì)存入到數(shù)據(jù)庫(kù)中。
在接下來(lái)的內(nèi)容中,我會(huì)跟大家挨個(gè)介紹這些流程變量的用法。
3. 全局流程變量
假設(shè)我們就是上面這個(gè)請(qǐng)假流程,我們一起來(lái)看下流程變量的設(shè)置和獲取。
3.1 啟動(dòng)時(shí)設(shè)置
第一種方式,就是我們可以在流程啟動(dòng)的時(shí)候,設(shè)置流程變量,如下:
@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());
}我們可以在啟動(dòng)的時(shí)候?yàn)榱鞒淘O(shè)置變量,小伙伴們注意到,流程變量的 value 也可以是一個(gè)對(duì)象(不過(guò)這個(gè)對(duì)象要能夠序列化,即實(shí)現(xiàn)了 Serializable 接口),然后在啟動(dòng)的時(shí)候傳入這個(gè)變量即可。
我們?cè)诹鞒虇?dòng)日志中搜索 休息一下 四個(gè)字,可以找到和流程變量相關(guān)的 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, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
從標(biāo)名稱上大概就能看出來(lái),ACT_HI_VARINST 是存儲(chǔ)流程執(zhí)行的歷史信息的,ACT_RU_VARIABLE 則是保存流程運(yùn)行時(shí)候的信息的。
我們打開(kāi) ACT_RU_VARIABLE 表來(lái)看一下:

從表中我們可以看到,每一個(gè)流程變量都有對(duì)應(yīng)的流程實(shí)例 ID,這就說(shuō)明這些流程變量是屬于某一個(gè)流程實(shí)例的,所以我們可以按照如下方式來(lái)查詢流程變量:
@Test
void test01() {
List<Execution> list = runtimeService.createExecutionQuery().list();
for (Execution execution : list) {
Object reason = runtimeService.getVariable(execution.getId(), "reason");
logger.info("reason:{}", reason);
}
}對(duì)應(yīng)的查詢 SQL 如下:
: ==> Preparing: select * from ACT_RU_VARIABLE WHERE EXECUTION_ID_ = ? AND TASK_ID_ is null AND NAME_ = ? : ==> Parameters: 6fdd2007-4c3a-11ed-aa7e-acde48001122(String), reason(String) : <== Total: 1
可以看到,這個(gè)就是去 ACT_RU_VARIABLE 表中進(jìn)行查詢,查詢條件中包含了變量的名稱。
當(dāng)然,我們也可以直接查詢某一個(gè)流程的所有變量,如下:
@Test
void test02() {
List<Execution> list = runtimeService.createExecutionQuery().list();
for (Execution execution : list) {
Map<String,Object> variables = runtimeService.getVariables(execution.getId());
logger.info("variables:{}", variables);
}
}這個(gè)對(duì)應(yīng)的查詢 SQL 如下:
: ==> Preparing: select * from ACT_RU_VARIABLE WHERE EXECUTION_ID_ = ? AND TASK_ID_ is null : ==> Parameters: 6fdd2007-4c3a-11ed-aa7e-acde48001122(String) : <== Total: 3
可以看到,這個(gè)跟上面的那個(gè)差不多,只不過(guò)少了 NAME_ 這個(gè)條件。
3.2 通過(guò) Task 設(shè)置
我們也可以在流程啟動(dòng)成功之后,再去設(shè)置流程變量,步驟如下:
首先啟動(dòng)一個(gè)流程:
@Test
void test01() {
ProcessInstance pi = runtimeService.startProcessInstanceByKey("demo01");
logger.info("id:{},activityId:{}", pi.getId(), pi.getActivityId());
}然后設(shè)置流程變量:
@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);
}查詢到某一個(gè) Task,然后設(shè)置流程變量,上面這段代碼和小伙伴們演示了兩種設(shè)置方式:
- 逐個(gè)設(shè)置
- 直接設(shè)置一個(gè) Map
上面這個(gè)設(shè)置流程變量的方式,本質(zhì)上還是往 ACT_HI_VARINST 和 ACT_RU_VARIABLE 表中插入數(shù)據(jù)。具體的 SQL 也和前面的一樣,我就不貼出來(lái)了。
3.3 完成任務(wù)時(shí)設(shè)置
也可以在完成一個(gè)任務(wù)的時(shí)候設(shè)置流程變量,如下:
@Test
void test04() {
Task task = taskService.createTaskQuery().singleResult();
Map<String, Object> variables = new HashMap<>();
variables.put("reason", "休息一下");
variables.put("startTime", new Date());
variables.put("days", 10);
taskService.complete(task.getId(),variables);
}底層涉及到的 SQL 都跟前面一樣,我就不贅述了。
3.4 通過(guò)流程設(shè)置
由于是全局流程變量,所以我們也可以通過(guò) RuntimeService 來(lái)進(jìn)行設(shè)置,如下:
@Test
void test05() {
Execution execution = runtimeService.createExecutionQuery().singleResult();
runtimeService.setVariable(execution.getId(), "days", 10);
Map<String, Object> variables = new HashMap<>();
variables.put("reason", "休息一下");
variables.put("startTime", new Date());
runtimeService.setVariables(execution.getId(), variables);
}好啦,一共就是這四種方式。
4. 本地流程變量
第三小節(jié)我們說(shuō)的全局流程變量是和某一個(gè)具體的流程綁定的,而本地流程變量則不同,本地流程變量和某一個(gè) Task 綁定。
4.1 通過(guò) Task 設(shè)置
假設(shè)我們啟動(dòng)流程之后,通過(guò) Task 來(lái)設(shè)置一個(gè)本地流程變量,方式如下:
@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);
}上面這段代碼中,我設(shè)置了一個(gè)本地變量,兩個(gè)全局變量,設(shè)置完成后,我們?nèi)?nbsp;ACT_RU_VARIABLE 表中來(lái)查看一下具體的效果。

大家看到,由于 days 是本地變量,所以它的 TASK_ID_ 有值,這個(gè)好理解,說(shuō)明 days 這個(gè)變量和這個(gè)具體的 Task 是有關(guān)的。
此時(shí)如果我們完成這個(gè) Task,代碼如下:
@Test
void test06() {
Task task = taskService.createTaskQuery().singleResult();
taskService.complete(task.getId());
}完成之后,再來(lái)查看 ACT_RU_VARIABLE 表,如下:

我們發(fā)現(xiàn)本地變量 days 已經(jīng)沒(méi)有了。因?yàn)樯弦粋€(gè) Task 都已經(jīng)執(zhí)行完畢了,這個(gè)時(shí)候如果還是按照第三小節(jié)介紹的方式去查詢變量,就查不到 days 了。此時(shí)如果需要查詢到曾經(jīng)的 days 變量,得去歷史表中查詢了,方式如下:
@Test
void test07() {
ProcessInstance pi = runtimeService.createProcessInstanceQuery().singleResult();
List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery().processInstanceId(pi.getId()).list();
for (HistoricVariableInstance hvi : list) {
logger.info("name:{},type:{},value:{}", hvi.getVariableName(), hvi.getVariableTypeName(), hvi.getValue());
}
}這是流程本地變量的特點(diǎn),當(dāng)然相關(guān)的方法還有好幾個(gè),這里列出來(lái)給小伙伴們參考:
- org.flowable.engine.TaskService#complete(java.lang.String, java.util.Map<java.lang.String,java.lang.Object>, boolean):在完成一個(gè) Task 的時(shí)候,如果傳遞了變量,則可以通過(guò)第三個(gè)參數(shù)來(lái)控制這個(gè)變量是全局的還是本地的,true 表示這個(gè)變量是本地的。
- org.flowable.engine.RuntimeService#setVariableLocal:為某一個(gè)執(zhí)行實(shí)例設(shè)置本地變量。
- org.flowable.engine.RuntimeService#setVariablesLocal:同上,批量設(shè)置。
好啦,這就是本地流程變量。
5. 臨時(shí)流程變量
臨時(shí)流程變量是不存數(shù)據(jù)庫(kù)的,一般來(lái)說(shuō)我們可以在啟動(dòng)流程或者完成任務(wù)的時(shí)候使用,用法如下:
@Test
void test21() {
Map<String, Object> variables = new HashMap<>();
variables.put("reason", "休息一下");
variables.put("startTime", new Date());
ProcessInstance pi = runtimeService
.createProcessInstanceBuilder()
.transientVariable("days", 10)
.transientVariables(variables)
.processDefinitionKey("demo01")
.start();
logger.info("id:{},activityId:{}", pi.getId(), pi.getActivityId());
}上面這段代碼涉及到的流程變量就是臨時(shí)流程變量,它是不會(huì)存入到數(shù)據(jù)庫(kù)中的。
也可以在完成一個(gè)任務(wù)的時(shí)候設(shè)置臨時(shí)變量,如下:
@Test
void test22() {
Task task = taskService.createTaskQuery().singleResult();
Map<String, Object> transientVariables = new HashMap<>();
transientVariables.put("days", 10);
taskService.complete(task.getId(), null, transientVariables);
}這個(gè)臨時(shí)變量也是不會(huì)存入到數(shù)據(jù)庫(kù)中的。
以上就是Flowable 設(shè)置流程變量的四種方式詳解的詳細(xì)內(nèi)容,更多關(guān)于Flowable 設(shè)置流程變量的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java使用異或?qū)崿F(xiàn)變量互換和異或加密解密示例
這篇文章主要介紹了使用異或?qū)崿F(xiàn)變量互換和異或加密解密示例,需要的朋友可以參考下2014-02-02
Windows同時(shí)配置兩個(gè)jdk環(huán)境變量的操作步驟
Java Development Kit (JDK) 是開(kāi)發(fā)Java應(yīng)用程序的基礎(chǔ),包含了編譯器、調(diào)試器以及其他必要的工具,本指南將一步步指導(dǎo)您完成在Windows操作系統(tǒng)上同時(shí)配置兩個(gè)jdk環(huán)境變量的操作步驟,需要的朋友可以參考下2024-09-09
Java實(shí)現(xiàn)Timer的定時(shí)調(diào)度函數(shù)schedule的四種用法
本文主要介紹了Java實(shí)現(xiàn)Timer的定時(shí)調(diào)度函數(shù)schedule的四種用法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
Java實(shí)現(xiàn)簡(jiǎn)單QQ聊天工具
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡(jiǎn)單QQ聊天工具,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-09-09
淺談spring的重試機(jī)制無(wú)效@Retryable@EnableRetry
這篇文章主要介紹了淺談spring的重試機(jī)制無(wú)效@Retryable@EnableRetry,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09

