Flowable是什么
-
Flowable是一個(gè)使用Java編寫(xiě)的輕量級(jí)業(yè)務(wù)流程引擎。Flowable流程引擎可用于部署B(yǎng)PMN 2.0流程定義(用于定義流程的行業(yè)XML標(biāo)準(zhǔn)), 創(chuàng)建這些流程定義的流程實(shí)例,進(jìn)行查詢(xún),訪問(wèn)運(yùn)行中或歷史的流程實(shí)例與相關(guān)數(shù)據(jù),等等。這個(gè)章節(jié)將用一個(gè)可以在你自己的開(kāi)發(fā)環(huán)境中使用的例子,逐步介紹各種概念與API。
-
Flowable可以十分靈活地加入你的應(yīng)用/服務(wù)/構(gòu)架??梢詫AR形式發(fā)布的Flowable庫(kù)加入應(yīng)用或服務(wù),來(lái)嵌入引擎。 以JAR形式發(fā)布使Flowable可以輕易加入任何Java環(huán)境:Java SE;Tomcat、Jetty或Spring之類(lèi)的servlet容器;JBoss或WebSphere之類(lèi)的Java EE服務(wù)器,等等。 另外,也可以使用Flowable REST API進(jìn)行HTTP調(diào)用。也有許多Flowable應(yīng)用(Flowable Modeler, Flowable Admin, Flowable IDM 與 Flowable Task),提供了直接可用的UI示例,可以使用流程與任務(wù)。
-
所有使用Flowable方法的共同點(diǎn)是核心引擎。核心引擎是一組服務(wù)的集合,并提供管理與執(zhí)行業(yè)務(wù)流程的API。 下面的教程從設(shè)置與使用核心引擎的介紹開(kāi)始。后續(xù)章節(jié)都建立在之前章節(jié)中獲取的知識(shí)之上。
-
官網(wǎng)使用手冊(cè)
鏈接: https://tkjohn.github.io/flowable-userguide/#_getting_started_2
下載使用flowableUI
目的:在flowableUI中畫(huà)bpmn20圖,生成bpmn20.xml文件
百度網(wǎng)盤(pán)下載
鏈接:https://pan.baidu.com/s/1EKOSIl9ZVUpF0VGmte0utw?pwd=wd0s
提取碼:wd0s
啟動(dòng)flowableUI
解壓開(kāi)后復(fù)制flowable-6.7.2\wars目錄下的兩個(gè)war包
將war包放入tomcat的webapps目錄下
啟動(dòng)tomcat:在bin目錄下點(diǎn)擊startup.bat
flowableUI使用(只操作創(chuàng)建bpmn20.xml文件)
- 進(jìn)入建模器應(yīng)用程序—>創(chuàng)建流程
- 創(chuàng)建流程
- 分配用戶(hù)
- 點(diǎn)擊固定值–>分配填入用戶(hù)–>例如張三–>另一個(gè)usertask以此類(lèi)推
- 保存
- 下載bpmn20.xml,點(diǎn)擊顯示詳情信息–>導(dǎo)出bomn2–>結(jié)束
Flowable項(xiàng)目使用
創(chuàng)建工程
通過(guò)idea創(chuàng)建或者eclipse創(chuàng)建一個(gè)maven工程
引入依賴(lài)
- 需要添加兩個(gè)依賴(lài):
Flowable流程引擎。使我們可以創(chuàng)建一個(gè)ProcessEngine流程引擎對(duì)象,并訪問(wèn)Flowable API。
數(shù)據(jù)庫(kù)驅(qū)動(dòng)依賴(lài)。生成flowable流程表
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-engine</artifactId>
<version>6.3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
引入測(cè)試包
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
如果控制臺(tái)沒(méi)有詳細(xì)的日志的話(huà),可以使用log4j作為slf4j的實(shí)現(xiàn)
- 在pom添加依賴(lài):
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
- 在src/main/resources文件夾下添加log4j.properties文件,并寫(xiě)入下列內(nèi)容:
log4j.rootLogger=DEBUG, CA
log4j.appender.CA=org.apache.log4j.ConsoleAppender
log4j.appender.CA.layout=org.apache.log4j.PatternLayout
log4j.appender.CA.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n
RepositoryService、RuntimeService、TaskService、HistoryService的使用
創(chuàng)建流程引擎
- 首先要做的就是初始化ProcessEngine流程引擎實(shí)例。這是一個(gè)線程安全的對(duì)象,因此通常只需要在一個(gè)應(yīng)用中初始化一次。ProcessEngine由ProcessEngineConfiguration實(shí)例創(chuàng)建。該實(shí)例可以配置與調(diào)整流程引擎的設(shè)置。通常使用一個(gè)配置xml文件創(chuàng)建ProcessEngineConfiguration,也可以通過(guò)編程方式創(chuàng)建它。
- 新建Test方法:
/**
* 獲取流程引擎對(duì)象
*/
@Test
public void testProcessEngine() {
//獲取ProcessEngineConfiguration對(duì)象
ProcessEngineConfiguration processEngineConfiguration = new StandaloneProcessEngineConfiguration();
//配置相關(guān)的數(shù)據(jù)庫(kù)信息
processEngineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?serverTimezone=UTC")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver");
//如果數(shù)據(jù)庫(kù)中表結(jié)構(gòu)不存在就新建
processEngineConfiguration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
//通過(guò)ProcessEngineConfiguration 構(gòu)建我們需要的ProcessEngine對(duì)象
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
}
- 執(zhí)行該程序,控制臺(tái)不出錯(cuò)的話(huà),就是操作完成了。查看下數(shù)據(jù)庫(kù),生成了34張act表。
部署流程定義
- 我們要構(gòu)建的流程是一個(gè)非常簡(jiǎn)單的請(qǐng)假流程。Flowable引擎需要流程定義為BPMN 2.0格式,這是一個(gè)業(yè)界廣泛接受的XML標(biāo)準(zhǔn)。 在Flowable術(shù)語(yǔ)中,我們將其稱(chēng)為一個(gè)流程定義(process definition)。一個(gè)流程定義可以啟動(dòng)多個(gè)流程實(shí)例(process instance)。流程定義可以看做是重復(fù)執(zhí)行流程的藍(lán)圖。 在這個(gè)例子中,流程定義定義了請(qǐng)假的各個(gè)步驟,而一個(gè)流程實(shí)例對(duì)應(yīng)某個(gè)雇員提出的一個(gè)請(qǐng)假申請(qǐng)。
- BPMN 2.0存儲(chǔ)為XML,并包含可視化的部分:使用標(biāo)準(zhǔn)方式定義了每個(gè)步驟類(lèi)型(人工任務(wù),自動(dòng)服務(wù)調(diào)用,等等)如何呈現(xiàn),以及如何互相連接。這樣BPMN 2.0標(biāo)準(zhǔn)使技術(shù)人員與業(yè)務(wù)人員能用雙方都能理解的方式交流業(yè)務(wù)流程。
- 我們要使用的流程定義為:
來(lái)自官網(wǎng)文檔圖 - 簡(jiǎn)單的說(shuō)明一下這個(gè)流程:
- 假定啟動(dòng)流程需要提供一些信息,例如雇員名字、請(qǐng)假時(shí)長(zhǎng)以及說(shuō)明。當(dāng)然,這些可以單獨(dú)建模為流程中的第一步。但是如果將他們作為流程的"輸入信息",就能保證只有在實(shí)際請(qǐng)求時(shí)才會(huì)建立一個(gè)流程實(shí)例。否則將提交作為流程的第一步,用戶(hù)可能在提交之前改變主意并取消,但流程實(shí)例已經(jīng)創(chuàng)建了。在某些場(chǎng)景中,就可能影響重要的指標(biāo)(例如提交了多少申請(qǐng),但未完成),取決于業(yè)務(wù)目標(biāo)。
- 圖中左側(cè)的圓圈叫做啟動(dòng)事件(start event)。這是一個(gè)流程實(shí)例的起點(diǎn)。
第一個(gè)矩形是一個(gè)用戶(hù)任務(wù)(user task)。這是流程中用戶(hù)操作的步驟。在這里例子中,后續(xù)經(jīng)理需要批準(zhǔn)或者駁回用戶(hù)的申請(qǐng)。 - 帶叉的菱形是一個(gè)排他網(wǎng)關(guān)(exclusive gateway)。后面還有其他的網(wǎng)關(guān)介紹。這里的排他網(wǎng)關(guān)取決于經(jīng)理的操作,然后將流程實(shí)例轉(zhuǎn)至批準(zhǔn)或者駁回路徑。
- 如果批準(zhǔn),則通過(guò)另一個(gè)用戶(hù)任務(wù)(user task),將經(jīng)理的決定通知給申請(qǐng)人。當(dāng)然也可以是別的通知方式(發(fā)郵件等)。
- 如果駁回,可以直接發(fā)郵件通知申請(qǐng)人。
- 這樣的流程定義使用可視化建模工具建立,如Flowable Designer(Eclipse)或Web應(yīng)用(flowableUI)。
- 與上面展示的流程圖對(duì)應(yīng)的BPMN 2.0 XML在下面顯示。請(qǐng)注意這只包含了“流程部分”。如果使用圖形化建模工具,實(shí)際的XML文件還將包含“可視化部分”,用于描述圖形信息,如流程定義中各個(gè)元素的坐標(biāo)(所有的圖形化信息包含在XML的BPMNDiagram標(biāo)簽中,作為definitions標(biāo)簽的子元素)。
- 在src/main/resources文件夾下創(chuàng)建名為holiday-request.bpmn20.xml的文件,這個(gè)名字隨意,這里當(dāng)前需要設(shè)計(jì)的流程定義的,請(qǐng)假流程申請(qǐng)
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
xmlns:flowable="http://flowable.org/bpmn"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.flowable.org/processdef">
<process id="holidayRequest" name="Holiday Request" isExecutable="true">
<startEvent id="startEvent"/>
<sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>
<!--flowable:assignee userTask審批人-->
<userTask id="approveTask" name="Approve or reject request" flowable:assignee="lisi"/>
<sequenceFlow sourceRef="approveTask" targetRef="decision"/>
<exclusiveGateway id="decision"/>
<sequenceFlow sourceRef="decision" targetRef="externalSystemCall">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[
${approved}
]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="decision" targetRef="sendRejectionMail">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[
${!approved}
]]>
</conditionExpression>
</sequenceFlow>
<serviceTask id="externalSystemCall" name="Enter holidays in external system"
flowable:class="com.flowable.demo.CallExternalSystemDelegate"/>
<sequenceFlow sourceRef="externalSystemCall" targetRef="holidayApprovedTask"/>
<userTask id="holidayApprovedTask" name="Holiday approved"/>
<sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/>
<serviceTask id="sendRejectionMail" name="Send out rejection email"
flowable:class="com.flowable.demo.SendRejectionMail"/>
<sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/>
<endEvent id="approveEnd"/>
<endEvent id="rejectEnd"/>
</process>
</definitions>
-
xml文件介紹
- 每一個(gè)步驟(在BPMN 2.0術(shù)語(yǔ)中稱(chēng)作活動(dòng)(activity))都有一個(gè)id屬性,為其提供一個(gè)在XML文件中唯一的標(biāo)識(shí)符。所有的活動(dòng)都可以設(shè)置一個(gè)名字,以提高流程圖的可讀性。
- 活動(dòng)之間通過(guò)**順序流(sequence flow)**連接,在流程圖中是一個(gè)有向箭頭。在執(zhí)行流程實(shí)例時(shí),執(zhí)行(execution)會(huì)從啟動(dòng)事件沿著順序流流向下一個(gè)活動(dòng)。
- 離開(kāi)排他網(wǎng)關(guān)(帶有X的菱形)的順序流很特別:都以表達(dá)式(execution)的形式定義了條件(condition)。當(dāng)流程實(shí)例的執(zhí)行到達(dá)這個(gè)網(wǎng)關(guān)時(shí),會(huì)計(jì)算條件,并使用第一個(gè)計(jì)算為true的順序流。這就是排他的含義:只選擇一個(gè)。當(dāng)然如果有需要不同的策略,也可以使用其他類(lèi)型的網(wǎng)格。
- 這里用作條件的表達(dá)式為a p p r o v e d ? ,這是 ? {approved},這是*approved?,這是?{approved == true}*的簡(jiǎn)寫(xiě)。變量approved被稱(chēng)作流程變量(process variable)。流程變量是持久化的數(shù)據(jù),與流程實(shí)例存儲(chǔ)在一起并可以在流程實(shí)例的生命周期中使用。在這個(gè)例子中,我們需要在特定的地方(當(dāng)經(jīng)理用戶(hù)任務(wù)提交時(shí),或者以Flowable的術(shù)語(yǔ)來(lái)說(shuō),完成(complete)時(shí))設(shè)置這個(gè)流程變量,因?yàn)檫@不是流程實(shí)例啟動(dòng)時(shí)就能獲取的數(shù)據(jù)。
-
現(xiàn)在我們已經(jīng)有了流程BPMN 2.0 XML文件,下來(lái)需要將它***部署(deploy)***到引擎中。部署一個(gè)流程定義意味著:
- 流程引擎會(huì)將XML文件存儲(chǔ)在數(shù)據(jù)庫(kù)中,這樣可以在需要的時(shí)候獲取它。
- 流程定義轉(zhuǎn)換為內(nèi)部的、可執(zhí)行的對(duì)象模型,這樣使用它就可以啟動(dòng)流程實(shí)例。
-
將流程定義部署至Flowable引擎,需要使用*RepositoryService,其可以從ProcessEngine對(duì)象獲取。使用RepositoryService,可以通過(guò)XML文件的路徑創(chuàng)建一個(gè)新的部署(Deployment),并調(diào)用deploy()*方法實(shí)際執(zhí)行:
- 測(cè)試類(lèi)中添加測(cè)試部署方式:
private ProcessEngineConfiguration processEngineConfiguration;
/**
* 初始化封裝下,不然每個(gè)測(cè)試方法都要寫(xiě),很麻煩
*/
@Before
public void init() {
//獲取ProcessEngineConfiguration對(duì)象
processEngineConfiguration = new StandaloneProcessEngineConfiguration();
//配置相關(guān)的數(shù)據(jù)庫(kù)信息
processEngineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?serverTimezone=UTC")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver");
//如果數(shù)據(jù)庫(kù)中表結(jié)構(gòu)不存在就新建
processEngineConfiguration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
}
/**
* 部署流程
* RepositoryService介紹:
* 查詢(xún)引擎現(xiàn)有的部署與流程定義。
* 暫停或激活部署中的某些流程,或整個(gè)部署。暫停意味著不能再對(duì)它進(jìn)行操作,激活剛好相反,重新使它可以操作。
* 獲取各種資源,比如部署中保存的文件,或者引擎自動(dòng)生成的流程圖。
* 獲取POJO版本的流程定義。它可以用Java而不是XML的方式查看流程。
*/
@Test
public void deployment() {
//獲取ProcessEngine對(duì)象
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
//獲取部署接口
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("holiday-request.bpmn20.xml")
.name("請(qǐng)假流程")
.deploy();
System.out.println("deploy.getId():" + deploy.getId());
System.out.println("deploy.getName():" + deploy.getName());
System.out.println("deploy.getKey():" + deploy.getKey());
System.out.println("deploy.getCategory():" + deploy.getCategory());
System.out.println("deploy.getTenantId():" + deploy.getTenantId());
}
- key,name自己根據(jù)業(yè)務(wù)定義
deploy.getId():70001
deploy.getName():請(qǐng)假流程
deploy.getKey():null
deploy.getCategory():null
deploy.getTenantId():
-
查看下數(shù)據(jù)庫(kù):
- act_re_deployment:流程定義部署表,沒(méi)部署一次就會(huì)增加一條記錄
- 這里的ID=67501,就是我們代碼部署生成的記錄
- act_re_procdef:流程定義表,部署新的流程定義就會(huì)新增一條記錄,表中DELOYMENT_ID就是act_re_deployment的主鍵ID
- act_ge_bytearray:流程資源表,流程部署的bpmn文件和png文件都會(huì)存在該表
-
現(xiàn)在可以通過(guò)API查詢(xún)驗(yàn)證流程定義已經(jīng)部署在引擎中(并學(xué)習(xí)一些API)。通過(guò)RepositoryService創(chuàng)建的ProcessDefinitionQuery對(duì)象實(shí)現(xiàn)。
//查詢(xún)流程定義的信息
@Test
public void queryDeployment() {
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.deploymentId("67501")
.singleResult();
System.out.println("processDefinition.getDeploymentId() = " + processDefinition.getDeploymentId());
System.out.println("processDefinition.getName() = " + processDefinition.getName());
System.out.println("processDefinition.getDescription() = " + processDefinition.getDescription());
System.out.println("processDefinition.getKey() = " + processDefinition.getKey());
System.out.println("processDefinition.getId() = " + processDefinition.getId());
}
processDefinition.getDeploymentId() = 70001
processDefinition.getName() = Holiday Request
processDefinition.getDescription() = null
processDefinition.getKey() = holidayRequest
processDefinition.getId() = holidayRequest:1:70003
啟動(dòng)流程實(shí)例
-
現(xiàn)在已經(jīng)在流程引擎中部署了流程定義,因此可以使用這個(gè)流程定義作為“藍(lán)圖”啟動(dòng)流程實(shí)例。
-
一個(gè)部署成功的流程定義可以啟動(dòng)多個(gè)流程實(shí)例,就好比請(qǐng)假申請(qǐng)單,是可以多個(gè)員工都可以去填寫(xiě)的。
-
要啟動(dòng)流程實(shí)例,通常需要提供一些初始化流程變量。一般來(lái)說(shuō),可以通過(guò)呈現(xiàn)給用戶(hù)的表單,或者在流程由其他系統(tǒng)自動(dòng)觸發(fā)時(shí)通過(guò)REST API,來(lái)獲取這些變量。這樣才能達(dá)到一個(gè)比較全面的數(shù)據(jù)交互。
-
接下來(lái),我們使用RuntimeService啟動(dòng)一個(gè)流程實(shí)例。收集的數(shù)據(jù)作為一個(gè)java.util.Map實(shí)例傳遞,其中的鍵就是之后用于獲取變量的標(biāo)識(shí)符。這個(gè)流程實(shí)例使用key啟動(dòng)。這個(gè)key就是BPMN 2.0 XML文件中設(shè)置的id屬性,在這個(gè)例子里是holidayRequest,也就是act_re_procdef表中的KEY_字段
//啟動(dòng)流程實(shí)例
@Test
public void startProcess() {
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
//獲取啟動(dòng)對(duì)象
RuntimeService runtimeService = processEngine.getRuntimeService();
//初始化流程變量,這些變量實(shí)際是從頁(yè)面表單傳過(guò)來(lái)的,員工填寫(xiě)請(qǐng)假申請(qǐng)單的一些相關(guān)表單數(shù)據(jù)
Map<String, Object> var = new HashMap<>();
var.put("employee", "張三");
var.put("description", "累了想請(qǐng)假");
//啟動(dòng)流程實(shí)例
//holidayRequest就是流程定義的ID,在xml或者`act_re_procdef`的`KEY_`字段都能查到
ProcessInstance holidayRequest = runtimeService.startProcessInstanceByKey("holidayRequest", var);
System.out.println("holidayRequest.getProcessDefinitionId() = " + holidayRequest.getProcessDefinitionId());
}
-
執(zhí)行成功后,觀察數(shù)據(jù)庫(kù)表:
act_ru_task:任務(wù)信息表,會(huì)新增一條任務(wù)記錄 -
act_ru_variable:流程實(shí)例的流程變量信息
可以看到代碼中,map存放的變量數(shù)據(jù) -
act_ru_execution:流程執(zhí)行的過(guò)程信息
-
act_hi_procinst:流程實(shí)例歷史信息
-
act_hi_taskinst:流程任務(wù)歷史信息
-
act_hi_actinst:流程實(shí)例執(zhí)行歷史
查詢(xún)?nèi)蝿?wù)
-
在實(shí)際的應(yīng)用中,會(huì)為用戶(hù)提供界面化操作,讓他們可以登錄并查看任務(wù)列表。可以看到作為流程變量存儲(chǔ)的流程實(shí)例數(shù)據(jù),并決定后續(xù)如何操作。現(xiàn)在通過(guò)API的方式調(diào)用查詢(xún)?nèi)蝿?wù)列表。
-
在開(kāi)始的創(chuàng)建的holiday-request.bpmn20.xml中并沒(méi)有為用戶(hù)任務(wù)配置處理人,即某個(gè)員工發(fā)起了請(qǐng)假流程申請(qǐng),但是后續(xù)并沒(méi)有領(lǐng)導(dǎo)去審核。我們?cè)谶@里需要加上任務(wù)的處理人
<!--在審核任務(wù)的節(jié)點(diǎn)上加上處理人,通過(guò)flowable:assignee屬性設(shè)置,目前是直接寫(xiě)死的,后續(xù)可以動(dòng)態(tài)設(shè)置-->
<userTask id="approveTask" name="Approve or reject request" flowable:assignee="lisi"/>
- 流程實(shí)例執(zhí)行完成后,去act_ru_task任務(wù)表去查看ASSIGNEE_字段,可以看到當(dāng)前任務(wù)的處理人就是剛剛flowable:assignee設(shè)置的
- 查詢(xún)lisi的任務(wù):
/**
* 查詢(xún)?nèi)蝿?wù)
*/
@Test
public void queryTask() {
//先獲取ProcessEngine對(duì)象
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
//獲取TaskService對(duì)象
TaskService taskService = processEngine.getTaskService();
// 查詢(xún)?nèi)蝿?wù)
List<Task> taskList = taskService
//創(chuàng)建查詢(xún)
.createTaskQuery()
//根據(jù)流程定義查詢(xún)
.processDefinitionKey("holidayRequest")
//根據(jù)任務(wù)人查詢(xún)
.taskAssignee("lisi")
.list();
for (Task task : taskList) {
System.out.println("task.getProcessDefinitionId() = " + task.getProcessDefinitionId());
System.out.println("task.getId() = " + task.getId());
System.out.println("task.getAssignee() = " + task.getAssignee());
System.out.println("task.getName() = " + task.getName());
}
}
- 查詢(xún)結(jié)果
task.getProcessDefinitionId() = holidayRequest:1:70003
task.getId() = 72507
task.getAssignee() = lisi
task.getName() = Approve or reject request
完成任務(wù)
- 上面流程已經(jīng)發(fā)起成功了,任務(wù)成功流轉(zhuǎn)到lisi來(lái)處理,現(xiàn)在通過(guò)lisi來(lái)完成任務(wù),確定任務(wù)的下一步走向
-
按照事先定好的流程圖,下一步操作是通過(guò)排他網(wǎng)關(guān)處理,這里暫時(shí)不用管網(wǎng)關(guān)具體是什么,我們只需要這一步經(jīng)理lisi的操作需要通過(guò)網(wǎng)關(guān)來(lái)流轉(zhuǎn)到不同的走向,這里目前有兩個(gè)走向,通過(guò)和拒絕,我們先拒絕這個(gè)任務(wù)
-
在流程的xml文件可以看到serviceTask中flowable:class=com.flowable.demo.SendRejectionMail,這個(gè)意思是,當(dāng)我們拒絕后會(huì)觸發(fā)Send out rejection email 這個(gè)任務(wù)標(biāo)簽的實(shí)現(xiàn)類(lèi),這個(gè)類(lèi)需要我們自己定義然后去實(shí)現(xiàn)JavaDelegate
-
定義一個(gè)這樣的類(lèi):flowable:class的路徑及類(lèi)根據(jù)自己的創(chuàng)建的來(lái)設(shè)置,這里就按照com.flowable.demo.SendRejectionMail來(lái)創(chuàng)建了
-
package com.flowable.demo;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
public class SendRejectionMail implements JavaDelegate {
/**
* flowable中的觸發(fā)器
* @param delegateExecution
*/
@Override
public void execute(DelegateExecution delegateExecution) {
//觸發(fā)執(zhí)行的邏輯 發(fā)送郵件
System.out.println("SendRejectionMail:被拒絕了");
}
}
- list完成任務(wù):
/**
* 完成任務(wù)
*/
@Test
public void completeTask() {
//獲取ProcessEngine對(duì)象
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
//再獲取lisi的任務(wù)
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().processDefinitionKey("holidayRequest").taskAssignee("lisi").singleResult();
//完成該任務(wù),同時(shí)添加該任務(wù)的流程變量信息
Map<String, Object> variables = new HashMap<>();
//這個(gè)approved變量就是流程里面排他網(wǎng)關(guān)節(jié)點(diǎn)設(shè)置的,通過(guò)給這個(gè)流程變量值后判斷流程的下一步走向
variables.put("approved", false);//這里false是拒絕
//完成任務(wù),complete需要的參數(shù):任務(wù)ID,流程節(jié)點(diǎn)中的流程變量
taskService.complete(task.getId(), variables);
}
- 執(zhí)行代碼,可以看到拒絕流程自定義的JavaDelegate觸發(fā)了
- 按照當(dāng)前的流程設(shè)計(jì),拒絕之后,流程也就結(jié)束了,再去查看act_ru_task表已經(jīng)沒(méi)有該任務(wù)數(shù)據(jù)了
歷史任務(wù)
-
當(dāng)流程處于執(zhí)行過(guò)程中,或者已經(jīng)執(zhí)行結(jié)束了,我們都可以查詢(xún)到該流程實(shí)例的歷史數(shù)據(jù)文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-802666.html
-
可以通過(guò)ProcessEngine獲取HistoryService創(chuàng)建歷史活動(dòng)查詢(xún)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-802666.html
/**
* 流程實(shí)例的歷史任務(wù)
*/
@Test
public void historyTask() {
//獲取ProcessEngine對(duì)象
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
//獲取historyService
HistoryService historyService = processEngine.getHistoryService();
List<HistoricActivityInstance> activityInstances = historyService
.createHistoricActivityInstanceQuery()
//按流程實(shí)例ID查詢(xún),這個(gè)流程定義是啟動(dòng)流程后有的
.processDefinitionId("holidayRequest:1:70003")
//查詢(xún)已完成的
.finished()
//按照結(jié)束時(shí)間排序
.orderByHistoricActivityInstanceEndTime().asc()
.list();
for (HistoricActivityInstance activityInstance : activityInstances) {
System.out.println(historicActivityInstance.getActivityId() + ":" + historicActivityInstance.getActivityName() +
":" + historicActivityInstance.getAssignee() + ":" + historicActivityInstance.getDurationInMillis() + "毫秒");
}
}
startEvent:null:null:2毫秒
approveTask:Approve or reject request:lisi:9388974毫秒
decision:null:null:15毫秒
sendRejectionMail:Send out rejection email:null:10毫秒
rejectEnd:null:null:2毫秒
刪除任務(wù)
/**
* 刪除任務(wù)
*/
@Test
public void deleteTask() {
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
taskService.deleteTask("xxx");
}
刪除流程
- 當(dāng)流程不需要的時(shí)候可以將其刪除
/**
* 刪除流程定義
*/
@Test
public void deleteProcess() {
//獲取ProcessEngine對(duì)象
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
//獲取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//刪除流程定義
//根據(jù)流程部署ID刪除,如果流程未啟動(dòng)可以直接通過(guò)流程部署ID刪除,否則流程啟動(dòng)后該刪除會(huì)報(bào)異常
//根據(jù)流程部署ID刪除,同時(shí)設(shè)置級(jí)聯(lián)刪除,true就是表示級(jí)聯(lián)刪除,即使流程已經(jīng)啟動(dòng)也會(huì)刪除成功及所關(guān)聯(lián)的數(shù)據(jù)
repositoryService.deleteDeployment("xxx", true);
}
流程掛起與激活
//流程的掛起和激活
@Test
public void suspendedProcess() {
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
//獲取對(duì)應(yīng)的流程定義信息
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionId("holidayRequest:1:70003")
.singleResult();
//獲取當(dāng)前的流程定義的 狀態(tài)信息
boolean suspended = processDefinition.isSuspended();
if (suspended) {
//當(dāng)前流程被掛起了
//激活流程
System.out.println("激活流程" + processDefinition.getId() + ":" + processDefinition.getName());
repositoryService.activateProcessDefinitionById("holidayRequest:1:70003");
} else {
//當(dāng)前流程是激活狀態(tài)
//掛起當(dāng)前流程
repositoryService.suspendProcessDefinitionById("holidayRequest:1:70003");
System.out.println("掛起流程" + processDefinition.getId() + ":" + processDefinition.getName());
}
}
到了這里,關(guān)于工作流Flowable入門(mén)教程:flowableUI的安裝使用,RepositoryService、RuntimeService、TaskService、HistoryService的使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!