前言
前面一節(jié)我們已經(jīng)了解了activiti的基礎(chǔ)概念,包括流程定義的用語(yǔ)和它的api功能,已經(jīng)如何入手activiti,在這一節(jié)我們將結(jié)合代碼具體學(xué)習(xí)使用。小圖是我們需要完成的請(qǐng)假流程圖:
正如我們?cè)趫D中看到的,這是一個(gè)非常簡(jiǎn)單的流程:?jiǎn)T工提出休假請(qǐng)求,提供休假天數(shù)和開始日期。請(qǐng)求發(fā)送給經(jīng)理。他們可以批準(zhǔn)/拒絕該請(qǐng)求。
如果獲得批準(zhǔn),則會(huì)定義一個(gè)服務(wù)任務(wù)servicetask來發(fā)送確認(rèn)電子郵件。如果被拒絕,員工可以選擇修改并重新發(fā)送請(qǐng)求,也可以不執(zhí)行任何操作。
此流程的bpmn 2.0定義文件vacationrequest.bpmn20.xml將start事件定義為:
1
2
3
4
5
6
7
8
9
10
|
<startevent id= "startevent" name= "請(qǐng)假" activiti:initiator= "employeename" > <extensionelements> <activiti:formproperty id= "numberofdays" name= "number of days" type= "long" required= "true" /> <activiti:formproperty id= "startdate" name= "vacation start date (mm-dd-yyyy)" type= "date" datepattern= "mm-dd-yyyy hh:mm" required= "true" /> <activiti:formproperty id= "reason" name= "reason for leave" type= "string" /> <modeler:editor-resource-id><![cdata[startevent1]]></modeler:editor-resource-id> </extensionelements> </startevent> |
分配給用戶組“management”的第一個(gè)用戶任務(wù)usertask將如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<usertask id= "handle_vacation_request" name= "申請(qǐng)請(qǐng)假" > <documentation>${employeename} 請(qǐng)假 ${numberofdays} 天 (motivation: ${reason}). </documentation> <extensionelements> <activiti:formproperty id= "vacationapproval" name= "你要批準(zhǔn)這個(gè)請(qǐng)假要求嗎?" type= "enum" required= "true" /> <activiti:formproperty id= "comments" name= "經(jīng)理的批示" type= "string" /> <modeler:allow-send-email><![cdata[ true ]]></modeler:allow-send-email> <modeler:activiti-idm-initiator><![cdata[ true ]]></modeler:activiti-idm-initiator> <modeler:editor-resource-id> <![cdata[sid-b9aa8e66-2f11-45d0-a270-b052e1a9248e]]></modeler:editor-resource-id> </extensionelements> <potentialowner> <resourceassignmentexpression> <formalexpression>management</formalexpression> </resourceassignmentexpression> </potentialowner> </usertask> |
使用servicetask,我們需要定義要執(zhí)行的代碼段。我們將sendemailservicetask.java類作為這段代碼執(zhí)行者。
1
2
3
4
5
6
7
|
<servicetask id= "send-email-confirmation" name= "發(fā)送郵件確認(rèn)" activiti: class = "com.example.activitiwithspring.servicetasks.sendemailservicetask.java" > <extensionelements> <modeler:editor-resource-id> <![cdata[sid-2c5e1831- 9101 -4f70-9aef-4ba72b704205]]></modeler:editor-resource-id> </extensionelements> </servicetask> |
sendemailservicetask的代碼如下:實(shí)現(xiàn)javadelegate接口,實(shí)現(xiàn)其execute方法:
1
2
3
4
5
6
7
|
public class sendemailservicetask implements javadelegate { public void execute(delegateexecution execution) { //logic to sent email confirmation } } |
通過在“sequenceflow”中添加“conditionexpression”標(biāo)記來決定發(fā)送郵件在什么條件下觸發(fā),也就是定義一個(gè)條件流:
1
2
3
4
5
6
7
8
9
10
|
<sequenceflow id= "flow3" name= "批準(zhǔn)" sourceref= "sid-12a577ae-5227-4918-8de1-dc077d70967c" targetref= "send-email-confirmation" > <extensionelements> <modeler:editor-resource-id> <![cdata[sid-609beb69-e833-4d2f-bd14-fc8f7fd3e9c7]]></modeler:editor-resource-id> </extensionelements> <conditionexpression xsi:type= "tformalexpression" > <![cdata[${vacationapproved == 'true' }]]></conditionexpression> </sequenceflow> |
這里,vacationapproved是上面的usertask的formproperty。
部署流程
為了使我們的流程被activiti engine所知,我們需要部署該流程。我們可以使用repositoryservice以編程方式執(zhí)行此操作。讓我們編寫一個(gè)junit測(cè)試來看看:
1
2
3
4
5
6
7
8
9
10
|
@test public void givenbpmn_whendeployprocess_thendeployed() { processengine processengine = processengines.getdefaultprocessengine(); repositoryservice repositoryservice = processengine.getrepositoryservice(); repositoryservice.createdeployment() .addclasspathresource( "org/activiti/test/vacationrequest.bpmn20.xml" ) .deploy(); long count = repositoryservice.createprocessdefinitionquery().count(); asserttrue(count >= 1 ); } |
部署意味著引擎將解析bpmn流程定義文件并將其轉(zhuǎn)換為可執(zhí)行文件。此外,還會(huì)將記錄添加到每個(gè)部署的repository表中。之后,我們可以查詢r(jià)epository服務(wù)從而獲取已部署的進(jìn)程:也就是processdefinitions。
啟動(dòng)流程實(shí)例processinstance
在將processdefinition部署到activiti engine之后,我們可以通過創(chuàng)建processinstances來執(zhí)行該流程定義。如果說processdefinition繪制的是一幅藍(lán)圖,那么processinstance就是它的執(zhí)行實(shí)現(xiàn)。
對(duì)于一個(gè)processdefinition,可以有多個(gè)processinstances。
可以通過runtimeservice訪問與processinstances相關(guān)的所有詳細(xì)信息。
在我們的示例中,在開始事件中,我們需要傳遞休假天數(shù)、開始日期和原因。我們將使用流程變量,并在創(chuàng)建processinstance時(shí)傳遞它們。
編寫一個(gè)junit測(cè)試用例實(shí)現(xiàn)上面想法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@test public void givendeployedprocess_whenstartprocessinstance_thenrunning() { //deploy the process definition map<string, object> variables = new hashmap >(); variables.put( "employeename" , "john" ); variables.put( "numberofdays" , 4 ); variables.put( "vacationmotivation" , "i need a break!" ); runtimeservice runtimeservice = processengine.getruntimeservice(); processinstance processinstance = runtimeservice .startprocessinstancebykey( "vacationrequest" , variables); long count=runtimeservice.createprocessinstancequery().count(); assertequals( "1" , count.tostring()); } |
某個(gè)流程定義的多個(gè)實(shí)例將因流程變量而異,也就是說,同一份流程定義,因?yàn)樽兞坎煌瑢?dǎo)致流程實(shí)例也會(huì)不同。
有多種方法啟動(dòng)流程實(shí)例,在這里,我們正在使用該流程的key:vacationrequest啟動(dòng)流程,啟動(dòng)流程實(shí)例后,我們可以通過查詢r(jià)untimeservice來獲取有關(guān)它的信息。
完成任務(wù)
當(dāng)我們的流程實(shí)例開始運(yùn)行時(shí),第一步執(zhí)行的是用戶任務(wù)usertask,分配任務(wù)給用戶組“management”的用戶。該用戶可能有一個(gè)收件箱,其中包含要由他們完成的任務(wù)列表。現(xiàn)在,如果我們想繼續(xù)執(zhí)行流程,則需要用戶完成此任務(wù)。對(duì)于activiti engine,它被稱為“完成任務(wù)”。
我們可以查詢taskservice,獲取任務(wù)對(duì)象,然后完成它。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@test public void givenprocessinstance_whencompletetask_thengotnexttask() { // 部署流程并開始一個(gè)流程實(shí)例 taskservice taskservice = processengine.gettaskservice(); list<task> tasks = taskservice.createtaskquery() .taskcandidategroup( "management" ).list(); task task = tasks.get( 0 ); map<string, object> taskvariables = new hashmap<>(); taskvariables.put( "vacationapproved" , "false" ); taskvariables.put( "comments" , "we have a tight deadline!" ); taskservice.complete(task.getid(), taskvariables); task currenttask = taskservice.createtaskquery() .taskname( "修改休假請(qǐng)求" ).singleresult(); assertnotnull(currenttask); } |
請(qǐng)注意,taskservice的complete()方法也接受所需的流程變量。我們傳遞了經(jīng)理的回復(fù)。
在此之后,流程引擎將繼續(xù)下一步。在這里,下一步詢問員工是否要重新發(fā)送休假請(qǐng)求。
因此,我們的processinstance正在等待此usertask,其名稱為“修改休假請(qǐng)求”。
暫停和激活流程
我們可以暫停processdefinition和processinstance。如果我們暫停一個(gè)流程定義processdefinition,則在它暫停掛起時(shí)我們就無法創(chuàng)建它的實(shí)例。我們可以使用repositoryservice來做到這一點(diǎn):
1
2
3
4
5
6
|
@test (expected = activitiexception. class ) public void givendeployedprocess_whensuspend_thennoprocessinstance() { // deploy the process definition repositoryservice.suspendprocessdefinitionbykey( "vacationrequest" ); runtimeservice.startprocessinstancebykey( "vacationrequest" ); } |
要再次激活它,我們只需要調(diào)用其中一個(gè)repositoryservice.activateprocessdefinitionxxx方法。
同樣,我們可以使用runtimeservice暫停processinstance 。
結(jié)論
在本文中,我們了解了如何將activiti與spring boot結(jié)合使用。我們創(chuàng)建了一個(gè)示例processenginecofiguration文件,它可以幫助我們創(chuàng)建processengine。processengine提供的服務(wù)幫助我們管理和跟蹤processdefinitions,processinstances,usertasks等。
示例代碼位于github上。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)服務(wù)器之家的支持。
原文鏈接:https://www.jdon.com/springboot/spring-activiti-2.html