activiti 實時流程圖追蹤 springboot

https://cloud.tencent.com/developer/article/1165460

https://blog.csdn.net/m0_37222746/article/details/73321680

 

springboot 與 activiti 參考 另一個blog

有接觸過activiti的朋友可能知道,在activiti5.x的追蹤流程節點查找,可以用

ActivityImpl這個類來實現,可惜在activiti6版本,pvm包整個類包都被刪除,再也沒有ActivityImpl這個類。這給流程圖追蹤造成一定的麻煩,不過沒關係,本章節就是教大家如何用activiti6來生成實時流程圖追蹤。

生成流程圖核心類

主要是利用ProcessDiagramGenerator這個接口實現類,去實現generateDiagram這個方法。默認可以採用ProcessDiagramGenerator的子類

DefaultProcessDiagramGenerator調用generateDiagram實現流程圖。當然也可以自定義相應的子類CustomProcessDiagramGenerator去定製化實現

 

生成流程圖核心方法

public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows, 
      String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor;

看這個方法,我們顯然要關注的是bpmnmodel,highLightedActivities,highLightedFlows

這三個字段值

bpmnmodel:bpmn模型,這個簡單,調用

BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());

調用默認api就可以獲取。相對有點繁瑣是

highLightedActivities(需要高亮的執行流程節點集合的獲取)以及

highLightedFlows(需要高亮流程連接線集合的獲取)。

 

上代碼

package com.zte.activi.controller;

import io.swagger.annotations.Api;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.spring.ProcessEngineFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zcy
 * @version 2019/9/23
 *          Created by zcy on 2019/9/23.
 */
@Controller
@RequestMapping("/draw")
@Api("draw")
public class DrawController {
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    ProcessEngineFactoryBean processEngine;
    @Autowired
    ProcessEngineConfiguration processEngineConfiguration;

    @RequestMapping("queryProPlan.html")
    public void queryProPlan(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String processInstanceId = "50023";  //57510   65037 50023
        //獲取歷史流程實例
        HistoricProcessInstance processInstance =  historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        //獲取流程圖
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        processEngineConfiguration = processEngine.getProcessEngineConfiguration();
        Context.setProcessEngineConfiguration((ProcessEngineConfigurationImpl) processEngineConfiguration);

        ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();
        ProcessDefinitionEntity definitionEntity = (ProcessDefinitionEntity)repositoryService.getProcessDefinition(processInstance.getProcessDefinitionId());

        List<HistoricActivityInstance> highLightedActivitList =  historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();

        //高亮環節id集合
        List<String> highLightedActivitis = new ArrayList<String>();
        for(HistoricActivityInstance tempActivity : highLightedActivitList){
            String activityId = tempActivity.getActivityId();
            highLightedActivitis.add(activityId);
        }

        //高亮線路id集合
        //List<String> highLightedFlows = getHighLightedFlows(bpmnModel,highLightedActivitList);

        List<String> highLightedFlows =  getHighLightedFlows(bpmnModel,definitionEntity,highLightedActivitList);

        //中文顯示的是口口口,設置字體就好了
        InputStream imageStream = diagramGenerator.generateDiagram(bpmnModel,"png",highLightedActivitis,highLightedFlows,"宋體","微軟雅黑","黑體",null,2.0);
        //單獨返回流程圖,不高亮顯示
       //InputStream imageStream = diagramGenerator.generatePngDiagram(bpmnModel);
        // 輸出資源內容到相應對象
        byte[] b = new byte[1024];
        int len;
        while ((len = imageStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }

    }
    /**
     * 獲取需要高亮的線
     *
     * @param historicActivityInstances
     * @return
     */
    private static List<String> getHighLightedFlows(BpmnModel bpmnModel, List<HistoricActivityInstance> historicActivityInstances) {
        // 高亮流程已發生流轉的線id集合
        List<String> highLightedFlowIds = new ArrayList<>();
        // 全部活動節點
        List<FlowNode> historicActivityNodes = new ArrayList<>();
        // 已完成的歷史活動節點
        List<HistoricActivityInstance> finishedActivityInstances = new ArrayList<>();

        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
            FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true);
            historicActivityNodes.add(flowNode);
            if (historicActivityInstance.getEndTime() != null) {
                finishedActivityInstances.add(historicActivityInstance);
            }
        }

        FlowNode currentFlowNode = null;
        FlowNode targetFlowNode = null;
        // 遍歷已完成的活動實例,從每個實例的outgoingFlows中找到已執行的
        for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) {
            // 獲得當前活動對應的節點信息及outgoingFlows信息
            currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true);
            List<SequenceFlow> sequenceFlows = currentFlowNode.getOutgoingFlows();

            /**
             * 遍歷outgoingFlows並找到已已流轉的 滿足如下條件認爲已已流轉: 1.當前節點是並行網關或兼容網關,則通過outgoingFlows能夠在歷史活動中找到的全部節點均爲已流轉 2.當前節點是以上兩種類型之外的,通過outgoingFlows查找到的時間最早的流轉節點視爲有效流轉
             */
            if ("parallelGateway".equals(currentActivityInstance.getActivityType()) || "inclusiveGateway".equals(currentActivityInstance.getActivityType())) {
                // 遍歷歷史活動節點,找到匹配流程目標節點的
                for (SequenceFlow sequenceFlow : sequenceFlows) {
                    targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true);
                    if (historicActivityNodes.contains(targetFlowNode)) {
                        highLightedFlowIds.add(targetFlowNode.getId());
                    }
                }
            } else {
                List<Map<String, Object>> tempMapList = new ArrayList<>();
                for (SequenceFlow sequenceFlow : sequenceFlows) {
                    for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
                        if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) {
                            Map<String, Object> map = new HashMap<>();
                            map.put("highLightedFlowId", sequenceFlow.getId());
                            map.put("highLightedFlowStartTime", historicActivityInstance.getStartTime().getTime());
                            tempMapList.add(map);
                        }
                    }
                }

                if (!CollectionUtils.isEmpty(tempMapList)) {
                    // 遍歷匹配的集合,取得開始時間最早的一個
                    long earliestStamp = 0L;
                    String highLightedFlowId = null;
                    for (Map<String, Object> map : tempMapList) {
                        long highLightedFlowStartTime = Long.valueOf(map.get("highLightedFlowStartTime").toString());
                        if (earliestStamp == 0 || earliestStamp >= highLightedFlowStartTime) {
                            highLightedFlowId = map.get("highLightedFlowId").toString();
                            earliestStamp = highLightedFlowStartTime;
                        }
                    }

                    highLightedFlowIds.add(highLightedFlowId);
                }

            }

        }
        return highLightedFlowIds;
    }


    public List<String> getHighLightedFlows(BpmnModel bpmnModel,ProcessDefinitionEntity processDefinitionEntity,List<HistoricActivityInstance> historicActivityInstances)
    {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //24小時制
        List<String> highFlows = new ArrayList<String>();// 用以保存高亮的線flowId

        for (int i = 0; i < historicActivityInstances.size() - 1; i++)
        {
            // 對歷史流程節點進行遍歷
            // 得到節點定義的詳細信息
            FlowNode activityImpl = (FlowNode)bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(i).getActivityId());


            List<FlowNode> sameStartTimeNodes = new ArrayList<FlowNode>();// 用以保存後續開始時間相同的節點
            FlowNode sameActivityImpl1 = null;

            HistoricActivityInstance activityImpl_ = historicActivityInstances.get(i);// 第一個節點
            HistoricActivityInstance activityImp2_ ;

            for(int k = i + 1 ; k <= historicActivityInstances.size() - 1; k++)
            {
                activityImp2_ = historicActivityInstances.get(k);// 後續第1個節點

                if ( activityImpl_.getActivityType().equals("userTask") && activityImp2_.getActivityType().equals("userTask") &&
                        df.format(activityImpl_.getStartTime()).equals(df.format(activityImp2_.getStartTime()))   ) //都是usertask,且主節點與後續節點的開始時間相同,說明不是真實的後繼節點
                {

                }
                else
                {
                    sameActivityImpl1 = (FlowNode)bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(k).getActivityId());//找到緊跟在後面的一個節點
                    break;
                }

            }
            sameStartTimeNodes.add(sameActivityImpl1); // 將後面第一個節點放在時間相同節點的集合裏
            for (int j = i + 1; j < historicActivityInstances.size() - 1; j++)
            {
                HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);// 後續第一個節點
                HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);// 後續第二個節點

                if (df.format(activityImpl1.getStartTime()).equals(df.format(activityImpl2.getStartTime()))  )
                {// 如果第一個節點和第二個節點開始時間相同保存
                    FlowNode sameActivityImpl2 = (FlowNode)bpmnModel.getMainProcess().getFlowElement(activityImpl2.getActivityId());
                    sameStartTimeNodes.add(sameActivityImpl2);
                }
                else
                {// 有不相同跳出循環
                    break;
                }
            }
            List<SequenceFlow> pvmTransitions = activityImpl.getOutgoingFlows() ; // 取出節點的所有出去的線

            for (SequenceFlow pvmTransition : pvmTransitions)
            {// 對所有的線進行遍歷
                FlowNode pvmActivityImpl = (FlowNode)bpmnModel.getMainProcess().getFlowElement( pvmTransition.getTargetRef());// 如果取出的線的目標節點存在時間相同的節點裏,保存該線的id,進行高亮顯示
                if (sameStartTimeNodes.contains(pvmActivityImpl)) {
                    highFlows.add(pvmTransition.getId());
                }
            }

        }
        return highFlows;

    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章