zoukankan      html  css  js  c++  java
  • activity通过流程实例id动态获取流程图并展示在jsp页面上

    提供的Service方法如下:

    Java

    /**
    * 获取当前任务流程图
    *
    * @param processInstanceId
    * @return
    */
    @Override
    public InputStream generateDiagram(String processInstanceId) {
        //方法中用到的参数是流程实例ID,其实TaskId也可以转为这个。调用taskService查询即可。
        Command<InputStream> cmd = new ProcessInstanceDiagramCmd(processInstanceId, runtimeService, repositoryService, processEngine, historyService);
        return managementService.executeCommand(cmd);
    }

    而ProcessInstanceDiagramCmd采用了Activiti的命令模式。就是继承Command接口,其实这个地方完全可以使用纯Service方法去搞定,我之所以这么写,还是受到了国内临远大师的影响。

    本次绘制的流程图分为两种情况:1、流程实例还未执行完毕,也就是流程还没有结束,还有运行的任务。2、已经执行完毕的流程,流程已经进入了流程历史。不管属于以上哪种情况的流程图都会绘制流程走向。

    具体代码如下:

    Java

    import com.google.common.collect.Lists;
    import org.activiti.bpmn.model.BpmnModel;
    import org.activiti.engine.HistoryService;
    import org.activiti.engine.RepositoryService;
    import org.activiti.engine.RuntimeService;
    import org.activiti.engine.history.HistoricActivityInstance;
    import org.activiti.engine.history.HistoricProcessInstance;
    import org.activiti.engine.impl.context.Context;
    import org.activiti.engine.impl.interceptor.Command;
    import org.activiti.engine.impl.interceptor.CommandContext;
    import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
    import org.activiti.engine.impl.pvm.PvmTransition;
    import org.activiti.engine.impl.pvm.process.ActivityImpl;
    import org.activiti.engine.runtime.ProcessInstance;
    import org.activiti.image.impl.DefaultProcessDiagramGenerator;
    import org.activiti.spring.ProcessEngineFactoryBean;
    
    import java.io.InputStream;
    import java.util.*;
    
    /**
     * 根据流程实例ID生成流程图
     *
     * @author Chen Zhiguo
     */
    public class ProcessInstanceDiagramCmd implements Command<InputStream> {
    
        protected String processInstanceId;
    
        private RuntimeService runtimeService;
    
        private RepositoryService repositoryService;
    
        private ProcessEngineFactoryBean processEngine;
    
        private HistoryService historyService;
    
        public ProcessInstanceDiagramCmd(String processInstanceId, RuntimeService runtimeService, RepositoryService repositoryService, ProcessEngineFactoryBean processEngine, HistoryService historyService) {
            this.processInstanceId = processInstanceId;
            this.runtimeService = runtimeService;
            this.repositoryService = repositoryService;
            this.processEngine = processEngine;
            this.historyService = historyService;
        }
    
        public InputStream execute(CommandContext commandContext) {
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(processInstanceId).singleResult();
    
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
    
            if (processInstance == null && historicProcessInstance == null) {
                return null;
            }
    
            ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService
                    .getProcessDefinition(processInstance == null ? historicProcessInstance.getProcessDefinitionId() : processInstance.getProcessDefinitionId());
    
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
    
            List<String> activeActivityIds = Lists.newArrayList();
            if (processInstance != null) {
                activeActivityIds = runtimeService.getActiveActivityIds(processInstance.getProcessInstanceId());
            } else {
                activeActivityIds.add(historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("endEvent")
                        .singleResult().getActivityId());
            }
            // 使用spring注入引擎请使用下面的这行代码
            Context.setProcessEngineConfiguration(processEngine.getProcessEngineConfiguration());
    
            List<String> highLightedFlows = getHighLightedFlows(processDefinition, processInstanceId);
    
            InputStream imageStream = new DefaultProcessDiagramGenerator().generateDiagram(bpmnModel, "png", activeActivityIds,
                    highLightedFlows);
    
            return imageStream;
        }
    
        /**
         * getHighLightedFlows
         *
         * @param processDefinition
         * @param processInstanceId
         * @return
         */
        private List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinition, String processInstanceId) {
    
            List<String> highLightedFlows = new ArrayList<String>();
    
    //        List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
    //                .processInstanceId(processInstanceId)
    //                        //order by startime asc is not correct. use default order is correct.
    //                        //.orderByHistoricActivityInstanceStartTime().asc()/*.orderByActivityId().asc()*/
    //                .list();
            //上面注释掉的代码是官方的rest方法中提供的方案,可是我在实际测试中有Bug出现,所以做了一下修改。注意下面List内容的排序会影响流程走向红线丢失的问题
            List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
                    .orderByHistoricActivityInstanceStartTime().orderByHistoricActivityInstanceEndTime().asc().list();
            LinkedList<HistoricActivityInstance> hisActInstList = new LinkedList<HistoricActivityInstance>();
            hisActInstList.addAll(historicActivityInstances);
    
            getHighlightedFlows(processDefinition.getActivities(), hisActInstList, highLightedFlows);
    
            return highLightedFlows;
        }
    
        /**
         * getHighlightedFlows
         * <p/>
         * code logic:
         * 1. Loop all activities by id asc order;
         * 2. Check each activity's outgoing transitions and eventBoundery outgoing transitions, if outgoing transitions's destination.id is in other executed activityIds, add this transition to highLightedFlows List;
         * 3. But if activity is not a parallelGateway or inclusiveGateway, only choose the earliest flow.
         *
         * @param activityList
         * @param hisActInstList
         * @param highLightedFlows
         */
        private void getHighlightedFlows(List<ActivityImpl> activityList, LinkedList<HistoricActivityInstance> hisActInstList, List<String> highLightedFlows) {
    
            //check out startEvents in activityList
            List<ActivityImpl> startEventActList = new ArrayList<ActivityImpl>();
            Map<String, ActivityImpl> activityMap = new HashMap<String, ActivityImpl>(activityList.size());
            for (ActivityImpl activity : activityList) {
    
                activityMap.put(activity.getId(), activity);
    
                String actType = (String) activity.getProperty("type");
                if (actType != null && actType.toLowerCase().indexOf("startevent") >= 0) {
                    startEventActList.add(activity);
                }
            }
    
            //These codes is used to avoid a bug:
            //ACT-1728 If the process instance was started by a callActivity, it will be not have the startEvent activity in ACT_HI_ACTINST table
            //Code logic:
            //Check the first activity if it is a startEvent, if not check out the startEvent's highlight outgoing flow.
            HistoricActivityInstance firstHistActInst = hisActInstList.getFirst();
            String firstActType = (String) firstHistActInst.getActivityType();
            if (firstActType != null && firstActType.toLowerCase().indexOf("startevent") < 0) {
                PvmTransition startTrans = getStartTransaction(startEventActList, firstHistActInst);
                if (startTrans != null) {
                    highLightedFlows.add(startTrans.getId());
                }
            }
    
            while (!hisActInstList.isEmpty()) {
                HistoricActivityInstance histActInst = hisActInstList.removeFirst();
                ActivityImpl activity = activityMap.get(histActInst.getActivityId());
                if (activity != null) {
                    boolean isParallel = false;
                    String type = histActInst.getActivityType();
                    if ("parallelGateway".equals(type) || "inclusiveGateway".equals(type)) {
                        isParallel = true;
                    } else if ("subProcess".equals(histActInst.getActivityType())) {
                        getHighlightedFlows(activity.getActivities(), hisActInstList, highLightedFlows);
                    }
    
                    List<PvmTransition> allOutgoingTrans = new ArrayList<PvmTransition>();
                    allOutgoingTrans.addAll(activity.getOutgoingTransitions());
                    allOutgoingTrans.addAll(getBoundaryEventOutgoingTransitions(activity));
                    List<String> activityHighLightedFlowIds = getHighlightedFlows(allOutgoingTrans, hisActInstList, isParallel);
                    highLightedFlows.addAll(activityHighLightedFlowIds);
                }
            }
        }
    
        /**
         * Check out the outgoing transition connected to firstActInst from startEventActList
         *
         * @param startEventActList
         * @param firstActInst
         * @return
         */
        private PvmTransition getStartTransaction(List<ActivityImpl> startEventActList, HistoricActivityInstance firstActInst) {
            for (ActivityImpl startEventAct : startEventActList) {
                for (PvmTransition trans : startEventAct.getOutgoingTransitions()) {
                    if (trans.getDestination().getId().equals(firstActInst.getActivityId())) {
                        return trans;
                    }
                }
            }
            return null;
        }
    
        /**
         * getBoundaryEventOutgoingTransitions
         *
         * @param activity
         * @return
         */
        private List<PvmTransition> getBoundaryEventOutgoingTransitions(ActivityImpl activity) {
            List<PvmTransition> boundaryTrans = new ArrayList<PvmTransition>();
            for (ActivityImpl subActivity : activity.getActivities()) {
                String type = (String) subActivity.getProperty("type");
                if (type != null && type.toLowerCase().indexOf("boundary") >= 0) {
                    boundaryTrans.addAll(subActivity.getOutgoingTransitions());
                }
            }
            return boundaryTrans;
        }
    
        /**
         * find out single activity's highlighted flowIds
         *
         * @param pvmTransitionList
         * @param hisActInstList
         * @param isParallel
         * @return
         */
        private List<String> getHighlightedFlows(List<PvmTransition> pvmTransitionList, LinkedList<HistoricActivityInstance> hisActInstList, boolean isParallel) {
    
            List<String> highLightedFlowIds = new ArrayList<String>();
    
            PvmTransition earliestTrans = null;
            HistoricActivityInstance earliestHisActInst = null;
    
            for (PvmTransition pvmTransition : pvmTransitionList) {
    
                String destActId = pvmTransition.getDestination().getId();
                HistoricActivityInstance destHisActInst = findHisActInst(hisActInstList, destActId);
                if (destHisActInst != null) {
                    if (isParallel) {
                        highLightedFlowIds.add(pvmTransition.getId());
                    } else if (earliestHisActInst == null || (earliestHisActInst.getId().compareTo(destHisActInst.getId()) > 0)) {
                        earliestTrans = pvmTransition;
                        earliestHisActInst = destHisActInst;
                    }
                }
            }
    
            if ((!isParallel) && earliestTrans != null) {
                highLightedFlowIds.add(earliestTrans.getId());
            }
    
            return highLightedFlowIds;
        }
    
        private HistoricActivityInstance findHisActInst(LinkedList<HistoricActivityInstance> hisActInstList, String actId) {
            for (HistoricActivityInstance hisActInst : hisActInstList) {
                if (hisActInst.getActivityId().equals(actId)) {
                    return hisActInst;
                }
            }
            return null;
        }
    }


    最重要的是在控制层,通过流程实例id获取到流程图的文件流时,通过以下方法可以展示在jsp页面上:
    public String viewImage(){
    InputStream in = repositoryService.getResourceAsStream.getImageStream(deploymentId,imageName);
    //此处方法实际项目应该放在service里面
    HttpServletResponse resp = ServletActionContext.getResponse();
    try { OutputStream out = resp.getOutputStream(); // 把图片的输入流程写入resp的输出流中
    byte[] b = new byte[1024];
    for (int len = -1; (len= in.read(b))!=-1; ) {
    out.write(b, 0, len);
    } // 关闭流
    out.close();
    in.close(); }
    catch (IOException e) {
    e.printStackTrace();
    }
    return null;
    }

    上面这个方法是控制层的代码,在jsp页面上,使用一个<img>标签来展示流程图
    <img src = ""> <img>标签的src属性为上面这个方法的路径


  • 相关阅读:
    Mac idea 打不开
    git学习之git reset命令
    更改 macOS 用户帐户和个人文件夹的名称
    SpringBoot系列: 如何优雅停止服务
    windows环境下启动mongodb服务
    rocketMq4.2.0启动broker报错找不到或无法加载主类 FilesJavajdk1.8.0_101libdt.jar;C:Program]
    初创公司与成熟的公司各有什么利弊?有5年工作经验的人适合进那一个?(行业职位是一样的情况下)
    mac 10.15 国内如何安装brew
    Mac下SSH Key配置
    买苹果MacBook Pro ,有必要买care吗?
  • 原文地址:https://www.cnblogs.com/baihaojie/p/5991968.html
Copyright © 2011-2022 走看看