通用解析
This commit is contained in:
parent
9c906be60a
commit
220e930040
@ -12,6 +12,7 @@ public class BpmnConstants {
|
|||||||
public static final String START = "start";
|
public static final String START = "start";
|
||||||
public static final String END = "end";
|
public static final String END = "end";
|
||||||
public static final String EDGE = "edge";
|
public static final String EDGE = "edge";
|
||||||
|
public static final String SHELL_TASK = "shellTask";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,6 +26,8 @@ public class BpmnConstants {
|
|||||||
public static final String TARGET = "target";
|
public static final String TARGET = "target";
|
||||||
public static final String DATA = "data";
|
public static final String DATA = "data";
|
||||||
public static final String CONDITION = "condition";
|
public static final String CONDITION = "condition";
|
||||||
|
public static final String SERVICE_TASK = "serviceTask";
|
||||||
|
public static final String FIELDS = "fields";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,6 +56,27 @@ public class BpmnConstants {
|
|||||||
public static final String SHELL_TASK = "${shellTaskDelegate}";
|
public static final String SHELL_TASK = "${shellTaskDelegate}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shell任务配置
|
||||||
|
*/
|
||||||
|
public static class ShellTaskConfig {
|
||||||
|
public static final String SCRIPT = "script";
|
||||||
|
public static final String WORK_DIR = "workDir";
|
||||||
|
public static final String TIMEOUT = "timeout";
|
||||||
|
public static final String RETRY_COUNT = "retryCount";
|
||||||
|
public static final String ENV = "env";
|
||||||
|
public static final String PRIORITY = "priority";
|
||||||
|
public static final String GROUP = "group";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程属性
|
||||||
|
*/
|
||||||
|
public static class ProcessAttribute {
|
||||||
|
public static final String CELLS = "cells";
|
||||||
|
public static final String EXECUTABLE = "true";
|
||||||
|
}
|
||||||
|
|
||||||
private BpmnConstants() {
|
private BpmnConstants() {
|
||||||
// 防止实例化
|
// 防止实例化
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,10 @@ import org.flowable.bpmn.model.FieldExtension;
|
|||||||
import org.flowable.bpmn.model.ServiceTask;
|
import org.flowable.bpmn.model.ServiceTask;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shell任务处理器
|
* Shell任务处理器
|
||||||
@ -19,27 +22,25 @@ import java.util.Map;
|
|||||||
@Component
|
@Component
|
||||||
public class ShellTaskHandler implements BpmnNodeHandler<ServiceTask> {
|
public class ShellTaskHandler implements BpmnNodeHandler<ServiceTask> {
|
||||||
|
|
||||||
|
// Shell任务的必需字段
|
||||||
|
private static final List<String> REQUIRED_FIELDS = Arrays.asList(
|
||||||
|
BpmnConstants.ShellTaskConfig.SCRIPT,
|
||||||
|
BpmnConstants.ShellTaskConfig.WORK_DIR
|
||||||
|
);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(JsonNode nodeData, ServiceTask element, BpmnNodeConfig config) {
|
public void handle(JsonNode nodeData, ServiceTask element, BpmnNodeConfig config) {
|
||||||
element.setImplementationType(BpmnConstants.DelegateExpression.TYPE);
|
// 设置任务委托表达式
|
||||||
element.setImplementation(BpmnConstants.DelegateExpression.SHELL_TASK);
|
setupTaskDelegate(element);
|
||||||
element.setAsynchronous(true); // Shell任务默认异步执行
|
|
||||||
|
|
||||||
// 从配置中获取字段
|
// 设置任务属性
|
||||||
Map<String, Object> properties = config.getProperties();
|
setupTaskProperties(element, config);
|
||||||
properties.forEach((key, value) -> {
|
|
||||||
if (value != null) {
|
// 验证必需字段
|
||||||
addFieldExtension(element, key, value.toString());
|
validateRequiredFields(element);
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 处理扩展字段
|
// 处理扩展字段
|
||||||
Map<String, String> extensions = config.getExtensions();
|
handleExtensionFields(element, config);
|
||||||
extensions.forEach((key, value) -> {
|
|
||||||
if (value != null) {
|
|
||||||
addFieldExtension(element, key, value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -60,10 +61,72 @@ public class ShellTaskHandler implements BpmnNodeHandler<ServiceTask> {
|
|||||||
return ServiceTask.class;
|
return ServiceTask.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置任务委托表达式
|
||||||
|
*/
|
||||||
|
private void setupTaskDelegate(ServiceTask element) {
|
||||||
|
element.setImplementationType(BpmnConstants.DelegateExpression.TYPE);
|
||||||
|
element.setImplementation(BpmnConstants.DelegateExpression.SHELL_TASK);
|
||||||
|
element.setAsynchronous(true); // Shell任务默认异步执行
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置任务属性
|
||||||
|
*/
|
||||||
|
private void setupTaskProperties(ServiceTask element, BpmnNodeConfig config) {
|
||||||
|
Map<String, Object> properties = config.getProperties();
|
||||||
|
properties.forEach((key, value) -> {
|
||||||
|
if (value != null) {
|
||||||
|
addFieldExtension(element, key, value.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证必需字段
|
||||||
|
*/
|
||||||
|
private void validateRequiredFields(ServiceTask element) {
|
||||||
|
List<FieldExtension> fields = element.getFieldExtensions();
|
||||||
|
for (String requiredField : REQUIRED_FIELDS) {
|
||||||
|
boolean fieldExists = fields.stream()
|
||||||
|
.anyMatch(field -> field.getFieldName().equals(requiredField));
|
||||||
|
if (!fieldExists) {
|
||||||
|
log.warn("Required field '{}' is missing for shell task '{}'",
|
||||||
|
requiredField, element.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理扩展字段
|
||||||
|
*/
|
||||||
|
private void handleExtensionFields(ServiceTask element, BpmnNodeConfig config) {
|
||||||
|
Map<String, String> extensions = config.getExtensions();
|
||||||
|
extensions.forEach((key, value) -> {
|
||||||
|
if (value != null) {
|
||||||
|
addFieldExtension(element, key, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加字段扩展
|
||||||
|
*/
|
||||||
private void addFieldExtension(ServiceTask serviceTask, String name, String value) {
|
private void addFieldExtension(ServiceTask serviceTask, String name, String value) {
|
||||||
|
// 检查字段是否已存在
|
||||||
|
Optional<FieldExtension> existingField = serviceTask.getFieldExtensions().stream()
|
||||||
|
.filter(field -> field.getFieldName().equals(name))
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (existingField.isPresent()) {
|
||||||
|
// 更新现有字段
|
||||||
|
existingField.get().setStringValue(value);
|
||||||
|
} else {
|
||||||
|
// 添加新字段
|
||||||
FieldExtension field = new FieldExtension();
|
FieldExtension field = new FieldExtension();
|
||||||
field.setFieldName(name);
|
field.setFieldName(name);
|
||||||
field.setStringValue(value);
|
field.setStringValue(value);
|
||||||
serviceTask.getFieldExtensions().add(field);
|
serviceTask.getFieldExtensions().add(field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@ -17,6 +17,7 @@ import org.springframework.stereotype.Component;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -44,52 +45,103 @@ public class BpmnConverter {
|
|||||||
|
|
||||||
public String convertToBpmnXml(String x6Json, String processId) throws Exception {
|
public String convertToBpmnXml(String x6Json, String processId) throws Exception {
|
||||||
JsonNode jsonNode = objectMapper.readTree(x6Json);
|
JsonNode jsonNode = objectMapper.readTree(x6Json);
|
||||||
|
BpmnModel bpmnModel = createBpmnModel(processId);
|
||||||
|
Process process = bpmnModel.getMainProcess();
|
||||||
|
|
||||||
// 创建BPMN模型
|
// 处理节点
|
||||||
|
Map<String, FlowElement> elementMap = new HashMap<>();
|
||||||
|
JsonNode cells = jsonNode.path(BpmnConstants.ProcessAttribute.CELLS);
|
||||||
|
|
||||||
|
if (!cells.isMissingNode()) {
|
||||||
|
// 处理所有节点
|
||||||
|
processNodes(cells, process, elementMap);
|
||||||
|
|
||||||
|
// 确保存在开始事件和结束事件(如果没有显式定义)
|
||||||
|
ensureStartAndEndEvents(process, elementMap);
|
||||||
|
|
||||||
|
// 处理所有连线
|
||||||
|
processSequenceFlows(cells, process, elementMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动布局
|
||||||
|
new BpmnAutoLayout(bpmnModel).execute();
|
||||||
|
|
||||||
|
// 转换为XML
|
||||||
|
return new String(bpmnXMLConverter.convertToXML(bpmnModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建BPMN模型
|
||||||
|
*/
|
||||||
|
private BpmnModel createBpmnModel(String processId) {
|
||||||
BpmnModel bpmnModel = new BpmnModel();
|
BpmnModel bpmnModel = new BpmnModel();
|
||||||
Process process = new Process();
|
Process process = new Process();
|
||||||
process.setId(processId);
|
process.setId(processId);
|
||||||
process.setName(processId);
|
process.setName(processId);
|
||||||
process.setExecutable(true);
|
process.setExecutable(Boolean.parseBoolean(BpmnConstants.ProcessAttribute.EXECUTABLE));
|
||||||
bpmnModel.addProcess(process);
|
bpmnModel.addProcess(process);
|
||||||
|
return bpmnModel;
|
||||||
// 处理节点
|
|
||||||
Map<String, FlowElement> elementMap = new HashMap<>();
|
|
||||||
JsonNode cells = jsonNode.get("cells");
|
|
||||||
|
|
||||||
if (cells != null) {
|
|
||||||
// 第一遍:处理所有节点
|
|
||||||
for (JsonNode cell : cells) {
|
|
||||||
if (!isNode(cell)) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理所有节点
|
||||||
|
*/
|
||||||
|
private void processNodes(JsonNode cells, Process process, Map<String, FlowElement> elementMap) {
|
||||||
|
cells.forEach(cell -> {
|
||||||
|
if (isNode(cell)) {
|
||||||
|
processNode(cell, process, elementMap);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理单个节点
|
||||||
|
*/
|
||||||
|
private void processNode(JsonNode cell, Process process, Map<String, FlowElement> elementMap) {
|
||||||
String shape = cell.path(BpmnConstants.NodeAttribute.SHAPE).asText();
|
String shape = cell.path(BpmnConstants.NodeAttribute.SHAPE).asText();
|
||||||
String id = cell.path(BpmnConstants.NodeAttribute.ID).asText();
|
String id = cell.path(BpmnConstants.NodeAttribute.ID).asText();
|
||||||
String label = cell.path(BpmnConstants.NodeAttribute.DATA)
|
String label = cell.path(BpmnConstants.NodeAttribute.DATA)
|
||||||
.path(BpmnConstants.NodeAttribute.LABEL).asText("");
|
.path(BpmnConstants.NodeAttribute.LABEL).asText("");
|
||||||
|
|
||||||
// 处理特殊节点类型
|
// 处理特殊节点类型
|
||||||
|
Optional<FlowElement> specialElement = createSpecialElement(shape, id, label);
|
||||||
|
if (specialElement.isPresent()) {
|
||||||
|
process.addFlowElement(specialElement.get());
|
||||||
|
elementMap.put(id, specialElement.get());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理普通节点
|
||||||
|
processRegularNode(cell, process, elementMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建特殊元素(开始/结束事件)
|
||||||
|
*/
|
||||||
|
private Optional<FlowElement> createSpecialElement(String shape, String id, String label) {
|
||||||
|
FlowElement element = null;
|
||||||
|
|
||||||
if (BpmnConstants.NodeShape.START.equals(shape)) {
|
if (BpmnConstants.NodeShape.START.equals(shape)) {
|
||||||
StartEvent startEvent = new StartEvent();
|
StartEvent startEvent = new StartEvent();
|
||||||
startEvent.setId(id);
|
startEvent.setId(id);
|
||||||
startEvent.setName(label);
|
startEvent.setName(label);
|
||||||
process.addFlowElement(startEvent);
|
element = startEvent;
|
||||||
elementMap.put(id, startEvent);
|
|
||||||
continue;
|
|
||||||
} else if (BpmnConstants.NodeShape.END.equals(shape)) {
|
} else if (BpmnConstants.NodeShape.END.equals(shape)) {
|
||||||
EndEvent endEvent = new EndEvent();
|
EndEvent endEvent = new EndEvent();
|
||||||
endEvent.setId(id);
|
endEvent.setId(id);
|
||||||
endEvent.setName(label);
|
endEvent.setName(label);
|
||||||
process.addFlowElement(endEvent);
|
element = endEvent;
|
||||||
elementMap.put(id, endEvent);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析节点配置
|
return Optional.ofNullable(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理普通节点
|
||||||
|
*/
|
||||||
|
private void processRegularNode(JsonNode cell, Process process, Map<String, FlowElement> elementMap) {
|
||||||
BpmnNodeConfig config = configParser.parse(cell);
|
BpmnNodeConfig config = configParser.parse(cell);
|
||||||
if (config.getType() != null) {
|
if (config.getType() != null) {
|
||||||
// 使用对应的处理器处理节点
|
|
||||||
BpmnNodeHandler<?> handler = handlers.get(config.getType());
|
BpmnNodeHandler<?> handler = handlers.get(config.getType());
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
FlowElement element = createAndHandleElement(handler, cell, config);
|
FlowElement element = createAndHandleElement(handler, cell, config);
|
||||||
@ -99,23 +151,15 @@ public class BpmnConverter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确保存在开始事件和结束事件(如果没有显式定义)
|
/**
|
||||||
ensureStartAndEndEvents(process, elementMap);
|
* 处理所有连线
|
||||||
|
*/
|
||||||
// 第二遍:处理所有连线
|
private void processSequenceFlows(JsonNode cells, Process process, Map<String, FlowElement> elementMap) {
|
||||||
for (JsonNode cell : cells) {
|
cells.forEach(cell -> {
|
||||||
if (isEdge(cell)) {
|
if (isEdge(cell)) {
|
||||||
handleSequenceFlow(cell, process, elementMap);
|
handleSequenceFlow(cell, process, elementMap);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// 自动布局
|
|
||||||
new BpmnAutoLayout(bpmnModel).execute();
|
|
||||||
|
|
||||||
// 转换为XML
|
|
||||||
byte[] xmlBytes = bpmnXMLConverter.convertToXML(bpmnModel);
|
|
||||||
return new String(xmlBytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureStartAndEndEvents(Process process, Map<String, FlowElement> elementMap) {
|
private void ensureStartAndEndEvents(Process process, Map<String, FlowElement> elementMap) {
|
||||||
@ -141,37 +185,66 @@ public class BpmnConverter {
|
|||||||
|
|
||||||
// 如果没有开始事件,创建一个并连接到第一个任务
|
// 如果没有开始事件,创建一个并连接到第一个任务
|
||||||
if (startEvent == null && firstElement != null) {
|
if (startEvent == null && firstElement != null) {
|
||||||
startEvent = new StartEvent();
|
startEvent = createStartEvent();
|
||||||
startEvent.setId(BpmnConstants.DefaultNodeId.START_EVENT);
|
|
||||||
startEvent.setName(BpmnConstants.DefaultNodeName.START_EVENT);
|
|
||||||
process.addFlowElement(startEvent);
|
process.addFlowElement(startEvent);
|
||||||
elementMap.put(startEvent.getId(), startEvent);
|
elementMap.put(startEvent.getId(), startEvent);
|
||||||
|
|
||||||
// 创建从开始事件到第一个任务的连线
|
// 创建从开始事件到第一个任务的连线
|
||||||
SequenceFlow startFlow = new SequenceFlow();
|
SequenceFlow startFlow = createSequenceFlow(
|
||||||
startFlow.setId(BpmnConstants.DefaultNodeId.START_FLOW);
|
BpmnConstants.DefaultNodeId.START_FLOW,
|
||||||
startFlow.setSourceRef(startEvent.getId());
|
startEvent.getId(),
|
||||||
startFlow.setTargetRef(firstElement.getId());
|
firstElement.getId()
|
||||||
|
);
|
||||||
process.addFlowElement(startFlow);
|
process.addFlowElement(startFlow);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没有结束事件,创建一个并从最后一个任务连接到它
|
// 如果没有结束事件,创建一个并从最后一个任务连接到它
|
||||||
if (endEvent == null && lastElement != null) {
|
if (endEvent == null && lastElement != null) {
|
||||||
endEvent = new EndEvent();
|
endEvent = createEndEvent();
|
||||||
endEvent.setId(BpmnConstants.DefaultNodeId.END_EVENT);
|
|
||||||
endEvent.setName(BpmnConstants.DefaultNodeName.END_EVENT);
|
|
||||||
process.addFlowElement(endEvent);
|
process.addFlowElement(endEvent);
|
||||||
elementMap.put(endEvent.getId(), endEvent);
|
elementMap.put(endEvent.getId(), endEvent);
|
||||||
|
|
||||||
// 创建从最后一个任务到结束事件的连线
|
// 创建从最后一个任务到结束事件的连线
|
||||||
SequenceFlow endFlow = new SequenceFlow();
|
SequenceFlow endFlow = createSequenceFlow(
|
||||||
endFlow.setId(BpmnConstants.DefaultNodeId.END_FLOW);
|
BpmnConstants.DefaultNodeId.END_FLOW,
|
||||||
endFlow.setSourceRef(lastElement.getId());
|
lastElement.getId(),
|
||||||
endFlow.setTargetRef(endEvent.getId());
|
endEvent.getId()
|
||||||
|
);
|
||||||
process.addFlowElement(endFlow);
|
process.addFlowElement(endFlow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建开始事件
|
||||||
|
*/
|
||||||
|
private StartEvent createStartEvent() {
|
||||||
|
StartEvent startEvent = new StartEvent();
|
||||||
|
startEvent.setId(BpmnConstants.DefaultNodeId.START_EVENT);
|
||||||
|
startEvent.setName(BpmnConstants.DefaultNodeName.START_EVENT);
|
||||||
|
return startEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建结束事件
|
||||||
|
*/
|
||||||
|
private EndEvent createEndEvent() {
|
||||||
|
EndEvent endEvent = new EndEvent();
|
||||||
|
endEvent.setId(BpmnConstants.DefaultNodeId.END_EVENT);
|
||||||
|
endEvent.setName(BpmnConstants.DefaultNodeName.END_EVENT);
|
||||||
|
return endEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建连线
|
||||||
|
*/
|
||||||
|
private SequenceFlow createSequenceFlow(String id, String sourceRef, String targetRef) {
|
||||||
|
SequenceFlow flow = new SequenceFlow();
|
||||||
|
flow.setId(id);
|
||||||
|
flow.setSourceRef(sourceRef);
|
||||||
|
flow.setTargetRef(targetRef);
|
||||||
|
return flow;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isNode(JsonNode cell) {
|
private boolean isNode(JsonNode cell) {
|
||||||
return cell.has(BpmnConstants.NodeAttribute.SHAPE) &&
|
return cell.has(BpmnConstants.NodeAttribute.SHAPE) &&
|
||||||
!BpmnConstants.NodeShape.EDGE.equals(cell.path(BpmnConstants.NodeAttribute.SHAPE).asText());
|
!BpmnConstants.NodeShape.EDGE.equals(cell.path(BpmnConstants.NodeAttribute.SHAPE).asText());
|
||||||
@ -199,10 +272,7 @@ public class BpmnConverter {
|
|||||||
FlowElement targetElement = elementMap.get(targetId);
|
FlowElement targetElement = elementMap.get(targetId);
|
||||||
|
|
||||||
if (sourceElement != null && targetElement != null) {
|
if (sourceElement != null && targetElement != null) {
|
||||||
SequenceFlow sequenceFlow = new SequenceFlow();
|
SequenceFlow sequenceFlow = createSequenceFlow(id, sourceId, targetId);
|
||||||
sequenceFlow.setId(id);
|
|
||||||
sequenceFlow.setSourceRef(sourceId);
|
|
||||||
sequenceFlow.setTargetRef(targetId);
|
|
||||||
|
|
||||||
// 设置连线名称
|
// 设置连线名称
|
||||||
JsonNode label = cell.path(BpmnConstants.NodeAttribute.DATA)
|
JsonNode label = cell.path(BpmnConstants.NodeAttribute.DATA)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user