Flowable初級使用手冊


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.NAMEACT_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接口的實例。能夠經過ActivitimanagementService.getEventLogEntries(startLogNr, size)?獲取EventLogEntryEntity實例。容易看出這個表中的數據能夠經過JSON放入大數據NoSQL存儲,例如MongoDBElastic 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.1
deploymentQuery : 部署文件查詢器
ProcessDefinitionQuery : 流程定義文件查詢對象
Deployment : 流程部署文件對象,詳見本文4.1
ProcessDefinition : 流程定義文件對象,詳見本文4.1
BpmnModel : 流程定義的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外鍵,也就是本次執行實例id
act_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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM