如何自己實現一個可自定義業務流程步驟的工作流
專案功能需求簡述
由於業務需要,需要一個申請-審批的工作流,並且業務流程是不固定的,需要能靈活配置,比如現在是:開始->部門經理審批->結束,可能之後就會變為開始->部門經理審批->部門領導審批->結束。因此不能把程式碼寫死,必須做成高可配置的。
UML設計
專案設計說明
車輛申請專案
一個專案名稱,也可以是其他的,比如請假專案,報銷專案等都可以。主要就是提出申請時需要填寫的表單資訊。
任務列表
當用戶填完申請專案之後,王任務列表中插入一條資料,記錄所屬專案、當前步驟、任務狀態(審批中、任務結束)、使用的流程版本、下一步執行的人,整個任務重申請到結束都只是在更新當前步驟、任務狀態(審批中、任務結束)、下一步執行的人這幾個欄位,其他的都不變。也就是一次申請就只會有一條任務。
歷史任務
每一次申請、或者審批步驟都往裡邊插入一條資料,記錄當前的審判者、步驟、建立時間等資訊。一個申請專案中會有多條記錄。
流程列表
流程的新增,供申請時選擇所屬流程,流程可設定啟用或不啟用狀態。
流程步驟
比如申請車輛這個流程的所有步驟。省內用車:開始->步驟1:部門經理審批->結束;長途用車:開始->步驟1:部門經理審批->步驟2:部門領導審批->結束
步驟處理角色
每個步驟由哪個角色來處理。比如:步驟:部門經理審批——部門經理,步驟:部門領導審批——部門領導。
角色
系統角色,主要做許可權控制。
企業員工
系統使用者。
車輛管理
企業的所有車輛。
初始化資料
角色
使用者
車輛
步驟處理角色
流程
流程步驟
專案流程說明演示
這裡演示一個開始->部門經理審批->部門領導審批->結束的流程
提出申請
先填寫好資訊,再點選確定申請,則開始申請,並往歷史流程和任務列表插入一條資料
點選申請
插入兩條資料
自己專案中的程式碼為:
/**
* 選澤下一步審批人
*/
@RequestMapping(value="/submitApply")
public ModelAndView submitApply() throws Exception{
logBefore(logger, "提交Apply");
ModelAndView mv = this.getModelAndView();
PageData pd = new PageData();
pd = this.getPageData();
String APPLY_ID=pd.getString("APPLY_ID");//專案ID
//根據專案ID查詢專案基本資訊 -> 找出這個專案使用的流程 -> 檢視這個流程的第一步是那哪角色審批
//-> 查詢使用者中是這個角色的所有使用者供選擇
pd.put("nowCount","1");
List<User> userList=userService.listAllUserByApply(pd);
mv.setViewName("information/apply/tasklist_chooseUser");
mv.addObject("msg","submitApplyresult");
mv.addObject("pd", pd);
mv.addObject("userList",userList);
return mv;
}
/**
* 提交申請
* @return
* @throws Exception
*/
@RequestMapping(value="/submitApplyresult")
public ModelAndView submitApplyresult() throws Exception{
logBefore(logger, "提交Apply");
ModelAndView mv = this.getModelAndView();
PageData pd = new PageData();
pd = this.getPageData();
String APPLY_ID=pd.getString("APPLY_ID");//專案ID
String USER_ID=pd.getString("USER_ID");//選澤的使用者ID
//-------------往任務列表中插入一條資料--------------------
pd.put("ITEMID", APPLY_ID); //任務ID
pd.put("ACTORID", '1'); //步驟ID: -1表示結束 其他則按照流程定義裡的執行順序來
pd.put("STATE", "稽核流程進行中"); //稽核狀態
PageData pds=applyService.findById(pd);
pd.put("VERSION", pds.getString("SQLX")); //流程版本ID 也就是他的申請型別ID
pd.put("NextUserID",USER_ID);//下一步審批者ID
String TASKLIST_ID=this.get32UUID();
pd.put("TASKLIST_ID",TASKLIST_ID ); //主鍵ID
tasklistService.save(pd);
//-------------往歷史任務列表中插入一條資料--------------------
Subject currentUser = SecurityUtils.getSubject();//shiro管理的session
Session session = currentUser.getSession();
String USERNAME = session.getAttribute(Const.SESSION_USERNAME).toString(); //獲取當前登入者loginname
pd.put("ITEMID", APPLY_ID); //任務ID
pd.put("ACTORID","0"); //步驟ID:-1表示結束 其他則按照流程定義裡的執行順序來
pd.put("MEMO", USERNAME+"提出申請"); //備註
pd.put("OPERATEUSERID", USERNAME); //操作人
pd.put("CREATEDATE", DateUtil.getTime()); //操作建立時間
String TASKHISTORY_ID=this.get32UUID();
pd.put("TASKHISTORY_ID",TASKHISTORY_ID ); //主鍵ID
taskHistoryService.save(pd);
//-----------------------------------------------------//
mv.addObject("msg","success");
mv.setViewName("save_result");
return mv;
}
部門經理審批
有待審批任務的人點選待我審批任務後就會列出來
在稽核介面可以選擇同意或者拒絕
如果同意的話會判斷目前是不是最後一個步驟,是就選澤車輛,不是就選擇下一步的處理角色。
如果不同意的話則直接結束流程。
目前還不是最後一步
更新任務列表
歷史任務插入一條資料
部門領導審批
部門領導以及是這個審批流程中的最後一個審批
所以選擇車輛而不是下一步處理人
更新任務列表
插入歷史紀錄
審批程式碼
部門經理審批和部門領導審批的程式碼都是一樣的,就算在新增其他流程程式碼也是不需要修改的。
/**
* 選擇下一步審批人,流程繼續
*/
@RequestMapping(value="/taskSubmitApply")
public ModelAndView taskSubmitApply() throws Exception{
logBefore(logger, "提交Apply");
ModelAndView mv = this.getModelAndView();
PageData pd = new PageData();
pd = this.getPageData();
String APPLY_ID=pd.getString("APPLY_ID");//專案ID
//根據專案ID查詢專案基本資訊 -> 找出這個專案使用的流程 -> 檢視這個流程的第一步是那哪角色審批
//-> 查詢使用者中是這個角色的所有使用者供選擇
int nowCount=tasklistService.findNowCount(pd);//當前步驟
int allCount=tasklistService.findCount(pd);//總的步驟
if(allCount==nowCount){//供頁面判斷是否是最後
pd.put("iSLast",1);
}else pd.put("iSLast",0);
pd.put("nowCount",nowCount+1);
List<User> userList=userService.listAllUserByApply(pd);
List<Car> carList=carService.carlistAll();
//如果當前次數+1是最後一次,則進入派車頁面
// if(nowCount+1==tasklistService.findCount(pd)){
// mv.setViewName("information/car/list");
// mv.addObject("msg","tasklist/submitApplyresult");
// mv.addObject("pd", pd);
// }else {//否則進入設定下一個審批者頁面
mv.setViewName("information/tasklist/tasklist_chooseUser");
mv.addObject("pd", pd);
mv.addObject("userList",userList);
mv.addObject("carList",carList);
if(allCount==nowCount) {//供頁面判斷是最後
mv.addObject("msg","endtaskSubmitApplyresult");//同意 繼續下一步的角色選擇
}else {
mv.addObject("msg","taskSubmitApplyresult");//最後一個派車同意 繼續下一步的角色選擇
}
return mv;
}
/**
* 同意派車,流程結束
* @return
* @throws Exception
*/
@RequestMapping(value="/endtaskSubmitApplyresult")
public ModelAndView endtaskSubmitApplyresult() throws Exception{
logBefore(logger, "提交Apply");
ModelAndView mv = this.getModelAndView();
PageData pd = new PageData();
pd = this.getPageData();
String APPLY_ID=pd.getString("APPLY_ID");//專案ID
String Car_ID=pd.getString("Car_ID");//選澤的車輛ID
String TASKLIST_ID=pd.getString("TASKLIST_ID");//當前任務ID
//-------------更新任務列表的下一個審批者和下一步的步驟ID--------------------
int nowCount=tasklistService.findNowCount(pd);
int allCount=tasklistService.findCount(pd);
// if(nowCount<allCount){
pd.put("ACTORID", -1); //步驟ID: -1表示結束 其他則按照流程定義裡的執行順序來
pd.put("STATE", "流程結束,請提取車輛:"+Car_ID); //稽核狀態
pd.put("NextUserID","");//下一步審批者ID
pd.put("TASKLIST_ID",TASKLIST_ID ); //主鍵ID
tasklistService.edit(pd);
//-------------往歷史任務列表中插入一條資料--------------------
Subject currentUser = SecurityUtils.getSubject();//shiro管理的session
Session session = currentUser.getSession();
String USERNAME = session.getAttribute(Const.SESSION_USERNAME).toString(); //獲取當前登入者loginname
pd.put("ITEMID", APPLY_ID); //任務ID
pd.put("ACTORID",nowCount); //步驟ID:-1表示結束 其他則按照流程定義裡的執行順序來
pd.put("MEMO", USERNAME+"同意申請,稽核流程結束"); //備註
pd.put("OPERATEUSERID", USERNAME); //操作人
pd.put("CREATEDATE", DateUtil.getTime()); //操作建立時間
String TASKHISTORY_ID=this.get32UUID();
pd.put("TASKHISTORY_ID",TASKHISTORY_ID ); //主鍵ID
taskHistoryService.save(pd);
//-----------------------------------------------------//
mv.addObject("msg","success");
mv.setViewName("save_result");
return mv;
}
/**
* 同意的稽核,繼續下一個審批人選澤,流程繼續
* @return
* @throws Exception
*/
@RequestMapping(value="/taskSubmitApplyresult")
public ModelAndView taskSubmitApplyresult() throws Exception{
logBefore(logger, "提交Apply");
ModelAndView mv = this.getModelAndView();
PageData pd = new PageData();
pd = this.getPageData();
String APPLY_ID=pd.getString("APPLY_ID");//專案ID
String USER_ID=pd.getString("USER_ID");//選澤的使用者ID
String TASKLIST_ID=pd.getString("TASKLIST_ID");//當前任務ID
//-------------更新任務列表的下一個審批者和下一步的步驟ID--------------------
int nowCount=tasklistService.findNowCount(pd);
int allCount=tasklistService.findCount(pd);
// if(nowCount<allCount){
pd.put("ACTORID", nowCount+1); //步驟ID: -1表示結束 其他則按照流程定義裡的執行順序來
pd.put("STATE", "稽核流程進行中"); //稽核狀態
pd.put("NextUserID",USER_ID);//下一步審批者ID
pd.put("TASKLIST_ID",TASKLIST_ID ); //主鍵ID
tasklistService.edit(pd);
// }else {
// pd.put("ACTORID", "-1"); //步驟ID: -1表示結束 其他則按照流程定義裡的執行順序來
// pd.put("STATE", "稽核流程結束"); //稽核狀態
// pd.put("NextUserID","");//下一步審批者ID
// pd.put("TASKLIST_ID",TASKLIST_ID ); //主鍵ID
// tasklistService.edit(pd);
// }
//-------------往歷史任務列表中插入一條資料--------------------
Subject currentUser = SecurityUtils.getSubject();//shiro管理的session
Session session = currentUser.getSession();
String USERNAME = session.getAttribute(Const.SESSION_USERNAME).toString(); //獲取當前登入者loginname
pd.put("ITEMID", APPLY_ID); //任務ID
pd.put("ACTORID",nowCount); //步驟ID:-1表示結束 其他則按照流程定義裡的執行順序來
pd.put("MEMO", USERNAME+"同意申請"); //備註
pd.put("OPERATEUSERID", USERNAME); //操作人
pd.put("CREATEDATE", DateUtil.getTime()); //操作建立時間
String TASKHISTORY_ID=this.get32UUID();
pd.put("TASKHISTORY_ID",TASKHISTORY_ID ); //主鍵ID
taskHistoryService.save(pd);
//-----------------------------------------------------//
mv.addObject("msg","success");
mv.setViewName("save_result");
return mv;
}
/**
* 不同意的稽核,流程結束
* @return
* @throws Exception
*/
@RequestMapping(value="/refuseapply")
public ModelAndView refuseapply() throws Exception{
logBefore(logger, "提交Apply");
ModelAndView mv = this.getModelAndView();
PageData pd = new PageData();
pd = this.getPageData();
String APPLY_ID=pd.getString("APPLY_ID");//專案ID
String TASKLIST_ID=pd.getString("TASKLIST_ID");//當前任務ID
pd.put("ACTORID", "-1"); //步驟ID: -1表示結束 其他則按照流程定義裡的執行順序來
pd.put("STATE", "流程結束"); //稽核狀態
pd.put("NextUserID","");//下一步審批者ID
pd.put("TASKLIST_ID",TASKLIST_ID ); //主鍵ID
tasklistService.edit(pd);
//-------------往歷史任務列表中插入一條資料--------------------
Subject currentUser = SecurityUtils.getSubject();//shiro管理的session
Session session = currentUser.getSession();
String USERNAME = session.getAttribute(Const.SESSION_USERNAME).toString(); //獲取當前登入者loginname
pd.put("ITEMID", APPLY_ID); //任務ID
pd.put("ACTORID","-1"); //步驟ID:-1表示結束 其他則按照流程定義裡的執行順序來
pd.put("MEMO", USERNAME+"不同意申請"); //備註
pd.put("OPERATEUSERID", USERNAME); //操作人
pd.put("CREATEDATE", DateUtil.getTime()); //操作建立時間
String TASKHISTORY_ID=this.get32UUID();
pd.put("TASKHISTORY_ID",TASKHISTORY_ID ); //主鍵ID
taskHistoryService.save(pd);
//-----------------------------------------------------//
mv.addObject("msg","success");
mv.setViewName("save_result");
return mv;
}