1、流程(process)
bpmn文件一個流程的根元素。一個流程就代表一個工作流。
2、順序流(sequenceFlow)
順序流是連接兩個流程節點的連線,代表一個節點的出口。流程執行完一個節點后,會沿着節點的所有外出順序流繼續執行。 就是說,BPMN 2.0默認的行為就是並發的: 兩個外出順序流會創造兩個單獨的,並發流程分支。
順序流主要由4個屬性組成:
Id: 唯一標示,用來區分不同的順序流
sourceRef:連線的源頭節點ID
targetRef:連線的目標節點ID
name(可選):連線的名稱,不涉及業務,主要用於顯示
說明:
1) 結束節點沒有出口
2) 其他節點有一個或多個出口。如果有一個出口,則代表是一個單線流程;如果有多個出口,則代表是開啟並發流程。
3、節點
1、開始事件節點(startEvent)
開始事件用來指明流程在哪里開始。開始事件的類型(流程在接收事件時啟動, 還是在指定時間啟動,等等),定義了流程如何啟動, 這通過事件中不同的小圖表來展示。 在XML中,這些類型是通過聲明不同的子元素來區分的。
1)空開始事件
空開始事件技術上意味着沒有指定啟動流程實例的觸發條件。最常用的一種開始,意味着流程的啟動需要手動觸發,通過調用api的startProcessInstanceByXXX方法。注意: 子流程都有一個空開始事件。
ProcessInstanceprocessInstance =runtimeService.startProcessInstanceByXXX();
圖形標記:空開始事件顯示成一個圓圈,沒有內部圖表(沒有觸發類型)
XML結構如下:<startEventid="start"name="my start event"/>
2)定時開始事件
定時開始事件用來在指定的時間創建流程實例。 它可以同時用於只啟動一次的流程 和應該在特定時間間隔啟動多次的流程。
注意:
1.子流程不能使用定時開始事件。
2.定時開始事件在流程發布后就會開始計算時間。 不需要調用 startProcessInstanceByXXX,雖然也而已調用啟動流程的方法, 但是 那會導致調用 startProcessInstanceByXXX時啟動過多的流程。
3.當包含定時開始事件的新版本流程部署時, 對應的上一個定時器就會 被刪除。這是因為通常不希望自動啟動舊版本流程的流程實例。
圖形標記:定時開始事件顯示為一個圓圈,內部是一個表。
XML內容:
定時開始事件的XML內容是普通開始事件的聲明,包含一個定時定義子元素。
示例:流程會啟動4次,每次間隔5分鍾,從2013年9月18日,12:10開始計時。
<startEvent id="theStart"> <timerEventDefinition> <timeCycle>R4/2013-09-18T12:13/PT5M</timeCycle> </timerEventDefinition> </startEvent>
示例:流程會根據選中的時間啟動一次。
<startEventid="theStart"> <timerEventDefinition> <timeDate>2013-10-31T23:59:24</timeDate> </timerEventDefinition> </startEvent>
2、結束事件節點(endEvent)
結束事件表示(子)流程(分支)的結束。 結束事件都是觸發事件。 這是說當流程達到結束事件,會觸發一個結果。 結果的類型是通過事件的內部黑色圖標表示的。
1)空結束事件
空結束事件意味着到達事件時不會指定拋出的結果。 這樣,引擎會直接結束當前執行的分支,不會做其他事情。
圖形標記:空結束事件是一個粗邊圓圈,內部沒有小圖表(無結果類型)
XML內容:<endEvent id="end" name="my end event"/>
空結束事件的XML內容是普通結束事件定義,不包含子元素 (其他結束事件類型都會包含聲明類型的子元素)。
3、任務節點 (Task)
1)接收任務節點(receiveTask)
接收任務是一個簡單任務,它會等待對應消息的到達。 當前,官方只實現了這個任務的java語義。 當流程達到接收任務,流程狀態會保存到數據庫中。
在任務創建后,意味着流程會進入等待狀態, 直到引擎接收了一個特定的消息, 這會觸發流程穿過接收任務繼續執行。
圖形標記:接收任務顯示為一個任務(圓角矩形),右上角有一個消息小標記。 消息是白色的(黑色圖標表示發送語義)
XML內容:<receiveTask id="waitState" name="wait"/>
當前任務(一般指機器自動完成,但需要耗費一定時間的工作)完成后,向后推移流程,可以調用runtimeService.signal(executionId),傳遞接收任務上流程的id。
演示代碼如下:
ProcessInstance pi =runtimeService.startProcessInstanceByKey("receiveTask"); Execution execution=runtimeService.createExecutionQuery() .processInstanceId(pi.getId())
.activityId("waitState")
.singleResult(); assertNotNull(execution); runtimeService.signal(execution.getId());
2)用戶任務節點 (userTask)
用戶任務用來設置必須由人員完成的工作。 當流程執行到用戶任務,會創建一個新任務, 並把這個新任務加入到分配人或群組的任務列表中。
圖形標記:用戶任務顯示成一個普通任務(圓角矩形),左上角有一個小用戶圖標。
XML內容XML中的用戶任務定義如下。id屬性是必須的。 name屬性是可選的。
<userTask id="theTask" name="Important task"/>
用戶任務也可以設置描述(實際上所有BPMN 2.0元素都可以設置描述)。 添加documentation元素可以定義描述。
<userTask id="theTask" name="Schedule meeting"> <documentation> Schedule an engineering meeting for next week with the new hire. </documentation>
在實際應用中,用戶接到任務后可以參照任務描述來辦理任務,描述文本可以通過標准的java方法來獲得:task.getDescription()
任務分配
用戶任務的辦理都需要人工的參與。用戶任務可以分為兩大類。私有任務和公有任務(可接任務)。
私有任務
私有任務即有直接分配給指定用戶的任務。只有一個用戶可以成為任務 的執行者。 在activiti中,用戶叫做執行者。 擁有執行者的用戶任務 (即私有任務)對其他用戶是不可見的。只能出現執行者的個人任務列表中.
直接把用戶任務分配給指定用戶使用assignee屬性,XML代碼如下:
<userTask id="theTask" name="my task" activiti:assignee="sirius"/>
Assignee屬性對應的值為一個用戶的ID。
直接分配給用戶的任務可以通過TaskService像下面這樣辦理:
List<Task>tasks =taskService.createTaskQuery().taskAssignee("sirius").list(); Task task = tasks.get(0);// 假設任務集合的第一條是要辦理的任務 taskService.complete(task.getId());
公有任務
有的用戶任務在指派時無法確定具體的辦理者,這時任務也可以加入到 人員的候選任務列表中,然后讓這些人員選擇性認領和辦理任務。
公有任務的分配可以分為指定候選用戶和候選組兩種。
a) 把任務添加到一批用戶的候選任務列表中,使用candidateUsers 屬 性,XML內容如下:
<userTaskid="theTask"name="my task"activiti:candidateUsers="sirius,kermit"/>
candidateUsers屬性內為用戶的ID,多個用戶ID之間使用(半角)逗 號間隔。
b) 把任務添加到一個或多個候選組下,這時任務對組下的所有用戶可 見,首先得保證每個組下面有用戶,通過IdentityService對象創建用戶 和組,然后把用戶添加到對應的組下。
然后配置組任務,使用candidateGroups屬性,XML內容如下:
<userTask id="theTask" name="my task" activiti:candidateGroups="testGroup,developGroup"/>
間接分配給用戶的任務,可以通過TaskService像下面這樣操作:
List<Task>tasks =taskService.createTaskQuery() .taskCandidateUser("sirius").list(); Task task = tasks.get(0);// 假設任務集合的第一條是要辦理的任務 String taskId = task.getId(); taskService.claim(taskId ,“sirius”); //認領任務,讓用戶成為任務的執行者 taskService.complete(taskId );
說明:
1.要維護用戶和組得使用用戶管理服務對象,使用 processEngine 得到IdentityService。
2.要分配組任務必須先創建組,而且組下得有用戶,用戶和組的 最關鍵屬性是ID。
3.使用newUser(userId)和newGroup(groupId)創建用戶 和組。
4.使用createMembership(userId,groupId)把用戶掛到 組下。
5.辦理候選任務,首先得認領任務,讓用戶成為任務的執行者。
如果上面的方式還不夠靈活,那么我們也可以自定義一個任務分配處理器,通過代碼的方式來動態設置任務的屬性。XML代碼如下:
<userTask id="task1" name="My task"> <extensionElements> <activiti:taskListener event="create" class="org.activiti.MyAssignmentHandler"/> </extensionElements> </userTask>
DelegateTask會傳遞給TaskListener的實現, 通過它可以設置執行人,候選人和候選組:
Public class MyAssignmentHandler implements TaskListener { Public void notify(DelegateTask delegateTask){ // 執行用戶搜索相關代碼 ... // 然后把獲取到的用戶通過下面方法,設置給當前觸發事件的任務 delegateTask.setAssignee("sirius"); //delegateTask.addCandidateUser("kermit"); //delegateTask.addCandidateGroup("testGroup"); ... } }
上述兩個雖然都可以統稱為任務節點,但是還是有本質區別:
1.receiveTask主要代表機器自動執行的,userTask代表人工干預的。
2.receiveTask任務產生后會在act_ru_execution表中新增一條記錄, 而userTask產生后會在act_ru_execution和act_ru_task(主要記錄任 務的發布時間,辦理人等信息)中各產生一條記錄。
3.receiveTask任務提交方式使用RuntimeService的signal方法提交, userTask任務提交方式使用TaskService的complete方法提交。