activiti併發多例項子流程任務處理
一直在搞工作流(activiti),總結一下關於工作流(activiti)中同時併發處理多個子流程的操作方法。
先說下我要實現的業務:
1、辦公室發通知(在系統申報頁面上,勾選科室,被選中的科室執行第二步)
2、科室科員填報資料
3、科室科長做稽核(注意這裡的科長稽核是對應第二步的科室,本科科長去稽核本單位填報完的任務)
4、辦公室編制立項書,彙總資料
好,需求就先這樣,這裡主要是給講解一下關於子流程的使用,所以其他的需求就不往上寫了。
先看一眼畫好後的流程圖:
可以看到任務發起時(啟動流程例項時)就進入了子流程中,這裡需要關心的是怎麼才能生成多個子流程呢,請看:
接下來我們對這個子流程進行配置:
注:1、Collection:可以存放集合,集合中可以存任意值,工作流會根據你集合裡的值個數,去生成對應的子流程,
例如:我這裡存的是3個科室code,{0001,0002,0003},那麼就會生成出3個子流程,
其實這裡我簡單說明一下,如果只傳入1個值會生成4個流程例項,
傳2個會生成出6個流程例項(多出的兩個,一個是子流程subprocess的,一個是流程中第一個任務的),以此類推。
2、Element variable:顧名思義就是節點流程變數,用於在流程圖中代替集合中表示當前子流程的變數(我這存的是科室code,所以表示的就是科室code)。
這個節點流程變數可以在當前子流程中任意的task中使用,例如 子流程中的任務我就用到了這個變數,稍後會有圖詳細說明
3、Completion condition:顧名思義就是完成條件,這裡寫的表示式如果滿足即可到(第三步:立項書編制)這個任務,關於這裡的配置,
給大家推薦一個網址介紹:http://my.oschina.net/winHerson/blog/139267?fromerr=ApnxMXj5
接下來繼續配置,我的業務需求是 選中的科室做填報,並且有這個科室的科長去稽核,那麼我們接著去配置具體的使用者任務(userTask)
這裡簡單講一下我做的這個專案的許可權控制,我這裡是通過許可權點去控制顯示每個任務的待辦的許可權,假如張三 有PM10000101許可權點,
他就能看到任務中配置了PM10000101的待辦,因為我的系統是三級樹許可權控制,使用者--角色--許可權點(功能點),
所以我在工作流Candiate groups中配置的是功能點,各位可以根據自己系統的需要去合理配置。
順便在講一下將${candiateUser}配置到Candidate users或者Candidate groups的後果,
它會根據你集合中存的變數個數生成出任務來比較噁心的是這種形式,例如:
candiateUserList中存了{001,002,003},按照規則會生成出3個子流程(A、B、C),
但是在生成任務的時候會生成出這種A(001)、A(002)、A(003)、B(001)、B(002)、B(003)、C(001)、C(002)、C(003)
問題是我這裡不需要這麼生成任務,只需要一個流程對應1個任務就OK,所以我將${candiateUser}配置到了userTask的描述資訊中
配置到了這一步基本告一段落,下面我將我的查詢待辦sql貼出來,相信大家都懂了
我的待辦再貼一張系統圖:
接下來將啟動流程時的程式碼貼出來:
//工作流 String targetFilePath = ServletActionContext.getRequest().getSession().getServletContext() .getRealPath("/") + IcmisModels.TEMP_FOLD+ "/";//獲取專案臨時檔案目錄 //得到當前系統使用者物件 UserView u = (UserView) ServletActionContext.getRequest().getSession().getAttribute(FrameConstant.SESSION_USERVIEW); Map<String, Object> map=new HashMap<String, Object>();//要在啟動流程中存的流程變數map map.put(WorkFlowConstant.START_USER, u.getUsername());//設定發起人 List<String> candiateUserList=new ArrayList<String>();//建立多個子流程用的集合 //獲取從前臺傳過來的科室code,並將其解析出來存入集合 if(result.getAddinfoDep()!=null&&!"".equals(result.getAddinfoDep())){ String strs[]=result.getAddinfoDep().split(",");//將1,2,3,4..拼接的科室code字串解析到數組裡 for (String s : strs) { candiateUserList.add(s);//將科室code存入集合中 } }else{ candiateUserList.add("流程錯誤,無效任務"); //純粹扯淡,這種情況根本不存在 } map.put("candiateUserList", candiateUserList);//多個子流程集合 map.put(WorkFlowConstant.TASK_NAME, result.getProjectName()+"裝置清單填報");//任務名稱 map.put(WorkFlowConstant.DEADLINE,IcmisUnit.date2str(result.getDepDeadline()));//任務截止時間 map.put(WorkFlowConstant.IS_URGENCY,result.getTaskUrgency());//任務緊急度 //發起流程 String piId=wfservice.getWorkflowBaseService().startProcess("bpApply", map,targetFilePath);
public String startProcess(String processDefinitionKey, Map<String, Object> vMap,String targetFilePath) { RuntimeService rs = this.processEngine.getRuntimeService(); //得到執行時的service //設定發起人,這個方法是通過執行緒判斷是一個了流程例項的 this.processEngine.getIdentityService().setAuthenticatedUserId(vMap.get(WorkFlowConstant.START_USER).toString()); //根據傳入的使用者名稱得到工作流內建的使用者表物件 User user = this.processEngine.getIdentityService().createUserQuery() .userId(vMap.get(WorkFlowConstant.START_USER).toString()) .singleResult(); vMap.put("ac", processDefinitionKey);//設定流程定義key,存到流程變數中 //根據流程定義key得到流程定義物件 ProcessDefinition processDefinition = this.getProcessDefinitionByKey(processDefinitionKey); //vMap.put(WorkFlowConstant.VIEW_URL, processDefinition.getDescription()); Map<String,Object> map=getSeqFlowByBpmn(processDefinition.getDeploymentId(),targetFilePath);//得到所有連線駁回的任務節點的map vMap.put(WorkFlowConstant.SEQUENCEFLOW, map);//將連線駁回的任務節點map存入流程變數中 // 儲存日誌 ProcessInstance instance = rs.startProcessInstanceByKey( processDefinitionKey, vMap); TaskMarkModel taskMarkModel = new TaskMarkModel(); taskMarkModel.setAuditRemark("發起任務"); //排序使用 taskMarkModel.setCreateDate(new Date(new Date().getTime()-100000)); taskMarkModel.setDoDate(new Date(new Date().getTime()-100000)); taskMarkModel.setDoResult("發起任務"); taskMarkModel.setDoUserName(user.getFirstName()); taskMarkModel.setPid(instance.getProcessInstanceId()); taskMarkModel.setpName(processDefinition.getName()); taskMarkModel.setTaskName("發起任務"); this.saveTaskMark(taskMarkModel); // 儲存日誌結束 return instance.getProcessInstanceId(); }轉自:https://www.cnblogs.com/mycifeng/p/5309150.html