通用解析

This commit is contained in:
戚辰先生 2024-12-10 21:53:38 +08:00
parent 9c906be60a
commit 220e930040
3 changed files with 253 additions and 96 deletions

View File

@ -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() {
// 防止实例化 // 防止实例化
} }

View File

@ -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) {
FieldExtension field = new FieldExtension(); // 检查字段是否已存在
field.setFieldName(name); Optional<FieldExtension> existingField = serviceTask.getFieldExtensions().stream()
field.setStringValue(value); .filter(field -> field.getFieldName().equals(name))
serviceTask.getFieldExtensions().add(field); .findFirst();
if (existingField.isPresent()) {
// 更新现有字段
existingField.get().setStringValue(value);
} else {
// 添加新字段
FieldExtension field = new FieldExtension();
field.setFieldName(name);
field.setStringValue(value);
serviceTask.getFieldExtensions().add(field);
}
} }
} }

View File

@ -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,78 +45,121 @@ 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);
// 创建BPMN模型 Process process = bpmnModel.getMainProcess();
BpmnModel bpmnModel = new BpmnModel();
Process process = new Process();
process.setId(processId);
process.setName(processId);
process.setExecutable(true);
bpmnModel.addProcess(process);
// 处理节点 // 处理节点
Map<String, FlowElement> elementMap = new HashMap<>(); Map<String, FlowElement> elementMap = new HashMap<>();
JsonNode cells = jsonNode.get("cells"); JsonNode cells = jsonNode.path(BpmnConstants.ProcessAttribute.CELLS);
if (cells != null) { if (!cells.isMissingNode()) {
// 第一遍处理所有节点 // 处理所有节点
for (JsonNode cell : cells) { processNodes(cells, process, elementMap);
if (!isNode(cell)) {
continue;
}
String shape = cell.path(BpmnConstants.NodeAttribute.SHAPE).asText();
String id = cell.path(BpmnConstants.NodeAttribute.ID).asText();
String label = cell.path(BpmnConstants.NodeAttribute.DATA)
.path(BpmnConstants.NodeAttribute.LABEL).asText("");
// 处理特殊节点类型
if (BpmnConstants.NodeShape.START.equals(shape)) {
StartEvent startEvent = new StartEvent();
startEvent.setId(id);
startEvent.setName(label);
process.addFlowElement(startEvent);
elementMap.put(id, startEvent);
continue;
} else if (BpmnConstants.NodeShape.END.equals(shape)) {
EndEvent endEvent = new EndEvent();
endEvent.setId(id);
endEvent.setName(label);
process.addFlowElement(endEvent);
elementMap.put(id, endEvent);
continue;
}
// 解析节点配置
BpmnNodeConfig config = configParser.parse(cell);
if (config.getType() != null) {
// 使用对应的处理器处理节点
BpmnNodeHandler<?> handler = handlers.get(config.getType());
if (handler != null) {
FlowElement element = createAndHandleElement(handler, cell, config);
process.addFlowElement(element);
elementMap.put(config.getId(), element);
}
}
}
// 确保存在开始事件和结束事件如果没有显式定义 // 确保存在开始事件和结束事件如果没有显式定义
ensureStartAndEndEvents(process, elementMap); ensureStartAndEndEvents(process, elementMap);
// 第二遍处理所有连线 // 处理所有连线
for (JsonNode cell : cells) { processSequenceFlows(cells, process, elementMap);
if (isEdge(cell)) {
handleSequenceFlow(cell, process, elementMap);
}
}
} }
// 自动布局 // 自动布局
new BpmnAutoLayout(bpmnModel).execute(); new BpmnAutoLayout(bpmnModel).execute();
// 转换为XML // 转换为XML
byte[] xmlBytes = bpmnXMLConverter.convertToXML(bpmnModel); return new String(bpmnXMLConverter.convertToXML(bpmnModel));
return new String(xmlBytes); }
/**
* 创建BPMN模型
*/
private BpmnModel createBpmnModel(String processId) {
BpmnModel bpmnModel = new BpmnModel();
Process process = new Process();
process.setId(processId);
process.setName(processId);
process.setExecutable(Boolean.parseBoolean(BpmnConstants.ProcessAttribute.EXECUTABLE));
bpmnModel.addProcess(process);
return bpmnModel;
}
/**
* 处理所有节点
*/
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 id = cell.path(BpmnConstants.NodeAttribute.ID).asText();
String label = cell.path(BpmnConstants.NodeAttribute.DATA)
.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)) {
StartEvent startEvent = new StartEvent();
startEvent.setId(id);
startEvent.setName(label);
element = startEvent;
} else if (BpmnConstants.NodeShape.END.equals(shape)) {
EndEvent endEvent = new EndEvent();
endEvent.setId(id);
endEvent.setName(label);
element = endEvent;
}
return Optional.ofNullable(element);
}
/**
* 处理普通节点
*/
private void processRegularNode(JsonNode cell, Process process, Map<String, FlowElement> elementMap) {
BpmnNodeConfig config = configParser.parse(cell);
if (config.getType() != null) {
BpmnNodeHandler<?> handler = handlers.get(config.getType());
if (handler != null) {
FlowElement element = createAndHandleElement(handler, cell, config);
process.addFlowElement(element);
elementMap.put(config.getId(), element);
}
}
}
/**
* 处理所有连线
*/
private void processSequenceFlows(JsonNode cells, Process process, Map<String, FlowElement> elementMap) {
cells.forEach(cell -> {
if (isEdge(cell)) {
handleSequenceFlow(cell, process, elementMap);
}
});
} }
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)