Activiti 自帶一套使用者管理系統,維護了使用者和使用者組的對應關系,通過 identityService UserTask
可以對它們進行增删改查。當你在
中指定了使用者組時,Activiti 就會使用它維護的這個關系尋找使用者了。
但是這也為 Activiti 的使用帶來了困難,因為一般應用都有一套自建的使用者管理,不可能去使用 Activiti 這一套,就不得不花一些成本來對接,而且對接方法都比較 hack,個人覺得這是 Activiti 設計得不太好的地方。
受理人與候選人
一個
UserTask
可以設定一個受理人(Assignee),或者多個候選人。
受理人就是負責完成該任務的人,在審批場景下就可以了解成審批人,隻能有一個,如果要有多個的話則應該使用
上一篇文章提到的多執行個體任務。
<!--kermit就是受理人的 id-->
<userTask id="theTask" name="my task" activiti:assignee="kermit" />
候選人可以有一個或者多個,他們都是受理人的“候選”,他們要“搶”任務,誰先調用了
taskService.claim(taskId, userId);
,誰就變成了任務的受理人。
<!--兩個候選人 kermit與gonzo-->
<userTask id="theTask" name="my task" activiti:candidateUsers="kermit,gonzo"/>
<!--management使用者組的所有使用者作為候選人-->
<userTask id="theTask" name="my task" activiti:candidateGroups="management"/>
内置的使用者管理
Activiti 中的使用者模型非常簡單,就是使用者和使用者組之間的多對多關系,是以隻涉及三張表:
-
:使用者資訊ACT_ID_USER
-
:使用者組資訊ACT_ID_GROUP
-
:存儲使用者和使用者組之間的多對多關聯ACT_ID_MEMBERSHIP

流程運作時使用者資訊
在應用中一般會調用下面的方法查詢某個使用者的 task:
// 查詢所有候選 userId 的任務
List<Task> tasks = taskService.createTaskQuery()
.taskCandidateUser(userId).list();
// 查詢所有 userId 受理的任務
List<Task> tasks = taskService.createTaskQuery()
.taskAssignee(userId).list();
// 查詢所有 userId候選或者受理的任務
List<Task> tasks = taskService.createTaskQuery()
.taskCandidateOrAssigned(userId).list();
受理人查詢
在
ACT_RU_TASK
表中本來就有一個
ASSIGNEE_
字段表示受理人,所有當你使用
taskAssignee(userId)
查詢時,直接就是用的
ASSIGNEE_=userId
去
ACT_RU_TASK
表中去查的。
候選人查詢
在流程運作時還會有一張
ACT_RU_IDENTITYLINK
表,用來記錄流程運作時相關的人員資訊,比如流程發起人,參與人,Task 的候選人等資訊:
其中
TYPE_
有以下幾種取值:
- starter: 流程發起人
- participant: 流程參與人,目前的受理人就會被記錄在這裡
- candidate: Task 對應的候選人或者候選使用者組
因為這是一張運作時表,是以裡面資料是會随着流程運轉不斷增删改的。
當你使用
taskCandidateUser(userId)
條件查詢時其實就是去這張表裡根據
TYPE_='candidate' AND USER_ID_=userId
找到使用者候選的 Task
候選使用者組
假如你将 UserTask 配置成
activiti:candidateGroups="management"
,如果 userId 屬于
manangement
使用者組,那麼使用
taskCandidateUser(userId)
條件查詢,也是能查出該 UserTask 的。
此時就需要用到上一小節提到的使用者管理相關表了。Activiti 如果會去
ACT_ID_MEMBERSHIP
中找到該使用者的 groupId,然後去
ACT_RU_IDENTITYLINK
中根據
GROUP_ID_
查。
Activiti 如何與已有使用者管理系統對接?
從上面的分析可以看到,Activiti 隻有在你配置了
candidateGroups
才可能去查詢内置的使用者管理資訊,是以個人建議是就不要使用
candidateGroups
配置了,全部使用
candidateUsers
和
assignee
,然後在 userId 裡加入一些特征區分使用者組或者别的業務相關的東西,比如加個字首
GROUP-groupId
,之後就全部用自己業務系統裡的 id 去查 Task。不用擔心這些ID在 Activiti 内置的使用者管理系統中沒有,Activiti 根本不會去校驗這個。
當然也有人研究過一些更加麻煩的對接方法,列出如下,也可以參考:
- 同步或者重構Activiti Identify使用者資料的多種方案比較 ,裡面提到了三個方案
-
- 往 Activiti 内置的使用者表中,同步自己業務的使用者資料。個人感覺比較麻煩,而且也容易出各種問題
- 将 Activiti 使用者相關存儲類用自己的實作類換掉。聽起來很複雜,但是因為 Activiti 6 所采用的可插拔的存儲層設計,其實隻要替換兩類就可以了,後面我有空會再研究一下它的存儲層設計。而且如果要搞分庫分表的話,存儲層本來就是要重新弄的,順手就可以把使用者管理換掉。
- 用業務使用者資料的視圖替換掉 Activiti 内置使用者管理的這三張表。感覺不一定所有的業務使用者資料都可以映射到 Activiti 的使用者模型,所有通用性有限