工作流子流程和多例項開發
在專案中有子流程和多例項的需求,總結如下:
一、子流程
子流程分為兩種:
- CallActivity(呼叫任務)
- SubProcess(子流程)
由於呼叫任務能將子任務分離開來,能夠分別顯示單獨的流程圖,實際在專案中用到更多的是呼叫任務,這裡我們主要介紹呼叫任務:
呼叫任務的流程圖如下:
父流程圖1
子流程圖2
圖1中我們有一個普通的任務task1和一個呼叫任務,圖2是圖1呼叫任務要呼叫的流程,只有一個普通的任務sonTask,圖中這個任務下面有三道豎線說明它是多例項任務,我們一會兒再介紹,先不管它。
圖中的主要屬性如下:
- 父流程:{Id:parentProcess};
- task1:{Id:usertask1,Assignee:parent};
- 呼叫任務:{Id:callactivity1,Called element:sunProcess}
- 子流程:{Id:sunProcess};
- sonTask:{Id:usertask2,Assignee:son};
可以看到呼叫任務的配置很簡單,只需要將Called element的屬性值修改為需要呼叫的子流程id即可。
部署時父子流程都需要部署:
/**
* 部署流程定義(classpath)
*/
@Test
public void deploymentProcessDefinition () {
Deployment dp = pe.getRepositoryService().createDeployment()
.name("父子流程")
.addClasspathResource("diagrams/Parent.bpmn")
.addClasspathResource("diagrams/Parent.png")
.addClasspathResource("diagrams/Son.bpmn" )
.addClasspathResource("diagrams/Son.png")
.deploy();
System.out.println("部署ID:"+dp.getId());
System.out.println("部署名稱:"+dp.getName());
}
啟動流程例項時只啟動父流程:
/**
* 啟動流程例項
*/
@Test
public void startProcessInstance() {
String processDefinitionKey = "parentProcess";
ProcessInstance pi = pe.getRuntimeService()
.startProcessInstanceByKey(processDefinitionKey);
System.out.println("流程例項ID:"+pi.getProcessInstanceId());
System.out.println("流程定義ID:"+pi.getProcessDefinitionId());
}
接下來把流程跑通一遍,我們來看一下act_hi_actinst表的資料:
當完成usertask1之後,任務節點到達了callactivity,表中的CALL_PROC_INST_ID_欄位代表了要呼叫哪個流程,這時直接開啟了proc_inst_id_為5003的子流程,完成了startevent1節點,到達了usertask2任務,當完成usertask2之後,子流程結束,父流程結束,整個流程執行完畢。
這是最簡單的呼叫任務,但是如果我們在父流程中設定了流程變數,我們就需要將流程變數傳到子流程當中,這時就需要配置callactivity的Input parameters和Output parameters屬性:
其中Source是父流程的流程變數名稱,Target是子流程的流程變數名稱,也就是說子流程和父流程中對應同一個流程變數的名字可以不同,我們對映一下就可以了。同理Output parameters配置的是從子流程中返回的流程變數和父流程的對映關係。如果我們的流程變數是javabean的話,我們就用EL表示式來配置Source expression和Target expression。
我們在父流程中設定一個流程變數name,用來動態的設定子流程usertask2任務的辦理人,我們需要將Source和Target屬性都設定為name,將usertask2的Assignee屬性設定為${name},我們再跑通一次流程,觀察一下表中的變化:
act_ru_variable表1
act_hi_actinst表2
我們在啟動父流程的時候設定了流程變數name:
/**
* 啟動流程例項
*/
@Test
public void startProcessInstance() {
String processDefinitionKey = "parentProcess";
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "xiaowang");
ProcessInstance pi = pe.getRuntimeService()
.startProcessInstanceByKey(processDefinitionKey,map);
System.out.println("流程例項ID:"+pi.getProcessInstanceId());
System.out.println("流程定義ID:"+pi.getProcessDefinitionId());
}
我們看錶一中父流程和子流程都有一個叫name的流程變數,說明流程變數傳進了子流程,同時子流程的usertask2的辦理人設定成了”xiaowang”,完成了動態設定辦理人的需求。outputparameter的設定同理,大家可以自行測試。
這裡還有一個建議,如果有呼叫任務的需求,我們在開發中最好用javabean型別的流程變數來儲存業務資料,否則我們在inputparameter和outputparameter中就需要手動設定所有的流程變數,很麻煩,還需要去程式碼中看我到底設定了哪些流程變數。
二、多例項
單獨的多例項比較簡單,只是配置任務的幾個屬性就可以了。如下:
1.Sequential是設定多例項任務是同步執行還是按照順序執行,”false”為同步執行;
2.Collection是多例項的核心屬性,值為集合型別的流程變數名稱,這裡我在啟動流程例項時設定了一個型別為List的流程變數,名稱為names,程式碼如下:
/**
* 啟動流程例項
*/
@Test
public void startProcessInstance() {
String processDefinitionKey = "sunProcess";
Map<String, Object> map = new HashMap<String, Object>();
List<String> names = new ArrayList<String>();
names.add("xiaowang");
names.add("xiaoli");
names.add("xiaozhang");
map.put("names", names);
ProcessInstance pi = pe.getRuntimeService()
.startProcessInstanceByKey(processDefinitionKey,map);
System.out.println("流程例項ID:"+pi.getProcessInstanceId());
System.out.println("流程定義ID:"+pi.getProcessDefinitionId());
}
3.Element variable為Collection中每一個元素的名稱,這個名稱是自己定義的,當我們要使用多例項集合中的每一個元素時,總要有個名字。我們在動態設定每一個例項執行物件的Assignee時,用到了這個name:
這樣的話,每一個例項就可以根據我們程式中List的每一個元素值來動態設定,我們看一下表中的執行結果:
act_hi_actinst表
這裡我們可以看到同時執行的usertask2有三個,分別動態賦予了不同的Assignee,並且他們的execution_id是不同的,所以在多例項或者有分支和並行的流程中,我們能夠看出流程例項id(proc_inst_id_)和執行物件id(execution_id_)其實是不同的。
不過很多時候多例項流程不只需要動態配置一個assignee屬性,這種時候我們需要將流程變數List中的元素改成javabean物件,在配置assignee時用物件的屬性來配置:
這裡需要補充的是所有的多例項跑完才會執行下一步流程。