- 浏览: 39383 次
- 性别:
- 来自: 墨尔本
文章分类
最新评论
-
houjiezhuang:
如果节点名称是汉字,那么节点显示就是空白。这个怎么解决
activiti-跟踪流程图颜色变化之一篇 -
无色的童年:
无色的童年 写道scofier 写道scofier 写道请问 ...
activiti-跟踪流程图颜色变化之一篇 -
无色的童年:
scofier 写道scofier 写道请问 : worksp ...
activiti-跟踪流程图颜色变化之一篇 -
scofier:
scofier 写道请问 : workspaceService ...
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) 的实现代码?
相关推荐
赠送jar包:activiti-engine-5.21.0.jar; 赠送原API文档:activiti-engine-5.21.0-javadoc.jar; 赠送源代码:activiti-engine-5.21.0-sources.jar; 赠送Maven依赖信息文件:activiti-engine-5.21.0.pom; 包含...
activiti6的流程设计汉化,解压后将里面的activiti-app放入tomcat中运行就可以了。默认使用的H2,如果要使用mysql等其它数据库需要修改activiti-app\WEB-INF\classes\META-INF\activiti-app包下的activiti-app....
赠送jar包:activiti-image-generator-5.21.0.jar; 赠送原API文档:activiti-image-generator-5.21.0-javadoc.jar; 赠送源代码:activiti-image-generator-5.21.0-sources.jar; 赠送Maven依赖信息文件:activiti-...
activiti-5.22.0zip下载
activiti-6.0.0.zip 工作流官网包 (如果没有积分可以直接Q我:499384808,免费分享) 1. database里放着各种数据库的建表、删表、升级语句数据库包括db2、h2、hsql、mssql、mysql、oracle、postgres 2. libs 相关...
赠送jar包:activiti-common-rest-5.21.0.jar; 赠送原API文档:activiti-common-rest-5.21.0-javadoc.jar; 赠送源代码:activiti-common-rest-5.21.0-sources.jar; 赠送Maven依赖信息文件:activiti-common-rest-...
activiti-explorer-eclipse项目
赠送jar包:activiti-json-converter-5.21.0.jar; 赠送原API文档:activiti-json-converter-5.21.0-javadoc.jar; 赠送源代码:activiti-json-converter-5.21.0-sources.jar; 赠送Maven依赖信息文件:activiti-...
赠送jar包:activiti-image-generator-5.21.0.jar; 赠送原API文档:activiti-image-generator-5.21.0-javadoc.jar; 赠送源代码:activiti-image-generator-5.21.0-sources.jar; 赠送Maven依赖信息文件:activiti-...
赠送jar包:activiti-bpmn-model-5.21.0.jar; 赠送原API文档:activiti-bpmn-model-5.21.0-javadoc.jar; 赠送源代码:activiti-bpmn-model-5.21.0-sources.jar; 赠送Maven依赖信息文件:activiti-bpmn-model-...
activiti-bpmn-converter-5.18.0-sources.jar
activiti-designer-5.18.0.zip 官方 activiti-designer-5.18.0.zip 官方 activiti-designer-5.18.0.zip 官方
activiti-spring-boot-starter-basic-6.0.0适配springboot2.1.2
activiti-explorer5.2中文乱码解决方法
赠送jar包:activiti-json-converter-5.21.0.jar; 赠送原API文档:activiti-json-converter-5.21.0-javadoc.jar; 赠送源代码:activiti-json-converter-5.21.0-sources.jar; 赠送Maven依赖信息文件:activiti-...
activiti-app6.0汉化版,对界面进行汉化,流程设计器里的英文无法汉化,没有对应的国际化文件
赠送jar包:activiti-crystalball-5.21.0.jar; 赠送原API文档:activiti-crystalball-5.21.0-javadoc.jar; 赠送源代码:activiti-crystalball-5.21.0-sources.jar; 赠送Maven依赖信息文件:activiti-crystalball-...
赠送jar包:activiti-process-validation-5.21.0.jar; 赠送原API文档:activiti-process-validation-5.21.0-javadoc.jar; 赠送源代码:activiti-process-validation-5.21.0-sources.jar; 赠送Maven依赖信息文件:...
工作流引擎activiti-5.22.0,流程定义插件Activiti-activiti-5.22.0
activiti-bpmn-converter-5.16.4.jar