通用解析
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 END = "end";
|
||||
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 DATA = "data";
|
||||
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}";
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
// 防止实例化
|
||||
}
|
||||
|
||||
@ -10,7 +10,10 @@ import org.flowable.bpmn.model.FieldExtension;
|
||||
import org.flowable.bpmn.model.ServiceTask;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Shell任务处理器
|
||||
@ -19,27 +22,25 @@ import java.util.Map;
|
||||
@Component
|
||||
public class ShellTaskHandler implements BpmnNodeHandler<ServiceTask> {
|
||||
|
||||
// Shell任务的必需字段
|
||||
private static final List<String> REQUIRED_FIELDS = Arrays.asList(
|
||||
BpmnConstants.ShellTaskConfig.SCRIPT,
|
||||
BpmnConstants.ShellTaskConfig.WORK_DIR
|
||||
);
|
||||
|
||||
@Override
|
||||
public void handle(JsonNode nodeData, ServiceTask element, BpmnNodeConfig config) {
|
||||
element.setImplementationType(BpmnConstants.DelegateExpression.TYPE);
|
||||
element.setImplementation(BpmnConstants.DelegateExpression.SHELL_TASK);
|
||||
element.setAsynchronous(true); // Shell任务默认异步执行
|
||||
// 设置任务委托表达式
|
||||
setupTaskDelegate(element);
|
||||
|
||||
// 从配置中获取字段
|
||||
Map<String, Object> properties = config.getProperties();
|
||||
properties.forEach((key, value) -> {
|
||||
if (value != null) {
|
||||
addFieldExtension(element, key, value.toString());
|
||||
}
|
||||
});
|
||||
// 设置任务属性
|
||||
setupTaskProperties(element, config);
|
||||
|
||||
// 验证必需字段
|
||||
validateRequiredFields(element);
|
||||
|
||||
// 处理扩展字段
|
||||
Map<String, String> extensions = config.getExtensions();
|
||||
extensions.forEach((key, value) -> {
|
||||
if (value != null) {
|
||||
addFieldExtension(element, key, value);
|
||||
}
|
||||
});
|
||||
handleExtensionFields(element, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -60,10 +61,72 @@ public class ShellTaskHandler implements BpmnNodeHandler<ServiceTask> {
|
||||
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) {
|
||||
FieldExtension field = new FieldExtension();
|
||||
field.setFieldName(name);
|
||||
field.setStringValue(value);
|
||||
serviceTask.getFieldExtensions().add(field);
|
||||
// 检查字段是否已存在
|
||||
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();
|
||||
field.setFieldName(name);
|
||||
field.setStringValue(value);
|
||||
serviceTask.getFieldExtensions().add(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,7 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -44,78 +45,121 @@ public class BpmnConverter {
|
||||
|
||||
public String convertToBpmnXml(String x6Json, String processId) throws Exception {
|
||||
JsonNode jsonNode = objectMapper.readTree(x6Json);
|
||||
|
||||
// 创建BPMN模型
|
||||
BpmnModel bpmnModel = new BpmnModel();
|
||||
Process process = new Process();
|
||||
process.setId(processId);
|
||||
process.setName(processId);
|
||||
process.setExecutable(true);
|
||||
bpmnModel.addProcess(process);
|
||||
BpmnModel bpmnModel = createBpmnModel(processId);
|
||||
Process process = bpmnModel.getMainProcess();
|
||||
|
||||
// 处理节点
|
||||
Map<String, FlowElement> elementMap = new HashMap<>();
|
||||
JsonNode cells = jsonNode.get("cells");
|
||||
JsonNode cells = jsonNode.path(BpmnConstants.ProcessAttribute.CELLS);
|
||||
|
||||
if (cells != null) {
|
||||
// 第一遍:处理所有节点
|
||||
for (JsonNode cell : cells) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!cells.isMissingNode()) {
|
||||
// 处理所有节点
|
||||
processNodes(cells, process, elementMap);
|
||||
|
||||
// 确保存在开始事件和结束事件(如果没有显式定义)
|
||||
ensureStartAndEndEvents(process, elementMap);
|
||||
|
||||
// 第二遍:处理所有连线
|
||||
for (JsonNode cell : cells) {
|
||||
if (isEdge(cell)) {
|
||||
handleSequenceFlow(cell, process, elementMap);
|
||||
}
|
||||
}
|
||||
// 处理所有连线
|
||||
processSequenceFlows(cells, process, elementMap);
|
||||
}
|
||||
|
||||
// 自动布局
|
||||
new BpmnAutoLayout(bpmnModel).execute();
|
||||
|
||||
// 转换为XML
|
||||
byte[] xmlBytes = bpmnXMLConverter.convertToXML(bpmnModel);
|
||||
return new String(xmlBytes);
|
||||
return new String(bpmnXMLConverter.convertToXML(bpmnModel));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建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) {
|
||||
@ -141,37 +185,66 @@ public class BpmnConverter {
|
||||
|
||||
// 如果没有开始事件,创建一个并连接到第一个任务
|
||||
if (startEvent == null && firstElement != null) {
|
||||
startEvent = new StartEvent();
|
||||
startEvent.setId(BpmnConstants.DefaultNodeId.START_EVENT);
|
||||
startEvent.setName(BpmnConstants.DefaultNodeName.START_EVENT);
|
||||
startEvent = createStartEvent();
|
||||
process.addFlowElement(startEvent);
|
||||
elementMap.put(startEvent.getId(), startEvent);
|
||||
|
||||
// 创建从开始事件到第一个任务的连线
|
||||
SequenceFlow startFlow = new SequenceFlow();
|
||||
startFlow.setId(BpmnConstants.DefaultNodeId.START_FLOW);
|
||||
startFlow.setSourceRef(startEvent.getId());
|
||||
startFlow.setTargetRef(firstElement.getId());
|
||||
SequenceFlow startFlow = createSequenceFlow(
|
||||
BpmnConstants.DefaultNodeId.START_FLOW,
|
||||
startEvent.getId(),
|
||||
firstElement.getId()
|
||||
);
|
||||
process.addFlowElement(startFlow);
|
||||
}
|
||||
|
||||
// 如果没有结束事件,创建一个并从最后一个任务连接到它
|
||||
if (endEvent == null && lastElement != null) {
|
||||
endEvent = new EndEvent();
|
||||
endEvent.setId(BpmnConstants.DefaultNodeId.END_EVENT);
|
||||
endEvent.setName(BpmnConstants.DefaultNodeName.END_EVENT);
|
||||
endEvent = createEndEvent();
|
||||
process.addFlowElement(endEvent);
|
||||
elementMap.put(endEvent.getId(), endEvent);
|
||||
|
||||
// 创建从最后一个任务到结束事件的连线
|
||||
SequenceFlow endFlow = new SequenceFlow();
|
||||
endFlow.setId(BpmnConstants.DefaultNodeId.END_FLOW);
|
||||
endFlow.setSourceRef(lastElement.getId());
|
||||
endFlow.setTargetRef(endEvent.getId());
|
||||
SequenceFlow endFlow = createSequenceFlow(
|
||||
BpmnConstants.DefaultNodeId.END_FLOW,
|
||||
lastElement.getId(),
|
||||
endEvent.getId()
|
||||
);
|
||||
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) {
|
||||
return cell.has(BpmnConstants.NodeAttribute.SHAPE) &&
|
||||
!BpmnConstants.NodeShape.EDGE.equals(cell.path(BpmnConstants.NodeAttribute.SHAPE).asText());
|
||||
@ -199,10 +272,7 @@ public class BpmnConverter {
|
||||
FlowElement targetElement = elementMap.get(targetId);
|
||||
|
||||
if (sourceElement != null && targetElement != null) {
|
||||
SequenceFlow sequenceFlow = new SequenceFlow();
|
||||
sequenceFlow.setId(id);
|
||||
sequenceFlow.setSourceRef(sourceId);
|
||||
sequenceFlow.setTargetRef(targetId);
|
||||
SequenceFlow sequenceFlow = createSequenceFlow(id, sourceId, targetId);
|
||||
|
||||
// 设置连线名称
|
||||
JsonNode label = cell.path(BpmnConstants.NodeAttribute.DATA)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user