返回 登录
0

Activiti 流程监控 流程图

Activiti作为一款轻量级的流程引擎,基本满足日常的工作需要。但涉及到流程监控时,就会显得心有余而力不足。如何不借助其他插件,又尽量避免改写底层代码以实现流程的追踪呢?
设计思路:

(1)一个页面,两个tab标签:A和B。

(2)A标签加载流程图,B标签加载流程数据。

    流程图的作用:显示全局流程布局,高亮显示当前进行的环节。

    流程数据的作用:显示当前人,处理人,处理时间等需要的信息。

(3)加载流程图:

    页面传回businessKey,后台实现查询。查询需要用到的对象:HistoricProcessInstance 或者 ProcessInstance,两者有什么区别?

    HistoricProcessInstance:既可以查询历史流程实例(结束的流程),也可以查询运行中的流程实例。(调用getHistoricService()方法实现业务处理)

     ProcessInstance :只查询运行中的流程实例。(调用getRuntimeService()方法实现业务处理)

    结论:需要效率并且不关注结束流程的情况选择 ProcessInstance,而针对流程监控如果结束的流程也需要监控,应该选择 HistoricProcessInstance 。

重要代码:

/取历史流程实例,既能取到历史实例又能取到运行中的流程实例/
HistoricProcessInstance hpi = workFlowEngineServiceImpl.findHistoryProcessInstanceByBusKey(businessKey);
try {
if (hpi == null) {
throw new RuntimeException(“获取流程图异常!”);
} else {
InputStream imageStream = workFlowEngineServiceImpl.getFlowMap(hpi, hpi.getId(), flowType);
ServletOutputStream os = response.getOutputStream();
int bytesRead = 0;
byte[] buffer = new byte[1024];
while ((bytesRead = imageStream.read(buffer, 0, 1024)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.flush();
os.close();
imageStream.close();
}
} catch (Exception e) {
logger.error(e, e);
throw new RuntimeException(“获取流程图异常!”);
}

/findHistoryProcessInstanceByBusKey方法/
/**
* 根据流程businessKey查询历史流程实例
* @param processId
* @return
*/
public HistoricProcessInstance findHistoryProcessInstanceByBusKey(String businessKey){
HistoryService historyService = this.getHistoryService();
return historyService.createHistoricProcessInstanceQuery()
.processInstanceBusinessKey(businessKey).singleResult();
}

/getFlowMap方法/
public InputStream getFlowMap(HistoricProcessInstance processInstance, String instanceId, String flowType) {

    processEngine = getInstance();

    // RuntimeService runtimeService = processEngine.getRuntimeService();
    // DynamicBpmnService flowMoniService = processEngine.getDynamicBpmnService();

    /*资源服务*/
    RepositoryService repositoryService = processEngine.getRepositoryService();
    /*历史数据服务*/
    HistoryService historyService = processEngine.getHistoryService();
    ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity)repositoryService.getProcessDefinition(processInstance.getProcessDefinitionId());

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

    /*为了流程监控图显示效果,替换多有未取到的变量,只显示节点的中文描述*/
    List<ActivityImpl> activityList = processDefinition.getActivities();
    for(ActivityImpl activity : activityList){
            String name = bpmnModel.getFlowElement(activity.getId()).getName();
            bpmnModel.getFlowElement(activity.getId())
                    .setName(name.replaceAll("[\\w{}$\\-+]", ""));
    }

    /*历史节点,取出变量,设置为节点的名称*/
    List<ArkHistoricActivity> hisList = findProcessHistoryByPiid(instanceId);
    for(ArkHistoricActivity hisActivity : hisList){
            bpmnModel.getFlowElement(hisActivity.getActivityId())
                    .setName(hisActivity.getActivityName());
    }

    List<HistoricActivityInstance> activityInstances = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(instanceId).orderByHistoricActivityInstanceStartTime().asc().list();
    List<String> activitiIds = new ArrayList<String>();
    List<String> flowIds = new ArrayList<String>();

    /*获取流程走过的线*/
    flowIds = flowServiceImpl.getHighLightedFlows(processDefinition, activityInstances);

    /*获取流程走过的节点*/
    for (HistoricActivityInstance hai : activityInstances) {
            activitiIds.add(hai.getActivityId());
    }
    Context.setProcessEngineConfiguration(
                    (ProcessEngineConfigurationImpl) processEngine.getProcessEngineConfiguration());

    /**
     * 从配置文件中获取中文配置信息,避免中文乱码
     * processEngine.getProcessEngineConfiguration().getActivityFontName(), 
     * processEngine.getProcessEngineConfiguration().getLabelFontName(), 
     */
    InputStream imageStream = new DefaultProcessDiagramGenerator().generateDiagram(bpmnModel, "png", activitiIds,
                    flowIds, processEngine.getProcessEngineConfiguration().getActivityFontName(),
                    processEngine.getProcessEngineConfiguration().getLabelFontName(), 
                    "", null, 1.0);

    return imageStream;

}

/getHighLightedFlows方法/
public List getHighLightedFlows(ProcessDefinitionEntity processDefinitionEntity,
List historicActivityInstances) {

    /*用以保存高亮的线flowId*/
    List<String> highFlows = new ArrayList<String>();
    /*对历史流程节点进行遍历*/
    for (int i = 0; i < historicActivityInstances.size() - 1; i++) {
            /*得到节点定义的详细信息*/
            ActivityImpl activityImpl = processDefinitionEntity.findActivity(historicActivityInstances.get(i).getActivityId());
            /*用以保存后需开始时间相同的节点*/
            List<ActivityImpl> sameStartTimeNodes = new ArrayList<ActivityImpl>();
            /*将后面第一个节点放在时间相同节点的集合里*/
            ActivityImpl sameActivityImpl1 = processDefinitionEntity.findActivity(historicActivityInstances.get(i + 1).getActivityId());
            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 (activityImpl1.getStartTime().equals(activityImpl2.getStartTime())) {
                            ActivityImpl sameActivityImpl2 = processDefinitionEntity.findActivity(activityImpl2.getActivityId());
                            sameStartTimeNodes.add(sameActivityImpl2);
                    }
                    /*有不相同跳出循环*/
                    else {
                            break;
                    }
            }
            /*取出节点的所有出去的线*/
            List<PvmTransition> pvmTransitions = activityImpl.getOutgoingTransitions();
            /*对所有的线进行遍历*/
            for (PvmTransition pvmTransition : pvmTransitions) {
                    /*如果取出的线的目标节点存在时间相同的节点里,保存该线的id,进行高亮显示*/
                    ActivityImpl pvmActivityImpl = (ActivityImpl) pvmTransition.getDestination();
                    if (sameStartTimeNodes.contains(pvmActivityImpl)) {
                            highFlows.add(pvmTransition.getId());
                    }
            }
    }
    return highFlows;

}
注意:

1)流程图中可能需要处理${currName}类似的变量,代码中已有写出,但这些变量替换为真实数据的前提是环节已办理,因为已办理才会记录Variables,未办理的环节需要将这些变量替换为空字符串,这是一些细节处理。

2) HistoricProcessInstance 获取历史数据的前提是:需要配置历史数据的记录级别,与此同时,在配置中也可以处理流程图中文字的乱码。


评论