JBPM4

1、 JBPM4的結構特色
1.嵌入式的工做流引擎,不須要依賴特定的中間件或服務器,減小了硬件和軟件的綁定,徹底支持嵌入式應用的
  業務流程開發框架,能夠在事務處理、數據持久化等各個方面與業務應用程序進行靈活的集成。
2.可拔插的體系架構,採用模塊化的架構設計,採用了IOC的設計理念,各模塊之間能夠比較方便地解除耦合或
  替換不一樣的實現,例如持久化、事務處理、身份認證、日誌服務等,都由可選模塊實現。
3. 易擴展的流程語言。 html


2、 Jbpm4的安裝配置
1.下載地址:http://sourceforge.net/projects/jbpm/
2.解壓資源包,進入目錄install,在控制檯下運行腳本:ant demo.setup.tomcat。會執行以下操做:
   1)下載安裝Tomcat.
   2)安裝HSQLDB,並建立數據表結構。
   3)啓動Tomcat,建立examples.bar業務流程歸檔,併發布到JBPM數據庫中,初始化相關用戶和組。
   4)下載安裝Eclipse,並啓動Eclipse.
   5)安裝JBPM Web控制檯。
   6)安裝Signavio Web 設計器。
3.在Eclipse中安裝GPD插件,利用eclipse的軟件升級指定GPD安裝文件,文件爲
  下載資源包中install/src/gpd/jbpm-gpd-site.zip。
4.添加jbdl4 Schema檢驗,在eclipse中配置schema,指定jbpm4安裝目錄下src文件夾中jpdl.xsd文件。
  步驟爲:Window->Preferences->XML->XML CataLog->Add->File System。 java


3、 Jbpm流程API
1.流程相關概念
  流程定義:對業務過程步驟的描述,表現爲若干"活動"節點經過"轉移"線條串聯。
  流程實例:表示流程定義在運行時特有的執行例程。
  流程執行:流程實例在其生命週期中,指向當前執行活動的指針。 sql


2.流程的6個Service API,可經過流程引擎對象的接口方法獲取。
   ProcessEngine processEngine = Configuration.getProcessEngine(); 
   1)RepositoryService,流程資源服務的接口。提供對流程定義的部署、查詢、刪除等操做。
   2)ExecutionService,流程執行服務的接口。提供啓動流程實例、「執行」推動、設置流程變量等操做。
   3)TaskService,人工任務服務的接口。提供對任務的建立、提交、查詢、保存、刪除等操做。
   4)HistoryService,流程歷史服務的接口。提供對流程歷史庫中歷史流程實例、歷史活動實例等記錄的查詢操做。
   5)IdentityService,身份認證服務的接口。提供對流程用戶、用戶組以及組成員關係的相關服務。
   6)ManagementService,流程管理控制服務的接口。提供異步工做(Job)相關的執行和查詢操做。 數據庫

 

3.流程的佈署和刪除
   1)流程的佈署   tomcat

Java代碼 複製代碼  收藏代碼
  1. String deploymentId = repositoryService.createDeployment()   
  2. .addResourceFromClasspath("org/jbpm/examples/task/assignee/process.jpdl.xml") .deploy();  
  3.  // 可屢次調用addResourceFromClasspath方法部署其它流程定義  
String deploymentId = repositoryService.createDeployment() 
.addResourceFromClasspath("org/jbpm/examples/task/assignee/process.jpdl.xml") .deploy();
 // 可屢次調用addResourceFromClasspath方法部署其它流程定義

  

  2)流程的刪除 安全

Java代碼 複製代碼  收藏代碼
  1. repositoryService.deleteDeploymentCascade(deploymentId);   
repositoryService.deleteDeploymentCascade(deploymentId);

  

 4.發起流程實例
  1)流程Key  服務器

Java代碼 複製代碼  收藏代碼
  1. ProcessInstance processInstance = executionService.startProcessInstanceByKey("ICL");  
ProcessInstance processInstance = executionService.startProcessInstanceByKey("ICL");

 

  2)流程Id session

Java代碼 複製代碼  收藏代碼
  1. ProcessInstance processInstance = executionService.startProcessInstanceByKey("ICL-1");  
ProcessInstance processInstance = executionService.startProcessInstanceByKey("ICL-1");

 

  3)根據業務鍵指定流程實例ID 架構

Java代碼 複製代碼  收藏代碼
  1. ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL",「Order09278」);  
ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL",「Order09278」);

 

  4)傳入流程變量 併發

Java代碼 複製代碼  收藏代碼
  1. ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL", variablesMap);  
ProcessInstance processInstance = executionService.startProcessInstanceByKey ("ICL", variablesMap);

  

5.喚醒等待狀態的執行

Java代碼 複製代碼  收藏代碼
  1. executionService.signalExecutionById(executionId);  
executionService.signalExecutionById(executionId);

  

6.得到用戶的任務列表

Java代碼 複製代碼  收藏代碼
  1. List<Task> taskList = taskService.findPersonalTasks("johndoe");  
List<Task> taskList = taskService.findPersonalTasks("johndoe");

 

 

7.任務的完成提交
  1)將用戶界面的任務表單內容存入任務

Java代碼 複製代碼  收藏代碼
  1. taskService.setVariables(taskId,variablesMap);  
taskService.setVariables(taskId,variablesMap);

 

   2)根據任務ID完成任務

Java代碼 複製代碼  收藏代碼
  1. taskService.completeTask(taskId);  
taskService.completeTask(taskId);

 

   3)根據任務ID完成任務,同時設入變量

Java代碼 複製代碼  收藏代碼
  1. taskService.completeTask(taskId, variablesMap);  
taskService.completeTask(taskId, variablesMap);

 

   4)根據任務ID完成任務,並指定下一步的轉移路徑

Java代碼 複製代碼  收藏代碼
  1. taskService.completeTask(taskId, outcome);  
taskService.completeTask(taskId, outcome);

 

 

8.流程歷史實例獲取
  1)得到流程定義的全部歷史流程實例,返回結果按開始時間排序 

Java代碼 複製代碼  收藏代碼
  1. List<HistoryProcessInstance> historyProcessInstances = historyService  
  2.  .createHistoryProcessInstanceQuery() .processDefinitionId("ICL-1")   
  3. .orderAsc(HistoryProcessInstanceQuery.PROPERTY_STARTTIME).list();  
List<HistoryProcessInstance> historyProcessInstances = historyService
 .createHistoryProcessInstanceQuery() .processDefinitionId("ICL-1") 
.orderAsc(HistoryProcessInstanceQuery.PROPERTY_STARTTIME).list();

 

   2)得到流程的歷史活動實例,可指定具體名稱的活動實例 

Java代碼 複製代碼  收藏代碼
  1. List<HistoryActivityInstance> historyActivityInstances = historyService  
  2.  .createHistoryActivityInstanceQuery().processDefinitionId("ICL-1").list();  
List<HistoryActivityInstance> historyActivityInstances = historyService
 .createHistoryActivityInstanceQuery().processDefinitionId("ICL-1").list();

  

 9.查詢結果分頁
  1)流程實例查詢分頁

Java代碼 複製代碼  收藏代碼
  1. List<ProcessInstance> results = executionService.createProcessInstanceQuery()  
  2.  .processDefinitionId("ICL-1").page(050).list();  
List<ProcessInstance> results = executionService.createProcessInstanceQuery()
 .processDefinitionId("ICL-1").page(0, 50).list();

 

   2)流程任務查詢的分頁

Java代碼 複製代碼  收藏代碼
  1. List<Task> myTasks = taskService.createTaskQuery()  
  2. .processInstanceId("ICL.Order09278") .assignee("Alex")  
  3. .page(1020).list();  
List<Task> myTasks = taskService.createTaskQuery()
.processInstanceId("ICL.Order09278") .assignee("Alex")
.page(10, 20).list();

  

4、 流程定義

  

1.流程控制活動
  1)start,開始活動
  2)state,狀態活動
  3)decision,判斷活動
  4)fork,分支活動
  5)join,聚合活動
  6)end,結束活動

 

 


2.State活動

Jpdl定義:

Xml代碼 複製代碼  收藏代碼
  1. <state name="wait for response">   
  2. <transition name="accept" to="submit document" />   
  3. <transition name="reject" to="try again"/>  
  4.  </state>  
  5.  <state name="submit document"/>   
  6. <state name="try again"/>  
<state name="wait for response"> 
<transition name="accept" to="submit document" /> 
<transition name="reject" to="try again"/>
 </state>
 <state name="submit document"/> 
<state name="try again"/>

  

// 獲取流程實例ID

Java代碼 複製代碼  收藏代碼
  1. String executionId = processInstance.findActiveExecutionIn("wait for response").getId();  
  2.  // 觸發accept流向   
  3. processInstance = executionService.signalExecutionById(executionId, "accept");   
String executionId = processInstance.findActiveExecutionIn("wait for response").getId();
 // 觸發accept流向 
processInstance = executionService.signalExecutionById(executionId, "accept");

  

3.decision活動
   1)使用condition元素判斷decision活動 

Jpdl:

Xml代碼 複製代碼  收藏代碼
  1. <!-- decision 中會運行並判斷每個transition 裏的判斷條件。   
  2. 當遇到一個嵌套條件是true 或者沒有設置判斷條件的轉移,  
  3. 那麼轉移就會被運行 -->   
  4. <decision name="evaluate document" >   
  5. <transition to="submit document" >   
  6. <condition expr="#{content==’good’}" />   
  7. </transition>   
  8. <transition to="try again">   
  9. <condition expr="#{content==’bad’}" />   
  10. </transition>   
  11. <transition to="give up"/>   
  12. </decision>   
  13. <state name="submit document"/>   
  14. <state name="try again"/>   
  15. <state name="give up"/>  
<!-- decision 中會運行並判斷每個transition 裏的判斷條件。 
當遇到一個嵌套條件是true 或者沒有設置判斷條件的轉移,
那麼轉移就會被運行 --> 
<decision name="evaluate document" > 
<transition to="submit document" > 
<condition expr="#{content==’good’}" /> 
</transition> 
<transition to="try again"> 
<condition expr="#{content==’bad’}" /> 
</transition> 
<transition to="give up"/> 
</decision> 
<state name="submit document"/> 
<state name="try again"/> 
<state name="give up"/>

  

Java代碼 複製代碼  收藏代碼
  1. Map<String, Object> variables = new HashMap<String, Object>(); variables.put("content""good");  
  2.  // 因爲傳入變量爲good,流向了submit document活動   
  3. ProcessInstance processInstance = executionService  
  4.  .startProcessInstanceByKey("DecisionConditions", variables);   
Map<String, Object> variables = new HashMap<String, Object>(); variables.put("content", "good");
 // 因爲傳入變量爲good,流向了submit document活動 
ProcessInstance processInstance = executionService
 .startProcessInstanceByKey("DecisionConditions", variables);

 

  2)使用decision的expr屬性判斷decision活動。

Xml代碼 複製代碼  收藏代碼
  1. <!--可選擇的狀態結點,expr指定將被運行的指定腳本 -->  
  2.  <decision name="evaluate document" expr="#{content}" >  
  3.  <transition name="good" to="submit document"/>  
  4.  <transition name="bad" to="try again"/>   
  5. <transition name="ugly" to="give up"/>   
  6. </decision>  
<!--可選擇的狀態結點,expr指定將被運行的指定腳本 -->
 <decision name="evaluate document" expr="#{content}" >
 <transition name="good" to="submit document"/>
 <transition name="bad" to="try again"/> 
<transition name="ugly" to="give up"/> 
</decision>

 

 流程執行操做同上面condition元素的操做。


  3)使用decision活動的handler元素判斷decision活動。

Xml代碼 複製代碼  收藏代碼
  1. <!-- decision handler決定處理器繼承了DecisionHandler 接口的java 類,   
  2. 決定處理器負責選擇向外轉移 -->   
  3. <decision name="evaluate document" g="96,102,48,48">   
  4. <handler class="org.jbpm.examples.decision.handler.ContentEvaluation"/>  
  5.  <transition name="good" to="submit document"/>   
  6. <transition name="bad" to="try again"/>   
  7. <transition name="ugly" to="give up"/>   
  8. </decision>  
<!-- decision handler決定處理器繼承了DecisionHandler 接口的java 類, 
決定處理器負責選擇向外轉移 --> 
<decision name="evaluate document" g="96,102,48,48"> 
<handler class="org.jbpm.examples.decision.handler.ContentEvaluation"/>
 <transition name="good" to="submit document"/> 
<transition name="bad" to="try again"/> 
<transition name="ugly" to="give up"/> 
</decision>

    ContentEvaluation類以下:

Java代碼 複製代碼  收藏代碼
  1. public class ContentEvaluation implements DecisionHandler {   
  2. public String decide(OpenExecution execution) {  
  3.  String content = (String) execution.getVariable("content");   
  4. return content; }   
  5. }  
public class ContentEvaluation implements DecisionHandler { 
public String decide(OpenExecution execution) {
 String content = (String) execution.getVariable("content"); 
return content; } 
}

 

 流程執行操做同上面condition元素的操做。 

   Decision活動和state活動均可以實現條件流轉,但兩者的主要區別以下:
     若是decision活動定義的流轉條件沒有任何一個獲得知足,那麼流程實例將沒法進行下去,拋出異常。
     而state活動在沒有條件知足的條件下將流向state活動定義的第一條流出轉移,從而往下流轉。
     所以decision活動具備更加嚴格的條件判斷特性。

 

4.fork-join活動

Jpdl:

Xml代碼 複製代碼  收藏代碼
  1. <!-- fork活動在此產生3個並行分支,這些流程分支能夠同步執行。 -->  
  2.  <fork name="fork">   
  3. <transition to="send invoice"/>   
  4. <transition to="load truck"/>   
  5. <transition to="print shipping documents"/>   
  6. </fork>   
  7. <state name="send invoice">   
  8. <transition to="final join"/>   
  9. </state>   
  10. <state name="load truck">   
  11. <transition to="shipping join"/>   
  12. </state>   
  13. <state name="print shipping documents">  
  14.  <transition g="378,213:" to="shipping join"/>  
  15.  </state>   
  16. <!--join活動爲流程的合併,load truck和print shipping documents在此聚合 -->  
  17.  <join name="shipping join">  
  18.  <transition to="drive truck to destination"/>  
  19.  </join>  
  20.  <state name="drive truck to destination">   
  21. <transition to="final join"/>   
  22. </state>  
  23.  <!-- drive truck to destination活動和send invoice活動在此完成最終的聚合 -->   
  24. <join name="final join">  
  25.  <transition to="end"/>  
  26.  </join>  
<!-- fork活動在此產生3個並行分支,這些流程分支能夠同步執行。 -->
 <fork name="fork"> 
<transition to="send invoice"/> 
<transition to="load truck"/> 
<transition to="print shipping documents"/> 
</fork> 
<state name="send invoice"> 
<transition to="final join"/> 
</state> 
<state name="load truck"> 
<transition to="shipping join"/> 
</state> 
<state name="print shipping documents">
 <transition g="378,213:" to="shipping join"/>
 </state> 
<!--join活動爲流程的合併,load truck和print shipping documents在此聚合 -->
 <join name="shipping join">
 <transition to="drive truck to destination"/>
 </join>
 <state name="drive truck to destination"> 
<transition to="final join"/> 
</state>
 <!-- drive truck to destination活動和send invoice活動在此完成最終的聚合 --> 
<join name="final join">
 <transition to="end"/>
 </join>

 

Fork活動可使流程在一條主幹上出現並行的分支,join活動則可使流程的並行分支聚合成一條主幹。
部分執行測試代碼以下:

Java代碼 複製代碼  收藏代碼
  1. ProcessInstance processInstance = executionService  
  2. .startProcessInstanceByKey("ConcurrencyGraphBased");  
  3. // 當前活動爲產生的3個分支活動  
  4. assertNotNull(processInstance.findActiveExecutionIn("send invoice"));  
  5. assertNotNull(processInstance.findActiveExecutionIn("load truck"));  
  6. assertNotNull(processInstance.findActiveExecutionIn("print shipping documents"));  
  7. // 執行send invoice活動,流程會在聚合活動上等待其它分支的到來  
  8. String sendInvoiceExecutionId = processInstance  
  9.     .findActiveExecutionIn("send invoice").getId();  
  10. processInstance = executionService.signalExecutionById(sendInvoiceExecutionId); 


 5.task人工任務活動
   1)、使用task活動的assignee屬性進行任務分配

 

 

Xml代碼 複製代碼  收藏代碼
  1. <task name="review" assignee="#{order.owner}">   
  2. <transition to="wait" />   
  3. </task>  
<task name="review" assignee="#{order.owner}"> 
<transition to="wait" /> 
</task>

 

   Assignee屬性默認會被做爲EL表達式來執行,任務被分配給#{order.owner}。

  

Java代碼 複製代碼  收藏代碼
  1. Map<String, Object> variables = new HashMap<String, Object>();   
  2. variables.put("order"new Order("johndoe"));   
  3. //當一個新流程實例會被建立, 把order 做爲一個流程變量分配給它   
  4. ProcessInstance processInstance = executionService   
  5. .startProcessInstanceByKey("TaskAssignee", variables);   
  6. //獲取johndoe的任務列表   
  7. List<Task> taskList = taskService.findPersonalTasks("johndoe");   
Map<String, Object> variables = new HashMap<String, Object>(); 
variables.put("order", new Order("johndoe")); 
//當一個新流程實例會被建立, 把order 做爲一個流程變量分配給它 
ProcessInstance processInstance = executionService 
.startProcessInstanceByKey("TaskAssignee", variables); 
//獲取johndoe的任務列表 
List<Task> taskList = taskService.findPersonalTasks("johndoe");

 

   2)任務侯選者(candidate-groups,candidate-users)
      candidate-groups:一個使用逗號分隔的組id 列表,全部組內的用戶將會成爲這個任務的 候選人。
      candidate-users: 一個使用逗號分隔的用戶id 列表,全部的用戶將會成爲這個任務的候選人。

 

Xml代碼 複製代碼  收藏代碼
  1. <task name="review" candidate-groups="sales-dept>   
  2. <transition to="wait" />  
  3.  </task>  
<task name="review" candidate-groups="sales-dept> 
<transition to="wait" />
 </task>

 

   部分事例代碼以下:

 

Java代碼 複製代碼  收藏代碼
  1. // 建立sales-dept組   
  2. dept = identityService.createGroup("sales-dept");   
  3. // 建立用戶johndoe,並加入sales-dept組  
  4.  identityService.createUser("johndoe""John""Doe");   
  5. identityService.createMembership("johndoe", dept, "developer");  
  6.  // 建立用戶joesmoe,並加入sales-dept組   
  7. identityService.createUser("joesmoe""Joe""Smoe");   
  8. identityService.createMembership("joesmoe", dept, "developer");   
  9. //在流程建立後, 任務會出如今johndoe 和joesmoe 用戶的分組任務列表中   
  10. List<Task> taskList = taskService.findGroupTasks("joesmoe");   
  11. List<Task> taskList = taskService.findGroupTasks("johndoe");   
  12. //候選人在處理任務以前,必須先接受任務,接受任務後,就會由任務的候選者變成   
  13. // 任務的分配者。同時,此任務會從全部候選者的任務列表中消失。   
  14. taskService.takeTask(task.getId(), "johndoe");  
// 建立sales-dept組 
dept = identityService.createGroup("sales-dept"); 
// 建立用戶johndoe,並加入sales-dept組
 identityService.createUser("johndoe", "John", "Doe"); 
identityService.createMembership("johndoe", dept, "developer");
 // 建立用戶joesmoe,並加入sales-dept組 
identityService.createUser("joesmoe", "Joe", "Smoe"); 
identityService.createMembership("joesmoe", dept, "developer"); 
//在流程建立後, 任務會出如今johndoe 和joesmoe 用戶的分組任務列表中 
List<Task> taskList = taskService.findGroupTasks("joesmoe"); 
List<Task> taskList = taskService.findGroupTasks("johndoe"); 
//候選人在處理任務以前,必須先接受任務,接受任務後,就會由任務的候選者變成 
// 任務的分配者。同時,此任務會從全部候選者的任務列表中消失。 
taskService.takeTask(task.getId(), "johndoe");

 

 

   3)任務分配處理器(AssignmentHandler)

 

Xml代碼 複製代碼  收藏代碼
  1. <task name="review">  
  2.  <!--assignment-handler 是任務元素的一個子元素,它指定用戶代碼對象 -->   
  3. <assignment-handler   
  4. class="org.jbpm.examples.task.assignmenthandler.AssignTask">   
  5. <field name="assignee">   
  6. <string value="johndoe" />   
  7. </field>   
  8. </assignment-handler>   
  9. <transition to="wait" />   
  10. </task>  
<task name="review">
 <!--assignment-handler 是任務元素的一個子元素,它指定用戶代碼對象 --> 
<assignment-handler 
class="org.jbpm.examples.task.assignmenthandler.AssignTask"> 
<field name="assignee"> 
<string value="johndoe" /> 
</field> 
</assignment-handler> 
<transition to="wait" /> 
</task>

 

   AssignTask類必須實現AssignmentHandler類,代碼以下:

  

Java代碼 複製代碼  收藏代碼
  1. //默認AssignmentHandler 實現可使用使用流程變量   
  2. public class AssignTask implements AssignmentHandler {   
  3.      String assignee;  
  4.      public void assign(Assignable assignable, OpenExecution execution) {   
  5.        assignable.setAssignee(assignee);  
  6.      }  
  7.  }  
//默認AssignmentHandler 實現可使用使用流程變量 
public class AssignTask implements AssignmentHandler { 
     String assignee;
     public void assign(Assignable assignable, OpenExecution execution) { 
       assignable.setAssignee(assignee);
     }
 }

  

   4)任務泳道(Swimlanes)
     泳道能夠理解爲流程定義的」全局用戶組」,也能夠被看成一個流程規則。流程定義中的多個任務須要被分配或候選給
      同一個羣用戶,統一將這個「同一羣用戶」定義爲「一個泳道」。

 

Xml代碼 複製代碼  收藏代碼
  1. <!—-在這裏定義泳道,屬全局用戶組-->   
  2. <swimlane name="sales representative" candidate-groups="sales-dept" />   
  3. <!-- swimlane 引用一個定義在流程中的泳道 -->   
  4. <task name="enter order data" swimlane="sales representative">   
  5. <transition to="calculate quote"/>  
  6.  </task>   
  7. <task name="calculate quote" swimlane="sales representative">   
  8. </task>  
  9.   
  10.    
<!—-在這裏定義泳道,屬全局用戶組--> 
<swimlane name="sales representative" candidate-groups="sales-dept" /> 
<!-- swimlane 引用一個定義在流程中的泳道 --> 
<task name="enter order data" swimlane="sales representative"> 
<transition to="calculate quote"/>
 </task> 
<task name="calculate quote" swimlane="sales representative"> 
</task>

 

   泳道中的用戶組中的用戶在接受任務後成爲任務的分配者,同時泳道也會發生變化,接收任務者在流程實例中會被固化爲分配者。

Java代碼 複製代碼  收藏代碼
  1. taskService.takeTask(taskId, "johndoe");  
  2.  assertEquals(0, taskService.findGroupTasks("johndoe").size());   
  3. taskList = taskService.findPersonalTasks("johndoe");   
  4. assertEquals(1, taskList.size());   
taskService.takeTask(taskId, "johndoe");
 assertEquals(0, taskService.findGroupTasks("johndoe").size()); 
taskList = taskService.findPersonalTasks("johndoe"); 
assertEquals(1, taskList.size());

  

6.子流程活動(sub-process)


   1)父子流程間的數據交換(parameter-in,parameter-out)
       父流程SubProcessDocument定義JPDL:

Xml代碼 複製代碼  收藏代碼
  1. <process name="SubProcessDocument" xmlns="http://jbpm.org/4.4/jpdl">   
  2. <start>   
  3. <transition to="review" />   
  4. </start>   
  5. <sub-process name="review" sub-process-key="SubProcessReview">   
  6. <parameter-in var="document" subvar="document" />   
  7. <parameter-out var="reviewResult" subvar="result" />   
  8. <transition to="wait" />  
  9.  </sub-process>   
  10. <state name="wait"/>   
  11. </process>  
<process name="SubProcessDocument" xmlns="http://jbpm.org/4.4/jpdl"> 
<start> 
<transition to="review" /> 
</start> 
<sub-process name="review" sub-process-key="SubProcessReview"> 
<parameter-in var="document" subvar="document" /> 
<parameter-out var="reviewResult" subvar="result" /> 
<transition to="wait" />
 </sub-process> 
<state name="wait"/> 
</process>

 

    子流程SubProcessReview定義JPDL:

Xml代碼 複製代碼  收藏代碼
  1. <process name="SubProcessReview" xmlns="http://jbpm.org/4.4/jpdl">   
  2. <start>  
  3.  <transition to="get approval"/>   
  4. </start>  
  5.  <task name="get approval" assignee="johndoe">   
  6. <transition to="end"/>  
  7.  </task>   
  8. <end name="end"/>   
  9. </process>  
  10.    
<process name="SubProcessReview" xmlns="http://jbpm.org/4.4/jpdl"> 
<start>
 <transition to="get approval"/> 
</start>
 <task name="get approval" assignee="johndoe"> 
<transition to="end"/>
 </task> 
<end name="end"/> 
</process>
 

   流程變量是父子流程用來溝通的紐帶。父流程在子流程啓動時將本身的「父流程變量」輸入子流程,
   反之,子流程在結束時能夠將本身的「子流程變量」返回父流程,從而實現父子流程間的數據交換。
    部分事例代碼以下:

Java代碼 複製代碼  收藏代碼
  1. // 分別部署子流程跟父流程   
  2. String subProcessReviewDeploymentId = repositoryService.createDeployment()   
  3. .addResourceFromClasspath("org/jbpm/examples/subprocess/variables/SubProcessReview.jpdl.xml")  
  4.  .deploy();   
  5. String subProcessDocumentDeploymentId = repositoryService.createDeployment()   
  6. .addResourceFromClasspath("org/jbpm/examples/subprocess/variables/SubProcessDocument.jpdl.xml")   
  7. .deploy();   
  8. Map<String, Object> variables = new HashMap<String, Object>();   
  9. variables.put("document""This document describes how we can make more money...");   
  10. //設置父流程的變量document ProcessInstance processInstance = executionService  
  11.  .startProcessInstanceByKey("SubProcessDocument", variables);   
  12. List<Task> taskList = taskService.findPersonalTasks("johndoe"); Task task = taskList.get(0);  
  13.  // 父流程的變量document會被傳入子流程,此處爲獲取子流程的變量document   
  14. String document = (String) taskService  
  15. .getVariable(task.getId(), "document");   
  16. variables = new HashMap<String, Object>();   
  17. variables.put("result""accept");   
  18. // 在子流程中設置流程變量result,該流程變量可在父流程中獲取 taskService.setVariables(task.getId(), variables);  
  19.  taskService.completeTask(task.getId());  
  20.  processInstance = executionService.findProcessInstanceById(processInstance.getId());   
  21. // 在父流程中獲取子流程中設置的流程變量result,名稱爲reviewResult   
  22. String result = (String) executionService  
  23. .getVariable(processInstance.getId(), "reviewResult");   
  24. assertEquals("accept", result);  
// 分別部署子流程跟父流程 
String subProcessReviewDeploymentId = repositoryService.createDeployment() 
.addResourceFromClasspath("org/jbpm/examples/subprocess/variables/SubProcessReview.jpdl.xml")
 .deploy(); 
String subProcessDocumentDeploymentId = repositoryService.createDeployment() 
.addResourceFromClasspath("org/jbpm/examples/subprocess/variables/SubProcessDocument.jpdl.xml") 
.deploy(); 
Map<String, Object> variables = new HashMap<String, Object>(); 
variables.put("document", "This document describes how we can make more money..."); 
//設置父流程的變量document ProcessInstance processInstance = executionService
 .startProcessInstanceByKey("SubProcessDocument", variables); 
List<Task> taskList = taskService.findPersonalTasks("johndoe"); Task task = taskList.get(0);
 // 父流程的變量document會被傳入子流程,此處爲獲取子流程的變量document 
String document = (String) taskService
.getVariable(task.getId(), "document"); 
variables = new HashMap<String, Object>(); 
variables.put("result", "accept"); 
// 在子流程中設置流程變量result,該流程變量可在父流程中獲取 taskService.setVariables(task.getId(), variables);
 taskService.completeTask(task.getId());
 processInstance = executionService.findProcessInstanceById(processInstance.getId()); 
// 在父流程中獲取子流程中設置的流程變量result,名稱爲reviewResult 
String result = (String) executionService
.getVariable(processInstance.getId(), "reviewResult"); 
assertEquals("accept", result);

 

 

   2)經過outcome屬性影響父流程的流程轉移
      父流程SubProcessReview定義:

 

Xml代碼 複製代碼  收藏代碼
  1. <!--父流程中的outcome屬性引用名稱爲result的子流程變量  
  2.  <sub-process name="review" sub-process-key="SubProcessReview" outcome="#{result}">  
  3.  <!—若是result值等於ok,則流向此轉移-->   
  4. <transition name="ok" to="next step" />   
  5. <transition name="nok" to="update" />   
  6. <transition name="reject" to="close" />   
  7. </sub-process>  
<!--父流程中的outcome屬性引用名稱爲result的子流程變量
 <sub-process name="review" sub-process-key="SubProcessReview" outcome="#{result}">
 <!—若是result值等於ok,則流向此轉移--> 
<transition name="ok" to="next step" /> 
<transition name="nok" to="update" /> 
<transition name="reject" to="close" /> 
</sub-process>

 

   子流程SubProcessReview定義:

Xml代碼 複製代碼  收藏代碼
  1. <start>   
  2. <transition to="get approval"/>  
  3.  </start>   
  4. <task name="get approval" assignee="johndoe">   
  5. <transition to="end"/>   
  6. </task>   
  7. <end name="end" />  
<start> 
<transition to="get approval"/>
 </start> 
<task name="get approval" assignee="johndoe"> 
<transition to="end"/> 
</task> 
<end name="end" />

 

   部分事例代碼以下:

Java代碼 複製代碼  收藏代碼
  1. ProcessInstance processInstance = executionService   
  2. .startProcessInstanceByKey("SubProcessDocument");  
  3.  List<Task> taskList = taskService.findPersonalTasks("johndoe");   
  4. Task task = taskList.get(0);  
  5.  Map<String, Object> variables = new HashMap<String, Object>();   
  6. variables.put("result""ok");  
  7.  // 在子流程中設置流程變量result值爲ok,這個ok值會被傳遞給outcome屬性以決定父流程的走向。   
  8. taskService.setVariables(task.getId(), variables);   
  9. taskService.completeTask(task.getId());   
  10. processInstance = executionService.findProcessInstanceById  
  11. (processInstance.getId());   
  12. assertNotNull(processInstance.findActiveExecutionIn("next step"));   
ProcessInstance processInstance = executionService 
.startProcessInstanceByKey("SubProcessDocument");
 List<Task> taskList = taskService.findPersonalTasks("johndoe"); 
Task task = taskList.get(0);
 Map<String, Object> variables = new HashMap<String, Object>(); 
variables.put("result", "ok");
 // 在子流程中設置流程變量result值爲ok,這個ok值會被傳遞給outcome屬性以決定父流程的走向。 
taskService.setVariables(task.getId(), variables); 
taskService.completeTask(task.getId()); 
processInstance = executionService.findProcessInstanceById
(processInstance.getId()); 
assertNotNull(processInstance.findActiveExecutionIn("next step"));

 

    3)設置不一樣的子流程end活動名稱自動關聯父流程的流出轉移

      父流程SubProcessReview定義:

Xml代碼 複製代碼  收藏代碼
  1. <sub-process name="review" sub-process-key="SubProcessReview">   
  2. <transition name="ok" to="next step" />   
  3. <transition name="nok" to="update" />   
  4. <transition name="reject" to="close" />   
  5. </sub-process> <state name="next step" />   
  6. <state name="update" />   
  7. <state name="close" />   
<sub-process name="review" sub-process-key="SubProcessReview"> 
<transition name="ok" to="next step" /> 
<transition name="nok" to="update" /> 
<transition name="reject" to="close" /> 
</sub-process> <state name="next step" /> 
<state name="update" /> 
<state name="close" />

 

   子流程SubProcessReview定義:

Xml代碼 複製代碼  收藏代碼
  1. <task assignee="johndoe" name="get approval">  
  2.  <transition name="ok" to="ok"/>   
  3. <transition name="nok" to="nok"/>  
  4.  <transition name="reject" to="state1"/>  
  5.  </task>  
  6.  <end name="ok"/>   
  7. <end name="nok"/>   
  8. <end name="reject"/>  
  9.  <state name="state1" >  
  10.  <transition name="to reject" to="reject"/>   
  11. </state>  
<task assignee="johndoe" name="get approval">
 <transition name="ok" to="ok"/> 
<transition name="nok" to="nok"/>
 <transition name="reject" to="state1"/>
 </task>
 <end name="ok"/> 
<end name="nok"/> 
<end name="reject"/>
 <state name="state1" >
 <transition name="to reject" to="reject"/> 
</state>

 

    部分事例代碼以下:

Java代碼 複製代碼  收藏代碼
  1. ProcessInstance processInstance = executionService   
  2. .startProcessInstanceByKey("SubProcessDocument");  
  3.  List<Task> taskList = taskService.findPersonalTasks("johndoe");   
  4. Task task = taskList.get(0);   
  5. //子流程活動結束於ok活動返回父流程實例,父流程會自動地經過名稱爲ok的轉移,   
  6. //進入"next step活動" taskService.completeTask(task.getId(), "ok");   
  7. processInstance = executionService  
  8. .findProcessInstanceById(processInstance.getId());   
  9. assertNotNull(processInstance.findActiveExecutionIn("next step"));   
ProcessInstance processInstance = executionService 
.startProcessInstanceByKey("SubProcessDocument");
 List<Task> taskList = taskService.findPersonalTasks("johndoe"); 
Task task = taskList.get(0); 
//子流程活動結束於ok活動返回父流程實例,父流程會自動地經過名稱爲ok的轉移, 
//進入"next step活動" taskService.completeTask(task.getId(), "ok"); 
processInstance = executionService
.findProcessInstanceById(processInstance.getId()); 
assertNotNull(processInstance.findActiveExecutionIn("next step"));

 

 

7.自定義活動
   若是有特殊而複雜的業務需求,與其生套JBPM自己提供的流轉控制活動,不如本身實現一個自定義的活動使用。
Jpdl定義:

 

Xml代碼 複製代碼  收藏代碼
  1. <!-- custom調用用戶代碼,實現一個自定義的活動行爲 -->  
  2.  <custom name="print dots" class="org.jbpm.examples.custom.PrintDots"">   
  3. <transition to="end" />   
  4. </custom>  
<!-- custom調用用戶代碼,實現一個自定義的活動行爲 -->
 <custom name="print dots" class="org.jbpm.examples.custom.PrintDots""> 
<transition to="end" /> 
</custom>

 

 自定義活動的類需實現ExternalActivityBehaviour接口

Java代碼 複製代碼  收藏代碼
  1. public class PrintDots implements ExternalActivityBehaviour {   
  2. // 在流程實例進入到此活動時執行此方法   
  3. public void execute(ActivityExecution execution) {   
  4. // 執行自定義的處理邏輯   
  5. // 使流程陷入「等待」狀態   
  6. execution.waitForSignal();  
  7.  }  
  8.  // 在流程實例獲得執行信號離開此活動時執行此方法  
  9.  public void signal(ActivityExecution execution, String signalName,   Map<String, ?> parameters)  
  10.  { // 使流程實例進入下一步   
  11. execution.take(signalName);  
  12.  }   
  13. }  
public class PrintDots implements ExternalActivityBehaviour { 
// 在流程實例進入到此活動時執行此方法 
public void execute(ActivityExecution execution) { 
// 執行自定義的處理邏輯 
// 使流程陷入「等待」狀態 
execution.waitForSignal();
 }
 // 在流程實例獲得執行信號離開此活動時執行此方法
 public void signal(ActivityExecution execution, String signalName,   Map<String, ?> parameters)
 { // 使流程實例進入下一步 
execution.take(signalName);
 } 
}

 

 

8.自動活動
   自動活動是在執行過程當中徹底無須人工干預地編排好程序,jbpm在處理和執行這些自動活動時能把人工活動產生的數據
   經過流程變量等方式與之完美結合。
  1)java程序活動
  jpdl定義:

Xml代碼 複製代碼  收藏代碼
  1. <!-- java 任務,流程處理的流向會執行 這個活動配置的方法  
  2.  class:徹底類名   
  3. method:調用的方法名   
  4. var:返回值存儲的 變量名 -->   
  5. <java name="greet" class="org.jbpm.examples.java.JohnDoe"   
  6. method="hello" var="answer" g="96,16,83,52">   
  7. <!--fileld:在方法調用以前給成員變量注入 配置值 -->   
  8. <field name="state">  
  9. <string value="fine"/>  
  10. </field>  
  11.  <!--arg:方法參數 -->   
  12. <arg><string value="Hi, how are you?"/></arg>   
  13. <transition to="shake hand" />   
  14. </java>  
  15.  <!--expr:這個表達式返回方法被調用 產生的目標對象 ,經過對象參數傳入(new Hand()-->  
  16.  <java name="shake hand" expr="#{hand}"   
  17. method="shake" var="hand" g="215,17,99,52">   
  18. <!-- 經過表達式引用流程變量,爲shake方法提供2個參數 -->   
  19. <arg><object expr="#{joesmoe.handshakes.force}"/></arg>   
  20. <arg><object expr="#{joesmoe.handshakes.duration}"/></arg>   
  21. <transition to="wait" /> </java>  
<!-- java 任務,流程處理的流向會執行 這個活動配置的方法
 class:徹底類名 
method:調用的方法名 
var:返回值存儲的 變量名 --> 
<java name="greet" class="org.jbpm.examples.java.JohnDoe" 
method="hello" var="answer" g="96,16,83,52"> 
<!--fileld:在方法調用以前給成員變量注入 配置值 --> 
<field name="state">
<string value="fine"/>
</field>
 <!--arg:方法參數 --> 
<arg><string value="Hi, how are you?"/></arg> 
<transition to="shake hand" /> 
</java>
 <!--expr:這個表達式返回方法被調用 產生的目標對象 ,經過對象參數傳入(new Hand()-->
 <java name="shake hand" expr="#{hand}" 
method="shake" var="hand" g="215,17,99,52"> 
<!-- 經過表達式引用流程變量,爲shake方法提供2個參數 --> 
<arg><object expr="#{joesmoe.handshakes.force}"/></arg> 
<arg><object expr="#{joesmoe.handshakes.duration}"/></arg> 
<transition to="wait" /> </java>

 

 JohnDoe事例代碼以下:

Java代碼 複製代碼  收藏代碼
  1. public class JohnDoe implements Serializable {    
  2.   String state;    
  3.   public String hello(String msg) {  
  4.     if ( (msg.indexOf("how are you?")!=-1)  
  5.        ) {  
  6.       return "I'm "+state+", thank you.";  
  7.     }  
  8.     return null;  
  9.   }  
  10. }  
public class JohnDoe implements Serializable {  
  String state;  
  public String hello(String msg) {
    if ( (msg.indexOf("how are you?")!=-1)
       ) {
      return "I'm "+state+", thank you.";
    }
    return null;
  }
}

 

 

 Hand事例代碼以下:

Java代碼 複製代碼  收藏代碼
  1. public class Hand implements Serializable {  
  2.   private boolean isShaken;  
  3.   public Hand shake(Integer force, Integer duration) {  
  4.     if (force>3 && duration>7) {  
  5.       isShaken = true;  
  6.     }      
  7.     return this;  
  8.   }  
  9.   public boolean isShaken() {  
  10.     return isShaken;  
  11.   }  
  12. }  
public class Hand implements Serializable {
  private boolean isShaken;
  public Hand shake(Integer force, Integer duration) {
    if (force>3 && duration>7) {
      isShaken = true;
    }    
    return this;
  }
  public boolean isShaken() {
    return isShaken;
  }
}

 

 JoeSmoe事例代碼以下:

Java代碼 複製代碼  收藏代碼
  1. public class JoeSmoe implements Serializable {  
  2.   public Map<String, Integer> getHandshakes() {  
  3.     Map<String, Integer> handshakes = new HashMap<String, Integer>();  
  4.     handshakes.put("force"5);  
  5.     handshakes.put("duration"12);  
  6.     return handshakes;  
  7.   }  
  8. }  
public class JoeSmoe implements Serializable {
  public Map<String, Integer> getHandshakes() {
    Map<String, Integer> handshakes = new HashMap<String, Integer>();
    handshakes.put("force", 5);
    handshakes.put("duration", 12);
    return handshakes;
  }
}

  測試代碼以下:

 

Java代碼 複製代碼  收藏代碼
  1. Map<String, Object> variables = new HashMap<String, Object>();  
  2.     variables.put("hand"new Hand());  
  3.     variables.put("joesmoe"new JoeSmoe());  
  4.       
  5.     ProcessInstance processInstance = executionService.startProcessInstanceByKey("Java", variables);  
  6.     String pid = processInstance.getId();  
  7.       
  8.     // 獲取流程變量answer  
  9.     String answer = (String) executionService.getVariable(pid, "answer");  
  10.     assertEquals("I'm fine, thank you.", answer);  
  11.     // 獲取流程變量hand  
  12.     Hand hand = (Hand) executionService.getVariable(pid, "hand");  
  13. assertTrue(hand.isShaken());

八、JBPM自動活動


2)script腳本活動

jpdl定義:

Xml代碼 複製代碼  收藏代碼
  1. <!-- script 腳本活動會解析一個script 腳本。  
  2.     任何一種符合JSR-223 規範 的腳本引擎語言均可以在這裏運行。  
  3.     expr:執行表達式的文本  
  4.     var:返回值存儲的 變量名  
  5.   -->  
  6. <script name="invoke script"  
  7.       expr="Send packet to #{order.address}"  
  8.       var="text"  
  9.       g="96,16,104,52">  
  10. <transition to="wait" />  
  11. </script>  
<!-- script 腳本活動會解析一個script 腳本。
  	任何一種符合JSR-223 規範 的腳本引擎語言均可以在這裏運行。
  	expr:執行表達式的文本
  	var:返回值存儲的 變量名
  -->
<script name="invoke script"
      expr="Send packet to #{order.address}"
      var="text"
      g="96,16,104,52">
<transition to="wait" />
</script>

 

測試代碼以下:

Java代碼 複製代碼  收藏代碼
  1. Map<String, Object> variables = new HashMap<String, Object>();  
  2. variables.put("order"new Order("Berlin"));      
  3. Execution execution = executionService  
  4.     .startProcessInstanceByKey("ScriptExpression", variables);  
  5. String executionId = execution.getId();  
  6. String text = (String) executionService.getVariable(executionId, "text");  
  7. assertTextPresent("Send packet to Berlin", text);  
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("order", new Order("Berlin"));    
Execution execution = executionService
	.startProcessInstanceByKey("ScriptExpression", variables);
String executionId = execution.getId();
String text = (String) executionService.getVariable(executionId, "text");
assertTextPresent("Send packet to Berlin", text);

 

3)hql查詢
jpdl定義:

Xml代碼 複製代碼  收藏代碼
  1. <!-- 使用hql 活動,咱們能夠在database 中執行HQL query   
  2.     var:存儲結果的變量名  
  3.     unique:值爲true 是指從uniqueResult()方法中 得到hibernate query 的結果。  
  4.     默認值是false。 值爲false 的話會使用list()方法獲得結果。   
  5. -->  
  6. <hql name="get task names"  
  7.    var="tasknames with i"  
  8.    g="96,16,115,52">  
  9. <!--   
  10.     query:HQL query   
  11.     parameter:query 的參數  
  12. -->  
  13. <query>  
  14.   select task.name  
  15.   from org.jbpm.pvm.internal.task.TaskImpl as task  
  16.   where task.name like :taskName  
  17. </query>  
  18. <parameters>  
  19.   <string name="taskName" value="%i%" />  
  20. </parameters>  
  21. <transition to="count tasks" />  
  22. </hql>  
  23. <hql name="count tasks"  
  24.    var="tasks"  
  25.    unique="true"  
  26.    g="243,16,95,52">  
  27. <query>  
  28.   select count(*)  
  29.   from org.jbpm.pvm.internal.task.TaskImpl  
  30. </query>  
  31. <transition to="wait" />  
  32. </hql>  
<!-- 使用hql 活動,咱們能夠在database 中執行HQL query 
  	var:存儲結果的變量名
  	unique:值爲true 是指從uniqueResult()方法中 得到hibernate query 的結果。
  	默認值是false。 值爲false 的話會使用list()方法獲得結果。 
-->
<hql name="get task names"
   var="tasknames with i"
   g="96,16,115,52">
<!-- 
	query:HQL query 
	parameter:query 的參數
-->
<query>
  select task.name
  from org.jbpm.pvm.internal.task.TaskImpl as task
  where task.name like :taskName
</query>
<parameters>
  <string name="taskName" value="%i%" />
</parameters>
<transition to="count tasks" />
</hql>
<hql name="count tasks"
   var="tasks"
   unique="true"
   g="243,16,95,52">
<query>
  select count(*)
  from org.jbpm.pvm.internal.task.TaskImpl
</query>
<transition to="wait" />
</hql>

 測試事例代碼以下:

Java代碼 複製代碼  收藏代碼
  1. ProcessInstance processInstance = executionService.startProcessInstanceByKey("Hql");  
  2. String processInstanceId = processInstance.getId();  
  3. // 設定預期結果  
  4. Set<String> expectedTaskNames = new HashSet<String>();  
  5. expectedTaskNames.add("dishes");  
  6. expectedTaskNames.add("iron");  
  7. // 獲取第一個hql活動的執行結果,流程變量"tasknames with i"  
  8. Collection<String> taskNames = (Collection<String>) executionService  
  9.                 .getVariable(processInstanceId, "tasknames with i");  
  10. taskNames = new HashSet<String>(taskNames);  
  11. assertEquals(expectedTaskNames, taskNames);  
  12. // 獲取第二個hql活動的執行結果,流程數據庫中共有3條記錄  
  13. Object activities = executionService.getVariable(processInstanceId, "tasks");  
  14. assertEquals("3", activities.toString());  
ProcessInstance processInstance = executionService.startProcessInstanceByKey("Hql");
String processInstanceId = processInstance.getId();
// 設定預期結果
Set<String> expectedTaskNames = new HashSet<String>();
expectedTaskNames.add("dishes");
expectedTaskNames.add("iron");
// 獲取第一個hql活動的執行結果,流程變量"tasknames with i"
Collection<String> taskNames = (Collection<String>) executionService
				.getVariable(processInstanceId, "tasknames with i");
taskNames = new HashSet<String>(taskNames);
assertEquals(expectedTaskNames, taskNames);
// 獲取第二個hql活動的執行結果,流程數據庫中共有3條記錄
Object activities = executionService.getVariable(processInstanceId, "tasks");
assertEquals("3", activities.toString());

 

4)sql查詢
jpdl定義:

Xml代碼 複製代碼  收藏代碼
  1. <!--sql 活動和hql 活動十分類似, 惟一不一樣的地方就是 使用session.createSQLQuery(...) -->  
  2. <sql name="get task names"  
  3.       var="tasknames with i"  
  4.       g="96,16,126,52">  
  5. <query>  
  6.   select NAME_  
  7.   from JBPM4_TASK  
  8.   where NAME_ like :name  
  9. </query>  
  10. <parameters>  
  11.   <string name="name" value="%i%" />  
  12. </parameters>  
  13. <transition to="count tasks" />  
  14. </sql>  
  15.   
  16. <sql name="count tasks"  
  17.    var="tasks"  
  18.    unique="true"  
  19.    g="254,16,92,52">  
  20. <query>  
  21.   select count(*)  
  22.   from JBPM4_TASK  
  23. </query>  
  24. <transition to="wait" />  
  25. </sql>  
<!--sql 活動和hql 活動十分類似, 惟一不一樣的地方就是 使用session.createSQLQuery(...) -->
<sql name="get task names"
	  var="tasknames with i"
	  g="96,16,126,52">
<query>
  select NAME_
  from JBPM4_TASK
  where NAME_ like :name
</query>
<parameters>
  <string name="name" value="%i%" />
</parameters>
<transition to="count tasks" />
</sql>

<sql name="count tasks"
   var="tasks"
   unique="true"
   g="254,16,92,52">
<query>
  select count(*)
  from JBPM4_TASK
</query>
<transition to="wait" />
</sql>

 測試事例代碼同Hql事例代碼。

 

5) mail(郵件活動)

jpdl定義:

Xml代碼 複製代碼  收藏代碼
  1. <!--  from:發件者列表  
  2.         to: 主要收件人列表  
  3.         cc:抄送收件人列表  
  4.         bcc: 密送收件人列表  
  5.         subject:這個元素的文字內容會成爲消息的主題  
  6.         text:這個元素的文字內容會成爲消息的文字內容  
  7.         html:這個元素的文字內容會成爲消息的HTML 內容  
  8.         attachments:每一個附件都會配置在單獨的子元素中  
  9.    -->  
  10.   <mail g="99,25,115,45" language="juel" name="send rectify note">  
  11. <to addresses=" winston@minitrue"/>  
  12. <cc groups="innerparty" users="bb"/>  
  13. <bcc groups="thinkpol"/>  
  14. <subject>rectify ${newspaper}</subject>  
  15. <text>${newspaper} ${date} reporting bb dayorder doubleplusungood  
  16.   refs unpersons rewrite fullwise upsub antefiling</text>  
  17. <!--  
  18. <html><table><tr><td>${newspaper}</td><td>${date}</td>  
  19.   <td>reporting bb dayorder doubleplusungood  
  20.   refs unpersons rewrite fullwise upsub antefiling</td>  
  21.   </tr></table></html>  
  22. <attachments>  
  23.   <attachment url='http://www.george-orwell.org/1984/3.html' />  
  24.   <attachment resource='org/example/pic.jpg' />  
  25.   <attachment file='${user.home}/.face' />  
  26. </attachments>  
  27. -->  
  28. <transition to="wait"/>  
  29. </mail>  
<!--  from:發件者列表
		to: 主要收件人列表
		cc:抄送收件人列表
		bcc: 密送收件人列表
		subject:這個元素的文字內容會成爲消息的主題
		text:這個元素的文字內容會成爲消息的文字內容
		html:這個元素的文字內容會成爲消息的HTML 內容
		attachments:每一個附件都會配置在單獨的子元素中
   -->
  <mail g="99,25,115,45" language="juel" name="send rectify note">
<to addresses=" winston@minitrue"/>
<cc groups="innerparty" users="bb"/>
<bcc groups="thinkpol"/>
<subject>rectify ${newspaper}</subject>
<text>${newspaper} ${date} reporting bb dayorder doubleplusungood
  refs unpersons rewrite fullwise upsub antefiling</text>
<!--
<html><table><tr><td>${newspaper}</td><td>${date}</td>
  <td>reporting bb dayorder doubleplusungood
  refs unpersons rewrite fullwise upsub antefiling</td>
  </tr></table></html>
<attachments>
  <attachment url='http://www.george-orwell.org/1984/3.html' />
  <attachment resource='org/example/pic.jpg' />
  <attachment file='${user.home}/.face' />
</attachments>
-->
<transition to="wait"/>
</mail>

 

九、事件
Jpdl定義:

Xml代碼 複製代碼  收藏代碼
  1. <state name="wait" g="96,16,104,52">  
  2. <!-- event:事件名稱(start或end)  
  3.         event-listener:一個事件監聽器實現對象。  
  4.         start:活動開始時捕獲  
  5.         end:活動結束時捕獲  
  6. -->  
  7. <on event="start">  
  8. <event-listener class="org.jbpm.examples.eventlistener.LogListener">  
  9.   <field name="msg"><string value="start on activity wait"/></field>  
  10.     </event-listener>  
  11. </on>  
  12. <on event="end">  
  13.   <event-listener class="org.jbpm.examples.eventlistener.LogListener">  
  14. <field name="msg"><string value="end on activity wait"/></field>  
  15.   </event-listener>  
  16. </on>  
  17. <transition to="park">  
  18.   <event-listener class="org.jbpm.examples.eventlistener.LogListener">  
  19.      <field name="msg"><string value="take transition"/></field>  
  20.   </event-listener>  
  21. </transition>  
  22. </state>  
<state name="wait" g="96,16,104,52">
<!-- event:事件名稱(start或end)
 	    event-listener:一個事件監聽器實現對象。
 	    start:活動開始時捕獲
 	    end:活動結束時捕獲
-->
<on event="start">
<event-listener class="org.jbpm.examples.eventlistener.LogListener">
  <field name="msg"><string value="start on activity wait"/></field>
    </event-listener>
</on>
<on event="end">
  <event-listener class="org.jbpm.examples.eventlistener.LogListener">
<field name="msg"><string value="end on activity wait"/></field>
  </event-listener>
</on>
<transition to="park">
  <event-listener class="org.jbpm.examples.eventlistener.LogListener">
     <field name="msg"><string value="take transition"/></field>
  </event-listener>
</transition>
</state>

 監聽器LogListener代碼:

Java代碼 複製代碼  收藏代碼
  1. public class LogListener implements EventListener {  
  2.   String msg;    
  3.   public void notify(EventListenerExecution execution) {  
  4.     List<String> logs = (List<String>) execution.getVariable("logs");  
  5. if (logs==null) {  
  6.   logs = new ArrayList<String>();  
  7.   execution.setVariable("logs", logs);  
  8. }      
  9. logs.add(msg);      
  10. execution.setVariable("logs", logs);  
  11.   }  
  12. }  
public class LogListener implements EventListener {
  String msg;  
  public void notify(EventListenerExecution execution) {
    List<String> logs = (List<String>) execution.getVariable("logs");
if (logs==null) {
  logs = new ArrayList<String>();
  execution.setVariable("logs", logs);
}    
logs.add(msg);    
execution.setVariable("logs", logs);
  }
}

 測試事例代碼以下:

Java代碼 複製代碼  收藏代碼
  1. ProcessInstance processInstance = executionService  
  2.         .startProcessInstanceByKey("EventListener");  
  3. Execution execution = processInstance.findActiveExecutionIn("wait");  
  4. executionService.signalExecutionById(execution.getId());  
  5. List<String> expectedLogs = new ArrayList<String>();  
  6. expectedLogs.add("start on process definition");  
  7. expectedLogs.add("start on activity wait");  
  8. expectedLogs.add("end on activity wait");  
  9. expectedLogs.add("take transition");  
  10. List<String> logs = (List<String>) executionService  
  11.             .getVariable(processInstance.getId(), "logs");      
  12. assertEquals(expectedLogs, logs);  
ProcessInstance processInstance = executionService
		.startProcessInstanceByKey("EventListener");
Execution execution = processInstance.findActiveExecutionIn("wait");
executionService.signalExecutionById(execution.getId());
List<String> expectedLogs = new ArrayList<String>();
expectedLogs.add("start on process definition");
expectedLogs.add("start on activity wait");
expectedLogs.add("end on activity wait");
expectedLogs.add("take transition");
List<String> logs = (List<String>) executionService
			.getVariable(processInstance.getId(), "logs");    
assertEquals(expectedLogs, logs);

 默認狀況下,事件監聽器只對當前訂閱的元素所觸發的事件起做用,即propagation=」false」,
但經過指定事件監聽器的傳播屬性propagation=」enabled」或(propagation=」true」),
則該事件監聽器能夠對其監聽元素的全部子元素起做用。

 

10. 異步執行
   1)幾乎全部的活動都支持異步屬性,流程一旦進入異步執行方式,一個異步消息會被做爲當前事務的一部門發送出去,
       而後當前事務會當即自動提交。

    Jpdl定義:

Java代碼 複製代碼  收藏代碼
  1. <!--  
  2. continue屬性: sync (默認值) 做爲當前事務的一部分,繼續執行元素。   
  3.     async 使用一個異步調用(又名安全點)。當前事務被提交,元素在一個新事務中執行。  
  4.     事務性的異步消息被jBPM 用來 實現這個功能。  
  5. -->  
  6. <java name="generate pdf"  
  7.   continue="async"  
  8.   class="org.jbpm.examples.async.activity.Application"  
  9.   method="generatePdf"  
  10.   g="86,26,87,50">  
  11. <transition to="calculate primes"/>  
  12. </java>  
  13.   
  14. <java name="calculate primes"  
  15.   continue="async"  
  16.   class="org.jbpm.examples.async.activity.Application"  
  17.   method="calculatePrimes"  
  18.   g="203,26,98,50">  
  19. <transition to="end"/>  
  20. </java>  
<!--
continue屬性: sync (默認值) 做爲當前事務的一部分,繼續執行元素。 
	async 使用一個異步調用(又名安全點)。當前事務被提交,元素在一個新事務中執行。
	事務性的異步消息被jBPM 用來 實現這個功能。
-->
<java name="generate pdf"
  continue="async"
  class="org.jbpm.examples.async.activity.Application"
  method="generatePdf"
  g="86,26,87,50">
<transition to="calculate primes"/>
</java>

<java name="calculate primes"
  continue="async"
  class="org.jbpm.examples.async.activity.Application"
  method="calculatePrimes"
  g="203,26,98,50">
<transition to="end"/>
</java>

Application事例代碼以下: 

Java代碼 複製代碼  收藏代碼
  1. public class Application implements Serializable {  
  2.   private static final long serialVersionUID = 1L;  
  3.   public void generatePdf() {  
  4.     // 此方法執行須要消耗較長時間  
  5.   }  
  6.   public void calculatePrimes() {  
  7.     // 此方法執行須要消耗較長時間  
  8.   }  
  9. }  
public class Application implements Serializable {
  private static final long serialVersionUID = 1L;
  public void generatePdf() {
    // 此方法執行須要消耗較長時間
  }
  public void calculatePrimes() {
	// 此方法執行須要消耗較長時間
  }
}

 測試事例代碼以下:

Java代碼 複製代碼  收藏代碼
  1. ProcessInstance processInstance = executionService  
  2.                 .startProcessInstanceByKey("AsyncActivity");  
  3. String processInstanceId = processInstance.getId();  
  4. // 流程實例處於異步執行狀態  
  5. assertEquals(Execution.STATE_ASYNC, processInstance.getState());  
  6. // 獲取流程實例異步消息隊列中的第1條消息  
  7. Job job = managementService.createJobQuery()  
  8.   .processInstanceId(processInstanceId).uniqueResult();  
  9. // 手工執行異步消息  
  10. managementService.executeJob(job.getId());  
  11. processInstance = executionService.findProcessInstanceById(processInstanceId);  
  12. // 流程實例處於異步執行狀態  
  13. assertEquals(Execution.STATE_ASYNC, processInstance.getState());  
  14. // 獲取第2條消息(job)並執行之  
  15. job = managementService.createJobQuery()  
  16.       .processInstanceId(processInstanceId)  
  17.       .uniqueResult();  
  18. managementService.executeJob(job.getId());      
  19. assertNull(executionService.findProcessInstanceById(processInstanceId));  
ProcessInstance processInstance = executionService
				.startProcessInstanceByKey("AsyncActivity");
String processInstanceId = processInstance.getId();
// 流程實例處於異步執行狀態
assertEquals(Execution.STATE_ASYNC, processInstance.getState());
// 獲取流程實例異步消息隊列中的第1條消息
Job job = managementService.createJobQuery()
  .processInstanceId(processInstanceId).uniqueResult();
// 手工執行異步消息
managementService.executeJob(job.getId());
processInstance = executionService.findProcessInstanceById(processInstanceId);
// 流程實例處於異步執行狀態
assertEquals(Execution.STATE_ASYNC, processInstance.getState());
// 獲取第2條消息(job)並執行之
job = managementService.createJobQuery()
      .processInstanceId(processInstanceId)
      .uniqueResult();
managementService.executeJob(job.getId());    
assertNull(executionService.findProcessInstanceById(processInstanceId));

 

   2)異步分支/聚合
    Jpdl定義:

Xml代碼 複製代碼  收藏代碼
  1. <!--   
  2. exclusive 這個值被用來 將兩個來自分支的異步調用的job 結果進行持久化。  
  3. 各自的事務會分別執行ship goods 和send bill, 而後這兩個執行都會達到join 節點。   
  4. 在join 節點中,兩個事務會同步到一個相同的執行上(在數據庫總更新同一個執行),  
  5. 這可能致使一個潛在的樂觀鎖失敗。-->  
  6. <fork g="99,68,80,40" name="fork">  
  7.    <!-- 並行的流程分支以獨佔方式異步執行 -->  
  8.   <on event="end" continue="exclusive" />  
  9.   <transition g="122,41:" to="ship goods"/>  
  10.   <transition g="123,142:" to="send bill"/>  
  11. </fork>  
  12.   
  13. <java class="org.jbpm.examples.async.fork.Application" g="159,17,98,50"  
  14.     method="shipGoods" name="ship goods">  
  15.    <transition g="297,42:" to="join"/>  
  16. </java>  
  17.   
  18. <java class="org.jbpm.examples.async.fork.Application" g="159,117,98,50"   
  19.      method="sendBill" name="send bill">  
  20. <transition g="297,141:" to="join"/>  
  21. </java>  
  22.   
  23. <join g="274,66,80,40" name="join">  
  24.   <transition to="end"/>  
  25. </join>  
<!-- 
exclusive 這個值被用來 將兩個來自分支的異步調用的job 結果進行持久化。
各自的事務會分別執行ship goods 和send bill, 而後這兩個執行都會達到join 節點。 
在join 節點中,兩個事務會同步到一個相同的執行上(在數據庫總更新同一個執行),
這可能致使一個潛在的樂觀鎖失敗。-->
<fork g="99,68,80,40" name="fork">
   <!-- 並行的流程分支以獨佔方式異步執行 -->
  <on event="end" continue="exclusive" />
  <transition g="122,41:" to="ship goods"/>
  <transition g="123,142:" to="send bill"/>
</fork>

<java class="org.jbpm.examples.async.fork.Application" g="159,17,98,50"
	method="shipGoods" name="ship goods">
   <transition g="297,42:" to="join"/>
</java>

<java class="org.jbpm.examples.async.fork.Application" g="159,117,98,50" 
	 method="sendBill" name="send bill">
<transition g="297,141:" to="join"/>
</java>

<join g="274,66,80,40" name="join">
  <transition to="end"/>
</join>

 測試事例代碼以下:

Java代碼 複製代碼  收藏代碼
  1. ProcessInstance processInstance = executionService.startProcessInstanceByKey("AsyncFork");  
  2. String processInstanceId = processInstance.getId();  
  3. // 獲取異步消息列表  
  4. List<Job> jobs = managementService.createJobQuery()  
  5.   .processInstanceId(processInstanceId).list();  
  6. //有兩個分支,有2條異步消息  
  7. assertEquals(2, jobs.size());      
  8. Job job = jobs.get(0);  
  9. //手工執行第1條  
  10. managementService.executeJob(job.getId());      
  11. job = jobs.get(1);  
  12. //手工執行第2條  
  13. managementService.executeJob(job.getId());  
  14. Date endTime = historyService  
  15.   .createHistoryProcessInstanceQuery()  
  16.   .processInstanceId(processInstance.getId())  
  17.   .uniqueResult()  
  18.   .getEndTime();  
  19. // 流程已結束  
  20. assertNotNull(endTime);  
ProcessInstance processInstance = executionService.startProcessInstanceByKey("AsyncFork");
String processInstanceId = processInstance.getId();
// 獲取異步消息列表
List<Job> jobs = managementService.createJobQuery()
  .processInstanceId(processInstanceId).list();
//有兩個分支,有2條異步消息
assertEquals(2, jobs.size());    
Job job = jobs.get(0);
//手工執行第1條
managementService.executeJob(job.getId());    
job = jobs.get(1);
//手工執行第2條
managementService.executeJob(job.getId());
Date endTime = historyService
  .createHistoryProcessInstanceQuery()
  .processInstanceId(processInstance.getId())
  .uniqueResult()
  .getEndTime();
// 流程已結束
assertNotNull(endTime);

 

11. 流程變量
     1)流程變量與流程實例綁定, 可經過如下方法來操做流程變量:
     例:

Java代碼 複製代碼  收藏代碼
  1. ProcessInstance   startProcessInstanceById   
  2.  (String processDefinitionId,Map<String,Object>variables);  
  3.   
  4. ProcessInstance   startProcessInstanceById  
  5. (String processDefinitionId,Map<String,Object>variables,String processInstanceKey);  
ProcessInstance   startProcessInstanceById 
 (String processDefinitionId,Map<String,Object>variables);

ProcessInstance   startProcessInstanceById
(String processDefinitionId,Map<String,Object>variables,String processInstanceKey);

    2)其它引擎服務中也存在相似的方法,例如TaskService也提供方法操做任務綁定的流程變量。

    3)經過流程變量控制流程的流向是正確的作法,可是不要被這種「方便」的機制誘惑而往流程實例裏面放全部的東西,
        特別是與流轉控制無關的業務數據。

 

5、 JBPM數據表

 

JBPM4_DEPLOYMENT: 流程定義的部署記錄 JBPM4_DEPLOYPROP: 已部署的流程定義的具體屬性 JBPM4_LOB:流程定義的相關資源,包括JPDL XML、圖片、用戶代碼Java類等。 JBPM4_JOB:異步活動或定時執行的Job記錄。 JBPM4_VARIABLE:流程實例的變量。 JBPM4_EXECUTION:流程實例及執行對象。 JBPM4_SWIMLANE:任務泳道。 JBPM4_PARTICIPATION:任務參與者,任務的相關用戶,區別於任務的分配人。 JBPM4_TASK:流程實例的任務記錄。 JBPM4_HIST_PROCINST:保存歷史的流程實例記錄。 JBPM4_HIST_ACTINST:保存歷史的活動實例記錄。 JBPM4_HIST_TASK:保存歷史的任務實例記錄。 JBPM4_HIST_VAR:保存歷史的流程變量數據。 JBPM4_HIST_DETAIL:保存流程實例、活動實例、任務實例運行過程當中歷史明細數據。 JBPM4_ID_USER:保存用戶記錄。 JBPM4_ID_MEMBERSHIP:保存用戶和用戶組之間的關聯關係。 JBPM4_ID_GROUP:保存用戶組記錄。

相關文章
相關標籤/搜索