劉 聰,李世川,呂雪峰
(中央軍委后勤保障部 信息中心,北京 100842)
Activiti是當前流行并重要的業(yè)務(wù)流程管理框架.獲得Apache許可,它具有輕量級、可嵌入的優(yōu)點,同時還被設(shè)計適用于可擴展的云架構(gòu).Activiti具有以下特點:一是開源特性,它是一個開源項目[1],適用者可以閱讀源碼理解工作原理,也可以修改源代碼實現(xiàn)自定義功能.二是使用MyBatis框架,MyBatis具有輕量化的特點,利于上手和后期優(yōu)化,使用該框架可加快數(shù)據(jù)的持久化.三是可融合Spring,它提供了便捷的Spring接入機制,可充分利用Spring優(yōu)勢,快速實現(xiàn)項目開發(fā)[2,3].四是支持BPMN2.0規(guī)范,BPMN2.0用標準定義了描述業(yè)務(wù)的圖元和規(guī)范的執(zhí)行語義,保證在不同的流程引擎得到的結(jié)果一致[4].五是支持廣泛的數(shù)據(jù)庫,它支持當前主流數(shù)據(jù)庫如:Oracle、MySQL、PostgreSQL、DB2等.
MongoDB是一個目前流行使用的非結(jié)構(gòu)化數(shù)據(jù)庫,廣泛應用于大數(shù)據(jù)應用的后臺,是非關(guān)系型數(shù)據(jù)庫中最像關(guān)系數(shù)據(jù)庫和功能最豐富的一款.它支持松散的數(shù)據(jù)結(jié)構(gòu),類似于JSON的BSON格式,用來存儲較為復雜的數(shù)據(jù)類型.具有以下顯著特點:一是面向集合存儲,集合類似于關(guān)系數(shù)據(jù)庫中的表,一個集合中可包括任意多的文檔;二是模式自由,集合中存儲的數(shù)據(jù)是無模式的,這是區(qū)別于關(guān)系數(shù)據(jù)庫的重要特征;三是在支持索引、查詢等傳統(tǒng)關(guān)系數(shù)據(jù)庫的功能之外,具有強大聚合工具,如count,group等,支持采用MapReduce完成的聚合任務(wù);四是文件存儲采用BSON格式,它是二進制格式JSON的縮寫,支持文檔與數(shù)組的嵌套[5,6].
后勤業(yè)務(wù)涵蓋面比較廣泛,例如物資請領(lǐng)與采購、財務(wù)管理、營房管理、公車使用、人員管理、辦公辦文等等方面.一個較大單位的后勤保障必然涉及到上述的諸多方面,這些方面的信息化管理最常用的需求就是流程審批與管理,不夸張地說,后勤業(yè)務(wù)系統(tǒng)一刻也離不開流程使用[7,8].現(xiàn)有系統(tǒng)或使用標記位定義的流程,隨意性較大,修改復雜;或使用BPMN1.0的內(nèi)核,較為陳舊;或使用已完全封裝好的流程軟件,不利于修改流程.Activiti具有開源的優(yōu)勢,且可以自定義流程,通過開發(fā)可實現(xiàn)自由流程的源代碼,利于后勤業(yè)務(wù)系統(tǒng).
同時,后勤業(yè)務(wù)涵蓋面廣,產(chǎn)生的數(shù)據(jù)量也大,是最容易產(chǎn)生大數(shù)據(jù)的領(lǐng)域[9].現(xiàn)有的關(guān)系型數(shù)據(jù)庫在非結(jié)構(gòu)性數(shù)據(jù)的存儲處理上捉襟見肘,限制了快速高效地操作后勤數(shù)據(jù).適應新需求新前沿,引入主流非關(guān)系型數(shù)據(jù)庫MongoDB,可以更好滿足大數(shù)據(jù)的要求.將Activiti實現(xiàn)的自由流程和MongoDB結(jié)合起來,可以實現(xiàn)一種全新的后勤自由流程框架,帶來獨特的實現(xiàn)效果.文獻[2]中使用在線審批和Activiti相綁定,形成了實用在線審批流程算法,本文則側(cè)重于利用Activiti實現(xiàn)自由流程流轉(zhuǎn).文獻[5]中利用Node.js和MongoDB搭建的重點在實現(xiàn)高性能、維護成本低Web框架,本文則重點利用MongoDB服務(wù)于流程的高效性.
傳統(tǒng)帶流程的系統(tǒng),常常事先畫好復雜工作流程圖,寫死邏輯代碼,一旦人員機構(gòu)發(fā)生變化帶來輕微的修改,都給程序員帶來大量的工作.不指定流程流轉(zhuǎn)的下一個人、不綁死流程流轉(zhuǎn)的業(yè)務(wù)表,在系統(tǒng)中實現(xiàn)一個基本的自由流程框架很有意義.
圖1顯示了利用Activiti實現(xiàn)自由流程的示意圖.從左至右,流程啟動后,用戶填寫相應業(yè)務(wù)申請表單,并手動指定呈批對象,流程會自動流轉(zhuǎn)到該審批對象.審批對象完成相應批示后,既可以繼續(xù)呈批到更高級的審批人,也可以返回申請人修改申請.如果是繼續(xù)向上呈批,將循環(huán)前述審批步驟;如果是返回申請人修改,修改后可以自行決定是否重新呈批.最終審批人完成審批意見后可直接返回申請人確認,如果申請人認為工作完成則選擇結(jié)束流程,如果認為流程還需其他人員協(xié)助完成,還可繼續(xù)流轉(zhuǎn)到下一審批人,直至任務(wù)完成后再由本人結(jié)束.
圖1 Activiti實現(xiàn)自由流程圖
該自由流程框架有如下3個特點:(1)不自動指定流程流轉(zhuǎn)的下一人,由用戶根據(jù)單位線下實際工作的流程自行指定下一人,此舉利于適應單位組織人員的變化;(2)不綁定流程流轉(zhuǎn)的業(yè)務(wù)表,在流程啟動前,由用戶選擇業(yè)務(wù)表,這樣利于流程與業(yè)務(wù)表獨立出來,高效實現(xiàn)各自功能;(3)給予申請人充分自主權(quán),流程形成閉環(huán).流程由申請人發(fā)起,最后由同一人結(jié)束,符合信息流程閉環(huán)的要求,申請當事人可及時充分地知悉辦事過程,能起到一定的監(jiān)督作用.
表1給出了該流程框架實現(xiàn)的代碼接口和相應意義.其中接口1、2和4的意義最為典型,接口1的意義為:在起始申請和中間節(jié)點時,用戶填寫完相應表單后,提交給流程處理.接口2為用戶作為中間節(jié)點的處理人,處理待辦事件時的邏輯功能.接口4是某個流程的詳細歷史記錄.接口3為撤回發(fā)出的任務(wù).而其他接口則是接口4功能的延伸,為實現(xiàn)較完備功能而準備,實現(xiàn)原理類似.
表1 流程重要接口實現(xiàn)
算法2.中間節(jié)點流轉(zhuǎn)邏輯偽代碼輸入:流轉(zhuǎn)用戶名—nextUserName,當前任務(wù)Id—taskId,流轉(zhuǎn)標記—approval,當前任務(wù)—task 01 Task task=taskService.createTaskQuery().taskId(taskId).singleResult();02 String pId =task.getProcessInstanceId();//對各個任務(wù)節(jié)點需要分別進行處理03 switch(task.getTaskDefinitionKey()){04 case "usertask1"://0-在流程圖里轉(zhuǎn)向下一個審批人/轉(zhuǎn)辦(14)05 if (approval.equals("0")|| approval.equals("14")){06 if(nextUserName.equals(username)){07 msg="請?zhí)峤唤o正確的業(yè)務(wù)審核人員!";08 errInfo="false";09 map1.put("msg",msg);10 map1.put("result",errInfo);11 return AppUtil.returnObject(new PageData(),map1,true);12 } else {13 pdUserId.put("USERNAME",nextUserName);14 nextUserId = userService.findByUId(pdUserId).getString("USER_ID");15 map.put("leader",nextUserId);16 message = "請盡快完成審批! ";17 bussMessageService.sendMessage(sendSmsUser,nextUserName,processDefinitionKey,message);}}//1-轉(zhuǎn)給申請人修改18 else if(approval.equals("1")){19 startUserId =mapData.getString("userId");20 map.put("leader",startUserId);21 PageData apllypd = new PageData();22 applypd.put("USER_ID",startUserId);23 apllypd= userService.findByUiId(apllypd);24 String recieveUser = apllypd.getString("USERNAME");25 String message =null;26 nextUserName=recieveUser;27 message="請申請人修改申請表! ";28 bussMessageService.sendMessage(sendSmsUser,recieveUser,processDefinitionKey,massege);}//11-轉(zhuǎn)向申請人確認29 else if(approval.equals("11")|| approval.equals("17")){...//以請假流程為例,進行表的更新.30 if(tableId2.equals("leave")){31 mapData.put("isPass","1");32 freeModel.setMap(mapData);33 freeModel.setId(bId2);//update時,需要Id關(guān)鍵字34 freeDao.update(freeModel,tableId2);}35 Message = "請申請人確認! ";36 bussMessageService.sendMessage(sendSmsUser,recieveUser,processDefinitionKey,message);
37 }38 break;39 case "usertask2":…40 break;efault:…41 d}//根據(jù)流程分支條件,往下一節(jié)點流轉(zhuǎn)42 taskService.complete(taskId,map)
梳理這些接口的核心代碼,其中兩部分關(guān)鍵代碼邏輯值得特別展示.算法1和算法2給出了兩段關(guān)鍵原理代碼邏輯,它們分別實現(xiàn):開始一個新流程和流程的中間節(jié)點流轉(zhuǎn).此兩部分代碼構(gòu)成了自由流程正常流轉(zhuǎn)的核心部分.需要說明的是:一個流程(process),在每一個節(jié)點處都有一個任務(wù)(task),即一個process包含多個task.此外,此兩表只給出核心代碼的原理邏輯,其中用不少偽代碼示意.
圖2給出了本文自由流程框架的數(shù)據(jù)庫表設(shè)計關(guān)系圖,表中的箭頭方向為一對多的關(guān)系.其中淺灰色表為關(guān)系型數(shù)據(jù)庫表,深灰色表為非關(guān)系型數(shù)據(jù)庫表[10].表act_hi_procinst和act_ru_task是Activiti工作自帶的關(guān)鍵表,前者存儲了已完成流程的詳細記錄,后者存儲了已啟動、尚未結(jié)束流程的記錄.表log則不是Activiti的保留表,它用來存儲流程中各節(jié)點的處理意見,需要說明的是,它并不是業(yè)務(wù)表,而且配合流程使用的流程日志表.
圖2 數(shù)據(jù)結(jié)構(gòu)設(shè)計關(guān)系圖
圖2中虛線框部分給出了非結(jié)構(gòu)化自由業(yè)務(wù)表原理.深灰色標注表leave為舉例業(yè)務(wù)表——請銷假表,它存儲在MongoDB中,表中列出了請銷假需要的主要字段.這種業(yè)務(wù)表可以根據(jù)用戶的需要自由添加,并可修改對應字段,當用戶添加了一個新業(yè)務(wù)表時,關(guān)系型表free_bt會記錄下該表的相關(guān)信息.當用戶對新表字段進行添加或修改時,關(guān)系型表free_nr又會對相應字段信息進行登記.在前端配合的情況下,后端可以自如地添加修改表及表的字段結(jié)構(gòu),具體實現(xiàn)效果在第4部分中展示.
除了單一流程,還會存在如下情形:在某個流程尚未結(jié)束時,用戶需要啟動其他流程并在其中流轉(zhuǎn).圖3給出了延伸為多流程的數(shù)據(jù)表設(shè)計關(guān)系圖,該示意圖對應需求為:在用戶請假的同時需要申請派車送站.其中灰色部分仍為關(guān)系型表,深灰色部分為非關(guān)系型表.深灰色部分表leave和applyCar對應請假和派車的業(yè)務(wù)表,表act_hi_procinst和act_ru_task同圖2的意義,表multiProcess用來管理多個流程.在設(shè)計中,后臺視之為實質(zhì)是同一個流程的擴展,流程實例和id無需變化,只需變換相應業(yè)務(wù)表的對應關(guān)系,讓攜帶新業(yè)務(wù)表的流程繼續(xù)在自由流程框架中流轉(zhuǎn),直至結(jié)束,后再切換回前一流程對應的業(yè)務(wù)表繼續(xù)流轉(zhuǎn).當然,也可以做到兩個業(yè)務(wù)表不切換,讓它們同時流轉(zhuǎn),以利于后一流程處理人更加直觀方便知悉相關(guān)情況.
圖3 多流程的數(shù)據(jù)結(jié)構(gòu)設(shè)計關(guān)系圖
(1)自由流程的應用場景.自由流程可以應用到一個單位很多的后勤事務(wù)工作中去,詳見表2.
(2)以請銷假流程為例說明自由流程使用達到的效果.
圖4至圖6用實例給出了請銷假自由流程的過程,圖4中的承接人可以讓用戶選擇任意人完成對請假的審批工作.對于承接人,在完成了相應審批(圖5)時,他的上級審批人同樣由他選擇,從而實現(xiàn)申請-審批工作的自由靈活,最后結(jié)果可在圖6的歷史詳情頁中獲悉.
表2 自由流程應用場景
圖4 請假申請
圖5 審批過程
圖6 請假歷史頁
另外,用戶通過該系統(tǒng)能獲取參與但尚未結(jié)束的流程的各步驟詳情;還能在每次進入個人主頁時,看到需要待辦的事務(wù).由于篇幅所限,并不在此一一展示.對于通用事務(wù)處理,系統(tǒng)內(nèi)設(shè)了一些業(yè)務(wù)處理單,它們對應著不同的流程業(yè)務(wù)類型,可以為不同的后勤管理進行自由流轉(zhuǎn),從而滿足相應的工作需要.
(3)靈活添加業(yè)務(wù)表單.如圖7所示,點擊業(yè)務(wù)類型右邊的星型按鈕可以添加新表,點擊字段后的向下箭頭按鈕可以讓用戶添加新字段.從而實現(xiàn)了表和字段的自由添加,在申請之初為用戶提供方便.由于業(yè)務(wù)表和自由流程之間的保持相對獨立,這種設(shè)計非常有利于開展新業(yè)務(wù),并使之進行業(yè)務(wù)流轉(zhuǎn).
本文的主要貢獻如下:
(1)本文充分利用了流程框架Activiti和非關(guān)系型數(shù)據(jù)庫MongoDB的優(yōu)點,提出了適用于大型單位后勤管理的自由流程信息系統(tǒng)設(shè)計流程框架、系統(tǒng)重要接口、關(guān)鍵邏輯代碼和兩類數(shù)據(jù)庫結(jié)合的數(shù)據(jù)結(jié)構(gòu)協(xié)同設(shè)計方法.
(2)本文設(shè)計的系統(tǒng)支持多個流程同時并行進行,或者多個流程串行運行,支持針對不同的業(yè)務(wù)類型根據(jù)需求自由添加表和字段.
實現(xiàn)效果顯示本文設(shè)計的自由流程管理系統(tǒng)實用、靈活和高效,最大限度地支持業(yè)務(wù)工作和減少研發(fā)人員的工作量,對于單位后勤管理信息化具有較好的設(shè)計參考價值.
圖7 表和字段任意添加