Spring Boot中使用Activiti的方法教程(二)
前言
前面一節(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ù)和開(kāi)始日期。請(qǐng)求發(fā)送給經(jīng)理。他們可以批準(zhǔn)/拒絕該請(qǐng)求。
如果獲得批準(zhǔn),則會(huì)定義一個(gè)服務(wù)任務(wù)serviceTask來(lái)發(fā)送確認(rèn)電子郵件。如果被拒絕,員工可以選擇修改并重新發(fā)送請(qǐng)求,也可以不執(zhí)行任何操作。
此流程的BPMN 2.0定義文件VacationRequest.bpmn20.xml將start事件定義為:
<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>
分配給用戶(hù)組“management”的第一個(gè)用戶(hù)任務(wù)userTask將如下所示:
<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類(lèi)作為這段代碼執(zhí)行者。
<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方法:
public class SendEmailServiceTask implements JavaDelegate {
public void execute(DelegateExecution execution) {
//logic to sent email confirmation
}
}
通過(guò)在“sequenceFlow”中添加“conditionExpression”標(biāo)記來(lái)決定發(fā)送郵件在什么條件下觸發(fā),也就是定義一個(gè)條件流:
<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í)行此操作。讓我們編寫(xiě)一個(gè)JUnit測(cè)試來(lái)看看:
@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表中。之后,我們可以查詢(xún)Repository服務(wù)從而獲取已部署的進(jìn)程:也就是ProcessDefinitions。
啟動(dòng)流程實(shí)例ProcessInstance
在將ProcessDefinition部署到Activiti Engine之后,我們可以通過(guò)創(chuàng)建ProcessInstances來(lái)執(zhí)行該流程定義。如果說(shuō)ProcessDefinition繪制的是一幅藍(lán)圖,那么processInstance就是它的執(zhí)行實(shí)現(xiàn)。
對(duì)于一個(gè)ProcessDefinition,可以有多個(gè)ProcessInstances。
可以通過(guò)RuntimeService訪(fǎng)問(wèn)與ProcessInstances相關(guān)的所有詳細(xì)信息。
在我們的示例中,在開(kāi)始事件中,我們需要傳遞休假天數(shù)、開(kāi)始日期和原因。我們將使用流程變量,并在創(chuàng)建ProcessInstance時(shí)傳遞它們。
編寫(xiě)一個(gè)JUnit測(cè)試用例實(shí)現(xiàn)上面想法:
@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í)例將因流程變量而異,也就是說(shuō),同一份流程定義,因?yàn)樽兞坎煌?,?dǎo)致流程實(shí)例也會(huì)不同。
有多種方法啟動(dòng)流程實(shí)例,在這里,我們正在使用該流程的key:vacationRequest啟動(dòng)流程,啟動(dòng)流程實(shí)例后,我們可以通過(guò)查詢(xún)RuntimeService來(lái)獲取有關(guān)它的信息。
完成任務(wù)
當(dāng)我們的流程實(shí)例開(kāi)始運(yùn)行時(shí),第一步執(zhí)行的是用戶(hù)任務(wù)userTask,分配任務(wù)給用戶(hù)組“management”的用戶(hù)。該用戶(hù)可能有一個(gè)收件箱,其中包含要由他們完成的任務(wù)列表。現(xiàn)在,如果我們想繼續(xù)執(zhí)行流程,則需要用戶(hù)完成此任務(wù)。對(duì)于Activiti Engine,它被稱(chēng)為“完成任務(wù)”。
我們可以查詢(xún)TaskService,獲取任務(wù)對(duì)象,然后完成它。
@Test
public void givenProcessInstance_whenCompleteTask_thenGotNextTask() {
// 部署流程并開(kāi)始一個(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ù)下一步。在這里,下一步詢(xún)問(wèn)員工是否要重新發(fā)送休假請(qǐng)求。
因此,我們的ProcessInstance正在等待此UserTask,其名稱(chēng)為“修改休假請(qǐng)求”。
暫停和激活流程
我們可以暫停ProcessDefinition和ProcessInstance。如果我們暫停一個(gè)流程定義ProcessDefinition,則在它暫停掛起時(shí)我們就無(wú)法創(chuàng)建它的實(shí)例。我們可以使用RepositoryService來(lái)做到這一點(diǎn):
@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à)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
java 數(shù)據(jù)結(jié)構(gòu)中棧結(jié)構(gòu)應(yīng)用的兩個(gè)實(shí)例
這篇文章主要介紹了java 數(shù)據(jù)結(jié)構(gòu)中棧結(jié)構(gòu)應(yīng)用的兩個(gè)實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-06-06
Java Socket編程實(shí)例(三)- TCP服務(wù)端線(xiàn)程池
這篇文章主要講解Java Socket編程中TCP服務(wù)端線(xiàn)程池的實(shí)例,希望能給大家做一個(gè)參考。2016-06-06
java 中使用匿名類(lèi)直接new接口詳解及實(shí)例代碼
這篇文章主要介紹了java 中使用匿名類(lèi)直接new接口詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-03-03
Java實(shí)現(xiàn)提取QSV文件視頻內(nèi)容
QSV是一種加密的視頻文件格式。是愛(ài)奇藝公司研發(fā)的一種視頻文件格式,這篇文章主要為大家介紹了如何利用Java實(shí)現(xiàn)提取QSV文件視頻內(nèi)容,感興趣的可以了解一下2023-03-03
如何用java對(duì)接微信小程序下單后的發(fā)貨接口
這篇文章主要介紹了在微信小程序后臺(tái)實(shí)現(xiàn)發(fā)貨通知的步驟,包括獲取Access_token、使用RestTemplate調(diào)用發(fā)貨接口、處理AccessToken緩存以及發(fā)貨成功后的提醒,需要的朋友可以參考下2025-03-03
SpringBoot 任務(wù)調(diào)度動(dòng)態(tài)設(shè)置方式(不用重啟服務(wù))
這篇文章主要介紹了SpringBoot 任務(wù)調(diào)度 動(dòng)態(tài)設(shè)置方式(不用重啟服務(wù)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
java calendar 日期實(shí)現(xiàn)不斷加一天的代碼
這篇文章主要介紹了java calendar 日期實(shí)現(xiàn)不斷加一天的代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10
SpringBoot+SpringBatch+Quartz整合定時(shí)批量任務(wù)方式
這篇文章主要介紹了SpringBoot+SpringBatch+Quartz整合定時(shí)批量任務(wù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Java數(shù)據(jù)敏感詞轉(zhuǎn)換成符號(hào)的方法詳解
在某個(gè)論壇下用戶(hù)可以隨意留言,為了防止不法分子在網(wǎng)上任意沖浪,需要對(duì)一些敏感詞匯進(jìn)行一些校驗(yàn),所以這篇文章給大家介紹了Java數(shù)據(jù)敏感詞轉(zhuǎn)換成符號(hào)的方法,需要的朋友可以參考下2024-03-03

