jbpm4.4根据.jpdl.xml流程定义文件,得到流程图.pnghttp://www.oecp.cn/hi/yangtaoorange/blog/5804
只需将.jpdl.xml文件传过来,就可以根据这个文件解析出来.png图片
http://javaintelligence.blogspot.com/2010/08/jboss-jbpm-generating-image-at-runtime.html
写到:
Was tested with the latest version of JBPM 4.4 and works normally.
The following is a direct access to source code containing also the icons. The icons are extracted from a JAR used by the modeler of the eclipse ide.
http://www.planetacontabil.com.br/jbpm_image_sample.jar
先看节点类的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
Java代码 public class Node { private String name; private String type; private Rectangle rectangle; private List<Transition> transitions = new ArrayList<Transition>(); public Node(String name, String type) { this.name = name; this.type = type; } public Node(String name, String type, int x, int y, int w, int h) { this.name = name; this.type = type; this.rectangle = new Rectangle(x, y, w, h); } public Rectangle getRectangle() { return rectangle; } public void setRectangle(Rectangle rectangle) { this.rectangle = rectangle; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void addTransition(Transition transition) { transitions.add(transition); } public List<Transition> getTransitions() { return transitions; } public void setTransitions(List<Transition> transitions) { this.transitions = transitions; } public int getX() { return rectangle.x; } public int getY() { return rectangle.y; } public int getCenterX() { return (int) rectangle.getCenterX(); } public int getCenterY() { return (int) rectangle.getCenterY(); } public int getWitdth() { return rectangle.width; } public int getHeight() { return rectangle.height; } } |
其次是Transition的定义:
-
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950Java代码public class Transition {private Point labelPosition;private List<Point> lineTrace = new ArrayList<Point>();private String label;private String to;public Transition(String label, String to) {this.label = label;this.to = to;}public Point getLabelPosition() {return labelPosition;}public void setLabelPosition(Point labelPosition) {this.labelPosition = labelPosition;}public List<Point> getLineTrace() {return lineTrace;}public void setLineTrace(List<Point> lineTrace) {this.lineTrace = lineTrace;}public void addLineTrace(Point lineTrace) {if (lineTrace != null) {this.lineTrace.add(lineTrace);}}public String getLabel() {return label;}public void setLabel(String label) {this.label = label;}public String getTo() {return to;}public void setTo(String to) {this.to = to;}}
类JpdlModel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
Java代码 /** * CopyRight (C) 2006-2009 yy * @author yy * @project jbpm * @version 1.0 * @mail yy629_86 at 163 dot com * @date 2009-9-6 下午06:00:14 * @description */ package sofocus.bpm.jbpm.jpdl.model; import java.awt.Point; import java.io.InputStream; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.dom4j.Element; import org.dom4j.io.SAXReader; public class JpdlModel { private Map<String, Node> nodes = new LinkedHashMap<String, Node>(); public static final int RECT_OFFSET_X = -7; public static final int RECT_OFFSET_Y = -8; public static final int DEFAULT_PIC_SIZE = 48; private final static Map<String, Object> nodeInfos = new HashMap<String, Object>(); static { nodeInfos.put("start", "start_event_empty.png"); nodeInfos.put("end", "end_event_terminate.png"); nodeInfos.put("end-cancel", "end_event_cancel.png"); nodeInfos.put("end-error", "end_event_error.png"); nodeInfos.put("decision", "gateway_exclusive.png"); nodeInfos.put("fork", "gateway_parallel.png"); nodeInfos.put("join", "gateway_parallel.png"); nodeInfos.put("state", null); nodeInfos.put("hql", null); nodeInfos.put("sql", null); nodeInfos.put("java", null); nodeInfos.put("script", null); nodeInfos.put("task", null); nodeInfos.put("sub-process", null); nodeInfos.put("custom", null); } public JpdlModel(InputStream is) throws Exception { this(new SAXReader().read(is).getRootElement()); } @SuppressWarnings("unchecked") private JpdlModel(Element rootEl) throws Exception { for (Element el : (List<Element>) rootEl.elements()) { String type = el.getQName().getName(); if (!nodeInfos.containsKey(type)) { // 不是可展示的节点 continue; } String name = null; if (el.attribute("name") != null) { name = el.attributeValue("name"); } String[] location = el.attributeValue("g").split(","); int x = Integer.parseInt(location[0]); int y = Integer.parseInt(location[1]); int w = Integer.parseInt(location[2]); int h = Integer.parseInt(location[3]); if (nodeInfos.get(type) != null) { w = DEFAULT_PIC_SIZE; h = DEFAULT_PIC_SIZE; } else { x -= RECT_OFFSET_X; y -= RECT_OFFSET_Y; w += (RECT_OFFSET_X + RECT_OFFSET_X); h += (RECT_OFFSET_Y + RECT_OFFSET_Y); } Node node = new Node(name, type, x, y, w, h); parserTransition(node, el); nodes.put(name, node); } } @SuppressWarnings("unchecked") private void parserTransition(Node node, Element nodeEl) { for (Element el : (List<Element>) nodeEl.elements("transition")) { String label = el.attributeValue("name"); String to = el.attributeValue("to"); Transition transition = new Transition(label, to); String g = el.attributeValue("g"); if (g != null && g.length() > 0) { if (g.indexOf(":") < 0) { transition.setLabelPosition(getPoint(g)); } else { String[] p = g.split(":"); transition.setLabelPosition(getPoint(p[1])); String[] lines = p[0].split(";"); for (String line : lines) { transition.addLineTrace(getPoint(line)); } } } node.addTransition(transition); } } private Point getPoint(String exp) { if (exp == null || exp.length() == 0) { return null; } String[] p = exp.split(","); return new Point(Integer.valueOf(p[0]), Integer.valueOf(p[1])); } public Map<String, Node> getNodes() { return nodes; } public static Map<String, Object> getNodeInfos() { return nodeInfos; } } |
根据JpdlModel绘制出流程图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
Java代码 /** * CopyRight (C) 2006-2009 yy * @author yy * @project Jbpm * @version 1.0 * @mail yy629_86 at 163 dot com * @date 2009-9-6 下午06:00:14 * @description */ package sofocus.bpm.jbpm.jpdl; import java.awt.*; import java.awt.font.FontRenderContext; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; import java.util.Map; import javax.imageio.ImageIO; import sofocus.bpm.jbpm.jpdl.model.JpdlModel; import sofocus.bpm.jbpm.jpdl.model.Node; import sofocus.bpm.jbpm.jpdl.model.Transition; /** * @author yeyong * */ public class JpdlModelDrawer { public static final int RECT_OFFSET_X = JpdlModel.RECT_OFFSET_X; public static final int RECT_OFFSET_Y = JpdlModel.RECT_OFFSET_Y; public static final int RECT_ROUND = 25; public static final int DEFAULT_FONT_SIZE = 12; public static final Color DEFAULT_STROKE_COLOR = Color.decode("#03689A"); public static final Stroke DEFAULT_STROKE = new BasicStroke(2); public static final Color DEFAULT_LINE_STROKE_COLOR = Color.decode("#808080"); public static final Stroke DEFAULT_LINE_STROKE = new BasicStroke(1); public static final Color DEFAULT_FILL_COLOR = Color.decode("#F6F7FF"); private final static Map<String, Object> nodeInfos = JpdlModel.getNodeInfos(); public BufferedImage draw(JpdlModel jpdlModel) throws IOException { Rectangle dimension = getCanvasDimension(jpdlModel); BufferedImage bi = new BufferedImage(dimension.width, dimension.height, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = bi.createGraphics(); g2.setColor(Color.WHITE); g2.fillRect(0, 0, dimension.width, dimension.height); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Font font = new Font("宋体", Font.PLAIN, DEFAULT_FONT_SIZE); g2.setFont(font); Map<String, Node> nodes = jpdlModel.getNodes(); drawNode(nodes, g2, font); drawTransition(nodes, g2); return bi; } /** * 获得图片的矩形大小 * * @return */ private Rectangle getCanvasDimension(JpdlModel jpdlModel) { Rectangle rectangle = new Rectangle(); Rectangle rect; for (Node node : jpdlModel.getNodes().values()) { rect = node.getRectangle(); if (rect.getMaxX() > rectangle.getMaxX()) { rectangle.width = (int) rect.getMaxX(); } if (rect.getMaxY() > rectangle.getMaxY()) { rectangle.height = (int) rect.getMaxY(); } for (Transition transition : node.getTransitions()) { List<Point> trace = transition.getLineTrace(); for (Point point : trace) { if (rectangle.getMaxX() < point.x) { rectangle.width = point.x; } if (rectangle.getMaxY() < point.y) { rectangle.height = point.y; } } } } rectangle.width += 60; rectangle.height += 20; return rectangle; } /** * @param g2 * @throws IOException */ private void drawTransition(Map<String, Node> nodes, Graphics2D g2) throws IOException { g2.setStroke(DEFAULT_LINE_STROKE); g2.setColor(DEFAULT_LINE_STROKE_COLOR); for (Node node : nodes.values()) { for (Transition transition : node.getTransitions()) { String to = transition.getTo(); Node toNode = nodes.get(to); List<Point> trace = new LinkedList<Point>(transition.getLineTrace()); int len = trace.size() + 2; trace.add(0, new Point(node.getCenterX(), node.getCenterY())); trace.add(new Point(toNode.getCenterX(), toNode.getCenterY())); int[] xPoints = new int[len]; int[] yPoints = new int[len]; for (int i = 0; i < len; i++) { xPoints[i] = trace.get(i).x; yPoints[i] = trace.get(i).y; } final int taskGrow = 4; final int smallGrow = -2; int grow = 0; if (nodeInfos.get(node.getType()) != null) { grow = smallGrow; } else { grow = taskGrow; } Point p = GeometryUtils.getRectangleLineCrossPoint(node.getRectangle(), new Point(xPoints[1], yPoints[1]), grow); if (p != null) { xPoints[0] = p.x; yPoints[0] = p.y; } if (nodeInfos.get(toNode.getType()) != null) { grow = smallGrow; } else { grow = taskGrow; } p = GeometryUtils.getRectangleLineCrossPoint(toNode.getRectangle(), new Point(xPoints[len - 2], yPoints[len - 2]), grow); if (p != null) { xPoints[len - 1] = p.x; yPoints[len - 1] = p.y; } g2.drawPolyline(xPoints, yPoints, len); drawArrow(g2, xPoints[len - 2], yPoints[len - 2], xPoints[len - 1], yPoints[len - 1]); String label = transition.getLabel(); if (label != null && label.length() > 0) { int cx, cy; if (len % 2 == 0) { cx = (xPoints[len / 2 - 1] + xPoints[len / 2]) / 2; cy = (yPoints[len / 2 - 1] + yPoints[len / 2]) / 2; } else { cx = xPoints[len / 2]; cy = yPoints[len / 2]; } Point labelPoint = transition.getLabelPosition(); if (labelPoint != null) { cx += labelPoint.x; cy += labelPoint.y; } cy -= RECT_OFFSET_Y + RECT_OFFSET_Y / 2; g2.drawString(label, cx, cy); } } } } private void drawArrow(Graphics2D g2, int x1, int y1, int x2, int y2) { final double len = 8.0; double slopy = Math.atan2(y2 - y1, x2 - x1); double cosy = Math.cos(slopy); double siny = Math.sin(slopy); int[] xPoints = { 0, x2, 0 }; int[] yPoints = { 0, y2, 0 }; double a = len * siny, b = len * cosy; double c = len / 2.0 * siny, d = len / 2.0 * cosy; xPoints[0] = x2 - (int) (b + c); yPoints[0] = y2 - (int) (a - d); xPoints[2] = x2 - (int) (b - c); yPoints[2] = y2 - (int) (d + a); g2.fillPolygon(xPoints, yPoints, 3); } /** * @param g2 * @throws IOException */ private void drawNode(Map<String, Node> nodes, Graphics2D g2, Font font) throws IOException { for (Node node : nodes.values()) { String name = node.getName(); if (nodeInfos.get(node.getType()) != null) { BufferedImage bi2 = ImageIO.read(getClass().getResourceAsStream( "/icons/48/" + nodeInfos.get(node.getType()))); g2.drawImage(bi2, node.getX(), node.getY(), null); } else { int x = node.getX(); int y = node.getY(); int w = node.getWitdth(); int h = node.getHeight(); g2.setColor(DEFAULT_FILL_COLOR); g2.fillRoundRect(x, y, w, h, RECT_ROUND, RECT_ROUND); g2.setColor(DEFAULT_STROKE_COLOR); g2.setStroke(DEFAULT_STROKE); g2.drawRoundRect(x, y, w, h, RECT_ROUND, RECT_ROUND); FontRenderContext frc = g2.getFontRenderContext(); Rectangle2D r2 = font.getStringBounds(name, frc); int xLabel = (int) (node.getX() + ((node.getWitdth() - r2.getWidth()) / 2)); int yLabel = (int) ((node.getY() + ((node.getHeight() - r2.getHeight()) / 2)) - r2.getY()); g2.setStroke(DEFAULT_LINE_STROKE); g2.setColor(Color.black); g2.drawString(name, xLabel, yLabel); } } } } |
工具类,用来计算一些坐标的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
Java代码 /** * CopyRight (C) 2006-2009 yy * @author yy * @project jbpm * @version 1.0 * @mail yy629_86 at 163 dot com * @date 2009-9-11 上午06:16:26 * @description */ package sofocus.bpm.jbpm.jpdl; import java.awt.Point; import java.awt.Rectangle; /** * @author yeyong * */ public class GeometryUtils { /** * 获得直线(x1,y1)-(x2,y2)的斜率 * * @param x1 * @param y1 * @param x2 * @param y2 * @return */ public static double getSlope(int x1, int y1, int x2, int y2) { return ((double) y2 - y1) / (x2 - x1); } /** * 获得直线(x1,y1)-(x2,y2)的y轴截距 * * @param x1 * @param y1 * @param x2 * @param y2 * @return */ public static double getYIntercep(int x1, int y1, int x2, int y2) { return y1 - x1 * getSlope(x1, y1, x2, y2); } /** * 获得矩形的中点 * * @param rect * @return */ public static Point getRectangleCenter(Rectangle rect) { return new Point((int) rect.getCenterX(), (int) rect.getCenterY()); } /** * 获得矩形中心p0与p1的线段和矩形的交点 * * @param rectangle * @param p1 * @return */ public static Point getRectangleLineCrossPoint(Rectangle rectangle, Point p1, int grow) { Rectangle rect = rectangle.getBounds(); rect.grow(grow, grow); Point p0 = GeometryUtils.getRectangleCenter(rect); if (p1.x == p0.x) { if (p1.y < p0.y) { return new Point(p0.x, rect.y); } return new Point(p0.x, rect.y + rect.height); } if (p1.y == p0.y) { if (p1.x < p0.x) { return new Point(rect.x, p0.y); } return new Point(rect.x + rect.width, p0.y); } double slope = GeometryUtils.getSlope(p0.x, p0.y, rect.x, rect.y); double slopeLine = GeometryUtils.getSlope(p0.x, p0.y, p1.x, p1.y); double yIntercep = GeometryUtils.getYIntercep(p0.x, p0.y, p1.x, p1.y); if (Math.abs(slopeLine) > slope - 1e-2) { if (p1.y < rect.y) { return new Point((int) ((rect.y - yIntercep) / slopeLine), rect.y); } else { return new Point((int) ((rect.y + rect.height - yIntercep) / slopeLine), rect.y + rect.height); } } if (p1.x < rect.x) { return new Point(rect.x, (int) (slopeLine * rect.x + yIntercep)); } else { return new Point(rect.x + rect.width, (int) (slopeLine * (rect.x + rect.width) + yIntercep)); } } } |
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Java代码 public static void main(String[] args) { try { File file = new File("D:/test.jpdl.xml"); InputStream is = new FileInputStream(file); JpdlModel jpdlModel = new JpdlModel(is); ImageIO.write(new JpdlModelDrawer().draw(jpdlModel), "png", new File("D:/test.png")); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } |