新增流程图
This commit is contained in:
parent
41c192e28b
commit
3602de227d
|
@ -128,7 +128,7 @@ public class FlowModelerController extends BaseController
|
|||
@ResponseBody
|
||||
public void getProcessDiagram(String processInstanceId,HttpServletResponse response)
|
||||
{
|
||||
flowableService.getProcessDiagram(response,processInstanceId);
|
||||
flowableService.getFlowableProcessImage(processInstanceId,response);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.snow.flowable.common.constants;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author qimingjin
|
||||
* @Title:
|
||||
|
@ -41,4 +43,14 @@ public class FlowConstants {
|
|||
* 流程开始用户标识
|
||||
*/
|
||||
public static final String START_USER_ID="startUserId";
|
||||
|
||||
|
||||
|
||||
|
||||
/** 动态流程图颜色定义 **/
|
||||
public static final Color COLOR_NORMAL = new Color(0, 205, 0);
|
||||
public static final Color COLOR_CURRENT = new Color(255, 0, 0);
|
||||
|
||||
/** 定义生成流程图时的边距(像素) **/
|
||||
public static final int PROCESS_PADDING = 5;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,246 @@
|
|||
package com.snow.flowable.config;
|
||||
|
||||
import com.snow.flowable.common.constants.FlowConstants;
|
||||
import org.flowable.bpmn.model.AssociationDirection;
|
||||
import org.flowable.bpmn.model.GraphicInfo;
|
||||
import org.flowable.image.exception.FlowableImageException;
|
||||
import org.flowable.image.impl.DefaultProcessDiagramCanvas;
|
||||
import org.flowable.image.util.ReflectUtil;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.LineBreakMeasurer;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.text.AttributedString;
|
||||
|
||||
public class CustomProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
|
||||
|
||||
protected static Color LABEL_COLOR = new Color(0, 0, 0);
|
||||
|
||||
//font
|
||||
protected String activityFontName = "宋体";
|
||||
protected String labelFontName = "宋体";
|
||||
protected String annotationFontName = "宋体";
|
||||
|
||||
private static volatile boolean flag = false;
|
||||
|
||||
public CustomProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType) {
|
||||
super(width, height, minX, minY, imageType);
|
||||
}
|
||||
|
||||
public CustomProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType,
|
||||
String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
|
||||
super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName,
|
||||
customClassLoader);
|
||||
}
|
||||
|
||||
public void drawHighLight(boolean isStartOrEnd, int x, int y, int width, int height, Color color) {
|
||||
Paint originalPaint = g.getPaint();
|
||||
Stroke originalStroke = g.getStroke();
|
||||
|
||||
g.setPaint(color);
|
||||
g.setStroke(MULTI_INSTANCE_STROKE);
|
||||
if (isStartOrEnd) {// 开始、结束节点画圆
|
||||
g.drawOval(x, y, width, height);
|
||||
} else {// 非开始、结束节点画圆角矩形
|
||||
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 5, 5);
|
||||
g.draw(rect);
|
||||
}
|
||||
g.setPaint(originalPaint);
|
||||
g.setStroke(originalStroke);
|
||||
}
|
||||
|
||||
public void drawSequenceflow(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault,
|
||||
boolean highLighted, double scaleFactor, Color color) {
|
||||
drawConnection(xPoints, yPoints, conditional, isDefault, "sequenceFlow", AssociationDirection.ONE, highLighted,
|
||||
scaleFactor, color);
|
||||
}
|
||||
|
||||
public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault,
|
||||
String connectionType, AssociationDirection associationDirection, boolean highLighted, double scaleFactor,
|
||||
Color color) {
|
||||
|
||||
Paint originalPaint = g.getPaint();
|
||||
Stroke originalStroke = g.getStroke();
|
||||
|
||||
g.setPaint(CONNECTION_COLOR);
|
||||
if (connectionType.equals("association")) {
|
||||
g.setStroke(ASSOCIATION_STROKE);
|
||||
} else if (highLighted) {
|
||||
g.setPaint(color);
|
||||
g.setStroke(HIGHLIGHT_FLOW_STROKE);
|
||||
}
|
||||
|
||||
for (int i = 1; i < xPoints.length; i++) {
|
||||
Integer sourceX = xPoints[i - 1];
|
||||
Integer sourceY = yPoints[i - 1];
|
||||
Integer targetX = xPoints[i];
|
||||
Integer targetY = yPoints[i];
|
||||
Line2D.Double line = new Line2D.Double(sourceX, sourceY, targetX, targetY);
|
||||
g.draw(line);
|
||||
}
|
||||
|
||||
if (isDefault) {
|
||||
Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
|
||||
drawDefaultSequenceFlowIndicator(line, scaleFactor);
|
||||
}
|
||||
|
||||
if (conditional) {
|
||||
Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
|
||||
drawConditionalSequenceFlowIndicator(line, scaleFactor);
|
||||
}
|
||||
|
||||
if (associationDirection.equals(AssociationDirection.ONE)
|
||||
|| associationDirection.equals(AssociationDirection.BOTH)) {
|
||||
Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], yPoints[xPoints.length - 2],
|
||||
xPoints[xPoints.length - 1], yPoints[xPoints.length - 1]);
|
||||
drawArrowHead(line, scaleFactor);
|
||||
}
|
||||
if (associationDirection.equals(AssociationDirection.BOTH)) {
|
||||
Line2D.Double line = new Line2D.Double(xPoints[1], yPoints[1], xPoints[0], yPoints[0]);
|
||||
drawArrowHead(line, scaleFactor);
|
||||
}
|
||||
g.setPaint(originalPaint);
|
||||
g.setStroke(originalStroke);
|
||||
}
|
||||
|
||||
public void drawLabel(boolean highLighted, String text, GraphicInfo graphicInfo, boolean centered) {
|
||||
float interline = 1.0f;
|
||||
|
||||
// text
|
||||
if (text != null && text.length() > 0) {
|
||||
Paint originalPaint = g.getPaint();
|
||||
Font originalFont = g.getFont();
|
||||
if (highLighted) {
|
||||
g.setPaint(FlowConstants.COLOR_NORMAL);
|
||||
} else {
|
||||
g.setPaint(LABEL_COLOR);
|
||||
}
|
||||
g.setFont(new Font(labelFontName, Font.BOLD, 10));
|
||||
|
||||
int wrapWidth = 100;
|
||||
int textY = (int) graphicInfo.getY();
|
||||
|
||||
// TODO: use drawMultilineText()
|
||||
AttributedString as = new AttributedString(text);
|
||||
as.addAttribute(TextAttribute.FOREGROUND, g.getPaint());
|
||||
as.addAttribute(TextAttribute.FONT, g.getFont());
|
||||
AttributedCharacterIterator aci = as.getIterator();
|
||||
FontRenderContext frc = new FontRenderContext(null, true, false);
|
||||
LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
|
||||
|
||||
while (lbm.getPosition() < text.length()) {
|
||||
TextLayout tl = lbm.nextLayout(wrapWidth);
|
||||
textY += tl.getAscent();
|
||||
Rectangle2D bb = tl.getBounds();
|
||||
double tX = graphicInfo.getX();
|
||||
if (centered) {
|
||||
tX += (int) (graphicInfo.getWidth() / 2 - bb.getWidth() / 2);
|
||||
}
|
||||
tl.draw(g, (float) tX, textY);
|
||||
textY += tl.getDescent() + tl.getLeading() + (interline - 1.0f) * tl.getAscent();
|
||||
}
|
||||
|
||||
// restore originals
|
||||
g.setFont(originalFont);
|
||||
g.setPaint(originalPaint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage generateBufferedImage(String imageType) {
|
||||
if (closed) {
|
||||
throw new FlowableImageException("ProcessDiagramGenerator already closed");
|
||||
}
|
||||
|
||||
// Try to remove white space
|
||||
minX = (minX <= FlowConstants.PROCESS_PADDING) ? FlowConstants.PROCESS_PADDING : minX;
|
||||
minY = (minY <= FlowConstants.PROCESS_PADDING) ? FlowConstants.PROCESS_PADDING : minY;
|
||||
BufferedImage imageToSerialize = processDiagram;
|
||||
if (minX >= 0 && minY >= 0) {
|
||||
imageToSerialize = processDiagram.getSubimage(
|
||||
minX - FlowConstants.PROCESS_PADDING,
|
||||
minY - FlowConstants.PROCESS_PADDING,
|
||||
canvasWidth - minX + FlowConstants.PROCESS_PADDING,
|
||||
canvasHeight - minY + FlowConstants.PROCESS_PADDING);
|
||||
}
|
||||
return imageToSerialize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(String imageType) {
|
||||
this.processDiagram = new BufferedImage(canvasWidth, canvasHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
this.g = processDiagram.createGraphics();
|
||||
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g.setPaint(Color.black);
|
||||
|
||||
Font font = new Font(activityFontName, Font.BOLD, FONT_SIZE);
|
||||
g.setFont(font);
|
||||
this.fontMetrics = g.getFontMetrics();
|
||||
|
||||
LABEL_FONT = new Font(labelFontName, Font.ITALIC, 10);
|
||||
ANNOTATION_FONT = new Font(annotationFontName, Font.PLAIN, FONT_SIZE);
|
||||
//优化加载速度
|
||||
if(flag) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
USERTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/userTask.png", customClassLoader));
|
||||
SCRIPTTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/scriptTask.png", customClassLoader));
|
||||
SERVICETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/serviceTask.png", customClassLoader));
|
||||
RECEIVETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/receiveTask.png", customClassLoader));
|
||||
SENDTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/sendTask.png", customClassLoader));
|
||||
MANUALTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/manualTask.png", customClassLoader));
|
||||
BUSINESS_RULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/businessRuleTask.png", customClassLoader));
|
||||
SHELL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/shellTask.png", customClassLoader));
|
||||
CAMEL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/camelTask.png", customClassLoader));
|
||||
MULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/muleTask.png", customClassLoader));
|
||||
|
||||
TIMER_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/timer.png", customClassLoader));
|
||||
COMPENSATE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/compensate-throw.png", customClassLoader));
|
||||
COMPENSATE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/compensate.png", customClassLoader));
|
||||
ERROR_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/error-throw.png", customClassLoader));
|
||||
ERROR_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/error.png", customClassLoader));
|
||||
MESSAGE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/message-throw.png", customClassLoader));
|
||||
MESSAGE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/message.png", customClassLoader));
|
||||
SIGNAL_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/signal-throw.png", customClassLoader));
|
||||
SIGNAL_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/signal.png", customClassLoader));
|
||||
/* String baseUrl = Thread.currentThread().getContextClassLoader().getResource("static/img/activiti/").getPath();
|
||||
SCRIPTTASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"scriptTask.png"));
|
||||
USERTASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"userTask.png"));
|
||||
SERVICETASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"serviceTask.png"));
|
||||
RECEIVETASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"receiveTask.png"));
|
||||
SENDTASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"sendTask.png"));
|
||||
MANUALTASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"manualTask.png"));
|
||||
BUSINESS_RULE_TASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"businessRuleTask.png"));
|
||||
SHELL_TASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"shellTask.png"));
|
||||
CAMEL_TASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"camelTask.png"));
|
||||
MULE_TASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"muleTask.png"));
|
||||
|
||||
TIMER_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"timer.png"));
|
||||
COMPENSATE_THROW_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"compensate-throw.png"));
|
||||
COMPENSATE_CATCH_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"compensate.png"));
|
||||
ERROR_THROW_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"error-throw.png"));
|
||||
ERROR_CATCH_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"error.png"));
|
||||
MESSAGE_THROW_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"message-throw.png"));
|
||||
MESSAGE_CATCH_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"message.png"));
|
||||
SIGNAL_THROW_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"signal-throw.png"));
|
||||
SIGNAL_CATCH_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"signal.png"));*/
|
||||
flag = true;
|
||||
} catch (IOException e) {
|
||||
flag = false;
|
||||
LOGGER.warn("Could not load image for process diagram creation: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,361 @@
|
|||
package com.snow.flowable.config;
|
||||
|
||||
import org.flowable.bpmn.model.*;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.image.impl.DefaultProcessDiagramGenerator;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Component
|
||||
public class CustomProcessDiagramGenerator extends DefaultProcessDiagramGenerator implements ICustomProcessDiagramGenerator{
|
||||
//预初始化流程图绘制,大大提升了系统启动后首次查看流程图的速度
|
||||
static {
|
||||
new CustomProcessDiagramCanvas(10,10,0,0,"png", "宋体","宋体","宋体",null);
|
||||
}
|
||||
|
||||
public CustomProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType,
|
||||
List<String> highLightedActivities, List<String> highLightedFlows, String activityFontName,
|
||||
String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor,
|
||||
Color[] colors, Set<String> currIds) {
|
||||
|
||||
if(null == highLightedActivities) {
|
||||
highLightedActivities = Collections.<String>emptyList();
|
||||
}
|
||||
if(null == highLightedFlows) {
|
||||
highLightedFlows = Collections.<String>emptyList();
|
||||
}
|
||||
|
||||
prepareBpmnModel(bpmnModel);
|
||||
|
||||
CustomProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
|
||||
|
||||
// Draw pool shape, if process is participant in collaboration
|
||||
for (Pool pool : bpmnModel.getPools()) {
|
||||
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
|
||||
processDiagramCanvas.drawPoolOrLane(pool.getName(), graphicInfo,scaleFactor);
|
||||
}
|
||||
|
||||
// Draw lanes
|
||||
for (Process process : bpmnModel.getProcesses()) {
|
||||
for (Lane lane : process.getLanes()) {
|
||||
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId());
|
||||
processDiagramCanvas.drawPoolOrLane(lane.getName(), graphicInfo,scaleFactor);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw activities and their sequence-flows
|
||||
for (Process process: bpmnModel.getProcesses()) {
|
||||
List<FlowNode> flowNodeList= process.findFlowElementsOfType(FlowNode.class);
|
||||
for (FlowNode flowNode : flowNodeList) {
|
||||
drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, scaleFactor, colors, currIds);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw artifacts
|
||||
for (Process process : bpmnModel.getProcesses()) {
|
||||
|
||||
for (Artifact artifact : process.getArtifacts()) {
|
||||
drawArtifact(processDiagramCanvas, bpmnModel, artifact);
|
||||
}
|
||||
|
||||
List<SubProcess> subProcesses = process.findFlowElementsOfType(SubProcess.class, true);
|
||||
if (subProcesses != null) {
|
||||
for (SubProcess subProcess : subProcesses) {
|
||||
for (Artifact subProcessArtifact : subProcess.getArtifacts()) {
|
||||
drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return processDiagramCanvas;
|
||||
}
|
||||
|
||||
protected void drawActivity(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode,
|
||||
List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor, Color[] colors, Set<String> currIds) {
|
||||
ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass());
|
||||
if (drawInstruction != null) {
|
||||
|
||||
drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode);
|
||||
|
||||
// Gather info on the multi instance marker
|
||||
boolean multiInstanceSequential = false, multiInstanceParallel = false, collapsed = false;
|
||||
if (flowNode instanceof Activity) {
|
||||
Activity activity = (Activity) flowNode;
|
||||
MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics();
|
||||
if (multiInstanceLoopCharacteristics != null) {
|
||||
multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential();
|
||||
multiInstanceParallel = !multiInstanceSequential;
|
||||
}
|
||||
}
|
||||
|
||||
// Gather info on the collapsed marker
|
||||
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
|
||||
if (flowNode instanceof SubProcess) {
|
||||
collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded();
|
||||
} else if (flowNode instanceof CallActivity) {
|
||||
collapsed = true;
|
||||
}
|
||||
|
||||
if (scaleFactor == 1.0) {
|
||||
// Actually draw the markers
|
||||
processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(),(int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(),
|
||||
multiInstanceSequential, multiInstanceParallel, collapsed);
|
||||
}
|
||||
|
||||
// Draw highlighted activities
|
||||
if (highLightedActivities.contains(flowNode.getId())) {
|
||||
if(!CollectionUtils.isEmpty(currIds)
|
||||
&&currIds.contains(flowNode.getId())
|
||||
&& !(flowNode instanceof Gateway)) {//非结束节点,并且是当前节点
|
||||
drawHighLight((flowNode instanceof StartEvent), processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()), colors[1]);
|
||||
}else {//普通节点
|
||||
drawHighLight((flowNode instanceof StartEvent)||(flowNode instanceof EndEvent),processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()), colors[0]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Outgoing transitions of activity
|
||||
for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
|
||||
String flowId = sequenceFlow.getId();
|
||||
boolean highLighted = (highLightedFlows.contains(flowId));
|
||||
String defaultFlow = null;
|
||||
if (flowNode instanceof Activity) {
|
||||
defaultFlow = ((Activity) flowNode).getDefaultFlow();
|
||||
} else if (flowNode instanceof Gateway) {
|
||||
defaultFlow = ((Gateway) flowNode).getDefaultFlow();
|
||||
}
|
||||
|
||||
boolean isDefault = false;
|
||||
if (defaultFlow != null && defaultFlow.equalsIgnoreCase(flowId)) {
|
||||
isDefault = true;
|
||||
}
|
||||
// boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null && !(flowNode instanceof Gateway);
|
||||
|
||||
String sourceRef = sequenceFlow.getSourceRef();
|
||||
String targetRef = sequenceFlow.getTargetRef();
|
||||
FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef);
|
||||
FlowElement targetElement = bpmnModel.getFlowElement(targetRef);
|
||||
List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(flowId);
|
||||
if (graphicInfoList != null && graphicInfoList.size() > 0) {
|
||||
graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList);
|
||||
int xPoints[]= new int[graphicInfoList.size()];
|
||||
int yPoints[]= new int[graphicInfoList.size()];
|
||||
|
||||
for (int i=1; i<graphicInfoList.size(); i++) {
|
||||
GraphicInfo graphicInfo = graphicInfoList.get(i);
|
||||
GraphicInfo previousGraphicInfo = graphicInfoList.get(i-1);
|
||||
|
||||
if (i == 1) {
|
||||
xPoints[0] = (int) previousGraphicInfo.getX();
|
||||
yPoints[0] = (int) previousGraphicInfo.getY();
|
||||
}
|
||||
xPoints[i] = (int) graphicInfo.getX();
|
||||
yPoints[i] = (int) graphicInfo.getY();
|
||||
|
||||
}
|
||||
//画高亮线
|
||||
processDiagramCanvas.drawSequenceflow(xPoints, yPoints, false, isDefault, highLighted, scaleFactor, colors[0]);
|
||||
|
||||
// Draw sequenceflow label
|
||||
// GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(flowId);
|
||||
// if (labelGraphicInfo != null) {
|
||||
// processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false);
|
||||
// }else {//解决流程图连线名称不显示的BUG
|
||||
GraphicInfo lineCenter = getLineCenter(graphicInfoList);
|
||||
processDiagramCanvas.drawLabel(highLighted, sequenceFlow.getName(), lineCenter, Math.abs(xPoints[1]-xPoints[0]) >= 5);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
// Nested elements
|
||||
if (flowNode instanceof FlowElementsContainer) {
|
||||
for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) {
|
||||
if (nestedFlowElement instanceof FlowNode) {
|
||||
drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement, highLightedActivities, highLightedFlows, scaleFactor,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
protected void drawHighLight(boolean isStartOrEnd, CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo, Color color) {
|
||||
processDiagramCanvas.drawHighLight(isStartOrEnd, (int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(), color);
|
||||
}
|
||||
|
||||
protected static CustomProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType,
|
||||
String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
|
||||
|
||||
// We need to calculate maximum values to know how big the image will be in its entirety
|
||||
double minX = Double.MAX_VALUE;
|
||||
double maxX = 0;
|
||||
double minY = Double.MAX_VALUE;
|
||||
double maxY = 0;
|
||||
|
||||
for (Pool pool : bpmnModel.getPools()) {
|
||||
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
|
||||
minX = graphicInfo.getX();
|
||||
maxX = graphicInfo.getX() + graphicInfo.getWidth();
|
||||
minY = graphicInfo.getY();
|
||||
maxY = graphicInfo.getY() + graphicInfo.getHeight();
|
||||
}
|
||||
|
||||
List<FlowNode> flowNodes = gatherAllFlowNodes(bpmnModel);
|
||||
for (FlowNode flowNode : flowNodes) {
|
||||
|
||||
GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
|
||||
|
||||
// width
|
||||
if (flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) {
|
||||
maxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth();
|
||||
}
|
||||
if (flowNodeGraphicInfo.getX() < minX) {
|
||||
minX = flowNodeGraphicInfo.getX();
|
||||
}
|
||||
// height
|
||||
if (flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) {
|
||||
maxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight();
|
||||
}
|
||||
if (flowNodeGraphicInfo.getY() < minY) {
|
||||
minY = flowNodeGraphicInfo.getY();
|
||||
}
|
||||
|
||||
for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
|
||||
List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
|
||||
if (graphicInfoList != null) {
|
||||
for (GraphicInfo graphicInfo : graphicInfoList) {
|
||||
// width
|
||||
if (graphicInfo.getX() > maxX) {
|
||||
maxX = graphicInfo.getX();
|
||||
}
|
||||
if (graphicInfo.getX() < minX) {
|
||||
minX = graphicInfo.getX();
|
||||
}
|
||||
// height
|
||||
if (graphicInfo.getY() > maxY) {
|
||||
maxY = graphicInfo.getY();
|
||||
}
|
||||
if (graphicInfo.getY()< minY) {
|
||||
minY = graphicInfo.getY();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Artifact> artifacts = gatherAllArtifacts(bpmnModel);
|
||||
for (Artifact artifact : artifacts) {
|
||||
|
||||
GraphicInfo artifactGraphicInfo = bpmnModel.getGraphicInfo(artifact.getId());
|
||||
|
||||
if (artifactGraphicInfo != null) {
|
||||
// width
|
||||
if (artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth() > maxX) {
|
||||
maxX = artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth();
|
||||
}
|
||||
if (artifactGraphicInfo.getX() < minX) {
|
||||
minX = artifactGraphicInfo.getX();
|
||||
}
|
||||
// height
|
||||
if (artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight() > maxY) {
|
||||
maxY = artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight();
|
||||
}
|
||||
if (artifactGraphicInfo.getY() < minY) {
|
||||
minY = artifactGraphicInfo.getY();
|
||||
}
|
||||
}
|
||||
|
||||
List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId());
|
||||
if (graphicInfoList != null) {
|
||||
for (GraphicInfo graphicInfo : graphicInfoList) {
|
||||
// width
|
||||
if (graphicInfo.getX() > maxX) {
|
||||
maxX = graphicInfo.getX();
|
||||
}
|
||||
if (graphicInfo.getX() < minX) {
|
||||
minX = graphicInfo.getX();
|
||||
}
|
||||
// height
|
||||
if (graphicInfo.getY() > maxY) {
|
||||
maxY = graphicInfo.getY();
|
||||
}
|
||||
if (graphicInfo.getY()< minY) {
|
||||
minY = graphicInfo.getY();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nrOfLanes = 0;
|
||||
for (Process process : bpmnModel.getProcesses()) {
|
||||
for (Lane l : process.getLanes()) {
|
||||
|
||||
nrOfLanes++;
|
||||
|
||||
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId());
|
||||
// // width
|
||||
if (graphicInfo.getX() + graphicInfo.getWidth() > maxX) {
|
||||
maxX = graphicInfo.getX() + graphicInfo.getWidth();
|
||||
}
|
||||
if (graphicInfo.getX() < minX) {
|
||||
minX = graphicInfo.getX();
|
||||
}
|
||||
// height
|
||||
if (graphicInfo.getY() + graphicInfo.getHeight() > maxY) {
|
||||
maxY = graphicInfo.getY() + graphicInfo.getHeight();
|
||||
}
|
||||
if (graphicInfo.getY() < minY) {
|
||||
minY = graphicInfo.getY();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Special case, see https://activiti.atlassian.net/browse/ACT-1431
|
||||
if (flowNodes.isEmpty() && bpmnModel.getPools().isEmpty() && nrOfLanes == 0) {
|
||||
// Nothing to show
|
||||
minX = 0;
|
||||
minY = 0;
|
||||
}
|
||||
|
||||
return new CustomProcessDiagramCanvas((int) maxX + 10,(int) maxY + 10, (int) minX, (int) minY,
|
||||
imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities,
|
||||
List<String> highLightedFlows, String activityFontName, String labelFontName, String annotationFontName,
|
||||
ClassLoader customClassLoader, double scaleFactor, Color[] colors, Set<String> currIds) {
|
||||
CustomProcessDiagramCanvas customProcessDiagramCanvas = generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows,
|
||||
activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor,colors, currIds);
|
||||
BufferedImage bufferedImage = customProcessDiagramCanvas.generateBufferedImage(imageType);
|
||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||
ImageOutputStream imOut;
|
||||
try {
|
||||
imOut = ImageIO.createImageOutputStream(bs);
|
||||
ImageIO.write(bufferedImage, "PNG", imOut);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
InputStream is = new ByteArrayInputStream(bs.toByteArray());
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
|
||||
return generateDiagram(bpmnModel, imageType, Collections.<String>emptyList(), Collections.<String>emptyList(),
|
||||
activityFontName, labelFontName, annotationFontName, customClassLoader, 1.0, new Color[] {Color.BLACK, Color.BLACK}, null);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,14 +1,25 @@
|
|||
package com.snow.flowable.config;
|
||||
|
||||
import cn.hutool.bloomfilter.BitMapBloomFilter;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.lang.Snowflake;
|
||||
import cn.hutool.core.thread.ConcurrencyTester;
|
||||
import cn.hutool.core.thread.ExecutorBuilder;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.crypto.asymmetric.RSA;
|
||||
import cn.hutool.dfa.WordTree;
|
||||
import cn.hutool.poi.word.Word07Writer;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.flowable.common.engine.impl.cfg.IdGenerator;
|
||||
|
||||
import cn.hutool.core.lang.Console;
|
||||
|
||||
import java.awt.*;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
|
@ -29,8 +40,28 @@ public class FlowIdGenerator implements IdGenerator {
|
|||
|
||||
//很多时候,我们需要简单模拟N个线程调用某个业务测试其并发状况,于是Hutool提供了一个简单的并发测试类——ConcurrencyTester。
|
||||
public static void main(String[] args) {
|
||||
RSA rsa = new RSA();
|
||||
|
||||
ThreadPoolExecutor executor = ExecutorBuilder.create().
|
||||
//获得私钥
|
||||
PrivateKey privateKey = rsa.getPrivateKey();
|
||||
|
||||
//获得公钥
|
||||
PublicKey publicKey = rsa.getPublicKey();
|
||||
Console.log("privateKey:{}",privateKey.getEncoded());
|
||||
Console.log("publicKey:{}",publicKey.getEncoded());
|
||||
|
||||
/* Word07Writer writer = new Word07Writer();
|
||||
|
||||
// 添加段落(标题)
|
||||
writer.addText(new Font("方正小标宋简体", Font.PLAIN, 22), "我是第一部分", "我是第二部分");
|
||||
// 添加段落(正文)
|
||||
writer.addText(new Font("宋体", Font.PLAIN, 22), "我是正文第一部分", "我是正文第二部分");
|
||||
// 写出到文件
|
||||
writer.flush(FileUtil.file("d:/wordWrite.docx"));
|
||||
// 关闭
|
||||
writer.close();
|
||||
*/
|
||||
/* ThreadPoolExecutor executor = ExecutorBuilder.create().
|
||||
setCorePoolSize(5).
|
||||
setMaxPoolSize(10).
|
||||
setWorkQueue(new LinkedBlockingQueue<>(100))
|
||||
|
@ -46,7 +77,7 @@ public class FlowIdGenerator implements IdGenerator {
|
|||
}
|
||||
}
|
||||
});
|
||||
executor.shutdown();
|
||||
executor.shutdown();*/
|
||||
|
||||
/* ConcurrencyTester tester = ThreadUtil.concurrencyTest(100, () -> {
|
||||
// 测试的逻辑内容
|
||||
|
|
|
@ -7,6 +7,7 @@ import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
|
|||
import org.flowable.common.engine.impl.EngineDeployer;
|
||||
import org.flowable.engine.impl.rules.RulesDeployer;
|
||||
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -26,7 +27,8 @@ import java.util.Map;
|
|||
@Configuration
|
||||
@Slf4j
|
||||
public class FlowableConfig {
|
||||
|
||||
@Autowired
|
||||
private ICustomProcessDiagramGenerator customProcessDiagramGenerator;
|
||||
|
||||
@Primary
|
||||
@Bean(name = "processEngineConfiguration")
|
||||
|
@ -36,6 +38,7 @@ public class FlowableConfig {
|
|||
configuration.setTransactionManager(transactionManager);
|
||||
configuration.setDatabaseSchemaUpdate("false");
|
||||
configuration.setAsyncExecutorActivate(true);
|
||||
configuration.setProcessDiagramGenerator(customProcessDiagramGenerator);
|
||||
//修改id生成器
|
||||
configuration.setIdGenerator(new FlowIdGenerator());
|
||||
configuration.setCustomPostDeployers(new ArrayList<EngineDeployer>(){
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.snow.flowable.config;
|
||||
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.image.ProcessDiagramGenerator;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public interface ICustomProcessDiagramGenerator extends ProcessDiagramGenerator {
|
||||
InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities,
|
||||
List<String> highLightedFlows, String activityFontName, String labelFontName, String annotationFontName,
|
||||
ClassLoader customClassLoader, double scaleFactor, Color[] colors, Set<String> currIds);
|
||||
}
|
|
@ -114,7 +114,7 @@ public class HistoricTaskInstanceVO implements Serializable {
|
|||
*/
|
||||
private Map<String, Object> processVariables;
|
||||
|
||||
private List<? extends IdentityLinkInfo> identityLinks;
|
||||
|
||||
/* private String scopeId;
|
||||
private String subScopeId;
|
||||
private String scopeType;
|
||||
|
@ -150,7 +150,6 @@ public class HistoricTaskInstanceVO implements Serializable {
|
|||
historicTaskInstanceVO.setTaskLocalVariables(t.getTaskLocalVariables());
|
||||
|
||||
historicTaskInstanceVO.setProcessVariables(t.getProcessVariables());
|
||||
historicTaskInstanceVO.setIdentityLinks(t.getIdentityLinks());
|
||||
return historicTaskInstanceVO;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
|
|
@ -159,4 +159,9 @@ public interface FlowableService {
|
|||
* @return
|
||||
*/
|
||||
PageModel<HistoricTaskInstanceVO> getHistoricTaskInstance(HistoricTaskInstanceDTO historicTaskInstanceDTO);
|
||||
|
||||
/**
|
||||
* 获取流程图像,已执行节点和流程线高亮显示
|
||||
*/
|
||||
void getFlowableProcessImage(String processInstanceId, HttpServletResponse response);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.snow.common.core.page.PageModel;
|
|||
import com.snow.common.core.text.Convert;
|
||||
import com.snow.common.exception.BusinessException;
|
||||
import com.snow.flowable.common.constants.FlowConstants;
|
||||
import com.snow.flowable.config.ICustomProcessDiagramGenerator;
|
||||
import com.snow.flowable.domain.*;
|
||||
import com.snow.flowable.enums.FlowFinishedStatusEnum;
|
||||
import com.snow.flowable.service.FlowableService;
|
||||
|
@ -32,6 +33,8 @@ import org.flowable.engine.*;
|
|||
import org.flowable.engine.history.HistoricActivityInstance;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.engine.history.HistoricProcessInstanceQuery;
|
||||
import org.flowable.engine.impl.RepositoryServiceImpl;
|
||||
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
|
||||
import org.flowable.engine.repository.*;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.engine.task.Attachment;
|
||||
|
@ -52,11 +55,14 @@ import org.springframework.util.StringUtils;
|
|||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.awt.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
@ -876,7 +882,142 @@ public class FlowableServiceImpl implements FlowableService {
|
|||
return taskVOList;
|
||||
}
|
||||
|
||||
public String getUserNameById(String id){
|
||||
public String getUserNameById(String id){
|
||||
return sysUserService.selectUserById(Long.parseLong(id)).getUserName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程图像,已执行节点和流程线高亮显示
|
||||
*/
|
||||
@Override
|
||||
public void getFlowableProcessImage(String processInstanceId, HttpServletResponse response) {
|
||||
log.info("[开始]-获取流程图图像");
|
||||
try {
|
||||
// 获取历史流程实例
|
||||
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
|
||||
.processInstanceId(processInstanceId).singleResult();
|
||||
|
||||
if (historicProcessInstance == null) {
|
||||
throw new BusinessException("获取流程实例ID[" + processInstanceId + "]对应的历史流程实例失败!");
|
||||
}
|
||||
else {
|
||||
// 获取流程定义
|
||||
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
|
||||
.getDeployedProcessDefinition(historicProcessInstance.getProcessDefinitionId());
|
||||
|
||||
// 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
|
||||
List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
|
||||
.processInstanceId(processInstanceId).orderByHistoricActivityInstanceId().asc().list();
|
||||
|
||||
// 已执行的节点ID集合
|
||||
List<String> executedActivityIdList = new ArrayList<String>();
|
||||
int index = 1;
|
||||
for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
|
||||
executedActivityIdList.add(activityInstance.getActivityId());
|
||||
//logger.info("第[" + index + "]个已执行节点=" + activityInstance.getActivityId() + " : " +activityInstance.getActivityName());
|
||||
index++;
|
||||
}
|
||||
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
|
||||
|
||||
// 已执行的线集合
|
||||
List<String> flowIds = Lists.newArrayList();
|
||||
// 获取流程走过的线 (getHighLightedFlows是下面的方法)
|
||||
flowIds = getHighLightedFlows(bpmnModel,processDefinition, historicActivityInstanceList);
|
||||
|
||||
Set<String> currIds = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).list()
|
||||
.stream().map(e->e.getActivityId()).collect(Collectors.toSet());
|
||||
|
||||
ICustomProcessDiagramGenerator diagramGenerator = (ICustomProcessDiagramGenerator) processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
|
||||
InputStream imageStream = diagramGenerator.generateDiagram(bpmnModel, "png", executedActivityIdList,
|
||||
flowIds, "宋体", "宋体", "宋体", null, 1.0,
|
||||
new Color[] { FlowConstants.COLOR_NORMAL, FlowConstants.COLOR_CURRENT }, currIds);
|
||||
|
||||
response.setContentType("image/png");
|
||||
OutputStream os = response.getOutputStream();
|
||||
int bytesRead = 0;
|
||||
byte[] buffer = new byte[8192];
|
||||
while ((bytesRead = imageStream.read(buffer, 0, 8192)) != -1) {
|
||||
os.write(buffer, 0, bytesRead);
|
||||
}
|
||||
os.close();
|
||||
imageStream.close();
|
||||
}
|
||||
log.info("[完成]-获取流程图图像");
|
||||
} catch (Exception e) {
|
||||
log.error("【异常】-获取流程图失败!" + e.getMessage());
|
||||
throw new BusinessException("获取流程图失败!" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getHighLightedFlows(BpmnModel bpmnModel,ProcessDefinitionEntity processDefinitionEntity,List<HistoricActivityInstance> historicActivityInstances) {
|
||||
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //24小时制
|
||||
List<String> highFlows = new ArrayList<String>();// 用以保存高亮的线flowId
|
||||
for (int i = 0; i < historicActivityInstances.size() - 1; i++) {
|
||||
// 对历史流程节点进行遍历
|
||||
// 得到节点定义的详细信息
|
||||
FlowNode activityImpl=null;
|
||||
FlowElement flowElement1 = bpmnModel.getFlowElement(historicActivityInstances.get(i).getActivityId());
|
||||
if(flowElement1 instanceof FlowNode){
|
||||
activityImpl = (FlowNode)bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(i).getActivityId());
|
||||
}
|
||||
// 用以保存后续开始时间相同的节点
|
||||
List<FlowNode> sameStartTimeNodes = Lists.newArrayList();
|
||||
FlowNode sameActivityImpl1 = null;
|
||||
|
||||
HistoricActivityInstance activityImpl_ = historicActivityInstances.get(i);// 第一个节点
|
||||
HistoricActivityInstance activityImp2_ ;
|
||||
|
||||
for(int k = i + 1 ; k <= historicActivityInstances.size() - 1; k++) {
|
||||
activityImp2_ = historicActivityInstances.get(k);// 后续第1个节点
|
||||
//都是usertask,且主节点与后续节点的开始时间相同,说明不是真实的后继节点
|
||||
if ( activityImpl_.getActivityType().equals("userTask") && activityImp2_.getActivityType().equals("userTask") &&
|
||||
df.format(activityImpl_.getStartTime()).equals(df.format(activityImp2_.getStartTime())) )
|
||||
{
|
||||
|
||||
}
|
||||
else {
|
||||
FlowElement flowElement = bpmnModel.getFlowElement(historicActivityInstances.get(k).getActivityId());
|
||||
if(flowElement instanceof FlowNode){
|
||||
sameActivityImpl1 = (FlowNode)bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(k).getActivityId());//找到紧跟在后面的一个节点
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
sameStartTimeNodes.add(sameActivityImpl1); // 将后面第一个节点放在时间相同节点的集合里
|
||||
for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) {
|
||||
HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);// 后续第一个节点
|
||||
HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);// 后续第二个节点
|
||||
|
||||
if (df.format(activityImpl1.getStartTime()).equals(df.format(activityImpl2.getStartTime())) )
|
||||
{// 如果第一个节点和第二个节点开始时间相同保存
|
||||
FlowElement flowElement = bpmnModel.getFlowElement(activityImpl2.getActivityId());
|
||||
if(flowElement instanceof FlowNode){
|
||||
FlowNode sameActivityImpl2 = (FlowNode)bpmnModel.getMainProcess().getFlowElement(activityImpl2.getActivityId());
|
||||
sameStartTimeNodes.add(sameActivityImpl2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{// 有不相同跳出循环
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!StringUtils.isEmpty(activityImpl)){
|
||||
List<SequenceFlow> pvmTransitions = activityImpl.getOutgoingFlows() ; // 取出节点的所有出去的线
|
||||
|
||||
for (SequenceFlow pvmTransition : pvmTransitions)
|
||||
{// 对所有的线进行遍历
|
||||
FlowElement flowElement = bpmnModel.getFlowElement(pvmTransition.getTargetRef());
|
||||
if(flowElement instanceof FlowNode){
|
||||
FlowNode pvmActivityImpl = (FlowNode)bpmnModel.getMainProcess().getFlowElement( pvmTransition.getTargetRef());// 如果取出的线的目标节点存在时间相同的节点里,保存该线的id,进行高亮显示
|
||||
if (sameStartTimeNodes.contains(pvmActivityImpl)) {
|
||||
highFlows.add(pvmTransition.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return highFlows;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue