前后端分离的情况下生成activiti流程图

该篇博客主要讨论如何在Linux服务器上通过接口调用来显示图片流。当部署到某些最小化的Linux环境时,遇到中文显示不全的问题,原因是系统缺少宋体字体。解决方案是安装字体以确保正确显示。文中详细展示了接口定义、Activiti模板方法、ActivitiProcessImageHelper类以及相关方法的实现,用于处理图片流并高亮显示流程节点。
摘要由CSDN通过智能技术生成

页面用调接口的方式,将图片流显示。效果图:
注意:布署到有些最小安装的linux服务器时,用户任务框里面的中文会显示不出来,这是因为缺少系统字体(宋体),需要在服务器安装字体才能正常显示。
在这里插入图片描述
接口定义:

//instanceId为业务数据绑定到前端列表接口
@RequestMapping("/img")
	public void showProposess(String instanceId) throws Exception {
		activitiTemplate.responseProcessImg(instanceId, "proposes_410000_v1");
	}

activiti模板方法:

@Autowired
	private ActivitiProcessImageHelper imageHelper;

	public void responseProcessImg(String instanceId, String processDefinitionKey) {
		imageHelper.responseProcessImg(instanceId, processDefinitionKey);
	}

ActivitiProcessImageHelper 类:

public class ActivitiProcessImageHelper {

	@Autowired
	RuntimeService runtimeService;
	@Autowired
	RepositoryService repositoryService;
	@Autowired
	HistoryService historyService;
	@Autowired
	LakerProcessDiagramGenerator lakerProcessDiagramGenerator;
	@Autowired(required = false)
	HttpServletResponse response;

	public void responseProcessImg(String instanceId, String processDefinitionKey) {
		BpmnModel bpmnModel = getBpmnModel(processDefinitionKey);
		List<String> highLightedActivities = null;
		try {
			highLightedActivities = runtimeService.getActiveActivityIds(instanceId);
		} catch (Exception e) {
			// 已完结的流程查不到活动节点
			highLightedActivities = new ArrayList<String>();
		}

		List<HistoricActivityInstance> historyActivits = historyService.createHistoricActivityInstanceQuery()
				.processInstanceId(instanceId).orderByHistoricActivityInstanceId().asc().list();
		List<String> highLightedFlows = getHighLightedFlows(bpmnModel, historyActivits);
		try (InputStream ins = generateImgStream(bpmnModel, highLightedActivities, highLightedFlows);
				ServletOutputStream outputStream = response.getOutputStream()) {
			response.setContentType("image/jpg");
			int len = 0;
			byte[] b = new byte[1024];
			while ((len = ins.read(b)) != -1) {
				outputStream.write(b, 0, len);
				outputStream.flush();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private InputStream generateImgStream(BpmnModel bpmnModel, List<String> highLightedActivities,
			List<String> highLightedFlows) {
		return lakerProcessDiagramGenerator.generateDiagram(bpmnModel, "jpg", highLightedActivities, highLightedFlows,
				"宋体", "宋体", "宋体", null, 1);
	}

	private BpmnModel getBpmnModel(String definitionKey) {
		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().latestVersion()
				.processDefinitionKey(definitionKey).singleResult();
		return repositoryService.getBpmnModel(processDefinition.getId());// 模型
	}

	private List<String> getHighLightedFlows(BpmnModel bpmnModel, List<HistoricActivityInstance> historyActivitis) {
		// 高亮流程已发生流转的线id集合
		List<String> highLightedFlowIds = new ArrayList<>();
		// 全部活动节点
		List<FlowNode> historicActivityNodes = new ArrayList<>();
		// 已完成的历史活动节点
		List<HistoricActivityInstance> finishedActivityInstances = new ArrayList<>();

		for (HistoricActivityInstance historicActivityInstance : historyActivitis) {
			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 currentActivity : finishedActivityInstances) {
			// 获得当前活动对应的节点信息及outgoingFlows信息
			currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivity.getActivityId(),
					true);
			List<SequenceFlow> sequenceFlows = currentFlowNode.getOutgoingFlows();

			/**
			 * 遍历outgoingFlows 并找到已已流转的 满足如下条件认为已已流转: 
			 * 1.当前节点是并行网关或兼容网关 ,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转 
			 * 2.当前节点是以上两种类型之外的, 通过outgoingFlows查找到的时间最早的流转节点视为有效流转
			 */
			if ("parallelGateway".equals(currentActivity.getActivityType())
					|| "inclusiveGateway".equals(currentActivity.getActivityType())) {
				// 遍历历史活动节点,找到匹配流程目标节点的
				for (SequenceFlow sequenceFlow : sequenceFlows) {
					targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(),
							true);
					if (historicActivityNodes.contains(targetFlowNode)) {
						highLightedFlowIds.add(targetFlowNode.getId());
					}
				}
			} else {
				for (int i = 0; i < historyActivitis.size(); i++) {
					if (i != historyActivitis.size() - 1) {
						HistoricActivityInstance historyActiviti = historyActivitis.get(i);
						if (currentActivity.getActivityId().equals(historyActiviti.getActivityId())) {
							// 找到当前节点的下一个节点
							HistoricActivityInstance nexActivity = historyActivitis.get(i + 1);
							for (SequenceFlow sequenceFlow : sequenceFlows) {
								if (nexActivity.getActivityId().equals(sequenceFlow.getTargetRef())) {
									highLightedFlowIds.add(sequenceFlow.getId());
								}
							}
							continue;
						}
					}

				}
			}

		}
		return highLightedFlowIds;
	}
}

LakerProcessDiagramCanvas类:

public class LakerProcessDiagramCanvas extends DefaultProcessDiagramCanvas {

	public LakerProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType,
			String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
		super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName,
				customClassLoader);
		THICK_TASK_BORDER_STROKE = new BasicStroke(6.0f);
		Color wcolor = new Color(240, 240, 240);
		//任务盒子的底色
		TASK_BOX_COLOR = wcolor;
		//子流程底色
		SUBPROCESS_BOX_COLOR = wcolor;
		//事件的底色
		EVENT_COLOR = wcolor;
		//连接箭头颜色
		CONNECTION_COLOR = new Color(220, 220, 220);
		CONDITIONAL_INDICATOR_COLOR = wcolor;
		//高亮线条颜色
		HIGHLIGHT_COLOR = Color.BLUE;
		//任务里面那个字的颜色
		LABEL_COLOR =Color.RED;
		//任务边框颜色
		TASK_BORDER_COLOR = new Color(220, 220, 220);
		EVENT_BORDER_COLOR = new Color(220, 220, 220);
		SUBPROCESS_BORDER_COLOR = new Color(100, 100, 100);
		HIGHLIGHT_FLOW_STROKE = new BasicStroke(3f);
		GATEWAY_TYPE_STROKE = new BasicStroke(1.0f);
		try {
			//用户任务左上角那个图标的图片类路径地址
			USERTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("img/taskicon.jpg", customClassLoader));
		} catch (IOException e) {
			e.printStackTrace();
		}
		g.setColor(new Color(220, 220, 220));
	}

	public LakerProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType) {
		super(width, height, minX, minY, imageType);
		HIGHLIGHT_COLOR = Color.BLUE;
		THICK_TASK_BORDER_STROKE = new BasicStroke(6.0f);
	}

	public void drawHighLightColor(int x, int y, int width, int height, Color color) {
		Paint originalPaint = g.getPaint();
		Stroke originalStroke = g.getStroke();

		g.setPaint(color);
		g.setStroke(THICK_TASK_BORDER_STROKE);

		RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
		g.draw(rect);

		g.setPaint(originalPaint);
		g.setStroke(originalStroke);
	}
}

LakerProcessDiagramGenerator 类:

import java.awt.Color;
import java.util.List;

import org.activiti.bpmn.model.Activity;
import org.activiti.bpmn.model.Artifact;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.CallActivity;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.FlowElementsContainer;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.Gateway;
import org.activiti.bpmn.model.GraphicInfo;
import org.activiti.bpmn.model.Lane;
import org.activiti.bpmn.model.MultiInstanceLoopCharacteristics;
import org.activiti.bpmn.model.Pool;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.SubProcess;
import org.activiti.image.impl.DefaultProcessDiagramCanvas;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;

public class LakerProcessDiagramGenerator extends DefaultProcessDiagramGenerator {
	// private BufferedImage processDiagram;

	@Override
	protected DefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType,
			List<String> highLightedActivities, List<String> highLightedFlows, String activityFontName,
			String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {

		{

			prepareBpmnModel(bpmnModel);

			DefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType,
					activityFontName, labelFontName, annotationFontName, customClassLoader);

			// Draw pool shape, if process is participant in collaboration
			for (Pool pool : bpmnModel.getPools()) {
				GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
				processDiagramCanvas.drawPoolOrLane(pool.getName(), graphicInfo);
			}

			// Draw lanes
			for (Process process : bpmnModel.getProcesses()) {
				for (Lane lane : process.getLanes()) {
					GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId());
					processDiagramCanvas.drawPoolOrLane(lane.getName(), graphicInfo);
				}
			}

			// Draw activities and their sequence-flows
			for (FlowNode flowNode : bpmnModel.getProcesses().get(0).findFlowElementsOfType(FlowNode.class)) {
				drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows,
						scaleFactor);
			}

			for (Process process : bpmnModel.getProcesses()) {
				for (FlowNode flowNode : process.findFlowElementsOfType(FlowNode.class)) {
					drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows,
							scaleFactor);
				}
			}

			// Draw artifacts
			for (Process process : bpmnModel.getProcesses()) {

				for (Artifact artifact : process.getArtifacts()) {
					drawArtifact(processDiagramCanvas, bpmnModel, artifact);
				}

				List<SubProcess> subProcesses = process.findFlowElementsOfType(SubProcess.class, true);
				if (subProcesses != null) {
					for (SubProcess subProcess : subProcesses) {
						for (Artifact subProcessArtifact : subProcess.getArtifacts()) {
							drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact);
						}
					}
				}
			}

			return processDiagramCanvas;
		}
	}

	@Override
	protected void drawActivity(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel,
			FlowNode flowNode, List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor) {

		{

			ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass());
			if (drawInstruction != null) {

				drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode);

				// Gather info on the multi instance marker
				boolean multiInstanceSequential = false, multiInstanceParallel = false, collapsed = false;
				if (flowNode instanceof Activity) {
					Activity activity = (Activity) flowNode;
					MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity
							.getLoopCharacteristics();
					if (multiInstanceLoopCharacteristics != null) {
						multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential();
						multiInstanceParallel = !multiInstanceSequential;
					}
				}

				// Gather info on the collapsed marker
				GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
				if (flowNode instanceof SubProcess) {
					collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded();
				} else if (flowNode instanceof CallActivity) {
					collapsed = true;
				}

				if (scaleFactor == 1.0) {
					// Actually draw the markers
					processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(),
							(int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(), multiInstanceSequential,
							multiInstanceParallel, collapsed);
				}

			
				if (highLightedActivities.contains(flowNode.getId())) {
					if (highLightedActivities.get(highLightedActivities.size() - 1)
							.equalsIgnoreCase(flowNode.getId())) {

						LakerProcessDiagramCanvas lakerProcessDiagramCanvas = ((LakerProcessDiagramCanvas) processDiagramCanvas);
						lakerProcessDiagramCanvas.drawHighLightColor((int) graphicInfo.getX(), (int) graphicInfo.getY(),
								(int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(), Color.YELLOW);
					} else {
						processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(),
								(int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
					}

				}

			}

			// Outgoing transitions of activity
			for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
				boolean highLighted = (highLightedFlows.contains(sequenceFlow.getId()));
				String defaultFlow = null;
				if (flowNode instanceof Activity) {
					defaultFlow = ((Activity) flowNode).getDefaultFlow();
				} else if (flowNode instanceof Gateway) {
					defaultFlow = ((Gateway) flowNode).getDefaultFlow();
				}

				boolean isDefault = false;
				if (defaultFlow != null && defaultFlow.equalsIgnoreCase(sequenceFlow.getId())) {
					isDefault = true;
				}
				boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null
						&& !(flowNode instanceof Gateway);

				String sourceRef = sequenceFlow.getSourceRef();
				String targetRef = sequenceFlow.getTargetRef();
				FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef);
				FlowElement targetElement = bpmnModel.getFlowElement(targetRef);
				List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
				if (graphicInfoList != null && graphicInfoList.size() > 0) {
					graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement,
							targetElement, graphicInfoList);
					int xPoints[] = new int[graphicInfoList.size()];
					int yPoints[] = new int[graphicInfoList.size()];

					for (int i = 1; i < graphicInfoList.size(); i++) {
						GraphicInfo graphicInfo = graphicInfoList.get(i);
						GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1);

						if (i == 1) {
							xPoints[0] = (int) previousGraphicInfo.getX();
							yPoints[0] = (int) previousGraphicInfo.getY();
						}
						xPoints[i] = (int) graphicInfo.getX();
						yPoints[i] = (int) graphicInfo.getY();

					}

					processDiagramCanvas.drawSequenceflow(xPoints, yPoints, drawConditionalIndicator, isDefault,
							highLighted, scaleFactor);

					// Draw sequenceflow label
					GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId());
					if (labelGraphicInfo != null) {
						processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false);
					}
				}
			}

			// Nested elements
			if (flowNode instanceof FlowElementsContainer) {
				for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) {
					if (nestedFlowElement instanceof FlowNode) {
						drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement,
								highLightedActivities, highLightedFlows, scaleFactor);
					}
				}
			}
		}
	}

	protected static DefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType,
			String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {

		// We need to calculate maximum values to know how big the image will be in its
		// entirety
		double minX = Double.MAX_VALUE;
		double maxX = 0;
		double minY = Double.MAX_VALUE;
		double maxY = 0;

		for (Pool pool : bpmnModel.getPools()) {
			GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
			minX = graphicInfo.getX();
			maxX = graphicInfo.getX() + graphicInfo.getWidth();
			minY = graphicInfo.getY();
			maxY = graphicInfo.getY() + graphicInfo.getHeight();
		}

		List<FlowNode> flowNodes = gatherAllFlowNodes(bpmnModel);
		for (FlowNode flowNode : flowNodes) {

			GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());

			// width
			if (flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) {
				maxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth();
			}
			if (flowNodeGraphicInfo.getX() < minX) {
				minX = flowNodeGraphicInfo.getX();
			}
			// height
			if (flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) {
				maxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight();
			}
			if (flowNodeGraphicInfo.getY() < minY) {
				minY = flowNodeGraphicInfo.getY();
			}

			for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
				List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
				if (graphicInfoList != null) {
					for (GraphicInfo graphicInfo : graphicInfoList) {
						// width
						if (graphicInfo.getX() > maxX) {
							maxX = graphicInfo.getX();
						}
						if (graphicInfo.getX() < minX) {
							minX = graphicInfo.getX();
						}
						// height
						if (graphicInfo.getY() > maxY) {
							maxY = graphicInfo.getY();
						}
						if (graphicInfo.getY() < minY) {
							minY = graphicInfo.getY();
						}
					}
				}
			}
		}

		List<Artifact> artifacts = gatherAllArtifacts(bpmnModel);
		for (Artifact artifact : artifacts) {

			GraphicInfo artifactGraphicInfo = bpmnModel.getGraphicInfo(artifact.getId());

			if (artifactGraphicInfo != null) {
				// width
				if (artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth() > maxX) {
					maxX = artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth();
				}
				if (artifactGraphicInfo.getX() < minX) {
					minX = artifactGraphicInfo.getX();
				}
				// height
				if (artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight() > maxY) {
					maxY = artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight();
				}
				if (artifactGraphicInfo.getY() < minY) {
					minY = artifactGraphicInfo.getY();
				}
			}

			List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId());
			if (graphicInfoList != null) {
				for (GraphicInfo graphicInfo : graphicInfoList) {
					// width
					if (graphicInfo.getX() > maxX) {
						maxX = graphicInfo.getX();
					}
					if (graphicInfo.getX() < minX) {
						minX = graphicInfo.getX();
					}
					// height
					if (graphicInfo.getY() > maxY) {
						maxY = graphicInfo.getY();
					}
					if (graphicInfo.getY() < minY) {
						minY = graphicInfo.getY();
					}
				}
			}
		}

		int nrOfLanes = 0;
		for (Process process : bpmnModel.getProcesses()) {
			for (Lane l : process.getLanes()) {

				nrOfLanes++;

				GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId());
				// // width
				if (graphicInfo.getX() + graphicInfo.getWidth() > maxX) {
					maxX = graphicInfo.getX() + graphicInfo.getWidth();
				}
				if (graphicInfo.getX() < minX) {
					minX = graphicInfo.getX();
				}
				// height
				if (graphicInfo.getY() + graphicInfo.getHeight() > maxY) {
					maxY = graphicInfo.getY() + graphicInfo.getHeight();
				}
				if (graphicInfo.getY() < minY) {
					minY = graphicInfo.getY();
				}
			}
		}

		// Special case, see https://activiti.atlassian.net/browse/ACT-1431
		if (flowNodes.isEmpty() && bpmnModel.getPools().isEmpty() && nrOfLanes == 0) {
			// Nothing to show
			minX = 0;
			minY = 0;
		}

		return new LakerProcessDiagramCanvas((int) maxX + 10, (int) maxY + 10, (int) minX, (int) minY, imageType,
				activityFontName, labelFontName, annotationFontName, customClassLoader);
	}

}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值