背景
近幾年,互聯網企業從消費互聯網向產業互聯網轉型。在消費互聯網時期,企業面對的時C端消費者,而產業互聯網面對的是B端用戶。產業互聯網涉及方方面面,企業信息化的建設就是B端用戶的業務之一,在企業就存在上下級關系,存在審批業務,需要流程管理。在企業信息化建設中流程管理也是重要的一部分。
流程引擎是低代碼開發(流程引擎,數據源,連接器,權限管理,表單等)重要的一部分, 如下基於flowable簡單的分析流程定義。
流程的一點基本概念
流程
- process表示描述一個審批或自動執行的過程定義說明。
流程實例
- 一個流程定義,提交一些form參數變量列表啟動形成一個流程實例,即創建者對一個流程的實例化過程。
任務
- 一個流程定義中有諸如人工審批節點,自動節點等組成,流程實例運行到某一個節點后,會產生一個任務去執行,如人工任務,自動化任務等。
form表單
- form表單是流程啟動,人工審批等環節提交給流程實例的變量列表,這些變量列表會貫穿流程實例的生命周期,而變量的提交一般通過form表單的形式提交。
開始節點,結束節點和人工任務節點
網關
自動服務任務
順序流
網關分支
- 並行分叉 AND-split(Parallel Split)
- 兩個分支都需要執行
- 如 下單后 發快遞和開發票,兩個動作都會做。
- 排他分叉或叫異或 XOR-split(Exclusive Choice)
- 后續分支二選一,只能走一條
- 如 下單后的支付,選擇銀聯支付,微信支付還是支付寶支付,只能選擇一種支付方式。
網關合並
- 同步AND-join(Synchronization)
- 前面的所有的分支等待都需要完成
- 如上面的下單,收快遞和收發票,都收到了,流程才完成。
- 簡單合並XOR-join(Simple Merge)
- 前面的分支只要有一個完成,流程就完成
- 如上面的下單后支付,不管是銀聯,微信支付還是支付寶支付,只要有一個渠道支付成功,支付流程就完成。
Flowable相關說明
官網地址:https://flowable.com/
幫助文檔:https://flowable.com/open-source/docs/bpmn/ch02-GettingStarted/
中文幫助文檔:https://tkjohn.github.io/flowable-userguide/#_introduction
github代碼:https://github.com/flowable/flowable-engine
flowable的發展
- Flowable是來自從Activiti5.22
- Activiti6.0的bug太多
- Activiti7.0主要擁抱雲
- Flowable6版本開始按照模塊進行拆分,社區比較活躍
如下是JBoss,Alfresco和Flowable三個團隊的流程軟件關鍵時間點描述:
Flowable安裝和配置
Flow安裝
第一步、從flowable的github地址上下載如下幾個war,部署到apache的webapps下
flowable-admin.war flowable-idm.war flowable-modeler.war flowable-rest.war flowable-task.war
第二步、修改如上幾個包的配置文件,配置mysql數據地址或者使用自身的h2數據庫進行實驗。
修改admin idm modeler rest和task這5個包的配置文件WEB-INF/classes/flowable-default.properties,本實驗使用的是mysql數據庫。
spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/flowable?characterEncoding=UTF-8 spring.datasource.username=flowable spring.datasource.password=flowable
配置后,啟動tomcat服務器並登錄。
Flowable modeler登錄
訪問flowable的流程設計器
地址:http://localhost:8080/flowable-modeler
賬號密碼:admin/test
登錄后,可以訪問flowable的管理頁面
地址:http://localhost:8080/flowable-admin/#/engine
可以看到flowable流程由如下幾個引擎組成
可以通過編輯REST端點檢查對應的服務運行是否正常。
本例中以流程引擎為例簡單的說明。
流程定義
定義一個簡單的請假流程,包括一個開始節點,一個審批節點,經過排他網關后,審批通過后發送一個http通知,審批拒絕后也發送一個http通知。
如上流程定義使用bpmn2.0的xml表示大致如下所示
<?xml version="1.0" encoding="UTF-8"?> <definitions> <process id="flow_h1" name="holiday-new" isExecutable="true"> <documentation>請求流程描述</documentation> <startEvent id="startEvent1" name="請假開始" flowable:formKey="formKey1" flowable:formFieldValidation="true"> <extensionElements> <flowable:formProperty id="employee" name="請假人" type="string" required="true"></flowable:formProperty> <flowable:formProperty id="noOfHolidays" name="天數" type="long" required="true"></flowable:formProperty> </extensionElements> </startEvent> <userTask id="approveKey1" name="審批節點1" flowable:formFieldValidation="true"></userTask> <exclusiveGateway id="sid-D7F080C0-BC9D-4C03-B9EB-2D81E4010CA6" name="審批是否通過"></exclusiveGateway> <serviceTask id="AcceptKey1" name="通過" flowable:class="org.example.tut.flowable.handler.HolidayRejectionHandler"></serviceTask> <serviceTask id="RejectKey1" name="拒絕" flowable:class="org.example.tut.flowable.handler.HolidayApprovalHandler"></serviceTask> <endEvent id="sid-E86D23D8-DC24-44D0-B96D-BA3E8CF801C0"></endEvent> <serviceTask id="RejectHttpKey1" name="HTTP測試節點" flowable:type="http"> <extensionElements> <flowable:field name="requestMethod"> <flowable:string><![CDATA[POST]]></flowable:string> </flowable:field> <flowable:field name="requestUrl"> <flowable:string><![CDATA[http://127.0.0.1:9901/test]]></flowable:string> </flowable:field> <flowable:field name="requestBody"> <flowable:expression><![CDATA[Reject action, employee ${employee} apply ${noOfHolidays} days with reason ${description}]]></flowable:expression> </flowable:field> </extensionElements> </serviceTask> <sequenceFlow id="sid-84648711-833A-4ABE-AD08-3E32B026F247" sourceRef="RejectKey1" targetRef="RejectHttpKey1"></sequenceFlow> <sequenceFlow id="sid-448B4748-A744-43D9-B3EB-FC0846035F20" sourceRef="RejectHttpKey1" targetRef="sid-E86D23D8-DC24-44D0-B96D-BA3E8CF801C0"></sequenceFlow> <endEvent id="sid-683697FC-2E68-45C9-BE63-0F526FC2F3AB"></endEvent> <serviceTask id="AcceptHttpKey1" name="審批通過的HTTP消息" flowable:type="http"> <extensionElements> <flowable:field name="requestMethod"> <flowable:string><![CDATA[POST]]></flowable:string> </flowable:field> <flowable:field name="requestUrl"> <flowable:string><![CDATA[http://127.0.0.1:9901/test]]></flowable:string> </flowable:field> <flowable:field name="requestBody"> <flowable:expression><![CDATA[Accept Holiday employee ${employee} apply ${noOfHolidays} days with reason ${description}]]></flowable:expression> </flowable:field> </extensionElements> </serviceTask> <sequenceFlow id="sid-9788654A-171C-45B9-9A41-94A35C531AA8" sourceRef="AcceptHttpKey1" targetRef="sid-683697FC-2E68-45C9-BE63-0F526FC2F3AB"></sequenceFlow> <sequenceFlow id="sid-C4456145-0531-492F-AA80-E733CD0C35C9" sourceRef="AcceptKey1" targetRef="AcceptHttpKey1"></sequenceFlow> <sequenceFlow id="SeqFromStartToApprove" sourceRef="startEvent1" targetRef="approveKey1"></sequenceFlow> <sequenceFlow id="SeqFromApproveToGW" sourceRef="approveKey1" targetRef="sid-D7F080C0-BC9D-4C03-B9EB-2D81E4010CA6"></sequenceFlow> <sequenceFlow id="SeqRejectKey1" sourceRef="sid-D7F080C0-BC9D-4C03-B9EB-2D81E4010CA6" targetRef="RejectKey1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!approved}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="ReqAcceptKey1" sourceRef="sid-D7F080C0-BC9D-4C03-B9EB-2D81E4010CA6" targetRef="AcceptKey1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approved}]]></conditionExpression> </sequenceFlow> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_flow_h1"> ... 省 </bpmndi:BPMNDiagram> </definitions>
節點說明
這個簡單的流程中使用了flowable的幾個節點
流程定義的組成
process
- startEvent 表示開始節點
- 開始節點可以是空節點
- 開始節點也可以是定時節點
- userTask 表示人工審批節點
- 可以通過 flowable:assignee="userId" 表示這個節點的審批人是誰
- 可以通過 flowable:candidateGroups="managerGroup" 表示候選的審批組是什么,在這個組中的人都可以做為審批人。
- 人工審批節點可以增加extensionElements增加自定義擴展屬性,將流程定義的擴展信息保存到CDATA中
- exclusiveGateway 表示排他網關
- 人工審批后的審批結果做為排他網關的判斷依據
- serviceTask 表示自動節點
- 有自定義的節點需要自定義一個Handler做為serviceTask節點的處理。
- serviceTask也有一些系統內置實現(如HTTP服務 MAIL服務 MULE服務等)
- 自動服務節點可以增加extensionElements增加自定義擴展屬性,將流程定義的擴展信息保存到CDATA中
- sequenceFlow 表示分支流
- 在分支流上會存在一個條件,排他網關后會跟多個sequenceFlow,排他網關會根據各自sequenceFlow上的條件決定流程的流向。
- 條件會使用conditionExpression來表示,這個表達式一般使用JUEL表達式實現。
- endEvent 表示結束節點
bpmndi:BPMNDiagram
- bpmndi:BPMNShape
- omgdc:Bounds 表示圖像的輪廓包含寬高
- width 寬
- height 高
- omgdc:Bounds 表示圖像的輪廓包含寬高
- bpmndi:BPMNEdge
- pmgdi:waypoint
- x 橫軸坐標
- y 縱軸坐標
- pmgdi:waypoint
startEvent的定時節點如何定義?
<startEvent id="timer_start1" name="定時器節點" isInterrupting="false"> <timerEventDefinition> <timeDate>2021-06-30T15:01:02</timeDate> <timeCycle>R/P1DT0S</timeCycle> <timeDuration>P10DT0S</timeDuration> </timerEventDefinition> </startEvent>
時間定義參考ISO8601標准,可以參考@https://www.cnblogs.com/xdao/p/iso8601.html
格式解析 R2/2015-06-04T19:25:16.828696-07:00/P1DT10S 上面的字符串通過"/"分為了三部分即: 重復次數/開始時間/運行間隔 重復次數 R - 將永遠重復 R1 - 將重復一次 R231 - 將重復231次。 開始時間 任務第一次運行的時間。如果開始日期時間已經過去,Kala將返回一個錯誤。 其中"T"用來分割日期和時間,時間后面跟着的"-07:00"表示西七區,注意"-"是連字符,不是減號。 時區默認是0時區,可以用"Z"表示,也可以不寫。 對於我國,要使用"+08:00",表示東八區。 上面的字符串表示 2015年6月4日,19點25分16秒828696納秒,西七區。 運行間隔 運行間隔以"P"開始,和上面一樣也是用"T"分割日期和時間,如P1Y2M10DT2H30M15S P 開始標記 1Y - 一年 2M - 兩個月 10D - 十天 T - 時間和日期分的割標記 2H - 兩個小時 30M - 三十分鍾 15S 十五秒鍾 例子,注意如果沒有年月日,"T"也不能省略 P1DT1M - 一天一分鍾執行一次 P1W - 一周執行一次 PT1H - 一小時執行一次 PT10S - 十秒執行一次
啟動流程
啟動流程的代碼:
public ProcessInstanceResponse startProcessInstance(HolidayRequest holidayRequest) { Map<String, Object> variables = new HashMap<String, Object>(); variables.put("employee", holidayRequest.getEmpName()); variables.put("noOfHolidays", holidayRequest.getNoOfHolidays()); variables.put("description", holidayRequest.getRequestDescription()); variables.put("initiator", "admin"); ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(holidayRequest.getProcessKey(), variables); return new ProcessInstanceResponse(processInstance.getId(), processInstance.isEnded()); }
啟動流程后,會在數據庫中增加記錄
ACT_RU_ACTINST 增加流程實例信息。
ACT_RU_VARIABLE 增加variables變量列表的變量,這個變量會貫穿流程實例的全程。
分配任務
分配任務的代碼:
TaskService taskService; // taskId是任務Id,userId是用戶id,表示將任務分配給這個用戶 taskService.setAssignee(taskId, userId);
分配任務后,會在數據庫中設置審批人信息
ACT_RU_TASK 表的字段 ASSIGEE_表示審批人是誰
獲取待辦任務
獲取待辦任務的代碼
// 跟進userId用戶id查詢分配給這個用戶或將這個用戶設為候選的任務列表 List<Task> taskList = taskService.createTaskQuery().taskCandidateOrAssigned(userId).list();
會查詢ACT_RU_TASK表,獲取審批人的任務。
完成任務
完成任務也叫做審批任務
taskService.complete(taskId, variables);
流程運行
流程運行時,實例和變量說明什么
可以在管理頁面看到啟動流程實例是填寫的變量列表
啟動流程增加的變量
variables.put("employee", holidayRequest.getEmpName()); variables.put("noOfHolidays", holidayRequest.getNoOfHolidays()); variables.put("description", holidayRequest.getRequestDescription()); variables.put("initiator", "admin");
人工節點審批時增加的變量是什么
variables.put("approved", approved);
taskService.complete(taskId, variables);
即:變量時貫穿流程實例的全聲明周期,流程的很多自定義功能可以通過變量和擴展屬性進行實現。
展示流程實例的運行圖
done.
祝玩得開心~