當(dāng)我們在日常工作和業(yè)務(wù)中需要進(jìn)行各種審批流程時(shí),可能會(huì)面臨一系列技術(shù)和業(yè)務(wù)上的挑戰(zhàn)。手動(dòng)處理這些審批流程可能會(huì)導(dǎo)致開發(fā)成本的增加以及業(yè)務(wù)復(fù)雜度的上升。在這種情況下,引入工作流引擎能夠帶來很多好處,讓我們一起來看看:
在傳統(tǒng)的手動(dòng)審批系統(tǒng)中,開發(fā)人員需要從頭開始設(shè)計(jì)和實(shí)現(xiàn)整個(gè)審批流程,包括流程邏輯、狀態(tài)跟蹤、任務(wù)分配等。這可能需要大量的時(shí)間和精力,尤其是在涉及到復(fù)雜的業(yè)務(wù)場景時(shí)。
使用工作流引擎,開發(fā)人員可以利用其強(qiáng)大的流程建模和執(zhí)行功能,快速搭建審批系統(tǒng)。工作流引擎提供了圖形化的流程設(shè)計(jì)工具,讓流程建模變得簡單易懂。這樣,開發(fā)人員可以專注于業(yè)務(wù)邏輯的實(shí)現(xiàn),大大降低了開發(fā)成本和周期。
通過引入工作流引擎,我們可以克服手動(dòng)處理審批流程所帶來的開發(fā)成本高和業(yè)務(wù)復(fù)雜度的挑戰(zhàn)。它使得開發(fā)人員能夠更專注于業(yè)務(wù)邏輯的實(shí)現(xiàn),快速構(gòu)建符合實(shí)際需求的審批系統(tǒng)。同時(shí),流程圖的可視化設(shè)計(jì)和條件判斷的支持,使得業(yè)務(wù)流程更加清晰、透明,降低了錯(cuò)誤發(fā)生的概率,提高了審批過程的效率和準(zhǔn)確性。這將為企業(yè)帶來更高的效益和競爭力。
圖片
目前市面上比較主流的幾個(gè)工作流引擎包括Activiti、Flowable、Camunda等,體系較為成熟,使用最為廣泛的是activiti,flowable跟activiti本質(zhì)上沒什么區(qū)別,是由activiti改版而來,但是兩者后續(xù)發(fā)展路線則不一樣,Activiti后續(xù)發(fā)展重心是在商業(yè)版與云上面,并未對核心功能與性能優(yōu)化上有過多的跟進(jìn)優(yōu)化,而flowable當(dāng)下重心則是針對功能性、擴(kuò)展性、性能上進(jìn)行迭代優(yōu)化。
圖片
當(dāng)然,具體選型還是要看業(yè)務(wù)實(shí)際的需要,目前activiti迭代的方向并不是當(dāng)下我們業(yè)務(wù)所需要的,我們更重視性能、擴(kuò)展性這一塊,而flowbale與Camunda之間為什么選擇了flowable呢,則是因?yàn)閒lowable社區(qū)較為活躍,遇到并處理問題上更為效率,并且面對多節(jié)點(diǎn)審批時(shí),異步任務(wù)是提升吞吐率的優(yōu)質(zhì)之選。
圖片
下面我將簡單介紹下flowable的一些功能以及模塊。
在Flowable中,流程定義通常使用BPMN 2.0標(biāo)準(zhǔn)(Business Process Model and Notation)進(jìn)行建模,可以通過Flowable Modeler進(jìn)行圖形化設(shè)計(jì)。
圖片
這些是Flowable中的一些基礎(chǔ)元素,它們構(gòu)成了流程引擎的核心。通過這些元素,我們可以靈活地設(shè)計(jì)和管理復(fù)雜的業(yè)務(wù)流程,使得流程執(zhí)行更加高效、透明和可控。
在調(diào)用開始之前,我們簡單說明一下各個(gè)api的作用以及應(yīng)用場景:
啟動(dòng)后會(huì)自動(dòng)生成一些內(nèi)置的系統(tǒng)表(如果不想自動(dòng)生成可以通過配置關(guān)閉),這里簡單介紹一下表的含義:
ACT_HI_*: 歷史數(shù)據(jù)表,例如:
表名 | 含義 |
ACT_HI_PROCINST | 歷史流程實(shí)例表,存儲(chǔ)已完成的流程實(shí)例信息,包括流程開始時(shí)間、結(jié)束時(shí)間等。 |
ACT_HI_TASKINST | 歷史任務(wù)實(shí)例表,存儲(chǔ)已完成的任務(wù)實(shí)例信息,包括任務(wù)開始時(shí)間、結(jié)束時(shí)間、辦理人等。 |
ACT_HI_VARIABLE | 歷史流程變量表,用于存儲(chǔ)在流程運(yùn)行時(shí)設(shè)置的變量信息。 |
ACT_RU_*: 運(yùn)行時(shí)的數(shù)據(jù)表,節(jié)點(diǎn)結(jié)束時(shí)清除,例如:
表名 | 含義 |
ACT_RU_EXECUTION | 運(yùn)行時(shí)流程執(zhí)行實(shí)例表,存儲(chǔ)當(dāng)前正在執(zhí)行的流程實(shí)例信息。 |
ACT_RU_TASK | 運(yùn)行時(shí)任務(wù)表,存儲(chǔ)當(dāng)前正在執(zhí)行的任務(wù)信息。 |
ACT_RU_VARIABLE | 運(yùn)行時(shí)流程變量表,用于存儲(chǔ)在流程運(yùn)行時(shí)設(shè)置的變量信息。 |
另外,flowable支持定期清理歷史數(shù)據(jù),業(yè)務(wù)側(cè)可以定義一個(gè)時(shí)間范圍,超過時(shí)間范圍可以認(rèn)為數(shù)據(jù)可以被清理,系統(tǒng)內(nèi)部會(huì)自行將數(shù)據(jù)物理刪除,為歷史表做瘦身操作。
不過我們業(yè)務(wù)側(cè)接入的時(shí)候,往往業(yè)務(wù)需要?jiǎng)?chuàng)建幾個(gè)符合我們具體業(yè)務(wù)場景的表,例如工單表、任務(wù)表雖然框架提供了,但是并沒有記錄詳細(xì)的狀態(tài),這些狀態(tài)是我們業(yè)務(wù)自己定義的,所以需要額外創(chuàng)建業(yè)務(wù)工單表、審批任務(wù)(節(jié)點(diǎn))表、流水表等來進(jìn)行數(shù)據(jù)上的冗余來滿足實(shí)際的業(yè)務(wù)場景。
我們可以通過可視化后臺(tái)繪制流程建模,生成BPMN格式的文件,那么BMPN又是什么呢?
BPMN(Business Process Model and Notation)是一種用于建模業(yè)務(wù)流程的標(biāo)準(zhǔn)化符號和語法,用于描述業(yè)務(wù)流程的各個(gè)環(huán)節(jié)和活動(dòng)。BPMN的最新版本是BPMN 2.0,它是業(yè)務(wù)流程建模領(lǐng)域的國際標(biāo)準(zhǔn),由OMG(Object Management Group)制定和發(fā)布。
BPMN 2.0的主要目標(biāo)是提供一種統(tǒng)一的標(biāo)準(zhǔn),使得不同人員和組織能夠使用相同的符號和語法來建模和理解業(yè)務(wù)流程,從而增加流程的可視化和可讀性。
它具有以下特點(diǎn)和優(yōu)勢:
我們可以從Flowable官網(wǎng)下載flowable-ui部署到本地來啟動(dòng)可視化后臺(tái),可以使用在線的Flowable Modeler來繪制,這里我們使用官網(wǎng)的flowable-ui來繪制。
具體下載啟動(dòng)過程我就不過多贅述了,flowable-ui是基于 springboot2.0開發(fā)的,可以直接以下方式來啟動(dòng):
java -jar flowable-ui.war
啟動(dòng)成功后如圖所示:
圖片
我們打開建模器應(yīng)用程序并點(diǎn)擊【創(chuàng)建流程】按鈕,我們可以給模型進(jìn)行一個(gè)簡單的定義.
圖片
如圖繪制了一個(gè)最簡單的流程建模
圖片
我們也可以給用戶任務(wù)分配一些基礎(chǔ)屬性,這里我們配置一個(gè)固定用戶, 當(dāng)然這里也支持占位符來動(dòng)態(tài)控制
圖片
Image.png
圖片
這樣一個(gè)最簡單的流程建模(不含復(fù)雜節(jié)點(diǎn)、網(wǎng)關(guān)等)就繪制完畢了,繪制完成后會(huì)生成一個(gè)xml文件,
接下來我會(huì)從導(dǎo)入到執(zhí)行來執(zhí)行執(zhí)行一遍該流程。
<dependency> <groupId>org.flowable</groupId> <artifactId>flowable-spring-boot-starter</artifactId> <version>6.6.0</version> </dependency>
@Test public void createConfig() throws Exception{ File file = new File("/Users/xxx/Documents/flowbale/model/testModel.bpmn20.xml"); final FileInputStream fileInputStream = new FileInputStream(file); final Deployment deploy = repositoryService.createDeployment() .addInputStream("testModel.bpmn20.xml", fileInputStream).tenantId("類似于業(yè)務(wù)線的id,可以做數(shù)據(jù)隔離用") .name("testModel").deploy(); System.out.println("id=" + deploy.getId()); }
@Test public void getProcessDefinition() { final ProcessDefinition rst = repositoryService.createProcessDefinitionQuery().processDefinitionKey("testModel").orderByProcessDefinitionVersion().desc().list().get(0); System.out.println(rst.toString()); }
// processDefinitionKey 流程建模的key// businessId 具有業(yè)務(wù)屬性的id// variableMap變量的map 結(jié)果會(huì)存入 ACT_RU_VARIABLE表中,如果審批人傳入的是變量就需要再節(jié)點(diǎn)執(zhí)行前將變量傳入到系統(tǒng)中Map<String, Object> variableMap = new HashMap();variableMap.put("testUserList", Lists.newArrayList("nick","jack","tony"));String processDefinitionKey = "testModel";Long businessId = 1L;String tenantId = "1001";runtimeService.startProcessInstanceByKeyAndTenantId(processDefinitionKey, businessId + "", variableMap, tenantId);
final List<Task> taskList = taskService.createTaskQuery().taskAssignee("jack").list()
Map<String, Object> variableMap = new HashMap();// 我們自己定義了一個(gè)內(nèi)部標(biāo)準(zhǔn)化字段,flag代表著節(jié)點(diǎn)是通過還是駁回,在互斥網(wǎng)關(guān)判斷通過駁回的時(shí)候會(huì)用到。variableMap.put("flag", 1);taskService.complete(taskId), variableMap);
我們通過上述用例了解了一個(gè)工單是如何操作流轉(zhuǎn)的,但是一個(gè)完整的審批服務(wù)是應(yīng)該有消息推送的,當(dāng)審批節(jié)點(diǎn)到達(dá)某個(gè)人需要提醒他進(jìn)行審批操作,或者審批工單結(jié)束了需要通知發(fā)起人,我們應(yīng)該如何操作呢?Flowable提供了便攜的事件監(jiān)聽器,不需要我們額外編寫代碼來判斷是否到達(dá)相應(yīng)的節(jié)點(diǎn),我們這里常用的就是節(jié)點(diǎn)創(chuàng)建、節(jié)點(diǎn)完成、流程結(jié)束等。
Flowable支持的事件有幾十種,具體大家請自行去官網(wǎng)參考,下面僅展示“流程結(jié)束事件”監(jiān)聽器的代碼用例:
package com.zhuanzhuan.workflow_engine.config;import com.zhuanzhuan.workflow_engine.listener.*;import lombok.extern.slf4j.Slf4j;import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;import org.flowable.common.engine.api.delegate.event.FlowableEventDispatcher;import org.flowable.spring.SpringProcessEngineConfiguration;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationListener;import org.springframework.context.annotation.Configuration;import org.springframework.context.event.ContextRefreshedEvent;/** * @author:Live * @desc: * @date: 19:55 2023/1/13 */@Configuration@Slf4jpublic class FlowableListenerConfiguration implements ApplicationListener<ContextRefreshedEvent> { @Autowired private SpringProcessEngineConfiguration configuration; @Autowired private ProcessEndListener processEndListener; @Override public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { FlowableEventDispatcher dispatcher = configuration.getEventDispatcher(); dispatcher.addEventListener(processEndListener, FlowableEngineEventType.PROCESS_COMPLETED); }}
package com.zhuanzhuan.workflow_engine.listener;import com.bj58.zhuanzhuan.zzarch.common.util.JsonUtil;import com.zhuanzhuan.workflow_engine.entity.dto.WorkflowOrderDTO;import com.zhuanzhuan.workflow_engine.enums.CurrentFlagEnum;import com.zhuanzhuan.workflow_engine.enums.WorkflowStateEnum;import com.zhuanzhuan.workflow_engine.mq.MqConstant;import com.zhuanzhuan.workflow_engine.mq.body.ProcessExchangeMsgBody;import com.zhuanzhuan.workflow_engine.mq.producer.ProducerHandler;import com.zhuanzhuan.workflow_engine.service.WorkflowOrderBizService;import com.zhuanzhuan.workflow_engine.wrapper.FlowableWrapper;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.StringUtils;import org.flowable.common.engine.api.delegate.event.FlowableEvent;import org.flowable.engine.delegate.event.impl.FlowableEntityEventImpl;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import javax.annotation.Resource;/** * @author:Live * @desc: * @date: 19:34 2023/1/13 */@Component@Slf4jpublic class ProcessEndListener implements FlowableEventListener { @Override public void onEvent(FlowableEvent flowableEvent) { // 流程結(jié)束的監(jiān)聽器,發(fā)送mq、給發(fā)起人發(fā)送消息在此進(jìn)行 } @Override public boolean isFailOnException() { // 拋異常, 不姑息 return true; } @Override public boolean isFireOnTransactionLifecycleEvent() { // event觸發(fā)時(shí)機(jī)跟著 getOnTransaction走 return true; } @Override public String getOnTransaction() { // 提交事務(wù)后觸發(fā) return TransactionState.COMMITTED.name(); }}
以上就是Flowable工作流引擎的簡介以及基本用法,我們實(shí)際生產(chǎn)建設(shè)過程中,還需要基于框架進(jìn)行拓展開發(fā)來滿足我們項(xiàng)目的實(shí)際需要,例如是否需要引入用戶組、權(quán)限管理的模塊、是否存在性能問題從而引入異步任務(wù)的模塊、是否需要冗余業(yè)務(wù)表來滿足定制化查詢的需求,這些都屬于擴(kuò)展玩法,需要我們根據(jù)實(shí)際需求按需接入。畢竟沒有最好的架構(gòu),只有最適合的架構(gòu),選擇適合自己的才是最重要的。
1.flowable官方文檔 https://www.flowable.org/documentation.html
2.技術(shù)選型參考 https://www.zhihu.com/question/59274016/answer/2398240513
關(guān)于作者
王銳剛,線上回收業(yè)務(wù)后端開發(fā)工程師
本文鏈接:http://www.www897cc.com/showinfo-26-101-0.htmlFlowable工作流引擎的科普與實(shí)踐
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com