Commit 2bcc1810 by dengwei

流程demo

parents
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MavenImportPreferences">
<option name="generalSettings">
<MavenGeneralSettings>
<option name="mavenHome" value="D:/Maven/apache-maven-3.6.3" />
<option name="userSettingsFile" value="D:\Maven\apache-maven-3.6.3\conf\settings.xml" />
</MavenGeneralSettings>
</option>
<option name="importingSettings">
<MavenImportingSettings>
<option name="downloadSourcesAutomatically" value="true" />
<option name="vmOptionsForImporter" value="-Xmx768m" />
</MavenImportingSettings>
</option>
</component>
<component name="ProjectViewState">
<option name="autoscrollFromSource" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="settings.editor.selected.configurable" value="preferences.sourceCode.Java" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.oyc.activiti</groupId>
<artifactId>springboot-activiti</artifactId>
<version>1.0.1</version>
<name>springboot-activiti-processes</name>
<description>activiti demo</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<!-- lombok 可以为我们生产getter、setter、构造方法、toString方法等-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--activiti工作流-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>6.0.0</version>
</dependency>
<!-- swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.5.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package com.oyc.activiti;
import org.activiti.spring.boot.SecurityAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author oyc
*/
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
public class SpringBootActivityProcessesApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootActivityProcessesApplication.class, args);
}
}
package com.oyc.activiti.config;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @author :DW
* @date :2022-10-22-0022 15:50
* @description: swagger配置类
* @version:
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
}
package com.oyc.activiti.controller;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
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.activiti.image.ProcessDiagramGenerator;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @ClassName: ActivityProcessesController
* @Description: 流程相关控制器
* @Author dw
* @Date 2022年10月22日14:04:51
* @Version 1.0
*/
@RestController
@RequestMapping("processes")
public class ActivityProcessesController {
@Resource
private RepositoryService repositoryService;
@Resource
private RuntimeService runtimeService;
@Resource
private TaskService taskService;
@Resource
private ProcessEngine processEngine;
@Resource
private HistoryService historyService;
/**
* 部署申请流程
*/
@GetMapping("deploy")
public ResponseEntity<Map<String, Object>> deployProcesses() {
HashMap<String, Object> resultMap = new HashMap<>(8);
//部署对象
Deployment deployment = repositoryService.createDeployment()
// bpmn文件
.addClasspathResource("processes/holiday.bpmn")
// 图片文件
.addClasspathResource("processes/holiday.png")
.name("模拟申请流程")
.deploy();
System.out.println("流程部署id:" + deployment.getId());
System.out.println("流程部署名称:" + deployment.getName());
resultMap.put("id", deployment.getId());
resultMap.put("name", deployment.getName());
resultMap.put("key", deployment.getKey());
resultMap.put("dDeploymentTime", deployment.getDeploymentTime());
return ResponseEntity.ok(resultMap);
}
/**
* 启动申请流程--传入申请流程的key
*/
@GetMapping("start")
public ResponseEntity startProcessByKey(@RequestParam String processesKey) {
HashMap<String, Object> resultMap = new HashMap<>(8);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processesKey);
resultMap.put("id", processInstance.getId());
resultMap.put("name", processInstance.getName());
resultMap.put("deploymentId", processInstance.getDeploymentId());
resultMap.put("processDefinitionId", processInstance.getProcessDefinitionId());
resultMap.put("startUserId", processInstance.getStartUserId());
resultMap.put("processDefinitionName", processInstance.getProcessDefinitionName());
return ResponseEntity.ok(resultMap);
}
/**
* 根据流程key和用户名获取待办流程
*
* @param processDefinitionKey 流程key(holiday)
* @param userName 用户名(zhangsan)
*/
@GetMapping("task")
public ResponseEntity getTaskByUserName(@RequestParam String processDefinitionKey, @RequestParam String userName) {
ArrayList<Object> resultList = new ArrayList<>();
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey(processDefinitionKey)
//只查询该任务负责人的任务
.taskAssignee(userName)
.list();
taskList.forEach(task -> {
HashMap<String, Object> map = new HashMap<>(16);
System.out.println(task);
//任务ID
map.put("id", task.getId());
//任务名称
map.put("name", task.getName());
//任务委派人
map.put("assignee", task.getAssignee());
//任务创建时间
map.put("createTime", task.getCreateTime());
//任务描述
map.put("description", task.getDescription());
//任务对应得流程实例id
map.put("processInstanceId", task.getProcessInstanceId());
//任务对应得流程定义id
map.put("processDefinitionId", task.getProcessDefinitionId());
resultList.add(map);
});
return ResponseEntity.ok(resultList);
}
/**
* 根据任务id完成任务
*
* @param taskId 任务id
* @return
* @throws
*/
@GetMapping("completeTask")
public ResponseEntity completeTaskById(@RequestParam String taskId) {
taskService.complete(taskId);
return ResponseEntity.ok(String.format("任务id为:%s 已经完成", taskId));
}
/**
* 根据任务id委派(转派、转交)给指定用户
*
* @param taskId 任务id
* @param userName 用户名称
* @return
* @throws
*/
@GetMapping("assigneeTask")
public ResponseEntity assigneeTaskById(@RequestParam String taskId, @RequestParam String userName) {
taskService.setAssignee(taskId, userName);
return ResponseEntity.ok(String.format("任务id为:%s 已经委派(转派、转交)给 %s", taskId, userName));
}
/**
* 挂起激活流程定义
*
* @param processDefinitionId 流程定义Id
* @return
* @throws
*/
@GetMapping("suspendOrActivateProcessDefinition")
public ResponseEntity suspendOrActivateProcessDefinition(@RequestParam String processDefinitionId) {
// 获得流程定义
ProcessDefinition processDefinition = repositoryService
.createProcessDefinitionQuery()
.processDefinitionId(processDefinitionId)
.singleResult();
//是否暂停
boolean suspend = processDefinition.isSuspended();
if (suspend) {
//如果暂停则激活,这里将流程定义下的所有流程实例全部激活
repositoryService.activateProcessDefinitionById(processDefinitionId, true, null);
System.out.println("流程定义:" + processDefinitionId + "激活");
return ResponseEntity.ok(String.format("流程定义:%s激活", processDefinitionId));
} else {
//如果激活则挂起,这里将流程定义下的所有流程实例全部挂起
repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null);
System.out.println("流程定义:" + processDefinitionId + "挂起");
return ResponseEntity.ok(String.format("流程定义:%s挂起", processDefinitionId));
}
}
/**
* 生成流程图
*/
@RequestMapping("createProcessImg")
public void createProcessImg(@RequestParam String processInstanceId, HttpServletResponse response) throws Exception {
//获取历史流程实例
HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
//根据流程定义获取输入流
InputStream is = repositoryService.getProcessDiagram(processInstance.getProcessDefinitionId());
BufferedImage bi = ImageIO.read(is);
File file = new File(processInstanceId + "Img.png");
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
ImageIO.write(bi, "png", fos);
fos.close();
is.close();
System.out.println("图片生成成功");
List<Task> tasks = taskService.createTaskQuery().taskCandidateUser("userId").list();
for (Task t : tasks) {
System.out.println(t.getName());
}
}
/**
* 生成流程图
*/
@RequestMapping("viewProcessImg")
public void viewProcessImg(@RequestParam String processInstanceId, HttpServletResponse response) throws Exception {
//获取历史流程实例
try {
HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
OutputStream outputStream = response.getOutputStream();
//根据流程定义获取输入流
InputStream in = repositoryService.getProcessDiagram(processInstance.getProcessDefinitionId());
IOUtils.copy(in, outputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 生成流程图(高亮)
*/
@RequestMapping("viewProcessImgHighLighted")
public void viewProcessImgHighLighted(@RequestParam String processInstanceId, HttpServletResponse response) {
try {
byte[] processImage = getProcessImage(processInstanceId);
OutputStream outputStream = response.getOutputStream();
InputStream in = new ByteArrayInputStream(processImage);
IOUtils.copy(in, outputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
public byte[] getProcessImage(String processInstanceId) throws Exception {
// 获取历史流程实例
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if (historicProcessInstance == null) {
throw new Exception();
} else {
// 获取流程定义
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService
.getProcessDefinition(historicProcessInstance.getProcessDefinitionId());
// 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
List<HistoricActivityInstance> historicActivityInstanceList = historyService
.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceId().desc().list();
// 已执行的节点ID集合
List<String> executedActivityIdList = new ArrayList<>();
@SuppressWarnings("unused") int index = 1;
System.out.println("获取已经执行的节点ID");
for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
executedActivityIdList.add(activityInstance.getActivityId());
index++;
}
// 获取流程图图像字符流
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
//已执行flow的集合
List<String> executedFlowIdList = getHighLightedFlows(bpmnModel, historicActivityInstanceList);
ProcessDiagramGenerator processDiagramGenerator = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
InputStream imageStream = processDiagramGenerator.generateDiagram(bpmnModel, "png", executedActivityIdList, executedFlowIdList, "黑体", "黑体", "黑体", null, 1.0);
byte[] buffer = new byte[imageStream.available()];
imageStream.read(buffer);
imageStream.close();
return buffer;
}
}
/**
* 获取已经流转的线
*
* @param bpmnModel
* @param historicActivityInstances
* @return
*/
private static List<String> getHighLightedFlows(BpmnModel bpmnModel, List<HistoricActivityInstance> historicActivityInstances) {
// 高亮流程已发生流转的线id集合
List<String> highLightedFlowIds = new ArrayList<>();
// 全部活动节点
List<FlowNode> historicActivityNodes = new ArrayList<>();
// 已完成的历史活动节点
List<HistoricActivityInstance> finishedActivityInstances = new ArrayList<>();
for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true);
historicActivityNodes.add(flowNode);
if (historicActivityInstance.getEndTime() != null) {
finishedActivityInstances.add(historicActivityInstance);
}
}
FlowNode currentFlowNode = null;
FlowNode targetFlowNode = null;
// 遍历已完成的活动实例,从每个实例的outgoingFlows中找到已执行的
for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) {
// 获得当前活动对应的节点信息及outgoingFlows信息
currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true);
List<SequenceFlow> sequenceFlows = currentFlowNode.getOutgoingFlows();
/**
* 遍历outgoingFlows并找到已已流转的 满足如下条件认为已已流转: 1.当前节点是并行网关或兼容网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转 2.当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最早的流转节点视为有效流转
*/
if ("parallelGateway".equals(currentActivityInstance.getActivityType()) || "inclusiveGateway".equals(currentActivityInstance.getActivityType())) {
// 遍历历史活动节点,找到匹配流程目标节点的
for (SequenceFlow sequenceFlow : sequenceFlows) {
targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true);
if (historicActivityNodes.contains(targetFlowNode)) {
highLightedFlowIds.add(targetFlowNode.getId());
}
}
} else {
List<Map<String, Object>> tempMapList = new ArrayList<>();
for (SequenceFlow sequenceFlow : sequenceFlows) {
for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) {
Map<String, Object> map = new HashMap<>();
map.put("highLightedFlowId", sequenceFlow.getId());
map.put("highLightedFlowStartTime", historicActivityInstance.getStartTime().getTime());
tempMapList.add(map);
}
}
}
if (!CollectionUtils.isEmpty(tempMapList)) {
// 遍历匹配的集合,取得开始时间最早的一个
long earliestStamp = 0L;
String highLightedFlowId = null;
for (Map<String, Object> map : tempMapList) {
long highLightedFlowStartTime = Long.valueOf(map.get("highLightedFlowStartTime").toString());
if (earliestStamp == 0 || earliestStamp >= highLightedFlowStartTime) {
highLightedFlowId = map.get("highLightedFlowId").toString();
earliestStamp = highLightedFlowStartTime;
}
}
highLightedFlowIds.add(highLightedFlowId);
}
}
}
return highLightedFlowIds;
}
}
# 应用服务 WEB 访问端口
server:
port: 8083
# 应用名称
spring:
application:
name: springboot-activiti-processes
# activiti
activiti:
#每次应用启动不检查Activiti数据表是否存在及版本号是否匹配,提升应用启动速度
database-schema-update: true
check-process-definitions: true
process-definition-location-prefix: classpath:/processes/
process-definition-location-suffixes:
-**.bpmn
-**.bpmn20.xml
#保存历史数据级别设置为full最高级别,便于历史数据的追溯
history-level: full
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://127.0.0.1:3306/activiti_demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
redirect-url:
system-management: http://localhost:8764/swagger-ui.html
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 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" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1540200341676" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="holiday" isClosed="false" isExecutable="true" name="请假流程" processType="None">
<startEvent id="_2" name="StartEvent"/>
<userTask activiti:assignee="zhangsan" activiti:exclusive="true" id="_3" name="flow_first"/>
<userTask activiti:assignee="lisi" activiti:exclusive="true" id="_4" name="flow_second"/>
<userTask activiti:assignee="wangwu" activiti:exclusive="true" id="_5" name="flow_third"/>
<endEvent id="_6" name="EndEvent"/>
<sequenceFlow id="_7" sourceRef="_2" targetRef="_3"/>
<sequenceFlow id="_8" sourceRef="_3" targetRef="_4"/>
<sequenceFlow id="_9" sourceRef="_4" targetRef="_5"/>
<sequenceFlow id="_10" sourceRef="_5" targetRef="_6"/>
</process>
<bpmndi:BPMNDiagram documentation="background=#FFFFFF;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
<bpmndi:BPMNPlane bpmnElement="holiday">
<bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
<omgdc:Bounds height="32.0" width="32.0" x="280.0" y="45.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
<omgdc:Bounds height="55.0" width="85.0" x="255.0" y="140.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
<omgdc:Bounds height="55.0" width="85.0" x="255.0" y="245.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
<omgdc:Bounds height="55.0" width="85.0" x="255.0" y="350.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6" id="Shape-_6">
<omgdc:Bounds height="32.0" width="32.0" x="282.0" y="455.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_7" id="BPMNEdge__7" sourceElement="_2" targetElement="_3">
<omgdi:waypoint x="296.0" y="77.0"/>
<omgdi:waypoint x="296.0" y="140.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_3" targetElement="_4">
<omgdi:waypoint x="297.5" y="195.0"/>
<omgdi:waypoint x="297.5" y="245.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9" sourceElement="_4" targetElement="_5">
<omgdi:waypoint x="297.5" y="300.0"/>
<omgdi:waypoint x="297.5" y="350.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="_5" targetElement="_6">
<omgdi:waypoint x="291.0" y="405.0"/>
<omgdi:waypoint x="291.0" y="455.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment