為什么使用工作流引擎,什么是工作流引擎,工作流引擎選型以及如何使用
本文轉(zhuǎn)載自微信公眾號(hào)「Java大廠面試官」,作者laker 。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java大廠面試官代碼眾號(hào)。
為什么使用工作流引擎?
反證法,如果不使用工作流引擎,先以請(qǐng)假流程舉例,從頭開(kāi)始開(kāi)發(fā)流程的業(yè)務(wù)邏輯:(來(lái)看看會(huì)出現(xiàn)哪些問(wèn)題?使用工作流能解決哪些問(wèn)題?又會(huì)帶來(lái)什么問(wèn)題?)
一、業(yè)務(wù)流程梳理
“流程定義可能是hardcoding或者存儲(chǔ)在某張表
- 總經(jīng)理審批
- 結(jié)束
- 結(jié)束
- 員工發(fā)起請(qǐng)假單
- 組長(zhǎng)審批
- 請(qǐng)假天數(shù)小于等于2天
- 請(qǐng)假天數(shù)大于2天
二、每個(gè)節(jié)點(diǎn)都要記錄當(dāng)前操作人和判斷下個(gè)節(jié)點(diǎn)
- if(day>2)
- 總經(jīng)理審批 (記錄誰(shuí)發(fā)起的以及判斷下個(gè)節(jié)點(diǎn))
- 結(jié)束
- if(day<=2)
- 結(jié)束
- 同意或者拒絕
- nextUserId根據(jù)上面的流程定義獲取
- 存入transfer狀態(tài)流轉(zhuǎn)表, userId nextUserId等 驅(qū)動(dòng)到下一個(gè)節(jié)點(diǎn)
- 員工填寫(xiě)請(qǐng)假單并提交
- nextUserId根據(jù)上面的流程定義獲取
- 存入leave表,創(chuàng)建人,創(chuàng)建時(shí)間
- 存入transfer狀態(tài)流轉(zhuǎn)表, userId nextUserId等 驅(qū)動(dòng)到下一個(gè)節(jié)點(diǎn)
- 員工發(fā)起請(qǐng)假單 (記錄誰(shuí)發(fā)起的以及判斷下個(gè)節(jié)點(diǎn))
- 組長(zhǎng)審批 (記錄誰(shuí)發(fā)起的以及判斷下個(gè)節(jié)點(diǎn))
- 請(qǐng)假天數(shù)小于等于2天 (記錄誰(shuí)發(fā)起的以及判斷下個(gè)節(jié)點(diǎn))
- 請(qǐng)假天數(shù)大于2天 (記錄誰(shuí)發(fā)起的以及判斷下個(gè)節(jié)點(diǎn))
如果再來(lái)個(gè)用車流程、報(bào)銷流程等,那么你的項(xiàng)目將無(wú)法維護(hù)
不使用工作流存在以下問(wèn)題
- 流程設(shè)計(jì)沒(méi)有可視化
- 流程沒(méi)有版本管理,熱部署等
- 每個(gè)活動(dòng)的流轉(zhuǎn)都需要硬性判斷下一步活動(dòng)節(jié)點(diǎn)及其操作人
- 每次操作都需要維護(hù)業(yè)務(wù)數(shù)據(jù)和流程的相關(guān)數(shù)據(jù)
- 缺乏數(shù)據(jù)管理、流程監(jiān)控等功能
工作流優(yōu)缺點(diǎn)
對(duì)上面共性問(wèn)題進(jìn)行抽象,抽象,抽象,可以得出下面的視圖。
把業(yè)務(wù)和流程進(jìn)行了抽象分離,降低耦合,
優(yōu)點(diǎn)
- 具有可視化的流程設(shè)計(jì)工具
- 業(yè)務(wù)數(shù)據(jù)和流程數(shù)據(jù)的分離,可以進(jìn)行更專注的性能優(yōu)化,業(yè)務(wù)劃分
- 內(nèi)置API能很好的完成常見(jiàn)的功能場(chǎng)景
- 具有完善的流程監(jiān)控體系
- 具備大量的自定義擴(kuò)展接口
缺點(diǎn)
需要額外的學(xué)習(xí)成本
什么是工作流引擎
所謂工作流引擎是指workflow作為應(yīng)用系統(tǒng)的一部分,并為之提供對(duì)各應(yīng)用系統(tǒng)有決定作用的根據(jù)角色、分工和條件的不同決定信息傳遞路由、內(nèi)容等級(jí)等核心解決方案。工作流引擎包括流程的節(jié)點(diǎn)管理、流向管理、流程樣例管理等重要功能。(來(lái)自百科)
嘗試自己構(gòu)建工作流引擎
以下內(nèi)容取自:https://www.cnblogs.com/duck-and-duck/p/14436373.html
并進(jìn)行了部分修改。
第1天
我查了一天啥是工作流,然后做出了如下版本:
按順序添加任意個(gè)審批人組成一個(gè)鏈表,最后加一個(gè)結(jié)束節(jié)點(diǎn)
記錄當(dāng)前審批人,當(dāng)審批完后,審批人向后移動(dòng)一位
當(dāng)審批人對(duì)應(yīng)結(jié)束節(jié)點(diǎn)時(shí),流程結(jié)束
“每個(gè)節(jié)點(diǎn)執(zhí)行人是hardcoding的
第二天
發(fā)現(xiàn)部分業(yè)務(wù)需要支持會(huì)簽節(jié)點(diǎn)。
我又查了一天啥是會(huì)簽節(jié)點(diǎn),發(fā)現(xiàn)會(huì)簽節(jié)點(diǎn)就是一個(gè)大節(jié)點(diǎn),里面有很多審批人,當(dāng)這個(gè)大節(jié)點(diǎn)里的所有人都審批通過(guò)后,才能進(jìn)入下一個(gè)節(jié)點(diǎn)。
翻了原來(lái)的鏈表式設(shè)計(jì):
第三天
發(fā)現(xiàn)部分業(yè)務(wù)需要支持條件節(jié)點(diǎn)。
要根據(jù)表單的內(nèi)容確定下一步進(jìn)入哪個(gè)分支。
第四天
審批人多加兩種類型,比如可以從表單中選擇下一個(gè)審批人,還有根據(jù)發(fā)起人不同選擇不同的審批人。
第五天
需要滿足xxx需求,卒。。。
“看來(lái)實(shí)現(xiàn)一個(gè)工作流引擎還是蠻難的,那有什么可選的輪子嗎
有哪些選型方案呢
工作流整體流程如下:
建模(事前) | 運(yùn)行 (事中) | 管理 (事后) | 監(jiān)控(全生命周期) |
---|---|---|---|
流程設(shè)計(jì) | engine驅(qū)動(dòng) | 數(shù)據(jù)管理 | 流程監(jiān)控 |
基于bpmn標(biāo)準(zhǔn)進(jìn)行流程定義
什么是BPMN
BPMN 是 Business Process Modeling Notation 的簡(jiǎn)稱,即業(yè)務(wù)流程建模與標(biāo)注。BPMN 定義了一個(gè)業(yè)務(wù)流程圖,這個(gè)流程圖被設(shè)計(jì)用于創(chuàng)建業(yè)務(wù)流程操作的圖形化模型 。而一個(gè)業(yè)務(wù)流程模型( Business Process Model ),指一個(gè)由圖形對(duì)象( graphical objects )組成的網(wǎng)狀圖,圖形對(duì)象包括活動(dòng)(activities) 和用于定義這些活動(dòng)執(zhí)行順序的流程控制器( flow controls )。
代表實(shí)現(xiàn)產(chǎn)品如下:
- JBPM
- Activiti
- Flowable
國(guó)產(chǎn)自定義
- snaker
- jflow
如何使用SnakerFlow工作流
僅列出常見(jiàn)功能場(chǎng)景實(shí)現(xiàn),具體介紹和詳情文檔參見(jiàn):Spring Boot 集成SnakerFlow流程引擎,簡(jiǎn)介、功能列表、詳細(xì)解讀、擴(kuò)展點(diǎn)分析
“?? ?? ?? 已開(kāi)源基于SnakerFlow輕量級(jí)工作流引擎的腳手架項(xiàng)目 easy-admin
“詳情參見(jiàn):終于寫(xiě)了個(gè)開(kāi)源項(xiàng)目,easy-admin 為打造一款簡(jiǎn)單、輕量級(jí)的后臺(tái)管理系統(tǒng)腳手架
以請(qǐng)假流程來(lái)看下數(shù)據(jù)庫(kù)中數(shù)據(jù)流轉(zhuǎn)情況
相關(guān)源碼已開(kāi)源
已開(kāi)源基于SnakerFlow輕量級(jí)工作流引擎的腳手架項(xiàng)目 easy-admin
詳情參見(jiàn):終于寫(xiě)了個(gè)開(kāi)源項(xiàng)目,easy-admin 為打造一款簡(jiǎn)單、輕量級(jí)的后臺(tái)管理系統(tǒng)腳手架
初始狀態(tài)
wf_process
員工發(fā)起請(qǐng)假申請(qǐng)
- args.put("user1", StpUtil.getLoginIdAsString());
- args.put("user2", "yang");
- args.put("user3", "zhang");
- Object day = args.get("day");
- if (day != null) {
- args.put("day", Integer.valueOf((String) day));
- }b
- snakerEngineFacets.startAndExecute(name, version, StpUtil.getLoginIdAsString(), args);
員工laker發(fā)起一個(gè)請(qǐng)假單,請(qǐng)假3天
laker的待辦列表為空,已辦列表如下:
yang的待辦列表如下:
當(dāng)前監(jiān)控流程圖
wf_order
wf_task
wf_task_actor
wf_hist_order
wf_hist_task
wf_hist_task_actor
常見(jiàn)功能
流程標(biāo)題
我們經(jīng)常希望待辦任務(wù)列表有一列是流程實(shí)例的名稱,即標(biāo)題,例如,我們希望流程的標(biāo)題是:張三 - 2019-12-04 16:40:20的請(qǐng)假申請(qǐng) ,通常會(huì)采用一個(gè)命名規(guī)則:發(fā)起人+發(fā)起時(shí)間+流程模型名稱把它作為流程的標(biāo)題。這時(shí)候就希望啟動(dòng)流程實(shí)例時(shí)可以設(shè)置流程實(shí)例的名稱。
- args.put(SnakerEngine.ID, "張三 - 2019-12-04 16:40:20的請(qǐng)假申請(qǐng)");
- snakerEngineFacets.startAndExecute(name, version, StpUtil.getLoginIdAsString(), args);
發(fā)起申請(qǐng)
- args.put(SnakerEngine.ID, "張三 - 2019-12-04 16:40:20的請(qǐng)假申請(qǐng)");
- snakerEngineFacets.startAndExecute(name, version, StpUtil.getLoginIdAsString(), args);
我的發(fā)起
- QueryFilter filter = new QueryFilter();
- filter.setOperator(operator);
- filter.orderBy("create_Time").order(DESC);
- snakerEngineFacets.getEngine().query().getHistoryOrders(page, filter);
我的待辦
- Page<WorkItem> page = new Page<>(30);
- snakerEngineFacets.getEngine().query().getWorkItems(page,
- new QueryFilter().setOperator(operator));
我的已辦
- Page<WorkItem> page = new Page<>(30);
- snakerEngineFacets.getEngine().query().getHistoryWorkItems(page,
- new QueryFilter().setOperator(operator));
催辦
- List<Task> tasks = snakerEngineFacets.getEngine().query().getActiveTasks(new QueryFilter().setOrderId(orderId));
- 根據(jù)這個(gè)task跟指定人發(fā)消息
轉(zhuǎn)辦
轉(zhuǎn)辦任務(wù)(換當(dāng)前辦理人,或者叫變更當(dāng)前辦理人)
- snakerEngineFacets.transferMajor(taskId, operator, nextOperators);
駁回
駁回/退回上一步/退回至(即退回到歷史某一個(gè)節(jié)點(diǎn))
- snakerEngineFacets.executeAndJump(taskId, operator, args, nodeName);
撤回
根據(jù)歷史任務(wù)id,撤回由該歷史任務(wù)派發(fā)的所有活動(dòng)任務(wù),如果無(wú)活動(dòng)任務(wù),則不允許撤回
- snakerEngineFacets.getEngine().task().withdrawTask(taskId, operator);
抄送
實(shí)例的抄送類似于郵箱里面的抄送功能,一般用于將該流程實(shí)例抄送給領(lǐng)導(dǎo)查閱。
- 新增表wf_cc_order根據(jù)實(shí)例id、創(chuàng)建人、抄送人創(chuàng)建抄送記錄engine.order().createCCOrder(String orderId, String creator, String... actorIds)更新?tīng)顟B(tài)用于更新抄送記錄為已經(jīng)閱讀engine.order().updateCCStatus(String orderId, String... actorIds)
加簽
加簽(增加另一人或多人的審批)
- engine.task().addTaskActor(String taskId, 1, String... actorIds)
會(huì)簽
會(huì)簽(通常用于審批后給相關(guān)的人簽字確認(rèn),以獲得工作上的協(xié)調(diào)。)
snaker的會(huì)簽?zāi)壳跋鄬?duì)比較簡(jiǎn)單,僅僅是根據(jù)任務(wù)節(jié)點(diǎn)的performType屬性值確定是否產(chǎn)生多個(gè)相同任務(wù)。
performType的值有兩種,分別是ANY、ALL。
ANY多個(gè)參與者時(shí),任何一個(gè)完成任務(wù)即繼續(xù)流轉(zhuǎn) (或簽)
ALL多個(gè)參與者時(shí),所有都需要完成任務(wù)才能繼續(xù)流轉(zhuǎn)
會(huì)簽只需要在流程定義時(shí),將任務(wù)節(jié)點(diǎn)的屬性performType值設(shè)置為ALL即可,當(dāng)調(diào)用api時(shí)傳遞多個(gè)參與者時(shí),則自動(dòng)派發(fā)與參與者數(shù)量相同的任務(wù)。會(huì)簽任務(wù)必須等待所有參與者完成后,才繼續(xù)流轉(zhuǎn)
或簽
同上
已開(kāi)源基于SnakerFlow輕量級(jí)工作流引擎的腳手架項(xiàng)目 easy-admin詳情參見(jiàn):終于寫(xiě)了個(gè)開(kāi)源項(xiàng)目,easy-admin 為打造一款簡(jiǎn)單、輕量級(jí)的后臺(tái)管理系統(tǒng)腳手架