activiti工作流5.22.0自定義流程活動圖獲取接口

目標

在不使用activiti explore提供的流程實例圖diagram-viewer/index.html以及其繁雜的BaseProcessDefinitionDiagramLayoutResource四個類的情況下,自定義輕量的流程活動圖查詢接口,可以按順序返回串行顯示的流程數據,並標識執行與否,注意,本例僅解決串行顯示的需求,如果需要1:1完全繪製流程,包括排他網關等,則建議複用流程實例圖diagram-viewer/index.html以及後端接口。

返回格式

demo:
在這裏插入圖片描述

{
	"code":0,
	"data":[
		{
			"activityId":"start_1",
			"activityName":"發起任務",
			"assign":"admin",
			"endTime":"2020-05-07 13:54:15",
			"highLight":true,
			"startTime":1588830855000
		},
		{
			"activityId":"exec_4",
			"activityName":"執行任務",
			"assign":"xx",
			"endTime":"",
			"highLight":true,
			"startTime":1588830855000
		},
		{
			"activityId":"confirm_5",
			"activityName":"確認結果",
			"assign":"",
			"endTime":"",
			"highLight":false,
			"startTime":0
		}
	],
	"message":"成功",
	"success":true
}

後端接口邏輯

首先activiti 的數據表模塊分運行時(act_ru_execution)和歷史(act_hi_procinst、act_hi_actinst),一般來說業務需求中都會有查全部的功能,這個時候需要返回所有的數據,包括運行時和歷史。所以如果用戶從歷史流程列表入口點進流程圖頁面,這個時候他點擊的是已完成的歷史流程,後臺接口根據歷史流程ID採用runtimeService去查,立刻就報錯。而簡易渲染只關注userTask和startEvent,這個時候只需要查出這兩種類型即可。

HistoricActivityInstanceQuery query = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask");
List<HistoricActivityInstance> list = query.list();
HistoricActivityInstance startEvent = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("startEvent").singleResult();

然後再從中取出需要的活動節點信息,並封裝,準備下一步順序拼接。

for (HistoricActivityInstance tmpHisAct : list) {
            ProcessActivityModel processActivityModel = new ProcessActivityModel();
            if (tmpHisAct != null) {
                processActivityModel.setActivityId(tmpHisAct.getActivityId());
                processActivityModel.setActivityName(tmpHisAct.getActivityName());
                processActivityModel.setHighLight(true);
                Date endDate = tmpHisAct.getEndTime();
                if (endDate != null) {
                    processActivityModel.setEndTime(TimeHelper.formatDate(endDate, TimeHelper.LONG_DATE_PATTERN_LINE));
                }
                Date startDate = tmpHisAct.getStartTime();
                if (startDate != null) {
                    processActivityModel.setStartTime(startDate.getTime());
                }
                String assignee = tmpHisAct.getAssignee();
                ………………
             }
            results.add(processActivityModel);
   }

接下來根據節點啓動時間排序,建議增加time1 、time2爲0校驗,出現該特殊情況流程可以直接廢棄,視爲髒數據流程。

results.sort((pro1, pro2) -> {
            long time1 = pro1.getStartTime();
            long time2 = pro2.getStartTime();
            return (int) (time1 - time2);
        });

最後需要拼接未完成節點信息,因爲目前是根據act_hi_actinst表取出的已完成的節點,如果是已完成的歷史流程,則列表數據已完整,但是未完成流程還需要獲取後續節點信息。注意加入循環控制,防止死循環。

這就需要根據最後一個節點信息,不斷遍歷獲取下一節點信息,直到null,此外,如果存在多路排他網關,則視爲無法預測的情況,直接跳過。

 String actId = results.get(results.size()-1).getActivityId();//獲取最後一個節點
  if (hpins.getEndTime() == null) {//未結束流程,則需拼接未完成節點
            ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(hpins.getProcessDefinitionId());
            ……
            List<ActivityImpl> activities = processDefinition.getActivities();
            ActivityImpl lastAct = null;
            for (ActivityImpl tmp : activities) {//獲取最後節點定義
                if (actId.equals(tmp.getId())) {
                    lastAct = tmp;
                    break;
                }
            }
            ActivityImpl nextAct = findNextAct(lastAct);
            int loopTimes = 0;//循環次數,防死循環
            while(nextAct!=null && loopTimes<10){//次數可根據業務場景變更
                loopTimes++;
                String type = nextAct.getProperty("type") + "";
                if (type.equals("userTask") || type.equals("startEvent")) {
                    ProcessActivityModel procNex = new ProcessActivityModel();
                    procNex.setActivityId(nextAct.getId());
                    procNex.setActivityName(nextAct.getProperties().get("name") + "");
                    procNex.setStartTime(0l);
                    results.add(procNex);
                }
                nextAct = findNextAct(nextAct);
            }
        }

完整代碼

@ApiOperation("查詢流程活動圖")
    @RequestMapping(value = "queryProcessActivities", method = RequestMethod.GET, produces = "application/json")
    @ResponseBody
    public RetMsg queryProcessActivities(@ApiParam(value = "流程實例ID", required = true) @RequestParam(name = "processInstanceId", required = true) String processInstanceId) {
        RetMsg retMsg = new RetMsg (true, ErrorEnum.DEFAULT_SUCCESS.getCode(), ErrorEnum.DEFAULT_SUCCESS.getMessage(), null);
        HistoricActivityInstanceQuery query = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask");
        List<HistoricActivityInstance> list = query.list();
        HistoricActivityInstance startEvent = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("startEvent").singleResult();
        list.add(0,startEvent);

        List<ProcessActivityModel> results = new ArrayList<>();//返回結果集合

        if (list == null || list.size() == 0) {
            retMsg.setCode(ErrorEnum.ACT_NOT_FOUND.getCode());
            retMsg.setMessage(ErrorEnum.ACT_NOT_FOUND.getMessge());
            return retMsg;
        }

        HistoricProcessInstance hpins = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (hpins == null) {
            retMsg.setCode(ErrorEnum.ACT_NOT_FOUND.getCode());
            retMsg.setMessage(ErrorEnum.ACT_NOT_FOUND.getMessge());
            return retMsg;
        }

        //歷史流程封裝
        for (HistoricActivityInstance tmpHisAct : list) {
            ProcessActivityModel processActivityModel = new ProcessActivityModel();
            if (tmpHisAct != null) {
                processActivityModel.setActivityId(tmpHisAct.getActivityId());
                processActivityModel.setActivityName(tmpHisAct.getActivityName());
                processActivityModel.setHighLight(true);
                Date endDate = tmpHisAct.getEndTime();
                if (endDate != null) {
                    processActivityModel.setEndTime(TimeHelper.formatDate(endDate, TimeHelper.LONG_DATE_PATTERN_LINE));
                }
                Date startDate = tmpHisAct.getStartTime();
                if (startDate != null) {
                    processActivityModel.setStartTime(startDate.getTime());
                }
                String assignee = tmpHisAct.getAssignee();
                if (tmpHisAct.getActivityType().equals("startEvent")) {
                    assignee = hpins.getStartUserId();
                }
                if(StringUtils.isNotEmpty(assignee)){
                    Map<String, Object> userInfo = userService.getUserMsg(Long.parseLong(assignee));
                        if (userInfo != null) {
                            assignee = userInfo.get("name") + "";
                        }
                }else{
                    assignee = "";
                }

                processActivityModel.setAssign(assignee);
            }
            results.add(processActivityModel);
        }

        results.sort((pro1, pro2) -> {
            long time1 = pro1.getStartTime();
            long time2 = pro2.getStartTime();
            return (int) (time1 - time2);
        });

        String actId = results.get(results.size()-1).getActivityId();//獲取最後一個節點

        if (hpins.getEndTime() == null) {//未結束流程,則需拼接未完成節點
            ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(hpins.getProcessDefinitionId());
            if (processDefinition == null) {
                retMsg.setCode(ErrorEnum.ACT_DEFINE_NOT_FOUND.getCode());
                retMsg.setMessage(ErrorEnum.ACT_DEFINE_NOT_FOUND.getMessage());
                return retMsg;
            }
            List<ActivityImpl> activities = processDefinition.getActivities();
            ActivityImpl lastAct = null;
            for (ActivityImpl tmp : activities) {//獲取最後節點定義
                if (actId.equals(tmp.getId())) {
                    lastAct = tmp;
                    break;
                }
            }
            ActivityImpl nextAct = findNextAct(lastAct);
            int loopTimes = 0;//循環次數,防死循環
            while(nextAct!=null && loopTimes<10){
                loopTimes++;
                String type = nextAct.getProperty("type") + "";
                if (type.equals("userTask") || type.equals("startEvent")) {
                    ProcessActivityModel procNex = new ProcessActivityModel();
                    procNex.setActivityId(nextAct.getId());
                    procNex.setActivityName(nextAct.getProperties().get("name") + "");
                    procNex.setStartTime(0l);
                    results.add(procNex);
                }
                nextAct = findNextAct(nextAct);
            }
        }
        retMsg.setData(results);
        return retMsg;
    }


private ActivityImpl findNextAct(ActivityImpl tmp) {
        ActivityImpl nextOne = null;
        if (tmp != null) {
            List<PvmTransition> pvs = tmp.getOutgoingTransitions();
            if(pvs.size()==1){
                return (ActivityImpl)pvs.get(0).getDestination();
            }else{//多路排他網關則視爲無法獲取下一節點
                return null;
            }
        }
        return nextOne;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章