【Activiti工作流】10.排他閘道器
阿新 • • 發佈:2019-01-02
很久沒有更新Activiti的文章,有朋友想看之後的技術總結,我這裡就順著上一次的記憶繼續寫,把這個系列完結了。
上一次介紹了Activiti中的其中一種模式“連線”,該模式即是一件任務可能要分多種情況,有些情況需要走一個複雜流程,有些情況需要走簡單流程,就如同一條河的分支一樣。
而本次介紹的是Activiti的另一種模式“排他閘道器(ExclusiveGateWay)”。
我們開啟Eclipse中的某個bpmn的流程圖檢視,在左側的編輯框中就可以看到有一個“GateWay”的選項,其中有“ExclusiveGateWay”和“ParallelGateWay”兩個選項,其中“ExclusiveGateWay”就是我們要講的排他閘道器:
什麼是閘道器(GateWay)?其實閘道器說白了就是事件流到某一個核心節點,該節點需要做一個判斷,如果判斷符合某一個邏輯,那麼事件就流到合適的路徑上去,進行了分支。而做判斷的節點就是所謂的閘道器。
為了讓大家更加清晰的理解排他閘道器,我們利用之前的工程做一個排他閘道器的樣例。
我們要做一個類似“費用報銷申請”的流程圖,申請人進行費用報銷申請,然後利用閘道器來區分費用的大小。要求有達成如下條件進行不同的分支操作:
(1)如果報銷金額大於500,小於等於1000,則任務流轉至部門經理審批;
(2)如果報銷金額小於等於500,預設流轉至財務處審批;
(3)如果報銷金額大於1000,則任務流轉至總經理審批;
下面我們來利用排他閘道器來實現這個例項。
首先在測試工程“”中建立一個新的包“”來放置本次測試樣例的程式碼:
然後在該包下新建一個bpmn的流程圖:
進入編輯介面後,先建立一個StartEvent節點和一個連線以及一個UserTask:
其這裡的UserTask是報銷人的申請任務。該UserTask的Properties引數如下:
然後在下面建立3個任務,分別是排他閘道器根據情況進行分支後的任務:
三個任務的Properties引數如下:
然後我們在申請任務和下面三個任務之間新增一個排他閘道器:
然後三個任務最終流向結束節點:
然後最重要的幾步來了,首先定義排他閘道器下面的三條線的Name和相關message判斷資訊:
總經理審批的流線:
對於財務的線,我們沒有必要為其裝置“${message<=500}”的條件,直接將其設定為排他閘道器的預設Task(將指向該Task的線的id給排他閘道器的Defalut flow屬性),即是不滿足其它兩個條件時,預設走該Task:
到此我們的排他閘道器的流程圖就畫好了,Ctrl+S儲存流程圖,可以看到在相應的包下生成了一個png的流程圖片:
然後我們建立名為“ExclusiveGateWayTest”的測試類進行測試,先編寫一個部署流程的部署方法:
然後在資料庫中,可以看到act_re_deployment部署物件表、act_re_procdef流程定義表以及act_ge_bytearray資原始檔表中都生成了該次部署的流程定義資訊:
然後在ExclusiveGateWayTest中編寫啟動例項方法:
執行測試方法,啟動該流程:
在資料庫中的act_run_task表中有一個正在執行的任務:
那麼我們編寫查詢“姜曉巨集”流程任務的方法,檢視姜曉巨集當前的待辦任務:
可以看到他的任務ID為2304,下面編寫完成任務的測試方法,定義流程變數的名稱為message,值為450:
按照流程圖來說,節點應該流向預設的“財務”處,即是“張麗”來辦理該任務,所以我們查詢張麗的代辦任務:
然後執行張麗的任務:
最後任務完成:
歷史的任務節點:
流程中出現的流程變數:
然後重新啟動一個流程,將message設定為700:
執行2704任務後流程結束:
最後再重啟一個流程,將message設定為1300:
執行3004任務後流程結束:
總結:
1)一個排他閘道器對應一個以上的順序流。
2)由排他閘道器流出的順序流都有一個conditionExpression元素,在內部維護返回boolean型別的決策結果。
3)決策閘道器只會返回一條結果。當流程執行到排他閘道器時,流程引擎會自動檢索網關出口,從上到下檢索,如果發現第一條決策結果為true或者沒有設定條件的(預設成立),則流出。
4)如果沒有任何一個出口符合條件,則丟擲異常。
上一次介紹了Activiti中的其中一種模式“連線”,該模式即是一件任務可能要分多種情況,有些情況需要走一個複雜流程,有些情況需要走簡單流程,就如同一條河的分支一樣。
而本次介紹的是Activiti的另一種模式“排他閘道器(ExclusiveGateWay)”。
我們開啟Eclipse中的某個bpmn的流程圖檢視,在左側的編輯框中就可以看到有一個“GateWay”的選項,其中有“ExclusiveGateWay”和“ParallelGateWay”兩個選項,其中“ExclusiveGateWay”就是我們要講的排他閘道器:
什麼是閘道器(GateWay)?其實閘道器說白了就是事件流到某一個核心節點,該節點需要做一個判斷,如果判斷符合某一個邏輯,那麼事件就流到合適的路徑上去,進行了分支。而做判斷的節點就是所謂的閘道器。
為了讓大家更加清晰的理解排他閘道器,我們利用之前的工程做一個排他閘道器的樣例。
我們要做一個類似“費用報銷申請”的流程圖,申請人進行費用報銷申請,然後利用閘道器來區分費用的大小。要求有達成如下條件進行不同的分支操作:
(1)如果報銷金額大於500,小於等於1000,則任務流轉至部門經理審批;
(2)如果報銷金額小於等於500,預設流轉至財務處審批;
(3)如果報銷金額大於1000,則任務流轉至總經理審批;
下面我們來利用排他閘道器來實現這個例項。
首先在測試工程“”中建立一個新的包“”來放置本次測試樣例的程式碼:
然後在該包下新建一個bpmn的流程圖:
進入編輯介面後,先建立一個StartEvent節點和一個連線以及一個UserTask:
其這裡的UserTask是報銷人的申請任務。該UserTask的Properties引數如下:
然後在下面建立3個任務,分別是排他閘道器根據情況進行分支後的任務:
三個任務的Properties引數如下:
然後我們在申請任務和下面三個任務之間新增一個排他閘道器:
然後三個任務最終流向結束節點:
然後最重要的幾步來了,首先定義排他閘道器下面的三條線的Name和相關message判斷資訊:
總經理審批的流線:
對於財務的線,我們沒有必要為其裝置“${message<=500}”的條件,直接將其設定為排他閘道器的預設Task(將指向該Task的線的id給排他閘道器的Defalut flow屬性),即是不滿足其它兩個條件時,預設走該Task:
到此我們的排他閘道器的流程圖就畫好了,Ctrl+S儲存流程圖,可以看到在相應的包下生成了一個png的流程圖片:
然後我們建立名為“ExclusiveGateWayTest”的測試類進行測試,先編寫一個部署流程的部署方法:
執行該部署方法,可以看到控制檯輸出了部署資訊:package cn.com.eclusiveGateWay; import java.io.InputStream; import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngines; import org.activiti.engine.RepositoryService; import org.activiti.engine.repository.Deployment; import org.activiti.engine.repository.DeploymentBuilder; import org.junit.Test; public class ExclusiveGateWayTest {//獲取流程引擎物件 //getDefaultProcessEngine方法內部會自動讀取名為activiti.cfg.xml檔案的配置資訊 ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine(); /**部署流程定義*/ @Test public void deploymentProcessDefinition_inputStream(){ //獲得上傳檔案的輸入流 InputStream inputStreamBpmn=this.getClass().getResourceAsStream("exclusiveGateWayFlow.bpmn"); InputStream inputStreamPng=this.getClass().getResourceAsStream("exclusiveGateWayFlow.png"); //獲取倉庫服務,從類路徑下完成部署 RepositoryService repositoryService=processEngine.getRepositoryService(); DeploymentBuilder deploymentBuilder=repositoryService.createDeployment();//建立一個部署物件 deploymentBuilder.name("排他閘道器");//新增部署的名稱 deploymentBuilder.addInputStream("exclusiveGateWayFlow.bpmn", inputStreamBpmn); deploymentBuilder.addInputStream("exclusiveGateWayFlow.png", inputStreamPng); Deployment deployment=deploymentBuilder.deploy();//完成部署 //列印我們的流程資訊 System.out.println("部署Id:"+deployment.getId()); System.out.println("部署名稱Name:"+deployment.getName()); } }
然後在資料庫中,可以看到act_re_deployment部署物件表、act_re_procdef流程定義表以及act_ge_bytearray資原始檔表中都生成了該次部署的流程定義資訊:
然後在ExclusiveGateWayTest中編寫啟動例項方法:
/**啟動流程引擎*/
@Test
public void startProcessInstance(){
//獲取流程啟動Service
RuntimeService runtimeService=processEngine.getRuntimeService();
//使用流程定義的key,key對應bpmn檔案對應的id,
//(也是act_re_procdef表中對應的KEY_欄位),預設是按照最新版本啟動
String processDefinitionkey="myProcess";//流程定義的key就是myProcess
//獲取流程例項物件
ProcessInstance processInstance=runtimeService.startProcessInstanceByKey(processDefinitionkey);
System.out.println("流程例項ID:"+processInstance.getId());//流程例項ID
System.out.println("流程定義ID:"+processInstance.getProcessDefinitionId());//流程定義ID
}
執行測試方法,啟動該流程:
在資料庫中的act_run_task表中有一個正在執行的任務:
那麼我們編寫查詢“姜曉巨集”流程任務的方法,檢視姜曉巨集當前的待辦任務:
/**查詢當前的個人任務(實際就是查詢act_ru_task表)*/
@Test
public void findMyPersonalTask(){
String assignee="姜曉巨集";
//獲取事務Service
TaskService taskService=processEngine.getTaskService();
List<Task> taskList=taskService.createTaskQuery()//建立任務查詢物件
.taskAssignee(assignee)//指定個人任務查詢,指定辦理人
.list();//獲取該辦理人下的事務列表
if(taskList!=null&&taskList.size()>0){
for(Task task:taskList){
System.out.println("任務ID:"+task.getId());
System.out.println("任務名稱:"+task.getName());
System.out.println("任務的建立時間:"+task.getCreateTime());
System.out.println("任務辦理人:"+task.getAssignee());
System.out.println("流程例項ID:"+task.getProcessInstanceId());
System.out.println("執行物件ID:"+task.getExecutionId());
System.out.println("流程定義ID:"+task.getProcessDefinitionId());
System.out.println("#############################################");
}
}
}
查詢結果:可以看到他的任務ID為2304,下面編寫完成任務的測試方法,定義流程變數的名稱為message,值為450:
/**完成我的任務*/
@Test
public void completeMyPersonalTask(){
String taskId="2304";//上一次我們查詢的任務ID
//完成任務的同時,設定流程變數,使用流程變數用來制定完成任務後,下一個連線,
//對應exclusiveGateWayFlow.bpmn檔案中${message==450}
Map<String,Object> variables=new HashMap<String,Object>();
variables.put("message", 450);
TaskService taskService=processEngine.getTaskService();
taskService.complete(taskId,variables);//完成taskId對應的任務,並附帶流程變數
System.out.println("完成ID為"+taskId+"的任務");
}
完成結果:按照流程圖來說,節點應該流向預設的“財務”處,即是“張麗”來辦理該任務,所以我們查詢張麗的代辦任務:
然後執行張麗的任務:
最後任務完成:
歷史的任務節點:
流程中出現的流程變數:
然後重新啟動一個流程,將message設定為700:
執行2704任務後流程結束:
最後再重啟一個流程,將message設定為1300:
執行3004任務後流程結束:
總結:
1)一個排他閘道器對應一個以上的順序流。
2)由排他閘道器流出的順序流都有一個conditionExpression元素,在內部維護返回boolean型別的決策結果。
3)決策閘道器只會返回一條結果。當流程執行到排他閘道器時,流程引擎會自動檢索網關出口,從上到下檢索,如果發現第一條決策結果為true或者沒有設定條件的(預設成立),則流出。
4)如果沒有任何一個出口符合條件,則丟擲異常。
5)使用流程變數,設定連線的條件,並按照連線的條件執行工作流,如果沒有符合的條件,則執行預設的連線。