activiti动态创建流程图

1. pom依赖
  <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter-basic</artifactId>
            <version>5.23.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>mybatis</artifactId>
                    <groupId>org.mybatis</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- activiti 布局 -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-bpmn-layout</artifactId>
            <version>5.23.0</version>
        </dependency>
2. 简单封装下工具类
package com.yl.util;

import org.activiti.bpmn.model.EndEvent;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.StartEvent;
import org.activiti.bpmn.model.UserTask;

import java.util.UUID;

/**
 * activiti动态创建流程工具类
 *
 * @author liuxb
 * @date 2022/10/28 10:25
 */
public class DynamicActivitiUtil {
    /**
     * 创建任务节点
     * @param id
     * @param name
     * @param assignee
     * @return
     */
    public static UserTask createUserTask(String id, String name, String assignee) {
        UserTask userTask = new UserTask();
        userTask.setName(name);
        userTask.setId(id);
        userTask.setAssignee(assignee);
        return userTask;
    }

    /**
     * 创建连接线
     * @param from
     * @param to
     * @return
     */
    public static SequenceFlow createSequenceFlow(String from, String to) {
        SequenceFlow flow = new SequenceFlow();
        flow.setSourceRef(from);
        flow.setTargetRef(to);
        return flow;
    }

    /**
     * 创建开始节点
     * @return
     */
    public static StartEvent createStartEvent() {
        StartEvent startEvent = new StartEvent();
        startEvent.setId("start");
        startEvent.setName("start");
        return startEvent;
    }

    /**
     * 创建结束节点
     * @param endNumber 结束节点编号
     * @return
     */
    public static EndEvent createEndEvent(Integer endNumber) {
        EndEvent endEvent = new EndEvent();
        if(endNumber != null){
            endEvent.setId("end" + endNumber);
        }else{
            endEvent.setId("end");
        }
        endEvent.setName("end");
        return endEvent;
    }

}

其他工具类

package com.yl.util;


import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.*;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.javax.el.ExpressionFactory;
import org.activiti.engine.impl.javax.el.ValueExpression;
import org.activiti.engine.impl.juel.ExpressionFactoryImpl;
import org.activiti.engine.impl.juel.SimpleContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.task.Task;

import java.util.List;
import java.util.Map;

/**
 * 任务工具类,activiti5,6都支持
 *
 * @author liuxb
 * @version 1.0
 * @date 2021年10月3日 下午12:43:02
 */
@Slf4j
public class TaskUtil {
    private RuntimeService runtimeService;
    private RepositoryService repositoryService;
    private TaskService taskService;

    public TaskUtil(RuntimeService runtimeService, RepositoryService repositoryService, TaskService taskService) {
        this.runtimeService = runtimeService;
        this.repositoryService = repositoryService;
        this.taskService = taskService;
    }

    /**
     * 获取下一个审批节点
     *
     * @param processInstId 流程实例ID
     * @param varMap        流程变量,用于判断走哪一条线
     * @return
     */
    public FlowNode getNextUserTask(String processInstId, Map<String, Object> varMap) {
        //待办任务
        List<Task> taskList = taskService.createTaskQuery()
                .processInstanceId(processInstId)
                .list();
        if (taskList.isEmpty()) {
            throw new ActivitiException("流程实例不存在或者流程已结束");
        }

        ExecutionEntity execution = (ExecutionEntity) runtimeService.createExecutionQuery()
                .executionId(taskList.get(0).getExecutionId())
                .singleResult();

        // 当前任务的节点
        BpmnModel bpmnModel = repositoryService.getBpmnModel(taskList.get(0).getProcessDefinitionId());
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(execution.getActivityId());

        return getNextFlowNode(bpmnModel, flowNode, varMap);
    }


    /**
     * 获取下一个节点
     *
     * @param bpmnModel 流程对象模型
     * @param flowNode  当前审批节点
     * @param varMap    流程变量,用于判断走哪一条线
     * @return
     */
    private FlowNode getNextFlowNode(BpmnModel bpmnModel, FlowNode flowNode, Map<String, Object> varMap) {
        //下一个节点
        FlowNode nextFlowNode = getNextFlowNode(bpmnModel, flowNode.getOutgoingFlows(), varMap);

        if (nextFlowNode instanceof EndEvent) {
            return nextFlowNode;
        } else if (nextFlowNode instanceof Gateway) {
            log.info("{}, 下一个节点为网管,需要继续获取输出连线", flowNode.getId() + " --> " + nextFlowNode.getId());

            return getNextFlowNode(bpmnModel, nextFlowNode.getOutgoingFlows(), varMap);
        } else if (nextFlowNode instanceof UserTask) {
            return nextFlowNode;
        } else {
            //其他节点类型
            throw new ActivitiException("下一个节点名为" + nextFlowNode.getName() + "不支持用户任务审批");
        }
    }

    /**
     * 获取下一个节点
     *
     * @param bpmnModel        流程对象模型
     * @param sequenceFlowList 连线列表
     * @param varMap           流程变量
     * @return
     */
    private FlowNode getNextFlowNode(BpmnModel bpmnModel, List<SequenceFlow> sequenceFlowList, Map<String, Object> varMap) {
        if (sequenceFlowList == null || sequenceFlowList.isEmpty()) {
            throw new ActivitiException("输出连线为空");
        } else if (sequenceFlowList.size() == 1) {
            return (FlowNode) bpmnModel.getFlowElement(sequenceFlowList.get(0).getTargetRef());
        } else {
            for (SequenceFlow sequenceFlow : sequenceFlowList) {
                if (parseJuel(sequenceFlow.getConditionExpression(), varMap)) {
                    return (FlowNode) bpmnModel.getFlowElement(sequenceFlow.getTargetRef());
                }
            }
        }
        return null;
    }

    /**
     * 计算juel表达式
     *
     * @param el
     * @param varMap
     * @return
     */
    public boolean parseJuel(String el, Map<String, Object> varMap) {
        ExpressionFactory factory = new ExpressionFactoryImpl();
        SimpleContext context = new SimpleContext();
        for (Map.Entry<String, Object> entry : varMap.entrySet()) {
            Object value = entry.getValue();
            if (value != null) {
                context.setVariable(entry.getKey(), factory.createValueExpression(value, value.getClass()));
            }
        }
        ValueExpression e = factory.createValueExpression(context, el, boolean.class);
        return (Boolean) e.getValue(context);
    }
}

重写DefaultProcessDiagramGenerator类,实现连线上显示文字
修改这里
在这里插入图片描述

/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.yl.converter;

import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.image.impl.DefaultProcessDiagramCanvas;

import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.util.*;

/**
 * Class to generate an image based the diagram interchange information in a BPMN 2.0 process.
 * 改写org.activiti.image.impl.DefaultProcessDiagramGenerator类,实现连线显示文字
 *
 * @author Joram Barrez
 * @author Tijs Rademakers
 */
public class DefaultProcessDiagramGenerator implements ProcessDiagramGenerator {

  protected Map<Class<? extends BaseElement>, ActivityDrawInstruction> activityDrawInstructions = new HashMap<Class<? extends BaseElement>, ActivityDrawInstruction>();
  protected Map<Class<? extends BaseElement>, ArtifactDrawInstruction> artifactDrawInstructions = new HashMap<Class<? extends BaseElement>, ArtifactDrawInstruction>();
  
  public DefaultProcessDiagramGenerator() {
    this(1.0);
  }
  
  // The instructions on how to draw a certain construct is
  // created statically and stored in a map for performance.
  public DefaultProcessDiagramGenerator(final double scaleFactor) {
    // start event
    activityDrawInstructions.put(StartEvent.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        StartEvent startEvent = (StartEvent) flowNode;
        if (startEvent.getEventDefinitions() != null && !startEvent.getEventDefinitions().isEmpty()) {
          EventDefinition eventDefinition = startEvent.getEventDefinitions().get(0);
          if (eventDefinition instanceof TimerEventDefinition) {
            processDiagramCanvas.drawTimerStartEvent(graphicInfo, scaleFactor);
          } else if (eventDefinition instanceof ErrorEventDefinition) {
            processDiagramCanvas.drawErrorStartEvent(graphicInfo, scaleFactor);
          } else if (eventDefinition instanceof SignalEventDefinition) {
            processDiagramCanvas.drawSignalStartEvent(graphicInfo, scaleFactor);
          } else if (eventDefinition instanceof MessageEventDefinition) {
            processDiagramCanvas.drawMessageStartEvent(graphicInfo, scaleFactor);
          } else {
            processDiagramCanvas.drawNoneStartEvent(graphicInfo);
          }
        } else {
          processDiagramCanvas.drawNoneStartEvent(graphicInfo);
        }
      }
    });

    // signal catch
    activityDrawInstructions.put(IntermediateCatchEvent.class, new ActivityDrawInstruction() {
      
      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        IntermediateCatchEvent intermediateCatchEvent = (IntermediateCatchEvent) flowNode;
        if (intermediateCatchEvent.getEventDefinitions() != null && !intermediateCatchEvent.getEventDefinitions()
                                                                                           .isEmpty()) {
          if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) {
            processDiagramCanvas.drawCatchingSignalEvent(flowNode.getName(), graphicInfo, true, scaleFactor);
          } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof TimerEventDefinition) {
            processDiagramCanvas.drawCatchingTimerEvent(flowNode.getName(), graphicInfo, true, scaleFactor);
          } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) {
            processDiagramCanvas.drawCatchingMessageEvent(flowNode.getName(), graphicInfo, true, scaleFactor);  
          }
        }
      }
    });
    
    // signal throw
    activityDrawInstructions.put(ThrowEvent.class, new ActivityDrawInstruction() {
      
      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        ThrowEvent throwEvent = (ThrowEvent) flowNode;
        if (throwEvent.getEventDefinitions() != null && !throwEvent.getEventDefinitions().isEmpty()) {
          if (throwEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) {
            processDiagramCanvas.drawThrowingSignalEvent(graphicInfo, scaleFactor);
          } else if (throwEvent.getEventDefinitions().get(0) instanceof CompensateEventDefinition) {
            processDiagramCanvas.drawThrowingCompensateEvent(graphicInfo, scaleFactor);
          } else {
            processDiagramCanvas.drawThrowingNoneEvent(graphicInfo, scaleFactor);
          }
        } else {
          processDiagramCanvas.drawThrowingNoneEvent(graphicInfo, scaleFactor);
        }
      }
    });
    
    // end event
    activityDrawInstructions.put(EndEvent.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        EndEvent endEvent = (EndEvent) flowNode;
        if (endEvent.getEventDefinitions() != null && !endEvent.getEventDefinitions().isEmpty()) {
          if (endEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition) {
            processDiagramCanvas.drawErrorEndEvent(flowNode.getName(), graphicInfo, scaleFactor);
          } else {
            processDiagramCanvas.drawNoneEndEvent(graphicInfo, scaleFactor);
          }
        } else {
          processDiagramCanvas.drawNoneEndEvent(graphicInfo, scaleFactor);
        }
      }
    });

    // task
    activityDrawInstructions.put(Task.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawTask(flowNode.getName(), graphicInfo);
      }
    });

    // user task
    activityDrawInstructions.put(UserTask.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawUserTask(flowNode.getName(), graphicInfo, scaleFactor);
      }
    });

    // script task
    activityDrawInstructions.put(ScriptTask.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawScriptTask(flowNode.getName(), graphicInfo, scaleFactor);
      }
    });

    // service task
    activityDrawInstructions.put(ServiceTask.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        ServiceTask serviceTask = (ServiceTask) flowNode;
        if ("camel".equalsIgnoreCase(serviceTask.getType())) {
          processDiagramCanvas.drawCamelTask(serviceTask.getName(), graphicInfo, scaleFactor);
        } else if ("mule".equalsIgnoreCase(serviceTask.getType())) {
          processDiagramCanvas.drawMuleTask(serviceTask.getName(), graphicInfo, scaleFactor);
        } else {
          processDiagramCanvas.drawServiceTask(serviceTask.getName(), graphicInfo, scaleFactor);
        }
      }
    });

    // receive task
    activityDrawInstructions.put(ReceiveTask.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawReceiveTask(flowNode.getName(), graphicInfo, scaleFactor);
      }
    });

    // send task
    activityDrawInstructions.put(SendTask.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawSendTask(flowNode.getName(), graphicInfo, scaleFactor);
      }
    });

    // manual task
    activityDrawInstructions.put(ManualTask.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawManualTask(flowNode.getName(), graphicInfo, scaleFactor);
      }
    });
    
    // businessRuleTask task
    activityDrawInstructions.put(BusinessRuleTask.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawBusinessRuleTask(flowNode.getName(), graphicInfo, scaleFactor);
      }
    });

    // exclusive gateway
    activityDrawInstructions.put(ExclusiveGateway.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawExclusiveGateway(graphicInfo, scaleFactor);
      }
    });

    // inclusive gateway
    activityDrawInstructions.put(InclusiveGateway.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawInclusiveGateway(graphicInfo, scaleFactor);
      }
    });

    // parallel gateway
    activityDrawInstructions.put(ParallelGateway.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawParallelGateway(graphicInfo, scaleFactor);
      }
    });
    
    // event based gateway
    activityDrawInstructions.put(EventGateway.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawEventBasedGateway(graphicInfo, scaleFactor);
      }
    });
    

    // Boundary timer
    activityDrawInstructions.put(BoundaryEvent.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        BoundaryEvent boundaryEvent = (BoundaryEvent) flowNode;
        if (boundaryEvent.getEventDefinitions() != null && !boundaryEvent.getEventDefinitions().isEmpty()) {
          if (boundaryEvent.getEventDefinitions().get(0) instanceof TimerEventDefinition) {
            
            processDiagramCanvas.drawCatchingTimerEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
            
          } else if (boundaryEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition) {
            
            processDiagramCanvas.drawCatchingErrorEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
            
          } else if (boundaryEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) {
            processDiagramCanvas.drawCatchingSignalEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);

          } else if (boundaryEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) {
            processDiagramCanvas.drawCatchingMessageEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);  

          } else if (boundaryEvent.getEventDefinitions().get(0) instanceof CompensateEventDefinition) {
            processDiagramCanvas.drawCatchingCompensateEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
          }
        }
        
      }
    });

    // subprocess
    activityDrawInstructions.put(SubProcess.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
          processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false);
        } else {
          processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
        }
      }
    });
    
    // Event subprocess
    activityDrawInstructions.put(EventSubProcess.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
          processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, true);
        } else {
          processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, true, scaleFactor);
        }
      }
    });

    // call activity
    activityDrawInstructions.put(CallActivity.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawCollapsedCallActivity(flowNode.getName(), graphicInfo);
      }
    });

    // text annotation
    artifactDrawInstructions.put(TextAnnotation.class, new ArtifactDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(artifact.getId());
        TextAnnotation textAnnotation = (TextAnnotation) artifact;
        processDiagramCanvas.drawTextAnnotation(textAnnotation.getText(), graphicInfo);
      }
    });
    
    // association
    artifactDrawInstructions.put(Association.class, new ArtifactDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) {
        Association association = (Association) artifact;
        String sourceRef = association.getSourceRef();
        String targetRef = association.getTargetRef();
        
        // source and target can be instance of FlowElement or Artifact
        BaseElement sourceElement = bpmnModel.getFlowElement(sourceRef);
        BaseElement targetElement = bpmnModel.getFlowElement(targetRef);
        if (sourceElement == null) {
            sourceElement = bpmnModel.getArtifact(sourceRef);
        }
        if (targetElement == null) {
            targetElement = bpmnModel.getArtifact(targetRef);
        }
        List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId());
        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();
        }

        AssociationDirection associationDirection = association.getAssociationDirection();
        processDiagramCanvas.drawAssociation(xPoints, yPoints, associationDirection, false, scaleFactor);
      }
    });
  }

  public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows,
      String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {
    
    return generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, 
        activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor).generateImage(imageType);
  }
  
  public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows) {
    return generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, 1.0);
  }
  
  public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, 
      List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor) {
    return generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, scaleFactor);
  }
  
  public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities) {
    return generateDiagram(bpmnModel, imageType, highLightedActivities, Collections.<String>emptyList());
  }
  
  public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, double scaleFactor) {
    return generateDiagram(bpmnModel, imageType, highLightedActivities, Collections.<String>emptyList(), scaleFactor);
  }
  
  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);
  }
  
  public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName, 
      String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {
    
    return generateDiagram(bpmnModel, imageType, Collections.<String>emptyList(), Collections.<String>emptyList(), 
        activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor);
  }

  public InputStream generatePngDiagram(BpmnModel bpmnModel) {
    return generatePngDiagram(bpmnModel, 1.0);
  }
  
  public InputStream generatePngDiagram(BpmnModel bpmnModel, double scaleFactor) {
    return generateDiagram(bpmnModel, "png", Collections.<String>emptyList(), Collections.<String>emptyList(), scaleFactor);
  }

  public InputStream generateJpgDiagram(BpmnModel bpmnModel) {
    return generateJpgDiagram(bpmnModel, 1.0);
  }
  
  public InputStream generateJpgDiagram(BpmnModel bpmnModel, double scaleFactor) {
    return generateDiagram(bpmnModel, "jpg", Collections.<String>emptyList(), Collections.<String>emptyList());
  }
  
  public BufferedImage generateImage(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows,
      String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {
    
    return generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, 
        activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor).generateBufferedImage(imageType);
  }
  
  public BufferedImage generateImage(BpmnModel bpmnModel, String imageType, 
      List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor) {
    
    return generateImage(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, scaleFactor);
  }
  
  public BufferedImage generatePngImage(BpmnModel bpmnModel, double scaleFactor) {
    return generateImage(bpmnModel, "png", Collections.<String>emptyList(), Collections.<String>emptyList(), scaleFactor);
  }

  protected DefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType, 
      List<String> highLightedActivities, List<String> highLightedFlows,
      String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {
  	
  	prepareBpmnModel(bpmnModel);
    
    DefaultProcessDiagramCanvas 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);
    }
    
    // Draw lanes
    for (Process process : bpmnModel.getProcesses()) {
      for (Lane lane : process.getLanes()) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId());
        processDiagramCanvas.drawPoolOrLane(lane.getName(), graphicInfo);
      }
    }
    
    // Draw activities and their sequence-flows
    for (Process process: bpmnModel.getProcesses()) {
      for (FlowNode flowNode : process.findFlowElementsOfType(FlowNode.class)) {
        drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, scaleFactor);
      }
    }
    
    // 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 prepareBpmnModel(BpmnModel bpmnModel) {
  
  	// Need to make sure all elements have positive x and y. 
  	// Check all graphicInfo and update the elements accordingly
  	
  	List<GraphicInfo> allGraphicInfos = new ArrayList<GraphicInfo>();
  	if (bpmnModel.getLocationMap() != null) {
  		allGraphicInfos.addAll(bpmnModel.getLocationMap().values());
  	}
  	if (bpmnModel.getLabelLocationMap() != null) {
  		allGraphicInfos.addAll(bpmnModel.getLabelLocationMap().values());
  	}
  	if (bpmnModel.getFlowLocationMap() != null) {
  		for (List<GraphicInfo> flowGraphicInfos : bpmnModel.getFlowLocationMap().values()) {
  			allGraphicInfos.addAll(flowGraphicInfos);
  		}
  	}
  	
  	if (allGraphicInfos.size() > 0) {
  		
  		boolean needsTranslationX = false;
  		boolean needsTranslationY = false;
  		
  		double lowestX = 0.0;
  		double lowestY = 0.0;
  		
  		// Collect lowest x and y
  		for (GraphicInfo graphicInfo : allGraphicInfos) {
  			
  			double x = graphicInfo.getX();
  			double y = graphicInfo.getY();
  			
  			if (x < lowestX) {
  				needsTranslationX = true;
  				lowestX = x;
  			}
  			if (y < lowestY) {
  				needsTranslationY = true;
  				lowestY = y;
  			}
  			
  		}
  		
  		// Update all graphicInfo objects
  		if (needsTranslationX || needsTranslationY) {
  			
  			double translationX = Math.abs(lowestX);
  			double translationY = Math.abs(lowestY);
  			
  			for (GraphicInfo graphicInfo : allGraphicInfos) {
  				if (needsTranslationX) {
  					graphicInfo.setX(graphicInfo.getX() + translationX);
  				}
  				if(needsTranslationY) {
  					graphicInfo.setY(graphicInfo.getY() + translationY);
  				}
  			}
  		}

  	}
  	
  }

  protected void drawActivity(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, 
      FlowNode flowNode, List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor) {
    
    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())) {
        drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
      }

    }
    
    // Outgoing transitions of activity
    for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
      boolean highLighted = (highLightedFlows.contains(sequenceFlow.getId()));
      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(sequenceFlow.getId())) {
        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(sequenceFlow.getId());
      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, drawConditionalIndicator, isDefault, highLighted, scaleFactor);
  
        // Draw sequenceflow label
        GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId());
        if (labelGraphicInfo != null) {
          processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false);
        } else {
          // 解决流程图连线名称不显示的BUG
            GraphicInfo lineLeft = getLineLeft(graphicInfoList);
            processDiagramCanvas.drawLabel(sequenceFlow.getName(), lineLeft, false);
        }
      }
    }

    // Nested elements
    if (flowNode instanceof FlowElementsContainer) {
      for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) {
        if (nestedFlowElement instanceof FlowNode) {
          drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement, 
              highLightedActivities, highLightedFlows, scaleFactor);
        }
      }
    }
  }
  
  /**
   * This method makes coordinates of connection flow better.
   * @param processDiagramCanvas
   * @param bpmnModel
   * @param sourceElement
   * @param targetElement
   * @param graphicInfoList
   * @return
   */
  protected static List<GraphicInfo> connectionPerfectionizer(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, BaseElement sourceElement, BaseElement targetElement, List<GraphicInfo> graphicInfoList) {
    GraphicInfo sourceGraphicInfo = bpmnModel.getGraphicInfo(sourceElement.getId());
    GraphicInfo targetGraphicInfo = bpmnModel.getGraphicInfo(targetElement.getId());
    
    DefaultProcessDiagramCanvas.SHAPE_TYPE sourceShapeType = getShapeType(sourceElement);
    DefaultProcessDiagramCanvas.SHAPE_TYPE targetShapeType = getShapeType(targetElement);
    
    return processDiagramCanvas.connectionPerfectionizer(sourceShapeType, targetShapeType, sourceGraphicInfo, targetGraphicInfo, graphicInfoList);
  }

  /**
   * This method returns shape type of base element.<br>
   * Each element can be presented as rectangle, rhombus, or ellipse.
   * @param baseElement
   * @return DefaultProcessDiagramCanvas.SHAPE_TYPE
   */
  protected static DefaultProcessDiagramCanvas.SHAPE_TYPE getShapeType(BaseElement baseElement) {
    if (baseElement instanceof Task || baseElement instanceof Activity || baseElement instanceof TextAnnotation) {
        return DefaultProcessDiagramCanvas.SHAPE_TYPE.Rectangle;
    } else if (baseElement instanceof Gateway) {
        return DefaultProcessDiagramCanvas.SHAPE_TYPE.Rhombus;
    } else if (baseElement instanceof Event) {
        return DefaultProcessDiagramCanvas.SHAPE_TYPE.Ellipse;
    } else {
        // unknown source element, just do not correct coordinates
    }
    return null;
  }

  /**
   * 连线上文字居左
   * @param graphicInfoList
   * @return
   */
  protected static GraphicInfo getLineLeft(List<GraphicInfo> graphicInfoList) {
    GraphicInfo gi = new GraphicInfo();

    int xPoints[]= new int[graphicInfoList.size()];
    int yPoints[]= new int[graphicInfoList.size()];

    double length = 0;
    double[] lengths = new double[graphicInfoList.size()];
    lengths[0] = 0;
    double m;
    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();

      length += Math.sqrt(
              Math.pow((int) graphicInfo.getX() - (int) previousGraphicInfo.getX(), 2) +
                      Math.pow((int) graphicInfo.getY() - (int) previousGraphicInfo.getY(), 2)
      );
      lengths[i] = length;
    }
    m = length / 2;
    int p1 = 0, p2 = 1;
    for (int i = 1; i < lengths.length; i++) {
      double len = lengths[i];
      p1 = i-1;
      p2 = i;
      if (len > m) {
        break;
      }
    }

    GraphicInfo graphicInfo1 = graphicInfoList.get(p1);
    GraphicInfo graphicInfo2 = graphicInfoList.get(p2);

    double AB = (int)graphicInfo2.getX() - (int)graphicInfo1.getX();
    double OA = (int)graphicInfo2.getY() - (int)graphicInfo1.getY();
    double OB = lengths[p2] - lengths[p1];
    double ob =  m - lengths[p1];
    double ab =  AB * ob / OB;
    double oa =  OA * ob / OB;

    double mx = graphicInfo1.getX();
    double my = graphicInfo1.getY() + oa;

    gi.setX(mx);
    gi.setY(my);
    return gi;
  }
  
  protected static GraphicInfo getLineCenter(List<GraphicInfo> graphicInfoList) {
    GraphicInfo gi = new GraphicInfo();
    
    int xPoints[]= new int[graphicInfoList.size()];
    int yPoints[]= new int[graphicInfoList.size()];
    
    double length = 0;
    double[] lengths = new double[graphicInfoList.size()];
    lengths[0] = 0;
    double m;
    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();
        
        length += Math.sqrt(
      		  		Math.pow((int) graphicInfo.getX() - (int) previousGraphicInfo.getX(), 2) + 
      		  		Math.pow((int) graphicInfo.getY() - (int) previousGraphicInfo.getY(), 2)
      		  	);
        lengths[i] = length;
      }
      m = length / 2;
      int p1 = 0, p2 = 1;
      for (int i = 1; i < lengths.length; i++) {
			double len = lengths[i];
			p1 = i-1;
			p2 = i;
			if (len > m) {
				break;
			}
		}
      
      GraphicInfo graphicInfo1 = graphicInfoList.get(p1);
      GraphicInfo graphicInfo2 = graphicInfoList.get(p2);
      
      double AB = (int)graphicInfo2.getX() - (int)graphicInfo1.getX();
      double OA = (int)graphicInfo2.getY() - (int)graphicInfo1.getY();
      double OB = lengths[p2] - lengths[p1];
      double ob =  m - lengths[p1];
      double ab =  AB * ob / OB;
      double oa =  OA * ob / OB;
      
      double mx = graphicInfo1.getX() + ab;
      double my = graphicInfo1.getY() + oa;
      
      gi.setX(mx);
      gi.setY(my);
    return gi;
  }
  
  protected void drawArtifact(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) {
    ArtifactDrawInstruction drawInstruction = artifactDrawInstructions.get(artifact.getClass());
    if (drawInstruction != null) {
      drawInstruction.draw(processDiagramCanvas, bpmnModel, artifact);
    }
  }

  private static void drawHighLight(DefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
    processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());

  }

  protected static DefaultProcessDiagramCanvas 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 DefaultProcessDiagramCanvas((int) maxX + 10,(int) maxY + 10, (int) minX, (int) minY, 
        imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
  }
  
  protected static List<Artifact> gatherAllArtifacts(BpmnModel bpmnModel) {
    List<Artifact> artifacts = new ArrayList<Artifact>();
    for (Process process : bpmnModel.getProcesses()) {
    	artifacts.addAll(process.getArtifacts());
    }
    return artifacts;
  }
  
  protected static List<FlowNode> gatherAllFlowNodes(BpmnModel bpmnModel) {
    List<FlowNode> flowNodes = new ArrayList<FlowNode>();
    for (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 Map<Class<? extends BaseElement>, ActivityDrawInstruction> getActivityDrawInstructions() {
		return activityDrawInstructions;
	}

	public void setActivityDrawInstructions(
	    Map<Class<? extends BaseElement>, ActivityDrawInstruction> activityDrawInstructions) {
		this.activityDrawInstructions = activityDrawInstructions;
	}

	public Map<Class<? extends BaseElement>, ArtifactDrawInstruction> getArtifactDrawInstructions() {
		return artifactDrawInstructions;
	}

	public void setArtifactDrawInstructions(
	    Map<Class<? extends BaseElement>, ArtifactDrawInstruction> artifactDrawInstructions) {
		this.artifactDrawInstructions = artifactDrawInstructions;
	}



	protected interface ActivityDrawInstruction {
    void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode);
  }

  protected interface ArtifactDrawInstruction {
    void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact);
  }
}

3. 测试
package com.yl.process;

import com.alibaba.fastjson.JSON;
import com.yl.converter.DefaultProcessDiagramGenerator;
import com.yl.converter.DefaultProcessDiagramGeneratorExt;
import com.yl.converter.ProcessDiagramGeneratorExt;
import com.yl.util.ActivitiDrawUtil;
import com.yl.util.DynamicActivitiUtil;
import com.yl.util.TaskUtil;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.BpmnAutoLayout;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@Slf4j
public class TestDynamicActivitiProcess {
    /**
     * 增加节点
     */
    @Test
    public void createDynamicDeploy() {
        // 1. 从头开始构建模型
        BpmnModel model = new BpmnModel();
        Process process = new Process();
        model.addProcess(process);
        process.setId("my-simple-process");
        process.setName("我的简单流程");

        //任务节点
        process.addFlowElement(DynamicActivitiUtil.createStartEvent());
        process.addFlowElement(DynamicActivitiUtil.createUserTask("applySubmit", "申请人提交", "张三"));
        process.addFlowElement(DynamicActivitiUtil.createUserTask("check", "审批", "李四"));
        process.addFlowElement(DynamicActivitiUtil.createEndEvent(null));

        //连线
        process.addFlowElement(DynamicActivitiUtil.createSequenceFlow("start", "applySubmit"));

        SequenceFlow sequenceFlow = DynamicActivitiUtil.createSequenceFlow("applySubmit", "check");
        //连线上添加表达式
        sequenceFlow.setConditionExpression("${applySubmitPass}");
        sequenceFlow.setName("申请人通过");
        process.addFlowElement(sequenceFlow);

        SequenceFlow sequenceFlow1 = DynamicActivitiUtil.createSequenceFlow("check", "end");
        //连线上添加表达式
        sequenceFlow1.setConditionExpression("${checkPass}");
        sequenceFlow1.setName("校验通过");
        process.addFlowElement(sequenceFlow1);

        // 2.  生成图形信息
        new BpmnAutoLayout(model).execute();

        // 3.  将流程定义部署到引擎中
        // 创建流程引擎
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = engine.getRepositoryService();
        RuntimeService runtimeService = engine.getRuntimeService();
        TaskService taskService = engine.getTaskService();

        // 部署流程文件
        Deployment deployment = repositoryService.createDeployment()
                .addBpmnModel("my-simple-process.bpmn", model)
                .name("我的简单流程").deploy();

        // 查找流程定义
        ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deployment.getId()).singleResult();
        log.info("{},{},{},{}", pd.getId(), pd.getKey(), pd.getName(), pd.getDeploymentId());

        // 4.  启动一个流程实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(pd.getId());

        // 5. 查询待办任务
        taskQuery();

//        try {
//            // 6. 将流程图保存到一个文件中
//            InputStream processDiagram = repositoryService.getProcessDiagram(processInstance.getProcessDefinitionId());
//            FileUtils.copyInputStreamToFile(processDiagram, new File("D:/upload/my-simple-process.png"));
//
//            // 7.  将产生的BPMN xml保存到一个文件中
//            InputStream processBpmn = repositoryService.getResourceAsStream(deployment.getId(), "my-simple-process.bpmn");
//            FileUtils.copyInputStreamToFile(processBpmn, new File("D:/upload/my-simple-process.bpmn"));
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
    }

    /**
     * 查询 流程图 png
     */
    @Test
    public void bpmnFile() {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = engine.getRepositoryService();
        InputStream processBpmn = repositoryService.getResourceAsStream("45001", "my-simple-process.my-simple-process.png");
        try {
            FileUtils.copyInputStreamToFile(processBpmn, new File("D:/upload/my-simple-process.png"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 查询待办任务
     */
    @Test
    public void taskQuery() {
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = engine.getTaskService();
        List<Task> list = taskService.createTaskQuery()
                // 筛选 vacationChange 流程
                .processDefinitionKey("my-simple-process")
                .list();
        list.forEach(task -> {
            log.info("流程实例id:{},流程ExecutionId:{}, 任务处理人:{}, 任务名:{}, 任务定义Key:{}, 任务id:{}", task.getProcessInstanceId(), task.getExecutionId(),
                    task.getAssignee(), task.getName(), task.getTaskDefinitionKey(), task.getId());
        });
        if (list.isEmpty()) {
            log.info("没有代办任务了,流程结束");
        }
    }

    @Test
    public void nextTaskQuery() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        TaskService taskService = processEngine.getTaskService();
        TaskUtil taskUtil = new TaskUtil(runtimeService, repositoryService, taskService);

        Map<String, Object> varMap = new HashMap<>();
        FlowNode nextUserTask = taskUtil.getNextUserTask("2505", varMap);
        log.info("{}", JSON.toJSONString(nextUserTask));
    }

    /**
     * 根据流程定义获取流程图
     * @throws IOException
     */
    @Test
    public void createProcessImg() throws IOException {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        TaskService taskService = processEngine.getTaskService();

        Task task = taskService.createTaskQuery().taskId("17508").singleResult();
        ProcessDefinition processDefinition = repositoryService.getProcessDefinition(task.getProcessDefinitionId());
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());

        DefaultProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();

        // ID 为 流程定义Key
        org.activiti.bpmn.model.Process process = bpmnModel.getProcessById(processDefinition.getKey());
        // 流程节点ID
        FlowElement flowElement = process.getFlowElement(task.getTaskDefinitionKey());

        // 高亮显示的节点
        List<String> highLightedActivities = new ArrayList<>();
        highLightedActivities.add(flowElement.getId());

        // 高亮显示的连线
        List<String> highLightedFlows = Collections.emptyList();

        InputStream inputStream = generator.generateDiagram(bpmnModel, "png", highLightedActivities, highLightedFlows,
                "宋体", "宋体", "宋体", null, 2.0);

        FileUtils.copyInputStreamToFile(inputStream, new File("D:/upload/my-simple-process.png"));

    }

createDynamicDeploy方法注释放开,生成的流程图,连线上没有文字
在这里插入图片描述

生成的图,这种方式连线上的文字不清晰,后面有其他方法
在这里插入图片描述
流程定义文件

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="my-simple-process" name="我的简单流程" isExecutable="true">
    <startEvent id="start" name="start"></startEvent>
    <userTask id="applySubmit" name="申请人提交" activiti:assignee="张三"></userTask>
    <userTask id="check" name="审批" activiti:assignee="李四"></userTask>
    <endEvent id="end" name="end"></endEvent>
    <sequenceFlow id="sequenceFlow-56f230e4-e535-44e0-934d-ab2c0832f33d" sourceRef="start" targetRef="applySubmit"></sequenceFlow>
    <sequenceFlow id="sequenceFlow-67008443-da9b-427e-91cf-71cd67f47b4d" name="申请人通过" sourceRef="applySubmit" targetRef="check">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${applySubmitPass}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="sequenceFlow-f93455a4-2b89-43ab-8173-ce3e97f57a8b" name="校验通过" sourceRef="check" targetRef="end">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${checkPass}]]></conditionExpression>
    </sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_my-simple-process">
    <bpmndi:BPMNPlane bpmnElement="my-simple-process" id="BPMNPlane_my-simple-process">
      <bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">
        <omgdc:Bounds height="30.0" width="30.0" x="0.0" y="15.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end">
        <omgdc:Bounds height="30.0" width="30.0" x="380.0" y="15.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="check" id="BPMNShape_check">
        <omgdc:Bounds height="60.0" width="100.0" x="230.0" y="0.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="applySubmit" id="BPMNShape_applySubmit">
        <omgdc:Bounds height="60.0" width="100.0" x="80.0" y="0.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="sequenceFlow-56f230e4-e535-44e0-934d-ab2c0832f33d" id="BPMNEdge_sequenceFlow-56f230e4-e535-44e0-934d-ab2c0832f33d">
        <omgdi:waypoint x="30.0" y="30.0"></omgdi:waypoint>
        <omgdi:waypoint x="80.0" y="30.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sequenceFlow-67008443-da9b-427e-91cf-71cd67f47b4d" id="BPMNEdge_sequenceFlow-67008443-da9b-427e-91cf-71cd67f47b4d">
        <omgdi:waypoint x="180.0" y="30.0"></omgdi:waypoint>
        <omgdi:waypoint x="230.0" y="30.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sequenceFlow-f93455a4-2b89-43ab-8173-ce3e97f57a8b" id="BPMNEdge_sequenceFlow-f93455a4-2b89-43ab-8173-ce3e97f57a8b">
        <omgdi:waypoint x="330.0" y="30.0"></omgdi:waypoint>
        <omgdi:waypoint x="380.0" y="30.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值