今日繼續講解jbpm框架,早上湯老師領著大家把昨天的內容復習了一下,然后做了總結。總結之后十分清晰。
一、昨日回顧

1. 部署流程定義:“deployProcessDefinition”向“jbpm_processdefinition” 表中添加新的流程定義記錄,同時向其子表添加詳細信息。
2. 創建流程實例:“findLatestProcessDefinition”到“jbpm_processdefinition”表中獲取指定名稱的流程定義。“createProcessInstance”創建的流程實例被保存到“jbpm_ processinstance”表中。“pi.getRootToken().signal()”中的Token指向當前任務(游標),signal發出一個信號到達下一個任務節點,同時向“jbpm_ taskinstance” 表中添加一個任務節點。“pi.getRootToken().signal()”為到達第一個任務節點。
3. 獲取任務實例列表:“getTaskList”根據指定的actorId到“jbpm_ taskinstance”表中獲取對應的任務列表。
4. 開始任務:“getTaskInstance”到“jbpm_ taskinstance”表中獲取指定的任務實例。“start”向“jbpm_ taskinstance”表中對應的記錄添加任務起始時間。
5. 結束任務:“getTaskInstance”到“jbpm_ taskinstance”表中獲取指定的任務實例。“end”向“jbpm_ taskinstance”表中對應的記錄添加任務結束時間。“end”內部調用“taskIns.getToken().signal();”指向下一個任務節點。
今日新內容主要為四點,流程定義文檔、節點、動作與事件、任務分配。突然的感覺到事件在JavaEE中被廣泛應用,看來事件驅動還是十分重要的。
二、流程定義文檔(PAR)
1.打包流程文檔時必須使用zip格式。
2.在根目錄中或zip壓縮文件中,包含如下文件:
i. processdefinition.xml(必須,jbpm的流程配置文件。)
ii. processimage.jpg(可選,流程設計器生成的圖片文件。)
iii. gpd.xml(可選,流程設計器中圖元的坐標等信息。)
iv. classes/(可選,存放用到的java類。)
3.eclipse的jbpm插件可以打包和部署流程,在設計頁面的標簽的旁邊“Deployment”頁面。在“Files and Floders”與“Java Classes and Resources”中,選擇將要打包或部署的文件。“Local Save Settings”打包到…。“Deployment Server Settings”發布到JBOSS WEB容器,此時必須走動JBOSS WEB容器,采取默認設置即可。
4.更新的問題(版本)
我們每次部署流程時,JBOSSWEB容器都會為流程設置一個新的版本,而不會去覆蓋之前部署的應用。使用之前的應用與對應的版本保留,不會造成數據出錯。所以每次應該重新部署應用,也不要刪除以前的應用。
如果被刪除或覆蓋,新部署的流程相比以前的流程。多了或少了幾個任務節點,那使用之前的數據訪問就會出錯。
三、節點
1.預定義節點
1) Start-state:開始狀態節點。
2) End-state:結束狀態節點。
3) Task-Node:任務節點,非常重要,昨天已經學習過。
4) Decision:決策分支節點,此節點的handler委托類(delegation)必須實現DecisionHandler接口。如:

| Start-state |
需要為Decision的handler頁面的delegation屬性添加一個實現“DecisionHandler”接口的類。 此類返回一個String類型,用于指定decision節點執行哪個分支。 |
實現“DecisionHandler”接口的類:
package cn.itcast.cc.jbpm.node.decision; import org.jbpm.graph.exe.ExecutionContext; import org.jbpm.graph.node.Decision; import org.jbpm.graph.node.DecisionHandler; public class DecisionNodeTest extends Decision implements DecisionHandler { private static final long serialVersionUID = 1L; @Override public String decide(ExecutionContext arg0) throws Exception { //ExecutionContext節點的執行環境,通過這個參數可以獲取所有信息。 return "t2";//執行transition名為“t2”的分支。 } } |
5) Fork/join:分叉與合并結點,可以把Fork/join看作是一個大節點。內部包含多條并行的子節點流程。

| Start-state |
fork |
兩個分支是并行關系。直接兩個分支全部執行完成,才會到達join。此處自動生成transition名稱,tq和t3。如果沒有,重新連接即可。必須具有transition名稱。 |
Join,選擇到此處時不全停留,直接到達end-state。 |
End-state |
6) State:狀態節點,當流程執行到此節點時會暫停,直到調用token的signal方法時才會繼續向下執行。(沒有別的用處)
2.自定義節點
自定義節點的實現需要使用普通“Node”節點,與節點Action動作相配合。以實現預定義節點所不能完成的功能。
Node + action示例:

| Start-state |
Node |
End-state |
為node1的action->details屬性頁面的Handler添加一個實現了“ActionHandler”接口的類(必須選中頁面中的“Configuration Action”),我為在此類中打印一條語語句:
package cn.itcast.cc.jbpm.node.customize; import org.jbpm.graph.def.ActionHandler; import org.jbpm.graph.exe.ExecutionContext; public class CustomizeAction implements ActionHandler { private static final long serialVersionUID = 1L; @Override public void execute(ExecutionContext executionContext) throws Exception { //ExecutionContext節點的執行環境,通過這個參數可以獲取所有信息。 System.out.println("*****CustomizeAction*****"); } } |
四、動作與事件
動作我們在第三部分末尾已經介紹過,Jbpm的的節點包含三類事件(共7個事件)。Jbpm7個事件的執行順序:

| node-leave:離開start-state1節點,可通過插件配置。 |
Transition:從start-sate1過渡到task-node1的事件,可通過插件配置。 |
node-enter:進入task-node1節點,可通過插件配置。 task-create:創建任務事件,需要插件/手動配置。 task-assign:分配任務事件,需要插件/手動配置。 task-start:任務開始事件,需要插件/手動配置。 task-end:任務結束事件,需要插件/手動配置。 |
… |
… |
上表中的事件是jbpm流程中比較常用的事件,事件不影響流程的執行。
讓我們為上面的流程添加7個,表中對應的事件。事件處理統一使用一個實現了“ActionHandler”接口的類:
package cn.itcast.cc.jbpm.node.event; import org.jbpm.graph.def.ActionHandler; import org.jbpm.graph.exe.ExecutionContext; public class NodeEventTest implements ActionHandler { private static final long serialVersionUID = 1L; @Override public void execute(ExecutionContext executionContext) throws Exception { // 打印事件類型 System.out.println(executionContext.getEvent().getEventType()); } } |
processdefinition.xml文件內容為:
<?xml version="1.0" encoding="UTF-8"?> <process-definition xmlns="" name="NodeEvent"> <start-state name="start-state1"> <transition to="task-node1"></transition> <event type="node-leave"> <action class="cn.itcast.cc.jbpm.node.event.NodeEventTest" name="printNodeEventType"></action> </event> </start-state> <task-node name="task-node1"> <task name="下訂單"> <assignment actor-id="客戶"></assignment> <event type="task-create"> <action ref-name="printNodeEventType" /> </event> <event type="task-assign"> <action ref-name="printNodeEventType" /> </event> <event type="task-start"> <action ref-name="printNodeEventType" /> </event> <event type="task-end"> <action ref-name="printNodeEventType" /> </event> </task> <event type="node-enter"> <action ref-name="printNodeEventType"></action> </event> <transition to="end-state1"></transition> </task-node> <end-state name="end-state1"> <event type=""></event> </end-state> </process-definition> |
如果 task-node中包含多個task。將event放在task外部,task-node的內部,所有的task將共用同一個事件處理類。如果將event放在task內部,task將使用各自內部的事件處理類。
將流程發布到JBOSSWEB容器中(注意將類“NodeEventTest”一同發布),一步步執行查看控制臺的輸出。
五、任務分配
1.個人任務(推模型)
個人任務屬于個人,只有個人能看到,必須由個人完成。個人任務的分配方式:
1) 手動添加,通過設計器設置task的Actor屬性值。
2) Actor:通過設計器使用表達式將Actor設置為#{customer},在事件處理函數中通過“executionContext.getContextInstance().setTransientVariable(name, value)”設置變量值,動態更改actor。
3) 為Task的“Assignment->Handler”添加一個實現了AssignmentHandler接口的類,在“assign”方法中調用“assignable.setActorId(actor);”方法設置Actor屬性值。
4) 可以在程序的任何位置使用“TaskInstance.setActorId(actor)”設置Actor的值。
2.組任務(拉/競爭模型)
組任務屬于小組,只有小組成員可以查看,但必須僅有一個人來完成。組任務的分配試:
1) 手動添加,通過設計器設置task的PooledActors屬性值,使用“,”分隔。
2) PooledActors:通過設計器使用表達式將PooledActors屬性設置為#{actors},在事件處理函數中通過“executionContext.getContextInstance().setTransientVariable(name, value)”設置變量值,動態更改actor。
3) 為Task的“Assignment->Handler”添加一個實現了AssignmentHandler接口的類,在“assign”方法中調用“assignable. setPooleActors (actors);”方法設置PooleActors屬性值。
4) 可以在程序的任何位置使用“taskInstance.setPooledActors(actors)”,設置PooledActors的值。
3.查詢
1) 個人任務:jbpmContext.getTaskMgmtSession().findTaskInstances (actorId)。
2) 組任務:jbpmContext.getTaskMgmtSession().findPooledTaskInstances(actorId)。
actorId可以屏蔽pooledActors
4.Swimlane(泳道)
湯兄弟今天只是簡單介紹了一下泳道,這個功能并不常用。
泳道圖:

OK,今天的內容到此結束。明天就開始我們的OA系統了,主要使用struts+hibernate+jbpm開發!
哈哈,加油!