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>