有接触过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 bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
调用默认api就可以获取。相对有点繁琐是
activiti6如何获取这两个字段
// 获取历史流程实例
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
// 获取流程中已经执行的节点,按照执行先后顺序排序
List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceId().asc().list();
// 高亮已经执行流程节点ID集合
List<String> highLightedActivitiIds = new ArrayList<>();
for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
highLightedActivitiIds.add(historicActivityInstance.getActivityId());
}
/**
* 获取已经流转的线
*
* @param bpmnModel
* @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;
}
/**
* 根据流程实例Id,获取实时流程图片
*
* @param processInstanceId
* @param outputStream
* @return
*/
public static void getFlowImgByInstanceId(String processInstanceId, OutputStream outputStream) {
try {
if (StringUtils.isEmpty(processInstanceId)) {
logger.error("processInstanceId is null");
return;
}
// 获取历史流程实例
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
// 获取流程中已经执行的节点,按照执行先后顺序排序
List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceId().asc().list();
// 高亮已经执行流程节点ID集合
List<String> highLightedActivitiIds = new ArrayList<>();
for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
highLightedActivitiIds.add(historicActivityInstance.getActivityId());
}
List<HistoricProcessInstance> historicFinishedProcessInstances = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).finished()
.list();
ProcessDiagramGenerator processDiagramGenerator = null;
// 如果还没完成,流程图高亮颜色为绿色,如果已经完成为红色
if (!CollectionUtils.isEmpty(historicFinishedProcessInstances)) {
// 如果不为空,说明已经完成
processDiagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();
} else {
processDiagramGenerator = new CustomProcessDiagramGenerator();
}
BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
// 高亮流程已发生流转的线id集合
List<String> highLightedFlowIds = getHighLightedFlows(bpmnModel, historicActivityInstances);
// 使用默认配置获得流程图表生成器,并生成追踪图片字符流
InputStream imageStream = processDiagramGenerator.generateDiagram(bpmnModel, "png", highLightedActivitiIds, highLightedFlowIds, "宋体", "微软雅黑", "黑体", null, 2.0);
// 输出图片内容
byte[] b = new byte[1024];
int len;
while ((len = imageStream.read(b, 0, 1024)) != -1) {
outputStream.write(b, 0, len);
}
} catch (Exception e) {
logger.error("processInstanceId" + processInstanceId + "生成流程图失败,原因:" + e.getMessage(), e);
}
}
/**
* 根据流程实例Id,获取实时流程图片
*
* @param processInstanceId
* @return
*/
public static InputStream getFlowImgByInstantId(String processInstanceId) {
if (StringUtils.isEmpty(processInstanceId)) {
return null;
}
// 获取流程图输入流
InputStream inputStream = null;
// 查询历史
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if (historicProcessInstance.getEndTime() != null) { // 该流程已经结束
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(historicProcessInstance.getProcessDefinitionId())
.singleResult();
inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getDiagramResourceName());
} else {
// 查询当前的流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) repositoryService.createProcessDefinitionQuery()
.processDefinitionId(processInstance.getProcessDefinitionId()).singleResult();
List<String> highLightedFlows = new ArrayList<String>();
List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceStartTime().asc().list();
List<String> historicActivityInstanceList = new ArrayList<String>();
for (HistoricActivityInstance hai : historicActivityInstances) {
historicActivityInstanceList.add(hai.getActivityId());
}
List<String> highLightedActivities = runtimeService.getActiveActivityIds(processInstanceId);
historicActivityInstanceList.addAll(highLightedActivities);
for (ActivityImpl activity : processDefinitionEntity.getActivities()) {
int index = historicActivityInstanceList.indexOf(activity.getId());
if (index >= 0 && index + 1 < historicActivityInstanceList.size()) {
List<PvmTransition> pvmTransitionList = activity.getOutgoingTransitions();
for (PvmTransition pvmTransition : pvmTransitionList) {
String destinationFlowId = pvmTransition.getDestination().getId();
if (destinationFlowId.equals(historicActivityInstanceList.get(index + 1))) {
highLightedFlows.add(pvmTransition.getId());
}
}
}
}
ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();
List<String> activeActivityIds = new ArrayList<String>();
List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
for (org.activiti.engine.task.Task task : tasks) {
activeActivityIds.add(task.getTaskDefinitionKey());
}
inputStream = diagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds, highLightedFlows, "宋体", "宋体", null, null, 1.0);
}
return inputStream;
}
activiti提供的样式可能不是特别美观,它的api目前只能改字体大小。如果遇到改颜色等,可以通过重写ProcessDiagramCanvas这个类,并实现ProcessDiagramGenerator这个类的接口
https://github.com/lyb-geek/demo-act-boot