新聞中心
1. 繪制流程圖
首先我們還是使用之前舊的流程圖,但是在為 UserTask 設(shè)置分配用戶的時(shí)候,我們?cè)O(shè)置多個(gè)用戶,如下圖:

創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站設(shè)計(jì)、成都網(wǎng)站設(shè)計(jì)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的奉賢網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
設(shè)置完成后,我們下載這個(gè)流程文件,來(lái)看下對(duì)應(yīng)的 XML 文件,內(nèi)容如下:
demo01
小伙伴們看到,UserTask 中的 flowable:candidateUsers="javaboy,zhangsan,lisi" 就表示這個(gè) UserTask 由 javaboy、zhangsan 和 lisi 三個(gè)用戶處理,用戶名之間用 , 隔開(kāi)。
2. 查詢?nèi)蝿?wù)處理人
接下來(lái)我們部署并啟動(dòng)上面這個(gè)流程,具體如何部署如何啟動(dòng),這個(gè)在之前的文章中松哥已經(jīng)和大家聊過(guò)了,這里不再贅述。
當(dāng)流程啟動(dòng)成功之后,現(xiàn)在我們很容易想到像之前文章那樣,去查詢 javaboy 需要處理的 UserTask,如下:
Listlist = taskService.createTaskQuery().taskAssignee("javaboy").list();
for (Task task : list) {
logger.info("id:{};name:{};taskDefinitionKey:{}", task.getId(), task.getName(), task.getTaskDefinitionKey());
}
但是我們卻發(fā)現(xiàn)這個(gè) SQL 執(zhí)行完成后,查詢不到任何數(shù)據(jù)!為什么呢?我們來(lái)分析下。
經(jīng)過(guò)前面幾篇文章的介紹,現(xiàn)在小伙伴們都知道了,上面這個(gè)方法最終查詢的是數(shù)據(jù)庫(kù)中的 ACT_RU_TASK 表,查詢的 SQL 如下:
那我們就去檢查 ACT_RU_TASK 表以及它的 ASSIGNEE_ 字段,結(jié)果如下:
我們發(fā)現(xiàn) ACT_RU_TASK 表中記錄的 ASSIGNEE_ 字段值為 null!
為 null 這個(gè)其實(shí)也好理解,畢竟這個(gè) UserTask 有多個(gè)人可以處理,但是只有一個(gè)字段,沒(méi)法儲(chǔ)存,肯定有其他存儲(chǔ)方式。
好啦,不和大家賣關(guān)子了,這種有多個(gè)候選人的任務(wù),我們應(yīng)該按照如下方式來(lái)查詢:
@Test
void test12() {
Listlist = taskService.createTaskQuery().taskCandidateUser("javaboy").list();
for (Task task : list) {
logger.info("id:{};name:{};taskDefinitionKey:{}", task.getId(), task.getName(), task.getTaskDefinitionKey());
}
}
小伙伴們看到,這里應(yīng)該調(diào)用 taskCandidateUser 方法進(jìn)行處理。那么這個(gè)方法查詢的是哪張表呢?我們來(lái)看下上面方法最終執(zhí)行的 SQL,如下:
: ==> Preparing: SELECT RES.* from ACT_RU_TASK RES WHERE RES.ASSIGNEE_ is null and exists(select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TYPE_ = 'candidate' and LINK.TASK_ID_ = RES.ID_ and ( LINK.USER_ID_ = ? ) ) order by RES.ID_ asc
: ==> Parameters: javaboy(String)
: <== Total: 1
小伙伴們看到,這里的查詢涉及到兩張表,分別是 ACT_RU_TASK 和 ACT_RU_IDENTITYLINK,兩張表聯(lián)合查詢查出來(lái)的,那我們來(lái)看看 ACT_RU_IDENTITYLINK 表的內(nèi)容:
小伙伴們看到,TYPE_ 為 candidate 的就表示這個(gè) Task 的候選人,id 為 c5693038-3f42-11ed-b9e2-acde48001122 的 Task 一共有三個(gè)候選人,兩張表聯(lián)合查詢,才可以查到這個(gè) UserTask 該由誰(shuí)來(lái)處理。
另外一種常見(jiàn)的需求就是,已經(jīng)知道了要處理的流程實(shí)例了,但是不知道應(yīng)該由誰(shuí)來(lái)處理,此時(shí)通過(guò)查詢 ACT_RU_IDENTITYLINK 表就可以確定一個(gè)流程實(shí)例都有哪些參與者,如下:
@Test
void test13() {
Listlist = runtimeService.createProcessInstanceQuery().list();
for (ProcessInstance pi : list) {
ListidentityLinksForProcessInstance = runtimeService.getIdentityLinksForProcessInstance(pi.getId());
for (IdentityLink identityLink : identityLinksForProcessInstance) {
logger.info("ProcessInstanceId:{},UserId:{}",identityLink.getProcessInstanceId(),identityLink.getUserId());
}
}
}
我們來(lái)看看上面這個(gè)執(zhí)行的 SQL,如下:
可以看到,其實(shí)就是通過(guò)查詢 ACT_RU_IDENTITYLINK 表獲取我們想要的數(shù)據(jù)。
3. 認(rèn)領(lǐng)任務(wù)
對(duì)于這種有候選人的任務(wù),我們需要先認(rèn)領(lǐng),再處理。認(rèn)領(lǐng)的本質(zhì),其實(shí)就是給 ACT_RU_TASK 表中,這個(gè) UserTask 記錄的 ASSIGNEE_ 字段設(shè)置上值。
認(rèn)領(lǐng)任務(wù)的方式如下:
@Test
void test12() {
Listlist = taskService.createTaskQuery().taskCandidateUser("javaboy").list();
for (Task task : list) {
taskService.claim(task.getId(),"javaboy");
}
}
認(rèn)領(lǐng)之后,我們?cè)賮?lái)看 ACT_RU_TASK 表中的數(shù)據(jù),如下:
可以看到,此時(shí) ASSIGNEE_ 字段就有值了,同時(shí) CLAIM_TIME 字段也記錄了任務(wù)的認(rèn)領(lǐng)時(shí)間。
再來(lái)看看任務(wù)認(rèn)領(lǐng)執(zhí)行的 SQL,基本上和我們所想的一致。
4. 處理任務(wù)
認(rèn)領(lǐng)后的任務(wù)該如何處理,這個(gè)就和我們上篇文章中介紹的方式一致了,如下:
@Test
void test11() {
Listlist = taskService.createTaskQuery().taskAssignee("javaboy").list();
for (Task task : list) {
taskService.complete(task.getId());
}
}
具體原理上篇文章中已經(jīng)介紹過(guò)了,這里就不再贅述了。
任務(wù)執(zhí)行完成后,ACT_RU_IDENTITYLINK 表中的記錄也會(huì)隨之刪除。
5. 變量與監(jiān)聽(tīng)器
前面這種方式設(shè)置的任務(wù)候選人我們是在繪制流程圖的時(shí)候直接硬編碼的,這顯然不是一個(gè)好辦法。如果能通過(guò)變量來(lái)傳遞任務(wù)的候選人,就會(huì)方便很多。
5.1 候選人變量
我們可以在繪制流程圖的時(shí)候,用變量代替直接指定候選人,方式如下:
此時(shí),生成的流程 XML 文件中,UserTask 節(jié)點(diǎn)的處理人也就變成了下面這個(gè)樣子:
demo01
UserTask 節(jié)點(diǎn)中的 flowable:candidateUsers="${userIds}" 就表示流程的處理人由 userIds 變量控制。
好了,接下來(lái)我們來(lái)啟動(dòng)流程,注意,此時(shí)啟動(dòng)流程需要傳遞 userIds 變量,如下:
demo01
多個(gè)用戶之間,用英文 , 隔開(kāi)。
好了,流程啟動(dòng)成功后,接下來(lái)的操作參考 3、4 小節(jié),這里我就不再贅述了。
5.2 監(jiān)聽(tīng)器
當(dāng)然,我們也可以通過(guò)監(jiān)聽(tīng)器來(lái)為 UserTask 設(shè)置多個(gè)候選處理人用戶,首先我們創(chuàng)建一個(gè)監(jiān)聽(tīng)器如下:
@Test
void test01() {
MapuserIds = new HashMap<>();
userIds.put("userIds", "javaboy,zhangsan,lisi");
ProcessInstance pi = runtimeService.startProcessInstanceByKey("demo01",userIds);
logger.info("id:{},activityId:{}", pi.getId(), pi.getActivityId());
}
然后在繪制流程圖的時(shí)候,刪除掉 UserTask 分配的用戶,然后重新為 UserTask 設(shè)置一個(gè)監(jiān)聽(tīng)器:
然后設(shè)置一個(gè)在創(chuàng)建 UserTask 的時(shí)候觸發(fā)的監(jiān)聽(tīng)器:
然后我們下載這個(gè)流程圖對(duì)應(yīng)的 XML 文件,如下:
demo01
可以看到,在 userTask 節(jié)點(diǎn)中,通過(guò) extensionElements 指定了額外的監(jiān)聽(tīng)器。
好啦,這個(gè)流程現(xiàn)在就可以直接啟動(dòng)了,啟動(dòng)時(shí)也不需要額外的變量。
流程啟動(dòng)成功后,接下來(lái)的操作參考 3、4 小節(jié),這里我就不再贅述了。
6. 任務(wù)回退
當(dāng)一個(gè)任務(wù)認(rèn)領(lǐng)(Claim)之后,但是又不想處理,此時(shí)我們可以將任務(wù)退回。方式如下:
@Test
void test16() {
Listlist = taskService.createTaskQuery().taskAssignee("javaboy").list();
for (Task task : list) {
taskService.setAssignee(task.getId(), null);
}
}
其實(shí)思路很簡(jiǎn)答,就是重新為任務(wù)設(shè)置處理人,且處理人為 null,這就是將任務(wù)回退了,接下來(lái)其他人可以重新認(rèn)領(lǐng)該任務(wù)了。
7. 修改任務(wù)候選人
7.1 增加
任務(wù)候選人也不是一成不變的,也可以動(dòng)態(tài)修改,當(dāng)一個(gè)流程啟動(dòng)之后,流程已經(jīng)走到某一個(gè) Task 了,此時(shí)我們想要修改該 Task 的候選人,也是可以的,方式如下:
@Test
void test17() {
Listlist = taskService.createTaskQuery().taskCandidateUser("javaboy").list();
for (Task task : list) {
taskService.addCandidateUser(task.getId(),"wangwu");
}
}
添加完成后,查看 ACT_RU_IDENTITYLINK 表,我們發(fā)現(xiàn) wangwu 已經(jīng)添加進(jìn)來(lái)了:
7.2 刪除
如果想要?jiǎng)h除一個(gè)候選人,方式如下:
@Test
void test18() {
Listlist = taskService.createTaskQuery().taskCandidateUser("javaboy").list();
for (Task task : list) {
taskService.deleteCandidateUser(task.getId(), "wangwu");
}
}
刪除成功之后,ACT_RU_IDENTITYLINK 表中對(duì)應(yīng)的數(shù)據(jù)也就被清除掉了。
8. 查詢歷史數(shù)據(jù)
如果一個(gè)流程執(zhí)行結(jié)束了,我們還想查詢這個(gè)流程曾經(jīng)涉及到的參與者,可以通過(guò)如下方式查詢:
@Test
void test14() {
Listlist = historyService.createHistoricProcessInstanceQuery().list();
for (HistoricProcessInstance historicProcessInstance : list) {
Listlinks = historyService.getHistoricIdentityLinksForProcessInstance(historicProcessInstance.getId());
for (HistoricIdentityLink link : links) {
logger.info("userId:{},taskId:{},type:{},processInstanceId:{}",link.getUserId(),link.getTaskId(),link.getType(),link.getProcessInstanceId());
}
}
}
這里最終其實(shí)就是去 ACT_HI_IDENTITYLINK 表中查詢,對(duì)應(yīng)的 SQL 如下:
上面這是查詢一個(gè)流程的參與人,當(dāng)然我們也可以查詢一個(gè) Task 的候選人與處理人,如下:
@Test
void test15() {
Listlist = historyService.createHistoricTaskInstanceQuery().list();
for (HistoricTaskInstance historicTaskInstance : list) {
Listlinks = historyService.getHistoricIdentityLinksForTask(historicTaskInstance.getId());
for (HistoricIdentityLink link : links) {
logger.info("userId:{},taskId:{},type:{},processInstanceId:{}", link.getUserId(), link.getTaskId(), link.getType(), link.getProcessInstanceId());
}
}
}
查詢對(duì)應(yīng)的 SQL 如下:
和我們所想的基本一致。
當(dāng)前名稱:Flowable任務(wù)如何認(rèn)領(lǐng),回退?
文章轉(zhuǎn)載:http://fisionsoft.com.cn/article/djhssho.html


咨詢
建站咨詢
