- 浏览: 40285 次
- 性别:
- 来自: 墨尔本
文章分类
最新评论
-
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) 的实现代码?
相关推荐
赠送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; 包含...
总结来说,activiti-explorer-eclipse项目为Eclipse开发人员提供了一站式的解决方案,以便他们在IDE内实现和管理基于Activiti的工作流程。通过这个项目,开发者不仅可以更高效地设计流程,还可以在本地环境中便捷地...
activiti-6.0.0.zip 工作流官网包 (如果没有积分可以直接Q我:499384808,免费分享) 1. database里放着各种数据库的建表、删表、升级语句数据库包括db2、h2、hsql、mssql、mysql、oracle、postgres 2. libs 相关...
赠送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-5.22.0,我们关注的是一个用于流程设计的官方工具,即 activiti-explorer。这个工具为用户提供了一个直观的界面,以便于设计、部署和管理业务流程。 首先,让我们深入了解一下 ...
activiti6的流程设计汉化,解压后将里面的activiti-app放入tomcat中运行就可以了。默认使用的H2,如果要使用mysql等其它数据库需要修改activiti-app\WEB-INF\classes\META-INF\activiti-app包下的activiti-app....
标题中的 "activiti-5.22.0zip下载" 指的是Activiti的一个特定版本——5.22.0的压缩包文件,通常包含了该版本的所有源码、库文件、文档和示例。 在Activiti 5.22.0中,主要包含以下几个关键知识点: 1. **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-...
Activiti6-流程跟踪监控图-节点-流程线高亮显示-支持通过、不通过、驳回、退回 支持内容: 已完成节点高亮显示、当前执行中节点红色显示 支持一个节点多条流出线,包括通过、不通过、驳回、退回,按照已执行操作正确...
赠送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-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-...
赠送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-APP是Activiti工作流引擎的一个组成部分,它提供了用户友好的图形化界面,用于设计、执行和管理业务流程。用户可以通过这个APP来创建流程模型,定义任务流转规则,监控流程实例的状态,并进行相关的操作,...
赠送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-app6.0中文版.zip"是一个方便中文用户使用的完整工作流管理解决方案,它结合了强大的工作流引擎和直观的Web应用,使得流程管理变得简单而高效。无论是小型项目还是大型企业的复杂业务流程,...
activiti-spring-boot-starter-basic-6.0.0适配springboot2.1.2
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-...