1. Flowable數據庫表命名規則
1.0 act_procdef_info
:流程定義儲存表
流程定義更新信息,包含流程定義ID,版本號,內容等html
1.1 ACT_RE_*
’RE’表示repository(存儲)。RepositoryService
接口操做的表。帶此前綴的表包含的是靜態信息,如,流程定義,流程的資源(圖片,規則等)
1.1.1 act_re_deployment
:部署信息表核心表
部署流程定義時須要被持久化保存下來的信息
1.1.2 act_re_model
:流程設計模型部署表
流程設計器設計流程模型保存的數據,包含:建立時間,最后更新時間,元數據(META_INFO_:以json格式保存流程定義的信息),部署ID(DEPLOYMENT_ID_)
1.1.3 act_re_procdef
:流程定義數據表核心表
1.1.3.1 提示
此表和ACT_RE_DEPLOYMENT
是多對一的關系,即,一個部署的bar包里可能包含多個流程定義文件,每一個流程定義文件都會有一條記錄在ACT_REPROCDEF
表內,每一個流程定義的數據,都會對於ACT_GE_BYTEARRAY
表內的一個資源文件和PNG圖片文件。
1.1.3.2 和ACT_GE_BYTEARRAY
的關聯:
是經過程序用ACT_GE_BYTEARRAY
.NAME
與ACT_RE_PROCDEF
.NAME_
完成的,在數據庫表結構中沒有體現
1.1.3.3 包含
分類(CATEGORY_
:流程定義的Namespace就是類別),部署ID(DEPLOYMENT_ID_
),資源名稱(RESOURCE_NAME_
:流程bpmn文件名稱),擁有開始表單標識(HAS_START_FORM_KEY_
:start節點是否存在 formKey 0否 1是),掛起狀態(SUSPENSION_STATE_
:暫停狀態 1激活 2暫停)java
1.2 ACT_RU_*
’RU’表示runtime。這是運行時的表存儲着流程變量,用戶任務,變量,職責(job)等運行時的數據。
flowable只存儲實例執行期間的運行時數據,當流程實例結束時,將刪除這些記錄。這就保證了這些運行時的表小且快。
1.2.1 act_ru_event_subscr
:事件訂閱
包含:流程定義ID,流程實例ID,執行實例ID,節點ID,建立時間等
1.2.2 act_ru_execution
:運行時流程執行實例表核心表
包含:流程實例ID,流程定義ID,父級ID,父級的執行實例ID,節點ID,掛起狀態(SUSPENSION_STATE_:1激活 2暫停),緩存狀態(CACHED_ENT_STATE_:緩存的狀態, 1 事件監聽 2 人工任務 3 異步做業)
1.2.3 act_ru_identitylink
:運行時流程人員表
主要存儲當前節點參與者的信息,包含:用戶組ID,用戶ID,任務ID,流程實例ID,流程定義ID
1.2.4 act_ru_job
:運行時定時任務數據表
1.2.4.1 包含:
鎖定過時時間(LOCK_EXP_TIME_),掛起者(LOCK_OWNER_),是否惟一(EXCLUSIVE_),執行實例ID,流程實例ID,流程定義ID,重試次數(RETRIES_),截至時間(DUEDATE_)
1.2.4.2 須要啟用JOB組件
JobExecutor 是管理一組線程的組件,這些線程用於觸發定時器(包括后續的異步消息)。在單元測試場景下,使用多線程會很笨重。ManagementService.createJobQuery
用於查詢,ManagementService.executeJob
用於執行做業。
這樣做業的執行就能夠在單元測試內部控制。為了不做業執行器的干擾,能夠將它關閉。
默認狀況下, JobExecutor 在流程引擎啟動時激活。
當你不但願 JobExecutor 隨流程引擎啟動時,設置:<property name="jobExecutorActivate" value="false" />
1.2.4.3 啟用異步執行器 Async executor activation
AsyncExecutor 是管理線程池的組件,這個線程池用於觸發定時器與異步任務。
默認狀況下,因為歷史緣由,當使用 JobExecutor 時, AsyncExecutor 不生效。然而咱們建議使用新的 AsyncExecutor 代替JobExecutor ,經過定義兩個參數實現<property name="asyncExecutorEnabled" value="true" /><property name="asyncExecutorActivate" value="true" />
參數 asyncExecutorEnabled
用於啟用異步執行器,代替老的做業執行器。
參數 asyncExecutorActivate
命令Activiti引擎在啟動時啟動異步執行器線程池。
1.2.5 act_ru_task
:運行時任務節點表核心表
包含:
主鍵(任務ID),執行實例ID,流程實例ID,流程定義ID,父任務ID,被代理人(OWNER_:通常狀況下為空,只有在委托時才有值),經辦人(GNEE_:簽收人或者委托人),委托狀態(DELEGATION_:委托狀態 PENDING委托中,RESOLVED已處理),優先級(PRIORITY_),建立時間,截至時間,掛起狀態(SUSPENSION_STATE_:暫停狀態 1激活 2暫停)
1.2.6 act_ru_variable
:運行時流程變量數據表*核心表
類型:jpa-entity、boolean、bytes、serializable、自定義type、CustomVariableType、date、double、integer、long、null、short、string
包含:執行實例ID,流程實例ID,任務ID,資源ID(BYTEARRAY_ID_)git
1.3 ACT_ID_*
’ID’表示identity(組織機構)。這些表包含標識的信息,如用戶,用戶組,等等。
1.3.1 act_id_group
:用戶組表
自帶的用戶組表,用於組任務,包含:名稱,類型,版本號
1.3.2 act_id_info
:用戶擴展信息表
包含:用戶ID,類型,key,value,密碼,父級ID
1.3.3 act_id_membership
:用戶與分組對應信息表
用來保存用戶的分組信息,包含:用戶ID,用戶組ID
1.3.4 act_id_user
:用戶信息表
包含:姓,名,郵箱,密碼,版本號,頭像IDweb
1.4 ACT_HI_*
’HI’表示history。就是這些表包含着歷史的相關數據,如結束的流程實例,變量,任務,等等。
1.4.1 act_hi_actinst
:歷史活動信息
記錄流程流轉過的全部節點,包括流程定義ID,流程實例ID,執行節點的ID/名稱,執行的指向箭頭,辦理人ID,開始時間,結束時間,刪除緣由等
1.4.2 act_hi_attachment
:歷史附件表
存放歷史流程相關的附件的地址
1.4.3 act_hi_comment
:歷史審批意見表
存放歷史流程的審批意見
1.4.4 act_hi_detail
:歷史詳情信息表
流程中產生的變量詳細,包括控制流程流轉的變量,業務表單中填寫的流程須要用到的變量等
1.4.5 act_hi_identitylink
:歷史流程人員表,
主要存儲當前節點參與者的信息,好比參與者ID,參與的流程實例ID,任務ID,參與者扮演的角色類型{assignee(辦理者)、candidate(候補者)、owner(委托的辦理者)、starter(發起者) 、participant(參與者)}
1.4.6 act_hi_procinst
:流程實例歷史核心表
存放歷史的流程實例,包含流程實例ID,流程定義ID,開啟人ID,開始節點ID,結束節點ID,父級流程實例ID,刪除緣由
1.4.7 act_hi_taskinst
:歷史任務流程實例信息核心表
存放已經辦理的任務,包含有任務ID,流程實例ID,流程定義ID,任務節點key和名字,辦理人ID,最后修改時間
1.4.8 act_hi_varinst
:歷史變量表
存放歷史變量數據數據庫
1.5 ACT_GE_*
普通數據,各類狀況都使用的數據。
1.5.1 act_ge_bytearray
:資源表
保存部署文件的大文本數據,文件位置,流程定義部署ID(deployment_id),是一個二進制文件數據,(存儲流程定義相關的資源)–ByteArrayEntityImpl
1.5.2 act_ge_property
:屬性表
全局配置文件,(保存流程引擎的kv鍵值屬性)–PropertyEntityImplapache
1.6 act_evt_log
:事件日志表
事件日志,默認不開啟,若是不使用事件記錄,能夠刪除這個表,
1.6.1 做用:
來源於引擎的事件會被捕獲,並建立一個包含了全部事件數據(甚至更多)的映射,提供給org.activiti.engine.impl.event.logger.EventFlusher
,由它將這些數據刷入其余地方;默認狀況下,使用簡單的基於數據庫的事件處理/刷入,會使用Jackson將上述映射序列化為JSON
,並將其做為EventLogEntryEntity
接口存入數據庫。json
// 1.6.2 配置啟用事件日志 processEngineConfiguration.setEnableDatabaseEventLogging(true); // 1.6.3 運行時啟用事件日志 databaseEventLogger = new EventLogger(processEngineConfiguration.getClock()); runtimeService.addEventListener(databaseEventLogger);
1.6.4 能夠擴展EventLogger類。
若是默認的數據庫記錄不符合要求,須要覆蓋createEventFlusher()
方法返回一個org.activiti.engine.impl.event.logger.EventFlusher
接口的實例。能夠經過Activiti
的managementService.getEventLogEntries(startLogNr, size)
?獲取EventLogEntryEntity
實例。容易看出這個表中的數據能夠經過JSON
放入大數據NoSQL
存儲,例如MongoDB
,Elastic
Search
,等等.也容易看出這里使用的類(org.activiti.engine.impl.event.logger.EventLogger/EventFlusher
與許多其余 EventHandler
類)是可插入的,能夠按你的使用場景調整(例如不將JSON
存入數據庫,而是將其直接發送給一個隊列或大數據存儲)。請注意這個事件記錄機制是額外於Activiti
的“傳統”歷史管理器的。盡管全部數據都在數據庫表中,但並未對查詢或快速恢復作優化。實際使用場景是末端審計並將其存入大數據存儲。緩存
2.Flowable使用SLF4J做為內部日志框架
要看到關於引擎啟動與建立數據庫表結構的提示日志,在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
3.核心類:
3.1 RepositoryService 流程存儲服務
管理流程定義文件xml及靜態資源的服務
對特定流程的暫停和激活
流程定義啟動權限管理
類內部重要的成員有:deploymentBuilder
: 部署文件構造器,詳見本文4.1deploymentQuery
: 部署文件查詢器ProcessDefinitionQuery
: 流程定義文件查詢對象Deployment
: 流程部署文件對象,詳見本文4.1ProcessDefinition
: 流程定義文件對象,詳見本文4.1BpmnModel
: 流程定義的java格式
學習博客:https://www.jianshu.com/p/96df1d449cc3多線程
3.2 RuntimeService
流程運行控制服務
啟動流程及對流程數據的控制
流程實例(ProcessInstance
)與執行流(Execution
)的查詢,詳見本文4.4
觸發流程操做,接收消息和信號
啟動流程及變量管理
啟動流程的經常使用方法(id,key,message),詳見本文4.3
啟動流程可選參數(businessKey,variables,tenantId)
變量(variables)的設置和獲取,詳見本文4.4
學習博客:
https://blog.csdn.net/yijianqingyu/article/details/79746551
https://www.jianshu.com/p/4a9a52c62bcc
3.3 HistoryService
流程系統歷史服務
管理流程實例結束后的歷史數據
構建歷史數據的查詢對象
根據流程實例id刪除流程歷史數據
歷史數據實體HistoricProcessInstance
歷史流程實例實體類(學習博客:https://blog.csdn.net/yijianqingyu/article/details/80311179 )HistoricTaskInstance
用戶任務實例的信息HistoricActivityInstance
單個活動節點執行的信息HistoricVariableInstance
流程或任務的變量值實體HistoricDetail
歷史流程活動任務詳細信息
備注:歷史數據實體與運行時的數據實體的API大同小異
學習博客:https://blog.csdn.net/mchgogo/article/details/79126404
構建歷史查詢對象
create{歷史數據實體}Query();
createNative{歷史數據實體}Query();
createProcessInstanceHistoryLogQuery(processInstanceId);
備注:各歷史查詢對象API大同小異
刪除歷史操做
historyService.deleteHistoricProcessInstance(processInstanceId); historyService.deleteHistoricTaskInstance(processInstanceId);
學習博客:https://www.jianshu.com/p/0b6ecf500e9d
3.4 TaskService
任務管理服務
3.4.1 對用戶任務UserTask的管理和流程的控制
Task對象的建立和刪除
查詢Task,驅動Task節點完成執行
Task相關參數變量variable設置
3.4.2 設置用戶任務的權限信息(設置候選人等)
候選用戶candidateUser和候選組candidateGroup
指定擁有人Owner和辦理人Assignee
經過claim設置辦理人(簽收 )
3.4.3 針對用戶任務添加任務附件,任務評論和事件記錄
任務附件Attachment建立與查詢
任務評論Comment建立與查詢
事件記錄Event建立與查詢
3.4.5 學習博客
https://www.jianshu.com/p/dfad80be1dbf
https://blog.csdn.net/syq8023/article/details/89852339
3.5 IdentityService
用戶管理服務
管理用戶
管理用戶組
用戶與用戶組的關系(MemberShip)
學習博客:https://www.jianshu.com/p/4150818b924e
3.6 FormService 表單管理服務
解析流程定義中表單項的配置
提交表單的方式驅動用戶節點流轉
獲取自定義外部表單key
學習博客:https://www.jianshu.com/p/66e336554a06
3.7 managementService 工做管理服務
Job任務管理
數據庫相關通用操做
執行流程引擎命令(Command)
學習博客:https://www.jianshu.com/p/a1c132f729b9
4.flowable的使用
4.0 學習示例
https://gitee.com/lwj/flowable.git flowable-base分支
https://www.cnblogs.com/liuwenjun/category/1296599.html
將本地jar包導入maven倉庫:
PS E:\JVM\MavenRepository\com\dragon\tools>mvn install:install-file -D file=tools-1.0-SNAPSHOT.jar -D groupId=com.dragon -D artifactId=tools -D version=1.0-SNAPSHOT -D packaging=jar
4.1 部署流程定義(BPMN文件),獲取流程定義文件對象
// resouce:BPMN文件路徑,inputStream:該文件的字節流 DeploymentBuilder deploymentBuilder = repositoryService.createDeployment().addInputStream(resource, inputStream); // 根據參數設置流程部署構建器,parameter :部署參數,一個Map<String, Object> deploymentBuilder.category(parameter.get("flowType")).name(parameter.get("flowName")).key(parameter.get("flowKey")).tenantId(parameter.get("flowTenantId")); // 並獲取流程定義部署對象 Deployment deployment = deploymentBuilder.deploy(); String deploymentId = deployment.getId(); ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult(); // 流程定義ID String processDefinitionId = processDefinition.getId(); // 流程定義Key String processDefinitionKey = processDefinition.getKey();
4.2 掛起與恢復流程定義,掛起后發起流程實例就會拋出異常
// 掛起 repositoryService.suspendProcessDefinitionById(processDefinitionId); repositoryService.suspendProcessDefinitionByKey(processDefinitionKey); // 恢復 repositoryService.activateProcessDefinitionById(processDefinitionId); repositoryService.activateProcessDefinitionByKey(processDefinitionKey);
4.3 啟動流程實例,並獲取流程實例對象
// variables:流程變量,Map<String, Object>類型 ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId, variables); ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, variables); // 將流程實例與發起人綁定 identityService.setAuthenticatedUserId(userId);
4.4 對流程實例的操做
4.4.1 processInstance
// 流程實例ID String processInstanceId = processInstance.getId(); // 判斷流程是否結束 processInstance.isEnded(); // 判斷流程是否掛起 processInstance.isSuspended(); // 獲取流程的發起人ID String startUserId = processInstance.getStartUserId();
4.4.2 runtimeService
// 該流程的執行對象查詢 List<Execution> executionList = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).list(); Execution execution = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).singleResult(); // 該流程實例下的全部活動實例 List<Execution> executions = runtimeService.createExecutionQuery().parentId(processInstanceId).list(); // 更改多個活動實例的狀態節點為指定節點 activityId ,好比結束節點終止流程 runtimeService.createChangeActivityStateBuilder().moveExecutionsToSingleActivityId(executionIds, activityId).changeState(); // 掛起流程實例 runtimeService.suspendProcessInstanceById(processInstanceId); // 恢復掛起的流程實例 runtimeService.activateProcessInstanceById(processInstanceId); // 刪除一個正在流轉的流程 deleteReason:刪除緣由 HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId); // 獲取該流程實例下的任務數量 long count = query.count(); // 任務數量大於1,則流程已經啟動了,不能撤回 if (count > 1) { throw new FlowException(ResultEnum.EX_INSTANCE_BEGIN); } runtimeService.deleteProcessInstance(processInstanceId, deleteReason); // 獲取流程實例的查詢對象 ProcessInstanceQuery instanceQuery = runtimeService.createProcessInstanceQuery(); // 與某個用戶相關的 instanceQuery.involvedUser(userId); // 某個用戶開啟的 instanceQuery.startedBy(userId); // 或者查詢條件 .or().endOr() ==> (xx or xx or ... ... or xx),等於包裹內容的兩括號 instanceQuery.or().endOr(); // 掛起的流程 instanceQuery.suspended(); // 在某個時間點以后開始 instanceQuery.startedAfter(Date date); // 在某個時間點以前開始 instanceQuery.startedBefore(Date date); // 獲取正在流轉的一個指定的流程實例 instanceQuery.processInstanceId(processInstanceId); // 單個的流程實例 ProcessInstance processInstance = instanceQuery.singleResult(); // 多個流程實例 begin : 從第幾個開始 ; max : 展現多少個 List<ProcessInstance> processInstances = instanceQuery.list(); List<ProcessInstance> processInstances = instanceQuery.listPage(int begin,int max); // 流程實例的數量 long count = taskQuery.count();
4.4.3 historyService
// 獲取歷史流程實例查詢對象 HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery(); // 已完成的 historicProcessInstanceQuery.finished(); // 未完成的 historicProcessInstanceQuery.unfinished(); // 刪除的 historicProcessInstanceQuery.deleted(); // 沒有刪除的 historicProcessInstanceQuery.notDeleted(); // 在某個時間點以后結束 historicProcessInstanceQuery.finishedAfter(Date date); // 在某個時間點以前結束 historicProcessInstanceQuery.finishedBefore(Date date); // 指定父流程ID的流程實例 historicProcessInstanceQuery.superProcessInstanceId(processInstanceId) // 歷史流程實例 HistoricProcessInstance processInstance = historicProcessInstanceQuery.processInstanceId(processInstanceId).singleResult(); // 刪除該流程的歷史記錄 historyService.deleteHistoricProcessInstance(processInstanceId);
4.5 任務服務的操做
4.5.1 獲取task任務對象
// 任務基礎查詢對象 TaskQuery taskQuery = taskService.createTaskQuery(); // 某個任務 taskQuery.taskId(taskId); // 某個經辦人的任務 taskQuery.taskAssignee(userId); // 某個委托人的任務 taskQuery.taskOwner(userId); // 某個或多個流程實例的任務 taskQuery.processInstanceId(String processInstanceId); taskQuery.processInstanceIdIn(List<String> processInstanceIds); // 某個或多個部署實例的任務 taskQuery.deploymentId(String deploymentId); taskQuery.deploymentIdIn(List<String> deploymentIds); // 某個活動實例的任務 taskQuery.executionId(String executionId); // 按照任務建立時間倒序 taskQuery.orderByTaskCreateTime().desc(); // 存活的任務 taskQuery.active(); // 掛起的任務 taskQuery.suspended(); // 沒有 刪除緣由 的任務 taskQuery.taskWithoutDeleteReason(); // 沒有簽收的任務 taskQuery.taskUnassigned(); // 單個的任務對象 Task task = taskQuery.singleResult(); // 多個任務對象 begin : 從第幾個開始 ; max : 展現多少個 List<Task> tasks = taskQuery.list(); List<Task> tasks = taskQuery.listPage(int begin,int max); // 任務的數量 long count = taskQuery.count();
4.5.2 變量的設值與取值
// 任務ID String taskId = task.getId(); // 設置全局變量 taskService.setVariable(taskId,"key1","value1"); // 設置局部變量 taskService.setVariableLocal(taskId,"key2","value2"); // 獲取全局變量 Map<String,Object> a = taskService.getVariables(taskId); // 獲取局部變量 Map<String,Object> b = taskService.getVariablesLocal(taskId); // 流程啟動后獲取變量(全局變量) Map<String,Object> variables = runtimeService.getVariables(processInstanceId); // 設置變量(全局變量) runtimeService.setVariable(processInstanceId,"key","value");
4.5.3 任務的流轉
// 任務的執行(委托人) taskService.resolveTask(taskId); taskService.complete(taskId); // 任務的執行(經辦人) variables : 下次任務所須要的參數 localScope : 變量的存儲范圍(true:做用范圍為當前任務,false:表示這個變量是全局的) // 博客:https://blog.csdn.net/u013026207/article/details/53405265 taskService.complete(taskId); taskService.complete(String taskId, Map<String, Object> variables); taskService.complete(String taskId, Map<String, Object> variables, boolean localScope); // 添加和刪除候選人 taskService.addCandidateUser(taskId, userId); taskService.deleteCandidateUser(taskId, userId); // 簽收 taskService.claim(taskId, userId); // 委派 taskService.delegateTask(taskId, acceptUserId); // 轉發 taskService.setAssignee(taskId, acceptUserId); // 駁回 currTaskKeys : 該任務的節點 ; activityId : 上一個節點ID List<String> currTaskKeys = new ArrayList<>(); List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).list(); for (Task task : tasks) { currTaskKeys.add(task.getTaskDefinitionKey()); } runtimeService.createChangeActivityStateBuilder() .processInstanceId(processInstanceId) .moveActivityIdsToSingleActivityId(currTaskKeys, activityId) .changeState(); // 刪除任務 taskService.deleteTask(taskId, deleteReason); taskService.deleteTasks(List<String> taskIds, deleteReason);
4.5.4 根據流程實例ID獲取流程圖(流程圖在服務器上的訪問地址)
// 1.獲取流程實例 ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult(); // 2.根據流程實例ID獲取該實例全部的歷史軌跡對象 List<HistoricActivityInstance> historyProcess = historyService.createHistoricActivityInstanceQuery().processInstanceId(instanceId).finished().list(); // 全部的歷史軌跡對象 Map<String, HistoricActivityInstance> hisActivityMap = new HashMap<>(16); historyProcess.forEach(historicActivityInstance -> { if (!hisActivityMap.containsKey(historicActivityInstance.getActivityId())) { hisActivityMap.put(historicActivityInstance.getActivityId(), historicActivityInstance); } }); // 流程定義ID String processDefinitionId; // 節點ID的集合 List<String> activityIds = new ArrayList<>(); // 3.獲取高亮顯示的節點ID和流程定義ID if (pi == null) { // 若是流程已經走完了,則從歷史記錄查詢 historyService HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult(); processDefinitionId = historicProcessInstance.getProcessDefinitionId(); // 獲取該流程的結束節點高亮顯示 String endActivityId = historicProcessInstance.getEndActivityId(); activityIds.add(endActivityId); } else { // 若是流程沒有走完,則從運行記錄查詢 runtimeService processDefinitionId = pi.getProcessDefinitionId(); activityIds = runtimeService.getActiveActivityIds(instanceId); } // 4.獲取流程圖 BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); // 5.獲取流程定義的全部節點信息 Map<String, FlowElement> activityMap = new HashMap<>(16); List<Process> processes = bpmnModel.getProcesses(); for (Process process : processes) { Collection<FlowElement> flowElements = process.getFlowElements(); for (FlowElement flowElement : flowElements) { if (flowElement != null) { String flowElementId = flowElement.getId(); activityMap.put(flowElementId, flowElement); } } } // 6.獲取高亮顯示的連線集合 List<String> flows = new ArrayList<>(); // 遞歸獲取高亮連線 for (String activityId : activityIds) { this.getHighLightedFlows(activityMap, hisActivityMap, activityId, flows, activityId); > // 遞歸方法 > private void getHighLightedFlows(Map<String, FlowElement> flowNodeMap,Map<String, HistoricActivityInstance> hisActivityMap,String activeActivityId,List<String> highLightedFlows,String oldActivityId) { > // 獲取有效節點的節點信息 > FlowElement flowElement = flowNodeMap.get(activeActivityId); > FlowNode flowNode = (FlowNode) flowElement; > // 獲取連線信息集合 > List<SequenceFlow> incomingFlows = flowNode.getIncomingFlows(); > for (SequenceFlow sequenceFlow : incomingFlows) { > // 獲取連線ID > String sourceRefId = sequenceFlow.getSourceRef(); > if (hisActivityMap.containsKey(sourceRefId) && !oldActivityId.equals(sourceRefId)) { > highLightedFlows.add(sequenceFlow.getId()); > this.getHighLightedFlows(flowNodeMap, hisActivityMap, sourceRefId, highLightedFlows, oldActivityId); > } else { > if (hisActivityMap.containsKey(sourceRefId)) { > highLightedFlows.add(sequenceFlow.getId()); > } > break; > } > } > } } // 獲取流程引擎配置 ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration(); // 定義流程畫布生成器 ProcessDiagramGenerator processDiagramGenerator = engConf.getProcessDiagramGenerator(); // 獲取流程圖字節流 InputStream in = processDiagramGenerator.generateDiagram(bpmnModel, FlowableConstants.PNG, activityIds, flows, engConf.getActivityFontName(), engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, true); // 流程圖文件名 String fileName = instanceId.replace("-", ""); // 將流程圖保存到本地,並返回流程圖在服務器上的訪問地址 try { // ***該方法為本文4.5.6的方法***,應單獨封裝為一個工具類中的方法 return FileUtil.writeFile(in, filePath, fileName, FlowableConstants.PNG); } catch (IOException e) { return null; }
4.5.5 根據流程定義ID獲取流程圖(流程圖在服務器的訪問路徑)
// 獲取流程圖 BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); // 獲取流程引擎配置 ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration(); // 定義流程畫布生成器 ProcessDiagramGenerator processDiagramGenerator = engConf.getProcessDiagramGenerator(); InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel,FlowableConstants.PNG,engConf.getActivityFontName(),engConf.getLabelFontName(),engConf.getAnnotationFontName(),engConf.getClassLoader(),1.0,true); // 流程圖文件名 String fileName = bpmnModel.getTargetNamespace(); if (fileName == null || "".equals(fileName)) { fileName = processDefinitionId.substring(0, processDefinitionId.indexOf(":")).replace("-", ""); } // 將流程圖保存到本地 try { // ***該方法為本文4.5.6的方法***,應單獨封裝為一個工具類中的方法 return FileUtil.writeFile(inputStream, filePath, fileName, FlowableConstants.PNG); } catch (IOException e) { return null; }
4.5.6 保存文件到服務器,並返回保存文件在服務器的路徑
/** * 保存文件並返回保存文件的路徑 * * @param inputStream 數據流 * @param path 保存路徑 * @param fileName 文件名 * @param fileType 文件類型 * @return */ public static String writeFile(InputStream inputStream, String path, String fileName, String fileType) throws IOException { OutputStream out = null; // 按照文件類型分目錄存放 String folderPath = path + "/" + fileType + "/"; File file = new File(folderPath); // 判斷目錄是否存在 if (!file.exists()) { file.mkdirs(); } // 完整文件名 String fileNames = fileName + "." + fileType; // 文件存放路徑 String filePath = folderPath + fileNames; File image = new File(filePath); image.createNewFile(); byte[] bytes = new byte[1024]; int length = 0; try { out = new FileOutputStream(image); while ((length = inputStream.read(bytes)) != -1) { out.write(bytes, 0, length); } return fileType + "/" + fileNames; } finally { if (inputStream != null) { inputStream.close(); } if (out != null) { out.close(); } } }
5.flowable使用時的數據庫變化
5.1 流程模型
開始節點 ----> 審批人甲 ----> 審批人乙 ----> 結束節點
5.2 部署act_re_deployment
:會有一條部署記錄,記錄此次部署的基本信息act_ge_bytearray
:有兩條記錄,記錄的是本次上傳的bpmn文件和對應的圖片文件,每條記錄都有act_re_deployment
表的外鍵關聯act_re_procdef
:有一條記錄,記錄的是該bpmn文件包含的基本信息,包含act_re_deployment
表外鍵
5.3 發起申請,啟動流程act_ru_execution
:插入一條記錄,記錄這個流程定義的執行實例,其中id和proc_inst_id相同都是流程執行實例id,也就是本次執行這個流程定義的id,包含流程定義的id外鍵act_ru_task
:插入一條記錄,記錄的是第一個任務的信息,也就是開始執行第一個任務。包括act_ru_execution
表中的execution_id外鍵和proc_inst_id外鍵,也就是本次執行實例idact_hi_procinst
:插入一條記錄,記錄的是本次執行實例的歷史記錄act_hi_taskinst
:插入一條記錄,記錄的是本次任務的歷史記錄
5.4 審批人甲批准act_ru_variable
:插入變量信息,包含本次流程執行實例的兩個id外鍵,但不包括任務的id,由於setVariable方法設置的是全局變量,也就是整個流程都會有效的變量act_ru_task
:表中審批人甲的記錄被刪除,新插入審批人乙的任務記錄act_ru_execution
:活動記錄並無刪除,而是將正在執行的任務變成審批人乙act_hi_var_inst
:插入流程實例的歷史記錄act_hi_taskinst
:插入任務的歷史記錄
5.5 審批人乙批准(流程結束)act_ru_task
:該流程實例任務實例記錄全被清空act_ru_execution
:該流程實例活動實例記錄全被清空act_ru_variable
:該流程實例的參數記錄全被清空act_hi_actinst
:記錄該流程實例全部歷史活動信息
文獻:
https://www.jianshu.com/p/fd690eeb9d3c