activiti流转历史图绘制,工作流。

本文介绍了一种基于Activiti的工作流服务实现,包括检查流程是否结束、生成流程跟踪图片等功能。通过对历史活动实例的分析,获取流程的当前状态和关键路径,实现了流程图的动态生成与高亮显示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
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.engine.task.Task;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.apache.commons.io.IOUtils;

public class WorkflowServiceImpl {

	private ProcessEngine processEngine;
	
	/**
	 * 流程是否已经结束
	 * 
	 * @param processInstanceId 流程实例ID
	 * @return
	 */
	private boolean isFinished(String processInstanceId) {
		HistoryService historyService = processEngine.getHistoryService();
		return historyService.createHistoricProcessInstanceQuery().finished().processInstanceId(processInstanceId)
				.count() > 0;
	}

	/**
	 * 流程跟踪图片
	 * 
	 * @param processDefinitionId 流程定义ID
	 * @param executionId         流程运行ID
	 * @param out                 输出流
	 * @throws Exception
	 */
	@Override
	public void getProcessImg(String processDefinitionId, String executionId, OutputStream out) throws Exception {
		
		HistoryService historyService = processEngine.getHistoryService();
		RuntimeService runtimeService = processEngine.getRuntimeService();
		RepositoryService repositoryService = processEngine.getRepositoryService();
		
		// 当前活动节点、活动线
		List<String> activeActivityIds = new ArrayList<String>(), highLightedFlows = new ArrayList<String>();

		/**
		 * 获得当前活动的节点
		 */
		if (this.isFinished(executionId)) {// 如果流程已经结束,则得到结束节点
			activeActivityIds.add(historyService.createHistoricActivityInstanceQuery().executionId(executionId)
					.activityType("endEvent").singleResult().getActivityId());
		} else {// 如果流程没有结束,则取当前活动节点
			// 根据流程实例ID获得当前处于活动状态的ActivityId合集
			activeActivityIds = runtimeService.getActiveActivityIds(executionId);
		}
		/**
		 * 获得当前活动的节点-结束
		 */

		/**
		 * 获得活动的线
		 */
		// 获得历史活动记录实体(通过启动时间正序排序,不然有的线可以绘制不出来)
		List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
				.executionId(executionId).orderByHistoricActivityInstanceStartTime().asc().list();
		// 计算活动线
		highLightedFlows = this
				.getHighLightedFlows((ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
						.getDeployedProcessDefinition(processDefinitionId), historicActivityInstances);
		/**
		 * 获得活动的线-结束
		 */

		/**
		 * 绘制图形
		 */
		if (null != activeActivityIds) {
			InputStream imageStream = null;
			try {
				// 获得流程引擎配置
				ProcessEngineConfiguration processEngineConfiguration = processEngine.getProcessEngineConfiguration();
				// 根据流程定义ID获得BpmnModel
				BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
				// 输出资源内容到相应对象
				imageStream = new DefaultProcessDiagramGenerator().generateDiagram(bpmnModel, "png", activeActivityIds,
						highLightedFlows, processEngineConfiguration.getActivityFontName(),
						processEngineConfiguration.getLabelFontName(), processEngineConfiguration.getClassLoader(),
						1.0);
				IOUtils.copy(imageStream, out);
			} finally {
				IOUtils.closeQuietly(imageStream);
			}
		}
	}

	/**
	 * 获得高亮线
	 * 
	 * @param processDefinitionEntity   流程定义实体
	 * @param historicActivityInstances 历史活动实体
	 * @return 线ID集合
	 */
	protected List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinitionEntity,
			List<HistoricActivityInstance> historicActivityInstances) {

		List<String> highFlows = new ArrayList<String>();// 用以保存高亮的线flowId
		for (int i = 0; i < historicActivityInstances.size(); i++) {// 对历史流程节点进行遍历
			ActivityImpl activityImpl = processDefinitionEntity
					.findActivity(historicActivityInstances.get(i).getActivityId());// 得 到节点定义的详细信息
			List<ActivityImpl> sameStartTimeNodes = new ArrayList<ActivityImpl>();// 用以保存后需开始时间相同的节点
			if ((i + 1) >= historicActivityInstances.size()) {
				break;
			}
			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) {// 对所有的线进行遍历
				ActivityImpl pvmActivityImpl = (ActivityImpl) pvmTransition.getDestination();// 如果取出的线的目标节点存在时间相同的节点里,保存该线的id,进行高亮显示
				if (sameStartTimeNodes.contains(pvmActivityImpl)) {
					highFlows.add(pvmTransition.getId());
				}
			}
		}
		return highFlows;
	}

	public void setProcessEngine(ProcessEngine processEngine) {
		this.processEngine = processEngine;
	}

}

 

参考文献https://blog.youkuaiyun.com/daisy_xiu/article/details/44343653

图片输出参考https://blog.youkuaiyun.com/Bof_jangle/article/details/83212441

将下载的路径放到<img>的src中可展示在浏览器中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值