??Flowable是BPMN的一個基于java的軟件實現,不過Flowable不僅僅包括BPMN,還有DMN決策表和CMMN Case管理引擎,并且有自己的用戶管理、微服務API等一系列功能,是一個服務平臺。
官方手冊:https://tkjohn.github.io/flowable-userguide/#_introduction
??創建一個基本的maven工程,可以是Eclipse也可以是其他IDEA。然后添加兩個依賴
在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, CAlog4j.appender.CA=org.apache.log4j.ConsoleAppenderlog4j.appender.CA.layout=org.apache.log4j.PatternLayoutlog4j.appender.CA.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n
??重新運行應用。應該可以看到關于引擎啟動與創建數據庫表結構的提示日志:
??同時可以看到創建了相關的表結構在數據庫中
??這樣就得到了一個啟動可用的流程引擎。接下來為它提供一個流程!
??接下來我們構建一個非常簡單的請假流程,Flowable引擎需要流程定義為BPMN 2.0格式,這是一個業界廣泛接受的XML標準。 在Flowable術語中,我們將其稱為一個流程定義(process definition)。一個流程定義可以啟動多個流程實例(process instance)。流程定義可以看做是重復執行流程的藍圖。 在這個例子中,流程定義定義了請假的各個步驟,而一個流程實例對應某個雇員提出的一個請假申請。
??BPMN 2.0存儲為XML,并包含可視化的部分:使用標準方式定義了每個步驟類型(人工任務,自動服務調用,等等)如何呈現,以及如何互相連接。這樣BPMN 2.0標準使技術人員與業務人員能用雙方都能理解的方式交流業務流程。
??我們要使用的流程定義為:
??流程定義說明:
??一般來說,這樣的流程定義使用可視化建模工具建立,如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 name="Holiday Request" isExecutable="true"> <startEvent /> <sequenceFlow sourceRef="startEvent" targetRef="approveTask"/> <userTask name="Approve or reject request"/> <sequenceFlow sourceRef="approveTask" targetRef="decision"/> <exclusiveGateway /> <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 name="Enter holidays in external system" flowable:/> <sequenceFlow sourceRef="externalSystemCall" targetRef="holidayApprovedTask"/> <userTask name="Holiday approved"/> <sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/> <serviceTask name="Send out rejection email" flowable:/> <sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/> <endEvent /> <endEvent /> </process></definitions>
??現在我們已經有了流程BPMN 2.0 XML文件,下來需要將它部署(deploy)*到引擎中。部署*一個流程定義意味著:
??將流程定義部署至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:2503processDefinition.getName() = Holiday RequestprocessDefinition.getDeploymentId() = 2501processDefinition.getDescription() = null
??現在已經在流程引擎中部署了流程定義,因此可以使用這個流程定義作為“模板”啟動流程實例。
??要啟動流程實例,需要提供一些初始化流程變量。一般來說,可以通過呈現給用戶的表單,或者在流程由其他系統自動觸發時通過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
啟動流程實例涉及到的表結構:
??上面員工發起了一個請假流程,接下來就會流轉到總經理這兒來處理,之前我們沒有指定經理這的處理人,我們可以加一個
??然后我們來查看下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:10003task.getId() = 12508task.getAssignee() = lisitask.getName() = Approve or reject request
??現在李四這個角色可以來完成當前的任務了
??在此處我們直接解決掉這個請假,然后會走發送拒絕郵件的流程,這塊我們需要用到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觸發了
??有些流程已經沒有用了,我們需要刪除掉,其實也非常簡單
/** * 刪除流程 */ @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); }
??選擇使用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 millisecondsapproveTask took 837735 millisecondsdecision took 13 millisecondssendRejectionMail took 2 millisecondsrejectEnd took 1 milliseconds
好了~flowable的基本應用我們就先介紹到這里了。
??Flowable提供了名為Flowable Eclipse Designer的Eclipse插件,可以用于圖形化地建模、測試與部署BPMN 2.0流程。
??去Eclipse官網下載即可:https://www.eclipse.org/downloads/packages/release 注意2020-09后的版本不再支持jdk8
?解壓縮就可以了,然后進入解壓縮的目錄
??直接啟動即可
??然后我們再安裝下Flowable的插件,選擇Help → Install New Software。在下圖面板中,點擊Add按鈕,并填寫下列字段
??這種在線更新的方式已經被官網移除了,操作不了
??這時我們就只能通過離線安裝的方式來實現了,下載對應的離線文件
??安裝步驟來操作,
然后繼續:選擇Help → Install New Software
下一步
再下一步
然后finish。彈出如下窗口
重啟即可
??然后我們就可以創建一個Flowable Project了
??然后我們可以在src/mian/resources/ 的目錄下創建對應的流程圖了
??看到如下的界面說明插件安裝成功了
使用滑板來繪制流程,通過從右側把圖標拖拽到左側的面板,最終的效果
指定流程的主鍵
指定任務的負責人
在Properties視圖中指定每個任務節點的負責人
創建請假單:zhangsan
審批請假單:lisi
當我們設置完成后保存文件,會同時生成png圖片
注意:生成圖片需要如下配置
??首先在Eclipse中生成bar文件,選中項目然后鼠標右擊
然后會發現在項目的根目錄下多了一個deployment文件夾,里面多了一個MyProcess.bar文件
然后我們就可以把這個bar文件拷貝到IDEA中,繼續部署的流程
而部署的代碼和前面沒啥區別
@Test public void testDeploy(){ // 1.獲取 ProcessEngine 對象 ProcessEngine processEngine = configuration.buildProcessEngine(); // 2.獲取RepositoryService RepositoryService repositoryService = processEngine.getRepositoryService(); InputStream in = this.getClass().getClassLoader().getResourceAsStream("MyHoliday.bar"); ZipInputStream zipInputStream = new ZipInputStream(in); // 3.完成流程的部署操作 ZIP 或者 Bar文件 Deployment deploy = repositoryService.createDeployment() // .addClasspathResource("MyHoliday.bar")// 關聯要部署的流程文件 .addZipInputStream(zipInputStream) .name("XXX公司請求流程") .deploy() ;// 部署流程 System.out.println("deploy.getId() = " + deploy.getId()); System.out.println("deploy.getName() = " + deploy.getName()); }
執行后查看表結構,相關的信息就進去了
完整的案例代碼:
package com.bobo.flowable.test;import org.flowable.engine.*;import org.flowable.engine.history.HistoricActivityInstance;import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;import org.flowable.engine.repository.Deployment;import org.flowable.engine.runtime.ProcessInstance;import org.flowable.task.api.Task;import org.junit.Before;import org.junit.Test;import java.io.InputStream;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.zip.ZipInputStream;public class Test02 { ProcessEngineConfiguration configuration = null; @Before public void before(){ // 獲取 ProcessEngineConfiguration 對象 configuration = new StandaloneProcessEngineConfiguration(); // 配置 相關的數據庫的連接信息 configuration.setJdbcDriver("com.mysql.cj.jdbc.Driver"); configuration.setJdbcUsername("root"); configuration.setJdbcPassword("123456"); configuration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?serverTimezone=UTC&nullCatalogMeansCurrent=true"); // 如果數據庫中的表結構不存在就新建 configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE); } /** * 部署流程 * */ @Test public void testDeploy(){ // 1.獲取 ProcessEngine 對象 ProcessEngine processEngine = configuration.buildProcessEngine(); // 2.獲取RepositoryService RepositoryService repositoryService = processEngine.getRepositoryService(); InputStream in = this.getClass().getClassLoader().getResourceAsStream("MyHoliday.bar"); ZipInputStream zipInputStream = new ZipInputStream(in); // 3.完成流程的部署操作 ZIP 或者 Bar文件 Deployment deploy = repositoryService.createDeployment() // .addClasspathResource("MyHoliday.bar")// 關聯要部署的流程文件 .addZipInputStream(zipInputStream) .name("XXX公司請求流程") .deploy() ;// 部署流程 System.out.println("deploy.getId() = " + deploy.getId()); System.out.println("deploy.getName() = " + deploy.getName()); } /** * 啟動流程實例 */ @Test public void testRunProcess(){ ProcessEngine processEngine = configuration.buildProcessEngine(); // 我們需要通過RuntimeService來啟動流程實例 RuntimeService runtimeService = processEngine.getRuntimeService(); // 啟動流程實例 ProcessInstance holidayRequest = runtimeService.startProcessInstanceById("myProcess:1:25004"); System.out.println("holidayRequest.getProcessDefinitionId() = " + holidayRequest.getProcessDefinitionId()); System.out.println("holidayRequest.getActivityId() = " + holidayRequest.getActivityId()); System.out.println("holidayRequest.getId() = " + holidayRequest.getId()); } /** * 測試任務查詢 */ @Test public void testQueryTask(){ ProcessEngine processEngine = configuration.buildProcessEngine(); TaskService taskService = processEngine.getTaskService(); List<Task> list = taskService.createTaskQuery() .processDefinitionKey("myProcess") // 指定查詢的流程編程 .taskAssignee("zhangsan") // 查詢這個任務的處理人 .list(); for (Task task : list) { System.out.println("task.getProcessDefinitionId() = " + task.getProcessDefinitionId()); System.out.println("task.getName() = " + task.getName()); System.out.println("task.getAssignee() = " + task.getAssignee()); System.out.println("task.getDescription() = " + task.getDescription()); System.out.println("task.getId() = " + task.getId()); } } /** * 完成當前任務 */ @Test public void testCompleteTask(){ ProcessEngine processEngine = configuration.buildProcessEngine(); TaskService taskService = processEngine.getTaskService(); Task task = taskService.createTaskQuery() .processDefinitionKey("myProcess") .taskAssignee("lisi") .singleResult(); // 創建流程變量 if(task != null){ // 完成任務 taskService.complete(task.getId()); } } /** * 獲取流程任務的歷史數據 */ @Test public void testHistory(){ ProcessEngine processEngine = configuration.buildProcessEngine(); HistoryService historyService = processEngine.getHistoryService(); List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery() .processDefinitionId("myProcess:1:25004") .finished() // 查詢的歷史記錄的狀態是已經完成 .orderByHistoricActivityInstanceEndTime().asc() // 指定排序的字段和順序 .list(); for (HistoricActivityInstance history : list) { System.out.println(history.getActivityName()+":"+history.getAssignee()+"--" +history.getActivityId()+":" + history.getDurationInMillis()+"毫秒"); } }}
??Flowable提供了幾個web應用,用于演示及介紹Flowable項目提供的功能:
??所有其他的應用都需要Flowable IDM提供認證。每個應用的WAR文件可以部署在相同的servlet容器(如Apache Tomcat)中,也可以部署在不同的容器中。由于每個應用使用相同的cookie進行認證,因此應用需要運行在相同的域名下。
下載Tomcat:https://tomcat.apache.org/download-80.cgi 官網下載后解壓縮到非中文目錄即可,然后是下載FlowableUI的文件,在Flowable6.6之后把FlowableUI中提供的四個功能合并到了一起。
然后把解壓縮后的兩個war包拷貝到Tomcat的解壓縮的webapps目錄下
Tomcat目錄:
??啟動Tomcat服務,執行startup.bat文件
如果啟動中出現亂碼修改Tomcat的conf目錄下的 logging.properties 文件中的編碼
如果一閃而過則檢查jdk的環境變量配置。啟動成功后,在瀏覽器中訪問 http://localhost:8080/flowable-ui, 默認的賬號密碼是 admin/test
??我們先在 身份管理應用程序
中創建用戶并授權
創建用戶
填寫詳細信息
授權管理
創建新的流程
流程圖界面
創建流程,分配處理人
繼續完成流程圖的創建
??繪制好的流程圖,我們只需要一鍵導出即可
下載下來后拷貝到項目的resource目錄下即可
然后就是正常的操作流程了
??在FlowableUI中提供了演示程序
創建一個新的應用程序,并指定相關的信息
創建應用后需要指定對應的流程圖
發布應用程序
??發布了應用程序后我們就可以來啟動流程了
點擊顯示圖:
也就是可以看到當前是user1來處理,user1登錄后可以看到要處理的流程,user2登錄是看不到的。
點擊完成后流程就向下一步流轉了
這時再通過user2登錄,就可以看到對應的代辦的信息
然后點擊完成,那么整個流程就介紹了
??工作流程的相關操作都是操作存儲在對應的表結構中,為了能更好的弄清楚Flowable的實現原理和細節,我們有必要先弄清楚Flowable的相關表結構及其作用。在Flowable中的表結構在初始化的時候會創建五類表結構,具體如下:
具體的表結構的含義:
表分類 | 表名 | 解釋 |
---|---|---|
一般數據 | ||
[ACT_GE_BYTEARRAY] | 通用的流程定義和流程資源 | |
[ACT_GE_PROPERTY] | 系統相關屬性 | |
流程歷史記錄 | ||
[ACT_HI_ACTINST] | 歷史的流程實例 | |
[ACT_HI_ATTACHMENT] | 歷史的流程附件 | |
[ACT_HI_COMMENT] | 歷史的說明性信息 | |
[ACT_HI_DETAIL] | 歷史的流程運行中的細節信息 | |
[ACT_HI_IDENTITYLINK] | 歷史的流程運行過程中用戶關系 | |
[ACT_HI_PROCINST] | 歷史的流程實例 | |
[ACT_HI_TASKINST] | 歷史的任務實例 | |
[ACT_HI_VARINST] | 歷史的流程運行中的變量信息 | |
流程定義表 | ||
[ACT_RE_DEPLOYMENT] | 部署單元信息 | |
[ACT_RE_MODEL] | 模型信息 | |
[ACT_RE_PROCDEF] | 已部署的流程定義 | |
運行實例表 | ||
[ACT_RU_EVENT_SUBSCR] | 運行時事件 | |
[ACT_RU_EXECUTION] | 運行時流程執行實例 | |
[ACT_RU_IDENTITYLINK] | 運行時用戶關系信息,存儲任務節點與參與者的相關信息 | |
[ACT_RU_JOB] | 運行時作業 | |
[ACT_RU_TASK] | 運行時任務 | |
[ACT_RU_VARIABLE] | 運行時變量表 | |
用戶用戶組表 | ||
[ACT_ID_BYTEARRAY] | 二進制數據表 | |
[ACT_ID_GROUP] | 用戶組信息表 | |
[ACT_ID_INFO] | 用戶信息詳情表 | |
[ACT_ID_MEMBERSHIP] | 人與組關系表 | |
[ACT_ID_PRIV] | 權限表 | |
[ACT_ID_PRIV_MAPPING] | 用戶或組權限關系表 | |
[ACT_ID_PROPERTY] | 屬性表 | |
[ACT_ID_TOKEN] | 記錄用戶的token信息 | |
[ACT_ID_USER] | 用戶表 |
??我們前面講解案例的時候是通過ProcessEngineConfiguration這個配置類來加載的。
// 配置數據庫相關信息 獲取 ProcessEngineConfigurationProcessEngineConfiguration 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();
??這種方式會調用buildProcessEngine()方法,里面的核心代碼為:
??除了上面的硬編碼的方式外,我們還可以在resources目錄下創建一個flowable.cfg.xml
文件,注意這個名稱是固定的哦。內容如下:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean > <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/flow1?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC&nullCatalogMeansCurrent=true" /><property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver" /> <property name="jdbcUsername" value="root" /> <property name="jdbcPassword" value="123456" /> <property name="databaseSchemaUpdate" value="true" /> <property name="asyncExecutorActivate" value="false" /> </bean></beans>
??在上面的配置文件中配置相關的信息。我們在Java代碼中就可以簡化為:
@Test public void test01(){ // 獲取流程引擎對象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); System.out.println("processEngine = " + processEngine); }
??可以看下getDefaultProcessEngine的源碼,在里面最終還是執行了和硬編碼一樣的代碼
public static ProcessEngine getProcessEngine(String processEngineName) { if (!isInitialized()) { init(); // 完成初始化操作 } return processEngines.get(processEngineName); }
??進入init方法
public static synchronized void init() { if (!isInitialized()) { if (processEngines == null) { // Create new map to store process-engines if current map is null processEngines = new HashMap<>(); } ClassLoader classLoader = ReflectUtil.getClassLoader(); Enumeration<URL> resources = null; try { resources = classLoader.getResources("flowable.cfg.xml"); // 加載flowable.cfg.xml配置文件 } catch (IOException e) { throw new FlowableIllegalArgumentException("problem retrieving flowable.cfg.xml resources on the classpath: " + System.getProperty("java.class.path"), e); } // Remove duplicated configuration URL's using set. Some // classloaders may return identical URL's twice, causing duplicate // startups Set<URL> configUrls = new HashSet<>(); while (resources.hasMoreElements()) { configUrls.add(resources.nextElement()); } for (Iterator<URL> iterator = configUrls.iterator(); iterator.hasNext();) { URL resource = iterator.next(); LOGGER.info("Initializing process engine using configuration '{}'", resource.toString()); initProcessEngineFromResource(resource); // 初始化ProcessEngine } try { resources = classLoader.getResources("flowable-context.xml"); // 在整合Spring的情況下加載該文件 } catch (IOException e) { throw new FlowableIllegalArgumentException("problem retrieving flowable-context.xml resources on the classpath: " + System.getProperty("java.class.path"), e); } while (resources.hasMoreElements()) { URL resource = resources.nextElement(); LOGGER.info("Initializing process engine using Spring configuration '{}'", resource.toString()); initProcessEngineFromSpringResource(resource); // 從Spring的資源文件中完成ProcessEngine的初始化 } setInitialized(true); } else { LOGGER.info("Process engines already initialized"); } }
??在源碼中提供了單獨使用好整合Spring的配置加載方式。再進入到initProcessEngineFromResource(resource)方法中:
而且我們也可以看到ProcessEngine最終的實現是 ProcessEngineImpl對象。
??最后我們如果要加載自定義名稱的配置文件可以通過ProcessEngineConfiguration中的對應構造方法來實現
@Test public void test2() throws Exception{ ProcessEngineConfiguration configuration = ProcessEngineConfiguration .createProcessEngineConfigurationFromResource("flowable.cfg.xml"); ProcessEngine processEngine = configuration.buildProcessEngine(); System.out.println("processEngine = " + processEngine); }
Service是工作流引擎提供用于進行工作流部署、執行、管理的服務接口,我們使用這些接口可以就是操作服務對應的數據表
通過ProcessEngine創建Service
方式如下:
RuntimeService runtimeService = processEngine.getRuntimeService();RepositoryService repositoryService = processEngine.getRepositoryService();TaskService taskService = processEngine.getTaskService();// ...
service名稱 | service作用 |
---|---|
RepositoryService | Flowable的資源管理類 |
RuntimeService | Flowable的流程運行管理類 |
TaskService | Flowable的任務管理類 |
HistoryService | Flowable的歷史管理類 |
ManagerService | Flowable的引擎管理類 |
簡單介紹:
RepositoryService
是activiti的資源管理類,提供了管理和控制流程發布包和流程定義的操作。使用工作流建模工具設計的業務流程圖需要使用此service將流程定義文件的內容部署到計算機。
除了部署流程定義以外還可以:查詢引擎中的發布包和流程定義。
暫?;蚣せ畎l布包,對應全部和特定流程定義。 暫停意味著它們不能再執行任何操作了,激活是對應的反向操作。獲得多種資源,像是包含在發布包里的文件, 或引擎自動生成的流程圖。
獲得流程定義的pojo版本, 可以用來通過java解析流程,而不必通過xml。
RuntimeService
Activiti的流程運行管理類??梢詮倪@個服務類中獲取很多關于流程執行相關的信息
TaskService
Activiti的任務管理類??梢詮倪@個類中獲取任務的信息。
HistoryService
Flowable的歷史管理類,可以查詢歷史信息,執行流程時,引擎會保存很多數據(根據配置),比如流程實例啟動時間,任務的參與者, 完成任務的時間,每個流程實例的執行路徑,等等。 這個服務主要通過查詢功能來獲得這些數據。
ManagementService
Activiti的引擎管理類,提供了對Flowable 流程引擎的管理和維護功能,這些功能不在工作流驅動的應用程序中使用,主要用于 Flowable 系統的日常維護。
??BPMN 2.0是業務流程建模符號2.0的縮寫。它由Business Process Management Initiative這個非營利協會創建并不斷發展。作為一種標識,BPMN 2.0是使用一些符號來明確業務流程設計流程圖的一整套符號規范,它能增進業務建模時的溝通效率。目前BPMN2.0是最新的版本,它用于在BPM上下文中進行布局和可視化的溝通。接下來我們先來了解在流程設計中常見的 符號。
BPMN2.0的基本符合主要包含:
??在Flowable中的事件圖標啟動事件,邊界事件,中間事件和結束事件.
??活動是工作或任務的一個通用術語。一個活動可以是一個任務,還可以是一個當前流程的子處理流程; 其次,你還可以為活動指定不同的類型。常見活動如下:
??結構圖標可以看做是整個流程活動的結構,一個流程中可以包括子流程。常見的結構有:
??網關用來處理決策,有幾種常用網關需要了解:
??我們先來看下流程部署的具體過程。代碼實現
/** * 部署流程 */ @Test public void test3(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); RepositoryService repositoryService = processEngine.getRepositoryService(); Deployment deploy = repositoryService.createDeployment() .addClasspathResource("holiday-request-new.bpmn20.xml") .name("請假流程...") .category("請假") // 分類 .tenantId("dpb") // 租戶id .deploy(); System.out.println("deploy.getId() = " + deploy.getId()); System.out.println("deploy.getName() = " + deploy.getName()); System.out.println("deploy.getCategory() = " + deploy.getCategory()); }
涉及到的三張表:
部署資源表:act_ge_bytearray
字段 | 名稱 | 備注 |
---|---|---|
ID_ | 主鍵 | |
REV_ | 版本號 | |
NAME_ | 名稱 | 部署的文件名稱,如:holiday-request-new.bpmn20.xml、holiday-request-new.bpmn20.png |
DEPLOYMENT_ID_ | 部署ID | |
BYTES_ | 字節(二進制數據) | |
GENERATED_ | 是否系統生成 | 0為用戶上傳, 1為系統自動生成, 比如系統會 自動根據xml生 成png |
部署ID表:act_re_deployment
字段 | 名稱 | 備注 |
---|---|---|
ID_ | 主鍵 | |
NAME_ | 名稱 | |
CATEGORY_ | 分類 | |
TENANT_ID_ | 租戶ID | |
DEPLOY_TIME_ | 部署時間 | |
DERIVED_FROM_ | 來源于 | |
DERIVED_FROM_ROOT_ | 來源于 | |
ENGINE_VERSION_ | 流程引擎的版本 |
流程表:act_re_procdef
字段 | 名稱 | 備注 |
---|---|---|
ID_ | 主鍵 | |
REV_ | 版本號 | |
CATEGORY_ | 分類 | 流程定義的Namespace就是類別 |
NAME_ | 名稱 | |
KEY_ | 標識 | |
VERSION_ | 版本 | |
DEPLOYMENT_ID_ | 部署ID | |
RESOURCE_NAME_ | 資源名稱 | 流程bpmn文件名稱 |
DGRM_RESOURCE_NAME_ | 圖片資源名稱 | |
DESCRIPTION_ | 描述 | |
HAS_START_FORM_KEY_ | 擁有開始表單標識 | start節點是否存在formKey 0否 1是 |
HAS_GRAPHICAL_NOTATION_ | 擁有圖形信息 | |
SUSPENSION_STATE_ | 掛起狀態 | 暫停狀態 1激活 2暫停 |
TENANT_ID_ | 租戶ID | |
注意:
業務流程定義數據表。此表和ACT_RE_DEPLOYMENT是多對一的關系,即,一個部署的bar包里可能包含多個流程定義文件,每個流程定義文件都會有一條記錄在ACT_REPROCDEF表內,每個流程定義的數據,都會對于ACT_GE_BYTEARRAY表內的一個資源文件和PNG圖片文件。和ACT_GE_BYTEARRAY的關聯是通過程序用ACT_GE_BYTEARRAY.NAME與ACT_RE_PROCDEF.NAME_完成的
??部署的流程默認的狀態為激活,如果我們暫時不想使用該定義的流程,那么可以掛起該流程。當然該流程定義下邊所有的流程實例全部暫停。
流程定義為掛起狀態,該流程定義將不允許啟動新的流程實例,同時該流程定義下的所有的流程實例都將全部掛起暫停執行。
/** * 掛起流程 */ @Test public void test05(){ // 獲取流程引擎對象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); RepositoryService repositoryService = processEngine.getRepositoryService(); ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() .processDefinitionId("holiday:1:4") .singleResult(); // 獲取流程定義的狀態 boolean suspended = processDefinition.isSuspended(); System.out.println("suspended = " + suspended); if(suspended){ // 表示被掛起 System.out.println("激活流程定義"); repositoryService.activateProcessDefinitionById("holiday:1:4",true,null); }else{ // 表示激活狀態 System.out.println("掛起流程"); repositoryService.suspendProcessDefinitionById("holiday:1:4",true,null); } }
具體的實現其實就是更新了流程定義表中的字段
而且通過REV_字段來控制數據安全,也是一種樂觀鎖的體現了,如果要啟動一個已經掛起的流程就會出現如下的錯誤
??然后我們來看看啟動流程實例的過程。實現代碼如下:
/** * 啟動流程實例 */ @Test public void testRunProcess(){ // 獲取流程引擎對象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 啟動流程實例通過 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 .startProcessInstanceById("holiday:1:4", variables);// 啟動流程實例 // 輸出相關的流程實例信息 System.out.println("流程定義的ID:" + processInstance.getProcessDefinitionId()); System.out.println("流程實例的ID:" + processInstance.getId()); System.out.println("當前活動的ID:" + processInstance.getActivityId()); }
??當我們啟動了一個流程實例后,會在ACT_RU_*對應的表結構中操作,運行時實例涉及的表結構共10張:
??啟動一個流程實例的時候涉及到的表有
ACT_RU_EXECUTION表結構
字段 | 名稱 | 備注 |
---|---|---|
ID_ | 主鍵 | |
REV_ | 版本號 | |
PROC_INST_ID_ | 流程實例ID | |
BUSINESS_KEY_ | 業務主鍵ID | |
PARENT_ID_ | 父執行流的ID | |
PROC_DEF_ID_ | 流程定義的數據ID | |
SUPER_EXEC_ | ||
ROOT_PROC_INST_ID_ | 流程實例的root流程id | |
ACT_ID_ | 節點實例ID | |
IS_ACTIVE_ | 是否存活 | |
IS_CONCURRENT_ | 執行流是否正在并行 | |
IS_SCOPE_ | ||
IS_EVENT_SCOPE_ | ||
IS_MI_ROOT_ | ||
SUSPENSION_STATE_ | 流程終端狀態 | |
CACHED_ENT_STATE_ | ||
TENANT_ID_ | 租戶編號 | |
NAME_ | ||
START_TIME_ | 開始時間 | |
START_USER_ID_ | 開始的用戶編號 | |
LOCK_TIME_ | 鎖定時間 | |
IS_COUNT_ENABLED_ | ||
EVT_SUBSCR_COUNT_ | ||
TASK_COUNT_ | ||
JOB_COUNT_ | ||
TIMER_JOB_COUNT_ | ||
SUSP_JOB_COUNT_ | ||
DEADLETTER_JOB_COUNT_ | ||
VAR_COUNT_ | ||
ID_LINK_COUNT_ |
創建流程實例后對應的表結構的數據
ACT_RU_TASK 運行時任務表
字段 | 名稱 | 備注 |
---|---|---|
ID_ | 主鍵 | |
REV_ | 版本號 | |
EXECUTION_ID_ | 任務所在的執行流ID | |
PROC_INST_ID_ | 流程實例ID | |
PROC_DEF_ID_ | 流程定義數據ID | |
NAME_ | 任務名稱 | |
PARENT_TASK_ID_ | 父任務ID | |
DESCRIPTION_ | 說明 | |
TASK_DEF_KEY_ | 任務定義的ID值 | |
OWNER_ | 任務擁有人 | |
ASSIGNEE_ | 被指派執行該任務的人 | |
DELEGATION_ | 委托人 | |
PRIORITY_ | 優先級 | |
CREATE_TIME_ | 創建時間 | |
DUE_DATE_ | 耗時 | |
CATEGORY_ | 類別 | |
SUSPENSION_STATE_ | 是否掛起 | 1代表激活 2代表掛起 |
TENANT_ID_ | 租戶編號 | |
FORM_KEY_ | ||
CLAIM_TIME_ | 拾取時間 |
創建流程實例后對應的表結構的數據
ACT_RU_VARIABLE 運行時變量表
字段 | 名稱 | 備注 |
---|---|---|
ID_ | 主鍵 | |
REV_ | 版本號 | |
TYPE_ | 參數類型 | 可以是基本的類型,也可以用戶自行擴展 |
NAME_ | 參數名稱 | |
EXECUTION_ID_ | 參數執行ID | |
PROC_INST_ID_ | 流程實例ID | |
TASK_ID_ | 任務ID | |
BYTEARRAY_ID_ | 資源ID | |
DOUBLE_ | 參數為double,則保存在該字段中 | |
LONG_ | 參數為long,則保存在該字段中 | |
TEXT_ | 用戶保存文本類型的參數值 | |
TEXT2_ | 用戶保存文本類型的參數值 |
創建流程實例后對應的表結構的數據
ACT_RU_IDENTITYLINK 運行時用戶關系信息
字段 | 名稱 | 備注 |
---|---|---|
ID_ | 主鍵 | |
REV_ | 版本號 | |
GROUP_ID_ | 用戶組ID | |
TYPE_ | 關系數據類型 | assignee支配人(組)、candidate候選人(組)、owner擁有人,participant參與者 |
USER_ID_ | 用戶ID | |
TASK_ID_ | 任務ID | |
PROC_INST_ID_ | 流程定義ID | |
PROC_DEF_ID_ | 屬性ID |
創建流程實例后對應的表結構的數據:
??上面的流程已經流轉到了zhangsan這個用戶這里,然后可以開始審批了
// 獲取流程引擎對象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); Task task = taskService.createTaskQuery() .processDefinitionId("holiday:1:4") .taskAssignee("zhangsan") .singleResult(); // 添加流程變量 Map<String,Object> variables = new HashMap<>(); variables.put("approved",false); // 拒絕請假 // 完成任務 taskService.complete(task.getId(),variables);
??在正常處理流程中涉及到的表結構
ACT_RU_TASK 運行時任務表 :會新生成一條記錄
ACT_RU_VARIABLE 運行時變量表:會記錄新的流程變量
當然流程實例也可以掛起
// 1.獲取ProcessEngine對象ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();// 2.獲取RuntimeServiceRuntimeService runtimeService = engine.getRuntimeService();// 3.獲取流程實例對象ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() .processInstanceId("25001") .singleResult();// 4.獲取相關的狀態操作boolean suspended = processInstance.isSuspended();String id = processInstance.getId();if(suspended){ // 掛起--》激活 runtimeService.activateProcessInstanceById(id); System.out.println("流程定義:" + id + ",已激活");}else{ // 激活--》掛起 runtimeService.suspendProcessInstanceById(id); System.out.println("流程定義:" + id + ",已掛起");}
啟動第二個流程實例后再查看相關的表結構時,對他們的關系理解會更加的清楚一些
啟動一個新的流程實例對應的就會產生兩條記錄
IDENTITYLINK中會記錄每次流程操作的信息
流程變量數據,及時key 相同,但是屬于不同的流程實例相互間也是隔離的
??然后我們把第一個流程處理完成
ProcessEngine processEngine = cfg.buildProcessEngine();TaskService taskService = processEngine.getTaskService();Task task = taskService.createTaskQuery() .processDefinitionId("holiday:1:4") .taskAssignee("lisi") .singleResult();// 添加流程變量Map<String,Object> variables = new HashMap<>();variables.put("approved",false); // 拒絕請假// 完成任務taskService.complete(task.getId(),variables);
處理完了一個工作流程后,我們來看看相關的表結構信息
首先我們會發現
這四張表中對應的數據都沒有了,也就是這個流程已經不是運行中的流程了。然后在對應的歷史表中我們可以看到相關的信息
ACT_HI_ACTINST 歷史的流程實例
ACT_HI_ATTACHMENT 歷史的流程附件
ACT_HI_COMMENT 歷史的說明性信息
ACT_HI_DETAIL 歷史的流程運行中的細節信息
ACT_HI_IDENTITYLINK 歷史的流程運行過程中用戶關系
ACT_HI_PROCINST 歷史的流程實例
ACT_HI_TASKINST 歷史的任務實例
ACT_HI_VARINST 歷史的流程運行中的變量信息
在我們上面的處理流程的過程中設計到的歷史表有
ACT_HI_ACTINST 歷史的流程實例
字段 | 名稱 | 備注 |
---|---|---|
ID_ | 主鍵 | |
PROC_DEF_ID_ | 流程定義ID | |
PROC_INST_ID_ | 流程實例ID | |
EXECUTION_ID_ | 執行ID | |
ACT_ID_ | 節點實例ID | |
TASK_ID_ | 任務ID | |
CALL_PROC_INST_ID_ | 調用外部的流程實例ID | |
ACT_NAME_ | 節點名稱 | |
ACT_TYPE_ | 節點類型 | |
ASSIGNEE_ | 處理人 | |
START_TIME_ | 開始時間 | |
END_TIME_ | 結束時間 | |
DURATION_ | 耗時 | |
DELETE_REASON_ | 刪除原因 | |
TENANT_ID_ | 租戶編號 |
ACT_HI_IDENTITYLINK 歷史的流程運行過程中用戶關系
字段 | 名稱 | 備注 |
---|---|---|
ID_ | 主鍵 | |
GROUP_ID_ | 組編號 | |
TYPE_ | 類型 | |
USER_ID_ | 用戶編號 | |
TASK_ID_ | 任務編號 | |
CREATE_TIME_ | 創建時間 | |
PROC_INST_ID_ | 流程實例編號 | |
SCOPE_ID_ | ||
SCOPE_TYPE_ | ||
SCOPE_DEFINITION_ID_ | ||
ACT_HI_PROCINST 歷史的流程實例
字段 | 名稱 | 備注 |
---|---|---|
ID_ | 主鍵 | |
PROC_INST_ID_ | 流程實例ID | |
BUSINESS_KEY_ | 業務主鍵 | |
PROC_DEF_ID_ | 屬性ID | |
START_TIME_ | 開始時間 | |
END_TIME_ | 結束時間 | |
DURATION_ | 耗時 | |
START_USER_ID_ | 起始人 | |
START_ACT_ID_ | 起始節點 | |
END_ACT_ID_ | 結束節點 | |
SUPER_PROCESS_INSTANCE_ID_ | 父流程實例ID | |
DELETE_REASON_ | 刪除原因 | |
TENANT_ID_ | 租戶編號 | |
NAME_ | 名稱 |
ACT_HI_TASKINST 歷史的任務實例
字段 | 名稱 | 備注 |
---|---|---|
ID_ | 主鍵 | |
PROC_DEF_ID_ | 流程定義ID | |
TASK_DEF_KEY_ | 任務定義的ID值 | |
PROC_INST_ID_ | 流程實例ID | |
EXECUTION_ID_ | 執行ID | |
PARENT_TASK_ID_ | 父任務ID | |
NAME_ | 名稱 | |
DESCRIPTION_ | 說明 | |
OWNER_ | 實際簽收人 任務的擁有者 | 簽收人(默認為空,只有在委托時才有值) |
ASSIGNEE_ | 被指派執行該任務的人 | |
START_TIME_ | 開始時間 | |
CLAIM_TIME_ | 任務拾取時間 | |
END_TIME_ | 結束時間 | |
DURATION_ | 耗時 | |
DELETE_REASON_ | 刪除原因 | |
PRIORITY_ | 優先級別 | |
DUE_DATE_ | 過期時間 | |
FORM_KEY_ | 節點定義的formkey | |
CATEGORY_ | 類別 | |
TENANT_ID_ | 租戶 | |
ACT_HI_VARINST 歷史的流程運行中的變量信息:流程變量雖然在任務完成后在流程實例表中會刪除,但是在歷史表中還是會記錄的
字段 | 名稱 | 備注 |
---|---|---|
ID_ | 主鍵 | |
PROC_INST_ID_ | 流程實例ID | |
EXECUTION_ID_ | 指定ID | |
TASK_ID_ | 任務ID | |
NAME_ | 名稱 | |
VAR_TYPE_ | 參數類型 | |
REV_ | 數據版本 | |
BYTEARRAY_ID_ | 字節表ID | |
DOUBLE_ | 存儲double類型數據 | |
LONG_ | 存儲long類型數據 | |
..... |
好了一個相對簡單的流程處理涉及到的相關表結構內容就介紹完了
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...
在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...
在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...
石家莊有幾家北國超市?北國超市(天河店)地址:橋東區勝利北街243號北國超市(新百店)地址:橋西區中山西路139號(近中華街)北國超市(長江店)地址:長安區中山東路與翟穎北街交叉口向北100米(公交醫院附近)。北國超市(育才街店)地址:長安區育才街265號(近淮安東路)北國超市(北國店)地址:長安區中山東路188號北國超市(新市店)地址:橋東區中華南街585號(交管局對面)北國超市(長江店)地址:...
安徽毫州屬于哪個市 亳州屬于安徽東部嗎?亳州為什么叫亳州? 亳州市位于安徽省北部和安徽省北部。位于安徽省馬鞍山市北部。亳州市是安徽省的地級市,未來宜人宜居。它是中國古代著名醫生華佗的家鄉,也是中國最大的中草藥配送基地。中草藥的年營業額非常大。亳州也是安徽北部重要的交通樞紐,年勞務輸出人口相對較大。 安徽省亳州市屬于哪個市? 安微省毫州市是一個成立于1990年的縣級市,隸屬于蒙城縣、渦陽縣、...
成都限行單雙號應該怎么開?成都限行單雙號是按機動車號牌最后一位阿拉伯數字實行單號單日、雙號雙日行駛(單號為1、3、5、7、9,雙號為2、4、6、8、0)。限行時間是重污染天氣紅色預警期間,工作日的3:00至24:00(公休日因法定節假日調休為工作日的,不限行)。特殊車輛是不限行的,也可以買新能源車不限行。成都單雙號限號區域范圍?限行區域、范圍:成都市繞城高速(G4202)(不含)以內所有道路。限行...