JBPM(七)詳解流程圖

概念:

流程圖的組成:

a. 活動 Activity / 節點 Node

b. 流轉 Transition / 連線(單向箭頭)

c. 事件

 

1.流轉(Transition)

a) 一般情況一個活動中可以指定一個或多個Transition

i. 開始活動(Start)中只能有一個Transition

ii. 結束活動(End)中沒有Transition

iii. 其他活動中有一條或多條Transition

b) 如果Transition只有一個,則可以不指定名稱(名稱是null);如果有多個,則要分別指定唯一的名稱。

2.活動(Activity)

a) 流轉控制活動(預定義活動)

i. start開始活動

代表流程的開始邊界,一個流程有且只能有一個Start活動。開始活動只能指定一個Transition。在流程實例啓動後,會 自動的使用這個唯一的Transition離開開始活動,到一下個活動。

ii. end/end-error/end-cancel(結束活動)

代表流程的結束邊界,可以有多個,也可以沒有。如果有多個,則到達任一個結束活動,整個流程就都結束了;如果沒 有,則到達最後那個沒有Transition的活動,流程就結束了。

iii. state狀態活動

作用:等待。可以使用signal使其結束等待,並向後執行一步。

iv. task任務活動

-->個人任務的分配

1. 使用流程變量:assignee="#{manager}"

2. AssignmentHandlerassignable.setAssignee(userId); // 指定當前任務的辦理人(分配任務)

a) 需要在.jbdl.xml<task>元素中寫

[html] view plain copy
  1. <assignment-handler class="cn.grace.AssignmentHandlerImpl"/>  

b) 指定的AssignmentHandlerImpl類要實現AssignmentHandler接口

c) 在AssignmentHandlerImpl類中可以使用assignable.setAssignee(userId),分配個人任務。

3. TaskService.assignTask(taskId, userId)// 把指定的任務分配給指定的人

processEngine.getTaskService().assignTask(taskId, userId);

-->組任務的分配

1.  使用流程變量:assignee="#{userIdsString}" // 要是String型的變量,多個候選人之前用','隔開

2. AssignmentHandlerassignable.addCandidateUser(userId);// 添加組任務的候選人

a) 需要在.jbdl.xml<task>元素中寫

[html] view plain copy
  1. <assignment-handler class="cn.grace.GroupTaskAssignmentHandlerImpl"/>  

b) 指定的AssignmentHandlerImpl類要實現AssignmentHandler接口

c) 在AssignmentHandlerImpl類中可以使用assignable.addCandidateUser(userId),添加組任務候選人。

3. TaskService.addTaskParticipatingUser(taskId,userId,Participation.CANDIDATE);//添加組任務的候選人 

v. Decision判斷活動

1. 使用expression,如:expr="#{'to state2'}"

2. 使用Handler在Handler Class裏配置指定的DecisionHandlerImpl類的路徑

DecisionHandlerImpl.java

[java] view plain copy
  1. public class DecisionHandlerImpl implements DecisionHandler {  
  2.   
  3.     // 計算離開當前節點用的Transition的名稱並返回  
  4.     @Override  
  5.     public String decide(OpenExecution execution) {  
  6.         System.out.println("DecisionHandlerImpl.decide()");  
  7.         // 獲取業務數據  
  8.         Integer days = (Integer) execution.getVariable("請假天數");  
  9.         // 選擇Transition  
  10.         if (days > 7) {  
  11.             return "to 總經理審批";  
  12.         } else {  
  13.             return "to end1";  
  14.         }  
  15.     }  
  16. }  

ProcessTest.java

[java] view plain copy
  1. @Test  
  2. public void test() {  
  3.     // 1,部署流程定義  
  4.     InputStream in = this.getClass().getResourceAsStream("test.jpdl.xml"); 
  5.     processEngine.getRepositoryService()//  
  6.             .createDeployment()//  
  7.             .addResourceFromInputStream("test.jpdl.xml", in)//  
  8.             .deploy();  
  9.   
  10.     // 2,啓動流程實例  
  11.     Map<String, Object> variables = new HashMap<String, Object>();  
  12.     // variables.put("請假天數", 10);啓動流程實例後,進行到to 總經理審批環節。  
  13.     variables.put("請假天數"3);//啓動流程實例後,進行到to end1環節。  
  14.     ProcessInstance pi = processEngine.getExecutionService()
  15.                                 .startProcessInstanceByKey("test", variables);  
  16. }  

此時,如果variables.put("請假天數", 3);啓動流程實例後,進行到to end1環節。

此時,如果variables.put("請假天數", 10);啓動流程實例後,進行到to 總經理審批環節。

3. 如果同時配置了expressionHandler,則expression有效,忽略Handler

vi. forkjoin分支/聚合活動

[java] view plain copy
  1. public class ProcessTest {  
  2.   
  3.     private ProcessEngine processEngine = Configuration.getProcessEngine();  
  4.   
  5.     @Test  
  6.     public void test() {  
  7.         // 1,部署流程定義  
  8.         InputStream in = this.getClass().getResourceAsStream("test.jpdl.xml"); 
  9.         processEngine.getRepositoryService()//  
  10.                 .createDeployment()//  
  11.                 .addResourceFromInputStream("test.jpdl.xml", in)//  
  12.                 .deploy();  
  13.   
  14.         // 2,啓動流程實例  
  15.         ProcessInstance pi = processEngine.getExecutionService()
  16.                                         .startProcessInstanceByKey("test");  
  17.         System.out.println("processInstanceId = " + pi.getId());  
  18.         System.out.println("當前正在執行的活動:" + pi.findActiveActivityNames());  
  19.     }  
  20. }  

輸出結果爲:

processInstanceId = test.330007

當前正在執行的活動:[匯款, 發貨]

可以看出,匯款和發貨同時執行中。並且,只有當2條路線都到join活動,流程纔會繼續往後執行。

b) 自定義活動(custom)

i. 在<custom>元素中指定class屬性爲指定的類ExternalActivityBehaviourImpl

ii. 這個類要實現ExternalActivityBehaviour接口,其中有兩個方法:

1. execute(ActivityExecution):節點的功能代碼

2. signal(ActivityExecution, String, Map):在當前節點等待時,外部發信號時的行爲

3. 在execute()方法中,可以調用以下方法對流程進行控制

a) ActivityExecution.waitForSignal():在當前節點等待。

b) ActivityExecution.takeDefaultTransition():使用默認的Transition離開,當前節點中定義的第一個爲默認的。

c) ActivityExecution.take(String transitionName):使用指定的Transition離開

d) ActivityExecution.end():結束流程實例

4. 也可以實現 ExternalActivityBehaviour 接口,只有一個方法 execute(ActivityExecution),這樣就不能等待,否則 signal 時會有類轉換異常。

[java] view plain copy
  1. public class ExternalActivityBehaviourImpl implements ExternalActivityBehaviour {  
  2.   
  3.     // 到達這個活動時執行的方法  
  4.     @Override  
  5.     public void execute(ActivityExecution execution) throws Exception {  
  6.         System.out.println("已發送信息.");//此處寫自己要執行的事件  
  7.   
  8.         // 默認是執行完代碼後離開當前活動,不會執行signal方法,也可以寫如下代碼  
  9.         // execution.takeDefaultTransition(); // 離開當前活動  
  10.   
  11.         // // 使用指定名稱的Transition離開當前活動  
  12.         // execution.take(transitionName);  
  13.   
  14.         // 執行完後不要離開,而是要等待外部調用signal()方法時才離開  
  15.         execution.waitForSignal();  
  16.     }  
  17.   
  18.     // 調用signal()方法離開當前節點前執行的方法(如果在execute()中直接離開當前節點了,
  19.     // 這個方法就不會被執行)  
  20.     @Override  
  21.     public void signal(ActivityExecution execution, String signalName, Map<String, ?> parameters) throws Exception {  
  22.         System.out.println("ExternalActivityBehaviourImpl.signal()");  
  23.     }  
  24. }  

3.事件

a) 在根元素中,或在節點元素中,使用<on event="">元素指定事件,其中event屬性代表事件的類型。

b) 在<on>中用子元素<event-listener class="EventListenerImpl" />,指定處理的類,要求指定的類要實現 EventListener 接口

c) 事件類型:

i. <on>元素放在根元素(<process>)中,可以指定eventstartend,表示流程的開始與結束。

ii. <on>元素放在節點元素中,可以指定eventstartend,表示節點的進入與離開

iii. 在Start節點中只有end事件,在End節點中只有start事件。

iv. 在<transition>元素中直接寫<event-listener class="">,就是配置事件。(因爲在這裏只有一個事件,所以不用寫on與類型)

v. 在<task>元素中還可以配置assign事件,是在分配任務時觸發的。

 

[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.   
  3. <process name="test" xmlns="http://jbpm.org/4.4/jpdl">  
  4.   
  5.     <!-- 流程實例的啓動事件 -->  
  6.     <on event="start">  
  7.         <event-listener class="cn.grace.EventListenerImpl"></event-listener>  
  8.     </on>  
  9.     <!-- 流程實例的結束事件 -->  
  10.     <on event="end">  
  11.         <event-listener class="cn.grace.EventListenerImpl"></event-listener>  
  12.     </on>  
  13.   
  14.     <start name="start1" g="86,69,7,1">  
  15.         <!-- 開始活動中只有離開活動的事件 -->  
  16.         <on event="end">  
  17.             <event-listener class="cn.grace.EventListenerImpl"></event-listener>  
  18.         </on>  
  19.         <transition name="to task1" to="task1" g="-53,-17" />  
  20.     </start>  
  21.   
  22.     <task name="task1" g="61,171,92,52" assignee="張三">  
  23.         <!-- 進入活動的事件 -->  
  24.         <on event="start">  
  25.             <event-listener class="cn.grace.EventListenerImpl"></event-listener>  
  26.         </on>  
  27.         <!--離開活動的事件 -->  
  28.         <on event="end">  
  29.             <event-listener class="cn.grace.EventListenerImpl"></event-listener>  
  30.         </on>  
  31.         <transition name="to end1" to="end1" g="-47,-17" />  
  32.     </task>  
  33.   
  34.     <end name="end1" g="86,272,48,48">  
  35.         <!-- 結束活動中只有進入活動的事件 -->  
  36.         <on event="start">  
  37.             <event-listener class="cn.grace.EventListenerImpl"></event-listener>  
  38.         </on>  
  39.     </end>  
  40. </process>  

根據上述.jpdl.xml和對應的.png圖,啓動流程實例會執行3次 EventListenerImpl 事件,結束流程實例也會執行3次 EventListenerImpl 事件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章