劉 聰,李世川,呂雪峰
(中央軍委后勤保障部 信息中心,北京 100842)
Activiti是當前流行并重要的業務流程管理框架.獲得Apache許可,它具有輕量級、可嵌入的優點,同時還被設計適用于可擴展的云架構.Activiti具有以下特點:一是開源特性,它是一個開源項目[1],適用者可以閱讀源碼理解工作原理,也可以修改源代碼實現自定義功能.二是使用MyBatis框架,MyBatis具有輕量化的特點,利于上手和后期優化,使用該框架可加快數據的持久化.三是可融合Spring,它提供了便捷的Spring接入機制,可充分利用Spring優勢,快速實現項目開發[2,3].四是支持BPMN2.0規范,BPMN2.0用標準定義了描述業務的圖元和規范的執行語義,保證在不同的流程引擎得到的結果一致[4].五是支持廣泛的數據庫,它支持當前主流數據庫如:Oracle、MySQL、PostgreSQL、DB2等.
MongoDB是一個目前流行使用的非結構化數據庫,廣泛應用于大數據應用的后臺,是非關系型數據庫中最像關系數據庫和功能最豐富的一款.它支持松散的數據結構,類似于JSON的BSON格式,用來存儲較為復雜的數據類型.具有以下顯著特點:一是面向集合存儲,集合類似于關系數據庫中的表,一個集合中可包括任意多的文檔;二是模式自由,集合中存儲的數據是無模式的,這是區別于關系數據庫的重要特征;三是在支持索引、查詢等傳統關系數據庫的功能之外,具有強大聚合工具,如count,group等,支持采用MapReduce完成的聚合任務;四是文件存儲采用BSON格式,它是二進制格式JSON的縮寫,支持文檔與數組的嵌套[5,6].
后勤業務涵蓋面比較廣泛,例如物資請領與采購、財務管理、營房管理、公車使用、人員管理、辦公辦文等等方面.一個較大單位的后勤保障必然涉及到上述的諸多方面,這些方面的信息化管理最常用的需求就是流程審批與管理,不夸張地說,后勤業務系統一刻也離不開流程使用[7,8].現有系統或使用標記位定義的流程,隨意性較大,修改復雜;或使用BPMN1.0的內核,較為陳舊;或使用已完全封裝好的流程軟件,不利于修改流程.Activiti具有開源的優勢,且可以自定義流程,通過開發可實現自由流程的源代碼,利于后勤業務系統.
同時,后勤業務涵蓋面廣,產生的數據量也大,是最容易產生大數據的領域[9].現有的關系型數據庫在非結構性數據的存儲處理上捉襟見肘,限制了快速高效地操作后勤數據.適應新需求新前沿,引入主流非關系型數據庫MongoDB,可以更好滿足大數據的要求.將Activiti實現的自由流程和MongoDB結合起來,可以實現一種全新的后勤自由流程框架,帶來獨特的實現效果.文獻[2]中使用在線審批和Activiti相綁定,形成了實用在線審批流程算法,本文則側重于利用Activiti實現自由流程流轉.文獻[5]中利用Node.js和MongoDB搭建的重點在實現高性能、維護成本低Web框架,本文則重點利用MongoDB服務于流程的高效性.
傳統帶流程的系統,常常事先畫好復雜工作流程圖,寫死邏輯代碼,一旦人員機構發生變化帶來輕微的修改,都給程序員帶來大量的工作.不指定流程流轉的下一個人、不綁死流程流轉的業務表,在系統中實現一個基本的自由流程框架很有意義.
圖1顯示了利用Activiti實現自由流程的示意圖.從左至右,流程啟動后,用戶填寫相應業務申請表單,并手動指定呈批對象,流程會自動流轉到該審批對象.審批對象完成相應批示后,既可以繼續呈批到更高級的審批人,也可以返回申請人修改申請.如果是繼續向上呈批,將循環前述審批步驟;如果是返回申請人修改,修改后可以自行決定是否重新呈批.最終審批人完成審批意見后可直接返回申請人確認,如果申請人認為工作完成則選擇結束流程,如果認為流程還需其他人員協助完成,還可繼續流轉到下一審批人,直至任務完成后再由本人結束.

圖1 Activiti實現自由流程圖
該自由流程框架有如下3個特點:(1)不自動指定流程流轉的下一人,由用戶根據單位線下實際工作的流程自行指定下一人,此舉利于適應單位組織人員的變化;(2)不綁定流程流轉的業務表,在流程啟動前,由用戶選擇業務表,這樣利于流程與業務表獨立出來,高效實現各自功能;(3)給予申請人充分自主權,流程形成閉環.流程由申請人發起,最后由同一人結束,符合信息流程閉環的要求,申請當事人可及時充分地知悉辦事過程,能起到一定的監督作用.
表1給出了該流程框架實現的代碼接口和相應意義.其中接口1、2和4的意義最為典型,接口1的意義為:在起始申請和中間節點時,用戶填寫完相應表單后,提交給流程處理.接口2為用戶作為中間節點的處理人,處理待辦事件時的邏輯功能.接口4是某個流程的詳細歷史記錄.接口3為撤回發出的任務.而其他接口則是接口4功能的延伸,為實現較完備功能而準備,實現原理類似.

表1 流程重要接口實現

算法2.中間節點流轉邏輯偽代碼輸入:流轉用戶名—nextUserName,當前任務Id—taskId,流轉標記—approval,當前任務—task 01 Task task=taskService.createTaskQuery().taskId(taskId).singleResult();02 String pId =task.getProcessInstanceId();//對各個任務節點需要分別進行處理03 switch(task.getTaskDefinitionKey()){04 case "usertask1"://0-在流程圖里轉向下一個審批人/轉辦(14)05 if (approval.equals("0")|| approval.equals("14")){06 if(nextUserName.equals(username)){07 msg="請提交給正確的業務審核人員!";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-轉給申請人修改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-轉向申請人確認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關鍵字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}//根據流程分支條件,往下一節點流轉42 taskService.complete(taskId,map)
梳理這些接口的核心代碼,其中兩部分關鍵代碼邏輯值得特別展示.算法1和算法2給出了兩段關鍵原理代碼邏輯,它們分別實現:開始一個新流程和流程的中間節點流轉.此兩部分代碼構成了自由流程正常流轉的核心部分.需要說明的是:一個流程(process),在每一個節點處都有一個任務(task),即一個process包含多個task.此外,此兩表只給出核心代碼的原理邏輯,其中用不少偽代碼示意.
圖2給出了本文自由流程框架的數據庫表設計關系圖,表中的箭頭方向為一對多的關系.其中淺灰色表為關系型數據庫表,深灰色表為非關系型數據庫表[10].表act_hi_procinst和act_ru_task是Activiti工作自帶的關鍵表,前者存儲了已完成流程的詳細記錄,后者存儲了已啟動、尚未結束流程的記錄.表log則不是Activiti的保留表,它用來存儲流程中各節點的處理意見,需要說明的是,它并不是業務表,而且配合流程使用的流程日志表.

圖2 數據結構設計關系圖
圖2中虛線框部分給出了非結構化自由業務表原理.深灰色標注表leave為舉例業務表——請銷假表,它存儲在MongoDB中,表中列出了請銷假需要的主要字段.這種業務表可以根據用戶的需要自由添加,并可修改對應字段,當用戶添加了一個新業務表時,關系型表free_bt會記錄下該表的相關信息.當用戶對新表字段進行添加或修改時,關系型表free_nr又會對相應字段信息進行登記.在前端配合的情況下,后端可以自如地添加修改表及表的字段結構,具體實現效果在第4部分中展示.
除了單一流程,還會存在如下情形:在某個流程尚未結束時,用戶需要啟動其他流程并在其中流轉.圖3給出了延伸為多流程的數據表設計關系圖,該示意圖對應需求為:在用戶請假的同時需要申請派車送站.其中灰色部分仍為關系型表,深灰色部分為非關系型表.深灰色部分表leave和applyCar對應請假和派車的業務表,表act_hi_procinst和act_ru_task同圖2的意義,表multiProcess用來管理多個流程.在設計中,后臺視之為實質是同一個流程的擴展,流程實例和id無需變化,只需變換相應業務表的對應關系,讓攜帶新業務表的流程繼續在自由流程框架中流轉,直至結束,后再切換回前一流程對應的業務表繼續流轉.當然,也可以做到兩個業務表不切換,讓它們同時流轉,以利于后一流程處理人更加直觀方便知悉相關情況.

圖3 多流程的數據結構設計關系圖
(1)自由流程的應用場景.自由流程可以應用到一個單位很多的后勤事務工作中去,詳見表2.
(2)以請銷假流程為例說明自由流程使用達到的效果.
圖4至圖6用實例給出了請銷假自由流程的過程,圖4中的承接人可以讓用戶選擇任意人完成對請假的審批工作.對于承接人,在完成了相應審批(圖5)時,他的上級審批人同樣由他選擇,從而實現申請-審批工作的自由靈活,最后結果可在圖6的歷史詳情頁中獲悉.

表2 自由流程應用場景

圖4 請假申請

圖5 審批過程

圖6 請假歷史頁
另外,用戶通過該系統能獲取參與但尚未結束的流程的各步驟詳情;還能在每次進入個人主頁時,看到需要待辦的事務.由于篇幅所限,并不在此一一展示.對于通用事務處理,系統內設了一些業務處理單,它們對應著不同的流程業務類型,可以為不同的后勤管理進行自由流轉,從而滿足相應的工作需要.
(3)靈活添加業務表單.如圖7所示,點擊業務類型右邊的星型按鈕可以添加新表,點擊字段后的向下箭頭按鈕可以讓用戶添加新字段.從而實現了表和字段的自由添加,在申請之初為用戶提供方便.由于業務表和自由流程之間的保持相對獨立,這種設計非常有利于開展新業務,并使之進行業務流轉.
本文的主要貢獻如下:
(1)本文充分利用了流程框架Activiti和非關系型數據庫MongoDB的優點,提出了適用于大型單位后勤管理的自由流程信息系統設計流程框架、系統重要接口、關鍵邏輯代碼和兩類數據庫結合的數據結構協同設計方法.
(2)本文設計的系統支持多個流程同時并行進行,或者多個流程串行運行,支持針對不同的業務類型根據需求自由添加表和字段.
實現效果顯示本文設計的自由流程管理系統實用、靈活和高效,最大限度地支持業務工作和減少研發人員的工作量,對于單位后勤管理信息化具有較好的設計參考價值.

圖7 表和字段任意添加