Flowable基本操作
1.建立ProcessEngine
建立一個基本的maven工程,可以是Eclipse也可以是其他IDEA。然後新增兩個依賴
- Flowable流程引擎。使我們可以建立一個ProcessEngine流程引擎物件,並訪問Flowable API。
- 一個是MySQL的資料庫驅動
在pom.xml檔案中新增下列行:
<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>
然後建立一個普通的Java類,新增對應的main方法,首先要做的是初始化「ProcessEngine」流程引擎例項。這是一個執行緒安全的物件,因此通常只需要在一個應用中初始化一次。 ProcessEngine由「ProcessEngineConfiguration」例項建立。該例項可以配置與調整流程引擎的設定。 通常使用一個配置XML檔案建立ProcessEngineConfiguration,但是(像在這裡做的一樣)也可以程式設計方式建立它。 ProcessEngineConfiguration所需的最小配置,是資料庫JDBC連線:
public static void main(String[] args) {
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?serverTimezone=UTC")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
ProcessEngine processEngine = cfg.buildProcessEngine();
}
注意在mysql8.0中執行可能出現如下的錯誤
出現這種情況只需要在mysql的連線字串中新增上nullCatalogMeansCurrent=true,設定為只查當前連線的schema庫即可。
public static void main(String[] args) {
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn1?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
ProcessEngine processEngine = cfg.buildProcessEngine();
}
然後應用執行沒有問題,但也沒有在控制檯提供有用的資訊,只有一條訊息提示日誌沒有正確配置。Flowable使用SLF4J作為內部日誌框架。在這個例子中,我們使用log4j作為SLF4J的實現。因此在pom.xml檔案中新增下列依賴:
<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>
Log4j需要一個配置檔案。在src/main/resources資料夾下新增log4j.properties檔案,並寫入下列內容:
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
重新執行應用。應該可以看到關於引擎啟動與建立資料庫表結構的提示日誌:
同時可以看到建立了相關的表結構在資料庫中
這樣就得到了一個啟動可用的流程引擎。接下來為它提供一個流程!
2.部署流程定義
接下來我們構建一個非常簡單的請假流程,Flowable引擎需要流程定義為BPMN 2.0格式,這是一個業界廣泛接受的XML標準。 在Flowable術語中,我們將其稱為一個**流程定義(process definition)「。一個流程定義可以啟動多個」流程例項(process instance)**。流程定義可以看做是重複執行流程的藍圖。 在這個例子中,流程定義定義了請假的各個步驟,而一個流程例項對應某個僱員提出的一個請假申請。
BPMN 2.0儲存為XML,幷包含視覺化的部分:使用標準方式定義了每個步驟型別(人工任務,自動服務呼叫,等等)如何呈現,以及如何互相連線。這樣BPMN 2.0標準使技術人員與業務人員能用雙方都能理解的方式交流業務流程。
我們要使用的流程定義為:
流程定義說明:
- 我們假定啟動流程需要提供一些資訊,例如僱員名字、請假時長以及說明。當然,這些可以單獨建模為流程中的第一步。 但是如果將它們作為流程的“輸入資訊”,就能保證只有在實際請求時才會建立一個流程例項。否則(將提交作為流程的第一步),使用者可能在提交之前改變主意並取消,但流程例項已經建立了。 在某些場景中,就可能影響重要的指標(例如啟動了多少申請,但還未完成),取決於業務目標。
- 左側的圓圈叫做**啟動事件(start event)**。這是一個流程例項的起點。
- 第一個矩形是一個**使用者任務(user task)**。這是流程中使用者操作的步驟。在這個例子中,經理需要批准或駁回申請
- 取決於經理的決定,「排他閘道器(exclusive gateway)」 (帶叉的菱形)會將流程例項路由至批准或駁回路徑
- 如果批准,則需要將申請註冊至某個外部系統,並跟著另一個使用者任務,將經理的決定通知給申請人。當然也可以改為傳送郵件。
- 如果駁回,則為僱員傳送一封郵件通知他。
一般來說,這樣的流程定義使用視覺化建模工具建立,如Flowable Designer(Eclipse)或Flowable Web Modeler(Web應用)。但在這裡我們直接撰寫XML,以熟悉BPMN 2.0及其概念。
與上面展示的流程圖對應的BPMN 2.0 XML在下面顯示。請注意這隻包含了“流程部分”。如果使用圖形化建模工具,實際的XML檔案還將包含“視覺化部分”,用於描述圖形資訊,如流程定義中各個元素的座標(所有的圖形化資訊包含在XML的BPMNDiagram標籤中,作為definitions標籤的子元素)。
將下面的XML儲存在src/main/resources資料夾下名為holiday-request.bpmn20.xml的檔案中。
<?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"/>
<userTask id="approveTask" name="Approve or reject request"/>
<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="org.flowable.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="org.flowable.SendRejectionMail"/>
<sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/>
<endEvent id="approveEnd"/>
<endEvent id="rejectEnd"/>
</process>
</definitions>
現在我們已經有了流程BPMN 2.0 XML檔案,下來需要將它*部署(deploy)***到引擎中。部署一個流程定義意味著:
- 流程引擎會將XML檔案儲存在資料庫中,這樣可以在需要的時候獲取它
- 流程定義轉換為內部的、可執行的物件模型,這樣使用它就可以啟動流程例項。
將流程定義部署至Flowable引擎,需要使用RepositoryService,其可以從ProcessEngine物件獲取。使用RepositoryService,可以透過XML檔案的路徑建立一個新的*部署(Deployment),並呼叫deploy()*方法實際執行:
/**
* 部署流程
*/
@Test
public void testDeploy(){
// 配置資料庫相關資訊 獲取 ProcessEngineConfiguration
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn2?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 獲取流程引擎物件
ProcessEngine processEngine = cfg.buildProcessEngine();
// 部署流程 獲取RepositoryService物件
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()// 建立Deployment物件
.addClasspathResource("holiday-request.bpmn20.xml") // 新增流程部署檔案
.name("請求流程") // 設定部署流程的名稱
.deploy(); // 執行部署操作
System.out.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getName() = " + deployment.getName());
}
然後執行該方法日誌操作成功:
在後臺表結構也可以看到相關的資訊
act_re_deployment: 流程定義部署表,每部署一次就增加一條記錄
act_re_procdef :流程定義表,部署每個新的流程定義都會在這張表中增加一條記錄
act_ge_bytearray :流程資源表,流程部署的 bpmn檔案和png圖片會儲存在該表中
我們現在可以透過API查詢驗證流程定義已經部署在引擎中(並學習一些API)。透過RepositoryService建立的ProcessDefinitionQuery物件實現。
/**
* 檢視流程定義
*/
@Test
public void testDeployQuery(){
// 配置資料庫相關資訊 獲取 ProcessEngineConfiguration
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn2?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 獲取流程引擎物件
ProcessEngine processEngine = cfg.buildProcessEngine();
// 部署流程 獲取RepositoryService物件
RepositoryService repositoryService = processEngine.getRepositoryService();
// 獲取流程定義物件
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.deploymentId("2501")
.singleResult();
System.out.println("processDefinition.getId() = " + processDefinition.getId());
System.out.println("processDefinition.getName() = " + processDefinition.getName());
System.out.println("processDefinition.getDeploymentId() = " + processDefinition.getDeploymentId());
System.out.println("processDefinition.getDescription() = " + processDefinition.getDescription());
}
輸出結果為:
processDefinition.getId() = holidayRequest:2:2503
processDefinition.getName() = Holiday Request
processDefinition.getDeploymentId() = 2501
processDefinition.getDescription() = null
3.啟動流程例項
現在已經在流程引擎中部署了流程定義,因此可以使用這個流程定義作為“模板”啟動流程例項。
要啟動流程例項,需要提供一些初始化流程變數。一般來說,可以透過呈現給使用者的表單,或者在流程由其他系統自動觸發時透過REST API,來獲取這些變數。在這個例子裡,我們簡化直接在程式碼中定義了,我們使用RuntimeService啟動一個流程例項。
/**
* 啟動流程例項
*/
@Test
public void testRunProcess(){
// 配置資料庫相關資訊 獲取 ProcessEngineConfiguration
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn2?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 獲取流程引擎物件
ProcessEngine processEngine = cfg.buildProcessEngine();
// 啟動流程例項透過 RuntimeService 物件
RuntimeService runtimeService = processEngine.getRuntimeService();
// 構建流程變數
Map<String,Object> variables = new HashMap<>();
variables.put("employee","張三") ;// 誰申請請假
variables.put("nrOfHolidays",3); // 請幾天假
variables.put("description","工作累了,想出去玩玩"); // 請假的原因
// 啟動流程例項,第一個引數是流程定義的id
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey("holidayRequest", variables);// 啟動流程例項
// 輸出相關的流程例項資訊
System.out.println("流程定義的ID:" + processInstance.getProcessDefinitionId());
System.out.println("流程例項的ID:" + processInstance.getId());
System.out.println("當前活動的ID:" + processInstance.getActivityId());
}
啟動成功,輸出結果如下:
流程定義的ID:holidayRequest:2:2503
流程例項的ID:5001
當前活動的ID:null
對應的流程例項ID為:5001
啟動流程例項涉及到的表結構:
- act_hi_actinst 流程例項執行歷史
- act_hi_identitylink 流程的參與使用者的歷史資訊
- act_hi_procinst 流程例項歷史資訊
- act_hi_taskinst 流程任務歷史資訊
- act_ru_execution 流程執行資訊
- act_ru_identitylink 流程的參與使用者資訊
- act_ru_task 任務資訊
4.檢視任務
上面員工發起了一個請假流程,接下來就會流轉到總經理這兒來處理,之前我們沒有指定經理這的處理人,我們可以加一個
然後我們來檢視下lisi的任務
/**
* 檢視任務
*/
@Test
public void testQueryTask(){
// 配置資料庫相關資訊 獲取 ProcessEngineConfiguration
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn2?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 獲取流程引擎物件
ProcessEngine processEngine = cfg.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey("holidayRequestNew")
.taskAssignee("lisi")
.list();
for (Task task : list) {
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());
}
}
輸出結果為:
task.getProcessDefinitionId() = holidayRequestNew:1:10003
task.getId() = 12508
task.getAssignee() = lisi
task.getName() = Approve or reject request
5.完成任務
現在李四這個角色可以來完成當前的任務了
在此處我們直接解決掉這個請假,然後會走傳送拒絕郵件的流程,這塊我們需要用到JavaDelegate來觸發。
我們定義這樣一個Java類
public class SendRejectionMail implements JavaDelegate {
/**
* 觸發傳送郵件的操作
* @param delegateExecution
*/
@Override
public void execute(DelegateExecution delegateExecution) {
System.out.println("請假被拒絕,,,安心工作吧");
}
}
然後來完成任務
/**
* 完成任務
*/
@Test
public void testCompleteTask(){
// 配置資料庫相關資訊 獲取 ProcessEngineConfiguration
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn2?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 獲取流程引擎物件
ProcessEngine processEngine = cfg.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey("holidayRequestNew")
.taskAssignee("lisi")
.singleResult();
// 新增流程變數
Map<String,Object> variables = new HashMap<>();
variables.put("approved",false); // 拒絕請假
// 完成任務
taskService.complete(task.getId(),variables);
}
然後可以看到JavaDelegate觸發了
6.流程的刪除
有些流程已經沒有用了,我們需要刪除掉,其實也非常簡單
/**
* 刪除流程
*/
@Test
public void testDeleteProcess(){
// 配置資料庫相關資訊 獲取 ProcessEngineConfiguration
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn2?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 獲取流程引擎物件
ProcessEngine processEngine = cfg.buildProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
// 刪除流程定義,如果該流程定義已經有了流程例項啟動則刪除時報錯
// repositoryService.deleteDeployment("1");
// 設定為TRUE 級聯刪除流程定義,及時流程有例項啟動,也可以刪除,設定為false 非級聯刪除操作。
repositoryService.deleteDeployment("2501",true);
}
7.檢視歷史資訊
選擇使用Flowable這樣的流程引擎的原因之一,是它可以自動儲存所有流程例項的「審計資料」或「歷史資料」。這些資料可以用於建立報告,深入展現組織執行的情況,瓶頸在哪裡,等等。
例如,如果希望顯示流程例項已經執行的時間,就可以從ProcessEngine獲取HistoryService,並建立*歷史活動(historical activities)*的查詢。在下面的程式碼片段中,可以看到我們新增了一些額外的過濾條件:
- 只選擇一個特定流程例項的活動
- 只選擇已完成的活動
結果按照結束時間排序,代表其執行順序。
/**
* 檢視歷史
*/
@Test
public void testQueryHistory(){
// 配置資料庫相關資訊 獲取 ProcessEngineConfiguration
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn2?serverTimezone=UTC&nullCatalogMeansCurrent=true")
.setJdbcUsername("root")
.setJdbcPassword("123456")
.setJdbcDriver("com.mysql.cj.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 獲取流程引擎物件
ProcessEngine processEngine = cfg.buildProcessEngine();
HistoryService historyService = processEngine.getHistoryService();
List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
.processDefinitionId("holidayRequestNew:1:10003")
.finished()
.orderByHistoricActivityInstanceEndTime().asc()
.list();
for (HistoricActivityInstance historicActivityInstance : list) {
System.out.println(historicActivityInstance.getActivityId() + " took "
+ historicActivityInstance.getDurationInMillis() + " milliseconds");
}
}
輸出結果
startEvent took 1 milliseconds
approveTask took 837735 milliseconds
decision took 13 milliseconds
sendRejectionMail took 2 milliseconds
rejectEnd took 1 milliseconds
好了~flowable的基本應用我們就先介紹到這裡了。
zz:https://zhuanlan.zhihu.com/p/481828559?utm_id=0