- 浏览: 41202 次
- 性别:
- 来自: 墨尔本
-
文章分类
最新评论
-
houjiezhuang:
如果节点名称是汉字,那么节点显示就是空白。这个怎么解决
activiti-跟踪流程图颜色变化之一篇 -
无色的童年:
<div class="quote_title ...
activiti-跟踪流程图颜色变化之一篇 -
无色的童年:
<div class="quote_title ...
activiti-跟踪流程图颜色变化之一篇 -
scofier:
<div class="quote_title ...
activiti-跟踪流程图颜色变化之一篇 -
scofier:
请问 : workspaceService.executeCo ...
activiti-跟踪流程图颜色变化之一篇
我喜欢简要文字 主要还是发代码为主了,希望发现问题可以一起探讨!
我用的框架是spring mvc
controller
HistoryProcessInstanceDiagramCmd.java
CustomProcessDiagramGenerator.java
Graph.java
GraphElement.java
Edge.java
ActivitiHistoryGraphBuilder.java
ActivitiGraphBuilder.java
Node.java
希望对你有所帮助,如果有更好的办法记得分享给大家哦!
已经解决, 没有问题了, 非常感谢
可以说下是怎么解决的么
解决了 是ManagementService
已经解决, 没有问题了, 非常感谢
可以说下是怎么解决的么
已经解决, 没有问题了, 非常感谢
我用的框架是spring mvc
controller
/** * <功能简述>流程跟踪图 * <功能详细描述> * @param processInstanceId 流程实例id * @param response * @throws Exception * @see [类、类#方法、类#成员] */ @RequestMapping("graphHistoryProcessInstance") public void graphHistoryProcessInstance( @RequestParam("processInstanceId") String processInstanceId, HttpServletResponse response) throws Exception { Command<InputStream> cmd = new HistoryProcessInstanceDiagramCmd( processInstanceId); InputStream is = workspaceService.executeCommand( cmd); response.setContentType("image/png"); int len = 0; byte[] b = new byte[1024]; while ((len = is.read(b, 0, 1024)) != -1) { response.getOutputStream().write(b, 0, len); } is.close(); }
HistoryProcessInstanceDiagramCmd.java
package com.plate.bpm.graph; import java.io.*; import org.activiti.engine.impl.interceptor.Command; import org.activiti.engine.impl.interceptor.CommandContext; public class HistoryProcessInstanceDiagramCmd implements Command<InputStream> { protected String historyProcessInstanceId; public HistoryProcessInstanceDiagramCmd(String historyProcessInstanceId) { this.historyProcessInstanceId = historyProcessInstanceId; } public InputStream execute(CommandContext commandContext) { try { CustomProcessDiagramGenerator customProcessDiagramGenerator = new CustomProcessDiagramGenerator(); return customProcessDiagramGenerator .generateDiagram(historyProcessInstanceId); } catch (Exception ex) { throw new RuntimeException(ex); } } }
CustomProcessDiagramGenerator.java
package com.plate.bpm.graph; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Polygon; import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.geom.Ellipse2D.Double; import java.awt.geom.Line2D; import java.awt.geom.Path2D; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import javax.imageio.ImageIO; import org.activiti.bpmn.constants.BpmnXMLConstants; import org.activiti.bpmn.model.Artifact; import org.activiti.bpmn.model.BpmnModel; import org.activiti.bpmn.model.FlowElement; import org.activiti.bpmn.model.FlowElementsContainer; import org.activiti.bpmn.model.FlowNode; import org.activiti.bpmn.model.GraphicInfo; import org.activiti.bpmn.model.Lane; import org.activiti.bpmn.model.Pool; import org.activiti.bpmn.model.SequenceFlow; import org.activiti.engine.history.HistoricActivityInstance; import org.activiti.engine.history.HistoricProcessInstance; import org.activiti.engine.impl.HistoricActivityInstanceQueryImpl; import org.activiti.engine.impl.Page; import org.activiti.engine.impl.cmd.GetBpmnModelCmd; import org.activiti.engine.impl.cmd.GetDeploymentProcessDefinitionCmd; import org.activiti.engine.impl.context.Context; import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.activiti.engine.impl.pvm.process.ActivityImpl; import org.apache.commons.io.FilenameUtils; /** * 流程图绘制工具 */ public class CustomProcessDiagramGenerator { public static final int OFFSET_SUBPROCESS = 5; public static final int OFFSET_TASK = 20; private static List<String> taskType = new ArrayList<String>(); private static List<String> eventType = new ArrayList<String>(); private static List<String> gatewayType = new ArrayList<String>(); private static List<String> subProcessType = new ArrayList<String>(); private static Color RUNNING_COLOR = Color.RED; private static Color HISTORY_COLOR = Color.GREEN; private static Color SKIP_COLOR = Color.GRAY; private static Stroke THICK_BORDER_STROKE = new BasicStroke(3.0f); private int minX; private int minY; public CustomProcessDiagramGenerator() { init(); } protected static void init() { taskType.add(BpmnXMLConstants.ELEMENT_TASK_MANUAL); taskType.add(BpmnXMLConstants.ELEMENT_TASK_RECEIVE); taskType.add(BpmnXMLConstants.ELEMENT_TASK_SCRIPT); taskType.add(BpmnXMLConstants.ELEMENT_TASK_SEND); taskType.add(BpmnXMLConstants.ELEMENT_TASK_SERVICE); taskType.add(BpmnXMLConstants.ELEMENT_TASK_USER); gatewayType.add(BpmnXMLConstants.ELEMENT_GATEWAY_EXCLUSIVE); gatewayType.add(BpmnXMLConstants.ELEMENT_GATEWAY_INCLUSIVE); gatewayType.add(BpmnXMLConstants.ELEMENT_GATEWAY_EVENT); gatewayType.add(BpmnXMLConstants.ELEMENT_GATEWAY_PARALLEL); eventType.add("intermediateTimer"); eventType.add("intermediateMessageCatch"); eventType.add("intermediateSignalCatch"); eventType.add("intermediateSignalThrow"); eventType.add("messageStartEvent"); eventType.add("startTimerEvent"); eventType.add(BpmnXMLConstants.ELEMENT_ERROR); eventType.add(BpmnXMLConstants.ELEMENT_EVENT_START); eventType.add("errorEndEvent"); eventType.add(BpmnXMLConstants.ELEMENT_EVENT_END); subProcessType.add(BpmnXMLConstants.ELEMENT_SUBPROCESS); subProcessType.add(BpmnXMLConstants.ELEMENT_CALL_ACTIVITY); } public InputStream generateDiagram(String processInstanceId) throws IOException { HistoricProcessInstance historicProcessInstance = Context .getCommandContext().getHistoricProcessInstanceEntityManager() .findHistoricProcessInstance(processInstanceId); String processDefinitionId = historicProcessInstance .getProcessDefinitionId(); GetBpmnModelCmd getBpmnModelCmd = new GetBpmnModelCmd( processDefinitionId); BpmnModel bpmnModel = getBpmnModelCmd.execute(Context .getCommandContext()); Point point = getMinXAndMinY(bpmnModel); this.minX = point.x; this.minY = point.y; this.minX = (this.minX <= 5) ? 5 : this.minX; this.minY = (this.minY <= 5) ? 5 : this.minY; this.minX -= 5; this.minY -= 5; ProcessDefinitionEntity definition = new GetDeploymentProcessDefinitionCmd( processDefinitionId).execute(Context.getCommandContext()); String diagramResourceName = definition.getDiagramResourceName(); String deploymentId = definition.getDeploymentId(); byte[] bytes = Context .getCommandContext() .getResourceEntityManager() .findResourceByDeploymentIdAndResourceName(deploymentId, diagramResourceName).getBytes(); InputStream originDiagram = new ByteArrayInputStream(bytes); BufferedImage image = ImageIO.read(originDiagram); HistoricActivityInstanceQueryImpl historicActivityInstanceQueryImpl = new HistoricActivityInstanceQueryImpl(); historicActivityInstanceQueryImpl.processInstanceId(processInstanceId) .orderByHistoricActivityInstanceStartTime().asc(); Page page = new Page(0, 100); List<HistoricActivityInstance> activityInstances = Context .getCommandContext() .getHistoricActivityInstanceEntityManager() .findHistoricActivityInstancesByQueryCriteria( historicActivityInstanceQueryImpl, page); this.drawHistoryFlow(image, processInstanceId); for (HistoricActivityInstance historicActivityInstance : activityInstances) { String historicActivityId = historicActivityInstance .getActivityId(); ActivityImpl activity = definition.findActivity(historicActivityId); if (activity != null) { if (historicActivityInstance.getEndTime() == null) { // 节点正在运行中 signRunningNode(image, activity.getX(), activity.getY(), activity.getWidth(), activity.getHeight(), historicActivityInstance.getActivityType()); } else { String deleteReason = null; if (historicActivityInstance.getTaskId() != null) { deleteReason = Context .getCommandContext() .getHistoricTaskInstanceEntityManager() .findHistoricTaskInstanceById( historicActivityInstance.getTaskId()) .getDeleteReason(); } // 节点已经结束 if ("跳过".equals(deleteReason)) { signSkipNode(image, activity.getX(), activity.getY(), activity.getWidth(), activity.getHeight(), historicActivityInstance.getActivityType()); } else { signHistoryNode(image, activity.getX(), activity.getY() , activity.getWidth(), activity.getHeight(), historicActivityInstance.getActivityType()); } } } } ByteArrayOutputStream out = new ByteArrayOutputStream(); String formatName = getDiagramExtension(diagramResourceName); ImageIO.write(image, formatName, out); return new ByteArrayInputStream(out.toByteArray()); } private static String getDiagramExtension(String diagramResourceName) { return FilenameUtils.getExtension(diagramResourceName); } /** * 标记运行节点 * * @param image * 原始图片 * @param x * 左上角节点坐在X位置 * @param y * 左上角节点坐在Y位置 * @param width * 宽 * @param height * 高 * @param activityType * 节点类型 */ private static void signRunningNode(BufferedImage image, int x, int y, int width, int height, String activityType) { Color nodeColor = RUNNING_COLOR; Graphics2D graphics = image.createGraphics(); try { drawNodeBorder(x, y, width, height, graphics, nodeColor, activityType); } finally { graphics.dispose(); } } /** * 标记历史节点 * * @param image * 原始图片 * @param x * 左上角节点坐在X位置 * @param y * 左上角节点坐在Y位置 * @param width * 宽 * @param height * 高 * @param activityType * 节点类型 */ private static void signHistoryNode(BufferedImage image, int x, int y, int width, int height, String activityType) { Color nodeColor = HISTORY_COLOR; Graphics2D graphics = image.createGraphics(); try { drawNodeBorder(x, y, width, height, graphics, nodeColor, activityType); } finally { graphics.dispose(); } } private static void signSkipNode(BufferedImage image, int x, int y, int width, int height, String activityType) { Color nodeColor = SKIP_COLOR; Graphics2D graphics = image.createGraphics(); try { drawNodeBorder(x, y, width, height, graphics, nodeColor, activityType); } finally { graphics.dispose(); } } /** * 绘制节点边框 * * @param x * 左上角节点坐在X位置 * @param y * 左上角节点坐在Y位置 * @param width * 宽 * @param height * 高 * @param graphics * 绘图对象 * @param color * 节点边框颜色 * @param activityType * 节点类型 */ protected static void drawNodeBorder(int x, int y, int width, int height, Graphics2D graphics, Color color, String activityType) { graphics.setPaint(color); graphics.setStroke(THICK_BORDER_STROKE); if (taskType.contains(activityType)) { drawTask(x, y, width, height, graphics); } else if (gatewayType.contains(activityType)) { drawGateway(x, y, width, height, graphics); } else if (eventType.contains(activityType)) { drawEvent(x, y, width, height, graphics); } else if (subProcessType.contains(activityType)) { drawSubProcess(x, y, width, height, graphics); } } /** * 绘制任务 */ protected static void drawTask(int x, int y, int width, int height, Graphics2D graphics) { RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, OFFSET_TASK, OFFSET_TASK); graphics.draw(rect); } /** * 绘制网关 */ protected static void drawGateway(int x, int y, int width, int height, Graphics2D graphics) { Polygon rhombus = new Polygon(); rhombus.addPoint(x, y + (height / 2)); rhombus.addPoint(x + (width / 2), y + height); rhombus.addPoint(x + width, y + (height / 2)); rhombus.addPoint(x + (width / 2), y); graphics.draw(rhombus); } /** * 绘制任务 */ protected static void drawEvent(int x, int y, int width, int height, Graphics2D graphics) { Double circle = new Ellipse2D.Double(x, y, width, height); graphics.draw(circle); } /** * 绘制子流程 */ protected static void drawSubProcess(int x, int y, int width, int height, Graphics2D graphics) { RoundRectangle2D rect = new RoundRectangle2D.Double(x + 1, y + 1, width - 2, height - 2, OFFSET_SUBPROCESS, OFFSET_SUBPROCESS); graphics.draw(rect); } protected Point getMinXAndMinY(BpmnModel bpmnModel) { // We need to calculate maximum values to know how big the image will be in its entirety double theMinX = java.lang.Double.MAX_VALUE; double theMaxX = 0; double theMinY = java.lang.Double.MAX_VALUE; double theMaxY = 0; for (Pool pool : bpmnModel.getPools()) { GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId()); theMinX = graphicInfo.getX(); theMaxX = graphicInfo.getX() + graphicInfo.getWidth(); theMinY = graphicInfo.getY(); theMaxY = 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()) > theMaxX) { theMaxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth(); } if (flowNodeGraphicInfo.getX() < theMinX) { theMinX = flowNodeGraphicInfo.getX(); } // height if ((flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight()) > theMaxY) { theMaxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight(); } if (flowNodeGraphicInfo.getY() < theMinY) { theMinY = flowNodeGraphicInfo.getY(); } for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) { List<GraphicInfo> graphicInfoList = bpmnModel .getFlowLocationGraphicInfo(sequenceFlow.getId()); for (GraphicInfo graphicInfo : graphicInfoList) { // width if (graphicInfo.getX() > theMaxX) { theMaxX = graphicInfo.getX(); } if (graphicInfo.getX() < theMinX) { theMinX = graphicInfo.getX(); } // height if (graphicInfo.getY() > theMaxY) { theMaxY = graphicInfo.getY(); } if (graphicInfo.getY() < theMinY) { theMinY = 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()) > theMaxX) { theMaxX = artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth(); } if (artifactGraphicInfo.getX() < theMinX) { theMinX = artifactGraphicInfo.getX(); } // height if ((artifactGraphicInfo.getY() + artifactGraphicInfo .getHeight()) > theMaxY) { theMaxY = artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight(); } if (artifactGraphicInfo.getY() < theMinY) { theMinY = artifactGraphicInfo.getY(); } } List<GraphicInfo> graphicInfoList = bpmnModel .getFlowLocationGraphicInfo(artifact.getId()); if (graphicInfoList != null) { for (GraphicInfo graphicInfo : graphicInfoList) { // width if (graphicInfo.getX() > theMaxX) { theMaxX = graphicInfo.getX(); } if (graphicInfo.getX() < theMinX) { theMinX = graphicInfo.getX(); } // height if (graphicInfo.getY() > theMaxY) { theMaxY = graphicInfo.getY(); } if (graphicInfo.getY() < theMinY) { theMinY = graphicInfo.getY(); } } } } int nrOfLanes = 0; for (org.activiti.bpmn.model.Process process : bpmnModel.getProcesses()) { for (Lane l : process.getLanes()) { nrOfLanes++; GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId()); // // width if ((graphicInfo.getX() + graphicInfo.getWidth()) > theMaxX) { theMaxX = graphicInfo.getX() + graphicInfo.getWidth(); } if (graphicInfo.getX() < theMinX) { theMinX = graphicInfo.getX(); } // height if ((graphicInfo.getY() + graphicInfo.getHeight()) > theMaxY) { theMaxY = graphicInfo.getY() + graphicInfo.getHeight(); } if (graphicInfo.getY() < theMinY) { theMinY = graphicInfo.getY(); } } } // Special case, see http://jira.codehaus.org/browse/ACT-1431 if ((flowNodes.size() == 0) && (bpmnModel.getPools().size() == 0) && (nrOfLanes == 0)) { // Nothing to show theMinX = 0; theMinY = 0; } return new Point((int) theMinX, (int) theMinY); } protected static List<Artifact> gatherAllArtifacts(BpmnModel bpmnModel) { List<Artifact> artifacts = new ArrayList<Artifact>(); for (org.activiti.bpmn.model.Process process : bpmnModel.getProcesses()) { artifacts.addAll(process.getArtifacts()); } return artifacts; } protected static List<FlowNode> gatherAllFlowNodes(BpmnModel bpmnModel) { List<FlowNode> flowNodes = new ArrayList<FlowNode>(); for (org.activiti.bpmn.model.Process process : bpmnModel.getProcesses()) { flowNodes.addAll(gatherAllFlowNodes(process)); } return flowNodes; } protected static List<FlowNode> gatherAllFlowNodes( FlowElementsContainer flowElementsContainer) { List<FlowNode> flowNodes = new ArrayList<FlowNode>(); for (FlowElement flowElement : flowElementsContainer.getFlowElements()) { if (flowElement instanceof FlowNode) { flowNodes.add((FlowNode) flowElement); } if (flowElement instanceof FlowElementsContainer) { flowNodes .addAll(gatherAllFlowNodes((FlowElementsContainer) flowElement)); } } return flowNodes; } public void drawHistoryFlow(BufferedImage image, String processInstanceId) { HistoricProcessInstance historicProcessInstance = Context .getCommandContext().getHistoricProcessInstanceEntityManager() .findHistoricProcessInstance(processInstanceId); String processDefinitionId = historicProcessInstance .getProcessDefinitionId(); Graph graph = new ActivitiHistoryGraphBuilder(processInstanceId) .build(); for (Edge edge : graph.getEdges()) { drawSequenceFlow(image, processDefinitionId, edge.getName()); } } public void drawSequenceFlow(BufferedImage image, String processDefinitionId, String sequenceFlowId) { GetBpmnModelCmd getBpmnModelCmd = new GetBpmnModelCmd( processDefinitionId); BpmnModel bpmnModel = getBpmnModelCmd.execute(Context .getCommandContext()); Graphics2D graphics = image.createGraphics(); graphics.setPaint(HISTORY_COLOR); graphics.setStroke(new BasicStroke(2f)); try { List<GraphicInfo> graphicInfoList = bpmnModel .getFlowLocationGraphicInfo(sequenceFlowId); 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(); } int radius = 15; Path2D path = new Path2D.Double(); for (int i = 0; i < xPoints.length; i++) { Integer anchorX = xPoints[i]; Integer anchorY = yPoints[i]; double targetX = anchorX; double targetY = anchorY; double ax = 0; double ay = 0; double bx = 0; double by = 0; double zx = 0; double zy = 0; if ((i > 0) && (i < (xPoints.length - 1))) { Integer cx = anchorX; Integer cy = anchorY; // pivot point of prev line double lineLengthY = yPoints[i] - yPoints[i - 1]; // pivot point of prev line double lineLengthX = xPoints[i] - xPoints[i - 1]; double lineLength = Math.sqrt(Math.pow(lineLengthY, 2) + Math.pow(lineLengthX, 2)); double dx = (lineLengthX * radius) / lineLength; double dy = (lineLengthY * radius) / lineLength; targetX = targetX - dx; targetY = targetY - dy; // isDefaultConditionAvailable = isDefault && i == 1 && lineLength > 10; if ((lineLength < (2 * radius)) && (i > 1)) { targetX = xPoints[i] - (lineLengthX / 2); targetY = yPoints[i] - (lineLengthY / 2); } // pivot point of next line lineLengthY = yPoints[i + 1] - yPoints[i]; lineLengthX = xPoints[i + 1] - xPoints[i]; lineLength = Math.sqrt(Math.pow(lineLengthY, 2) + Math.pow(lineLengthX, 2)); if (lineLength < radius) { lineLength = radius; } dx = (lineLengthX * radius) / lineLength; dy = (lineLengthY * radius) / lineLength; double nextSrcX = xPoints[i] + dx; double nextSrcY = yPoints[i] + dy; if ((lineLength < (2 * radius)) && (i < (xPoints.length - 2))) { nextSrcX = xPoints[i] + (lineLengthX / 2); nextSrcY = yPoints[i] + (lineLengthY / 2); } double dx0 = (cx - targetX) / 3; double dy0 = (cy - targetY) / 3; ax = cx - dx0; ay = cy - dy0; double dx1 = (cx - nextSrcX) / 3; double dy1 = (cy - nextSrcY) / 3; bx = cx - dx1; by = cy - dy1; zx = nextSrcX; zy = nextSrcY; } if (i == 0) { path.moveTo(targetX, targetY); } else { path.lineTo(targetX, targetY); } if ((i > 0) && (i < (xPoints.length - 1))) { // add curve path.curveTo(ax, ay, bx, by, zx, zy); } } graphics.draw(path); // draw arrow Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], yPoints[xPoints.length - 2], xPoints[xPoints.length - 1], yPoints[xPoints.length - 1]); int ARROW_WIDTH = 5; int doubleArrowWidth = 2 * ARROW_WIDTH; Polygon arrowHead = new Polygon(); arrowHead.addPoint(0, 0); arrowHead.addPoint(-ARROW_WIDTH, -doubleArrowWidth); arrowHead.addPoint(ARROW_WIDTH, -doubleArrowWidth); AffineTransform transformation = new AffineTransform(); transformation.setToIdentity(); double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1); transformation.translate(line.x2, line.y2); transformation.rotate((angle - (Math.PI / 2d))); AffineTransform originalTransformation = graphics.getTransform(); graphics.setTransform(transformation); graphics.fill(arrowHead); graphics.setTransform(originalTransformation); } finally { graphics.dispose(); } } }
Graph.java
package com.plate.bpm.graph; import java.util.ArrayList; import java.util.List; public class Graph { private Node initial; public Node getInitial() { return initial; } public void setInitial(Node initial) { this.initial = initial; } public List<Node> getNodes() { List<Node> nodes = new ArrayList<Node>(); visitNode(initial, nodes); return nodes; } public void visitNode(Node node, List<Node> nodes) { nodes.add(node); for (Edge edge : node.getOutgoingEdges()) { Node nextNode = edge.getDest(); visitNode(nextNode, nodes); } } public List<Edge> getEdges() { List<Edge> edges = new ArrayList<Edge>(); visitEdge(initial, edges); return edges; } public void visitEdge(Node node, List<Edge> edges) { for (Edge edge : node.getOutgoingEdges()) { edges.add(edge); Node nextNode = edge.getDest(); visitEdge(nextNode, edges); } } public Node findById(String id) { for (Node node : this.getNodes()) { if (id.equals(node.getId())) { return node; } } return null; } }
GraphElement.java
package com.plate.bpm.graph; /** * 节点和连线的父类. */ public class GraphElement { /** * 实例id,历史的id. */ private String id; /** * 节点名称,bpmn图形中的id. */ private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Edge.java
package com.plate.bpm.graph; /** * 连线. */ public class Edge extends GraphElement { /** * 起点. */ private Node src; /** * 终点. */ private Node dest; /** * 循环. */ private boolean cycle; public Node getSrc() { return src; } public void setSrc(Node src) { this.src = src; } public Node getDest() { return dest; } public void setDest(Node dest) { this.dest = dest; } public boolean isCycle() { return cycle; } public void setCycle(boolean cycle) { this.cycle = cycle; } }
ActivitiHistoryGraphBuilder.java
package com.plate.bpm.graph; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.activiti.engine.ProcessEngine; import org.activiti.engine.history.HistoricActivityInstance; import org.activiti.engine.impl.HistoricActivityInstanceQueryImpl; import org.activiti.engine.impl.Page; import org.activiti.engine.impl.cmd.GetDeploymentProcessDefinitionCmd; import org.activiti.engine.impl.context.Context; import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.activiti.engine.impl.pvm.PvmActivity; import org.activiti.engine.impl.pvm.PvmTransition; import org.activiti.engine.impl.pvm.process.ActivityImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 根据历史,生成实时运行阶段的子图. */ public class ActivitiHistoryGraphBuilder { /** * logger. */ private static Logger logger = LoggerFactory .getLogger(ActivitiHistoryGraphBuilder.class); private String processInstanceId; private ProcessDefinitionEntity processDefinitionEntity; private List<HistoricActivityInstance> historicActivityInstances; private List<HistoricActivityInstance> visitedHistoricActivityInstances = new ArrayList<HistoricActivityInstance>(); private Map<String, Node> nodeMap = new HashMap<String, Node>(); public ActivitiHistoryGraphBuilder(String processInstanceId) { this.processInstanceId = processInstanceId; } public Graph build() { this.fetchProcessDefinitionEntity(); this.fetchHistoricActivityInstances(); Graph graph = new Graph(); for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) { Node currentNode = new Node(); currentNode.setId(historicActivityInstance.getId()); currentNode.setName(historicActivityInstance.getActivityId()); currentNode.setType(historicActivityInstance.getActivityType()); currentNode .setActive(historicActivityInstance.getEndTime() == null); logger.debug("currentNode : {}:{}", currentNode.getName(), currentNode.getId()); Edge previousEdge = this.findPreviousEdge(currentNode, historicActivityInstance.getStartTime().getTime()); if (previousEdge == null) { if (graph.getInitial() != null) { throw new IllegalStateException("already set an initial."); } graph.setInitial(currentNode); } else { logger.debug("previousEdge : {}", previousEdge.getName()); } nodeMap.put(currentNode.getId(), currentNode); visitedHistoricActivityInstances.add(historicActivityInstance); } if (graph.getInitial() == null) { throw new IllegalStateException("cannot find initial."); } return graph; } /** * 根据流程实例id获取对应的流程定义. */ public void fetchProcessDefinitionEntity() { String processDefinitionId = Context.getCommandContext() .getHistoricProcessInstanceEntityManager() .findHistoricProcessInstance(processInstanceId) .getProcessDefinitionId(); GetDeploymentProcessDefinitionCmd cmd = new GetDeploymentProcessDefinitionCmd( processDefinitionId); processDefinitionEntity = cmd.execute(Context.getCommandContext()); } public void fetchHistoricActivityInstances() { HistoricActivityInstanceQueryImpl historicActivityInstanceQueryImpl = new HistoricActivityInstanceQueryImpl(); // historicActivityInstanceQueryImpl.processInstanceId(processInstanceId) // .orderByHistoricActivityInstanceStartTime().asc(); // TODO: 如果用了uuid会造成这样排序出问题 // 但是如果用startTime,可能出现因为处理速度太快,时间一样,导致次序颠倒的问题 historicActivityInstanceQueryImpl.processInstanceId(processInstanceId) .orderByHistoricActivityInstanceId().asc(); Page page = new Page(0, 100); historicActivityInstances = Context .getCommandContext() .getHistoricActivityInstanceEntityManager() .findHistoricActivityInstancesByQueryCriteria( historicActivityInstanceQueryImpl, page); } /** * 找到这个节点前面的连线. */ public Edge findPreviousEdge(Node currentNode, long currentStartTime) { String activityId = currentNode.getName(); ActivityImpl activityImpl = processDefinitionEntity .findActivity(activityId); HistoricActivityInstance nestestHistoricActivityInstance = null; String temporaryPvmTransitionId = null; // 遍历进入当前节点的所有连线 for (PvmTransition pvmTransition : activityImpl .getIncomingTransitions()) { PvmActivity source = pvmTransition.getSource(); String previousActivityId = source.getId(); HistoricActivityInstance visitiedHistoryActivityInstance = this .findVisitedHistoricActivityInstance(previousActivityId); if (visitiedHistoryActivityInstance == null) { continue; } // 如果上一个节点还未完成,说明不可能是从这个节点过来的,跳过 if (visitiedHistoryActivityInstance.getEndTime() == null) { continue; } logger.debug("current activity start time : {}", new Date( currentStartTime)); logger.debug("nestest activity end time : {}", visitiedHistoryActivityInstance.getEndTime()); // 如果当前节点的开始时间,比上一个节点的结束时间要早,跳过 if (currentStartTime < visitiedHistoryActivityInstance.getEndTime() .getTime()) { continue; } if (nestestHistoricActivityInstance == null) { nestestHistoricActivityInstance = visitiedHistoryActivityInstance; temporaryPvmTransitionId = pvmTransition.getId(); } else if ((currentStartTime - nestestHistoricActivityInstance .getEndTime().getTime()) > (currentStartTime - visitiedHistoryActivityInstance .getEndTime().getTime())) { // 寻找离当前节点最近的上一个节点 // 比较上一个节点的endTime与当前节点startTime的差 nestestHistoricActivityInstance = visitiedHistoryActivityInstance; temporaryPvmTransitionId = pvmTransition.getId(); } } // 没找到上一个节点,就返回null if (nestestHistoricActivityInstance == null) { return null; } Node previousNode = nodeMap .get(nestestHistoricActivityInstance.getId()); if (previousNode == null) { return null; } logger.debug("previousNode : {}:{}", previousNode.getName(), previousNode.getId()); Edge edge = new Edge(); edge.setName(temporaryPvmTransitionId); previousNode.getOutgoingEdges().add(edge); edge.setSrc(previousNode); edge.setDest(currentNode); return edge; } public HistoricActivityInstance findVisitedHistoricActivityInstance( String activityId) { for (int i = visitedHistoricActivityInstances.size() - 1; i >= 0; i--) { HistoricActivityInstance historicActivityInstance = visitedHistoricActivityInstances .get(i); if (activityId.equals(historicActivityInstance.getActivityId())) { return historicActivityInstance; } } return null; } }
ActivitiGraphBuilder.java
package com.plate.bpm.graph; import java.util.HashSet; import java.util.Set; import org.activiti.engine.impl.cmd.GetDeploymentProcessDefinitionCmd; import org.activiti.engine.impl.context.Context; import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.activiti.engine.impl.pvm.PvmActivity; import org.activiti.engine.impl.pvm.PvmTransition; /** * 根据流程定义,构建设计阶段的图. */ public class ActivitiGraphBuilder { /** * 流程定义id. */ private String processDefinitionId; /** * 流程定义. */ private ProcessDefinitionEntity processDefinitionEntity; /** * 已访问的节点id. */ private Set<String> visitedNodeIds = new HashSet<String>(); /** * 构造方法. */ public ActivitiGraphBuilder(String processDefinitionId) { this.processDefinitionId = processDefinitionId; } /** * 构建图. */ public Graph build() { this.fetchProcessDefinitionEntity(); Node initial = visitNode(processDefinitionEntity.getInitial()); Graph graph = new Graph(); graph.setInitial(initial); return graph; } /** * 获取流程定义. */ public void fetchProcessDefinitionEntity() { GetDeploymentProcessDefinitionCmd cmd = new GetDeploymentProcessDefinitionCmd( processDefinitionId); processDefinitionEntity = cmd.execute(Context.getCommandContext()); } /** * 遍历. */ public Node visitNode(PvmActivity pvmActivity) { if (visitedNodeIds.contains(pvmActivity.getId())) { return null; } visitedNodeIds.add(pvmActivity.getId()); Node currentNode = new Node(); currentNode.setId(pvmActivity.getId()); currentNode.setName(this.getString(pvmActivity.getProperty("name"))); currentNode.setType(this.getString(pvmActivity.getProperty("type"))); for (PvmTransition pvmTransition : pvmActivity.getOutgoingTransitions()) { PvmActivity destination = pvmTransition.getDestination(); Node targetNode = this.visitNode(destination); if (targetNode == null) { continue; } Edge edge = new Edge(); edge.setId(pvmTransition.getId()); edge.setSrc(currentNode); edge.setDest(targetNode); currentNode.getOutgoingEdges().add(edge); } return currentNode; } /** * 把object转换为string. */ public String getString(Object object) { if (object == null) { return null; } else if (object instanceof String) { return (String) object; } else { return object.toString(); } } }
Node.java
package com.plate.bpm.graph; import java.util.ArrayList; import java.util.List; /** * 节点. */ public class Node extends GraphElement { /** * 类型,比如userTask,startEvent. */ private String type; /** * 是否还未完成. */ private boolean active; /** * 进入这个节点的所有连线. */ private List<Edge> incomingEdges = new ArrayList<Edge>(); /** * 外出这个节点的所有连线. */ private List<Edge> outgoingEdges = new ArrayList<Edge>(); public String getType() { return type; } public void setType(String type) { this.type = type; } public boolean isActive() { return active; } public void setActive(boolean active) { this.active = active; } public List<Edge> getIncomingEdges() { return incomingEdges; } public void setIncomingEdges(List<Edge> incomingEdges) { this.incomingEdges = incomingEdges; } public List<Edge> getOutgoingEdges() { return outgoingEdges; } public void setOutgoingEdges(List<Edge> outgoingEdges) { this.outgoingEdges = outgoingEdges; } }
希望对你有所帮助,如果有更好的办法记得分享给大家哦!
评论
5 楼
houjiezhuang
2018-08-29
如果节点名称是汉字,那么节点显示就是空白。这个怎么解决
4 楼
无色的童年
2018-04-04
无色的童年 写道
scofier 写道
scofier 写道
请问 : workspaceService.executeCommand(cmd) 的实现代码?
已经解决, 没有问题了, 非常感谢
可以说下是怎么解决的么
解决了 是ManagementService
3 楼
无色的童年
2018-04-04
scofier 写道
scofier 写道
请问 : workspaceService.executeCommand(cmd) 的实现代码?
已经解决, 没有问题了, 非常感谢
可以说下是怎么解决的么
2 楼
scofier
2017-02-04
scofier 写道
请问 : workspaceService.executeCommand(cmd) 的实现代码?
已经解决, 没有问题了, 非常感谢
1 楼
scofier
2017-02-04
请问 : workspaceService.executeCommand(cmd) 的实现代码?
相关推荐
- **动态流程图**:如果流程图是动态的(比如用户可以根据条件选择不同的路径),那么在高亮时需要考虑到这些动态变化。 - **性能优化**:当流程实例很多时,遍历历史数据可能会有性能问题,可以考虑缓存部分数据...
然而,在实际使用过程中,可能会遇到各种问题,其中之一就是在Activiti 5.22版本中出现的“流程图连线名称不显示”的bug。 该问题主要体现在使用Activiti的Modeler设计器时,用户在设计流程图时可以清晰地看到连线...
在Activiti中,流程图高亮是一个关键特性,它能够帮助用户更好地理解和跟踪流程的状态。"activity6.0-流程图高亮"是关于Activiti 6版本的一个特定功能,它强调了在流程执行过程中对图元(节点和流程线)的突出显示。...
在Activiti中,流程实例可以通过流程图直观地展示,每个节点代表一个任务或事件。高亮显示则能帮助用户快速识别流程当前的状态,提高工作效率。 文件描述中提到的"已执行绿色,待执行红色",这是一种常见的颜色编码...
在Activiti中,流程图是通过流程定义(Process Definition)来创建的,它由一系列相互连接的节点(Activity)组成。每个节点代表一个任务或事件,如用户任务、服务任务、网关等。节点之间的连线表示流程的流转路径。...