反序列化问题。
This commit is contained in:
parent
57f1a8d90f
commit
1914c67566
@ -18,6 +18,26 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class BaseNodeDelegate<P, L> implements JavaDelegate {
|
public abstract class BaseNodeDelegate<P, L> implements JavaDelegate {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行状态变量名
|
||||||
|
*/
|
||||||
|
protected static final String EXECUTION_STATUS = "executionStatus";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行状态:成功
|
||||||
|
*/
|
||||||
|
protected static final String STATUS_SUCCESS = "success";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行状态:失败
|
||||||
|
*/
|
||||||
|
protected static final String STATUS_FAILURE = "failure";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行状态:中止
|
||||||
|
*/
|
||||||
|
protected static final String STATUS_ABORTED = "aborted";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ObjectMapper objectMapper;
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
@ -47,12 +67,30 @@ public abstract class BaseNodeDelegate<P, L> implements JavaDelegate {
|
|||||||
// 执行具体的任务逻辑
|
// 执行具体的任务逻辑
|
||||||
executeInternal(execution, panelVars, localVars);
|
executeInternal(execution, panelVars, localVars);
|
||||||
|
|
||||||
|
// 如果节点没有设置状态,默认设置成功状态
|
||||||
|
if (execution.getVariable(EXECUTION_STATUS) == null) {
|
||||||
|
setExecutionStatus(execution, STATUS_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
// 设置失败状态
|
||||||
|
setExecutionStatus(execution, STATUS_FAILURE);
|
||||||
log.error("Task execution failed", e);
|
log.error("Task execution failed", e);
|
||||||
throw new RuntimeException("Task execution failed: " + e.getMessage(), e);
|
throw new RuntimeException("Task execution failed: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置执行状态
|
||||||
|
*
|
||||||
|
* @param execution 执行上下文
|
||||||
|
* @param status 状态值
|
||||||
|
*/
|
||||||
|
protected void setExecutionStatus(DelegateExecution execution, String status) {
|
||||||
|
execution.setVariable(EXECUTION_STATUS, status);
|
||||||
|
log.debug("Set execution status: {}", status);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取Panel变量的类型
|
* 获取Panel变量的类型
|
||||||
*
|
*
|
||||||
|
|||||||
@ -0,0 +1,19 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.dto.definition.node.localVariables;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.workflow.annotation.SchemaProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class GatewayNodeLocalVariables extends BaseNodeLocalVariables {
|
||||||
|
|
||||||
|
@SchemaProperty(
|
||||||
|
title = "委派者",
|
||||||
|
description = "委派者",
|
||||||
|
defaultValue = "${gatewayNodeDelegate}",
|
||||||
|
required = true
|
||||||
|
)
|
||||||
|
private String delegate;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables;
|
||||||
|
|
||||||
|
import com.qqchen.deploy.backend.workflow.annotation.SchemaProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class GatewayNodePanelVariables extends BaseNodePanelVariables {
|
||||||
|
|
||||||
|
@SchemaProperty(
|
||||||
|
title = "网关类型",
|
||||||
|
description = "网关类型",
|
||||||
|
required = true,
|
||||||
|
enumValues = {
|
||||||
|
"EXCLUSIVE_GATEWAY", // 排他网关
|
||||||
|
"PARALLEL_GATEWAY", // 并行网关
|
||||||
|
"INCLUSIVE_GATEWAY" // 包容网关
|
||||||
|
},
|
||||||
|
enumNames = {
|
||||||
|
"排他网关",
|
||||||
|
"并行网关",
|
||||||
|
"包容网关"
|
||||||
|
},
|
||||||
|
defaultValue = "EXCLUSIVE_GATEWAY"
|
||||||
|
)
|
||||||
|
private String gatewayType;
|
||||||
|
}
|
||||||
@ -8,7 +8,8 @@ public class Circle {
|
|||||||
@SchemaProperty(
|
@SchemaProperty(
|
||||||
title = "半径",
|
title = "半径",
|
||||||
description = "圆的半径",
|
description = "圆的半径",
|
||||||
required = true
|
required = true,
|
||||||
|
defaultValue = "5"
|
||||||
)
|
)
|
||||||
private Integer r;
|
private Integer r;
|
||||||
|
|
||||||
|
|||||||
@ -3,32 +3,12 @@ package com.qqchen.deploy.backend.workflow.dto.definition.workflow;
|
|||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
|
||||||
* 边配置
|
|
||||||
* @author cascade
|
|
||||||
* @date 2024-12-11
|
|
||||||
*/
|
|
||||||
@Data
|
@Data
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) // 只序列化非空字段
|
@JsonInclude(JsonInclude.Include.NON_NULL) // 只序列化非空字段
|
||||||
public class WorkflowDefinitionEdgeConfig {
|
public class WorkflowDefinitionEdgeConfig {
|
||||||
/**
|
|
||||||
* 条件
|
|
||||||
*/
|
|
||||||
private String condition;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 表达式
|
|
||||||
*/
|
|
||||||
private String expression;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 条件表达式
|
|
||||||
*/
|
|
||||||
private String conditionExpression;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 类型(sequence/message/association)
|
|
||||||
*/
|
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
|
private WorkflowDefinitionEdgeConfigCondition condition;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
package com.qqchen.deploy.backend.workflow.dto.definition.workflow;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) // 只序列化非空字段
|
||||||
|
public class WorkflowDefinitionEdgeConfigCondition {
|
||||||
|
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
private String expression;
|
||||||
|
|
||||||
|
private int priority;
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,21 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.dto.definition.workflow;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 节点大小
|
|
||||||
* @author cascade
|
|
||||||
* @date 2024-12-11
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class WorkflowDefinitionEdgeSize {
|
|
||||||
/**
|
|
||||||
* 宽度
|
|
||||||
*/
|
|
||||||
private Integer width;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 高度
|
|
||||||
*/
|
|
||||||
private Integer height;
|
|
||||||
}
|
|
||||||
@ -3,21 +3,16 @@ package com.qqchen.deploy.backend.workflow.dto.definition.workflow;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
|
||||||
* 工作流图形数据传输对象
|
|
||||||
* @author cascade
|
|
||||||
* @date 2024-12-11
|
|
||||||
*/
|
|
||||||
@Data
|
@Data
|
||||||
public class WorkflowDefinitionGraph {
|
public class WorkflowDefinitionGraph {
|
||||||
/**
|
/**
|
||||||
* 节点列表
|
* 节点列表
|
||||||
*/
|
*/
|
||||||
private List<WorkflowDefinitionNode> nodes;
|
private List<WorkflowDefinitionGraphNode> nodes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 边列表
|
* 边列表
|
||||||
*/
|
*/
|
||||||
private List<WorkflowDefinitionEdge> edges;
|
private List<WorkflowDefinitionGraphEdge> edges;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import java.util.Map;
|
|||||||
* @date 2024-12-11
|
* @date 2024-12-11
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class WorkflowDefinitionEdge {
|
public class WorkflowDefinitionGraphEdge {
|
||||||
/**
|
/**
|
||||||
* 边ID
|
* 边ID
|
||||||
*/
|
*/
|
||||||
@ -35,8 +35,4 @@ public class WorkflowDefinitionEdge {
|
|||||||
*/
|
*/
|
||||||
private WorkflowDefinitionEdgeConfig config;
|
private WorkflowDefinitionEdgeConfig config;
|
||||||
|
|
||||||
/**
|
|
||||||
* 边属性
|
|
||||||
*/
|
|
||||||
private Map<String, Object> properties;
|
|
||||||
}
|
}
|
||||||
@ -5,8 +5,6 @@ import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工作流节点数据传输对象
|
* 工作流节点数据传输对象
|
||||||
*
|
*
|
||||||
@ -14,7 +12,7 @@ import java.util.Map;
|
|||||||
* @date 2024-12-11
|
* @date 2024-12-11
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class WorkflowDefinitionNode {
|
public class WorkflowDefinitionGraphNode {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 节点ID
|
* 节点ID
|
||||||
@ -1,25 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.dto.definition.workflow;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 位置数据传输对象
|
|
||||||
* @author cascade
|
|
||||||
* @date 2024-12-11
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class WorkflowDefinitionPosition {
|
|
||||||
/**
|
|
||||||
* X坐标
|
|
||||||
*/
|
|
||||||
private Double x;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Y坐标
|
|
||||||
*/
|
|
||||||
private Double y;
|
|
||||||
}
|
|
||||||
@ -1,195 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.dto.definition.workflow;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 节点UI配置类
|
|
||||||
* 用于定义工作流节点的UI展示属性
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class WorkflowNodeGraph {
|
|
||||||
|
|
||||||
private String shape;
|
|
||||||
|
|
||||||
private Size size;
|
|
||||||
|
|
||||||
private Style style;
|
|
||||||
|
|
||||||
private Ports ports;
|
|
||||||
|
|
||||||
private Position position;
|
|
||||||
|
|
||||||
public WorkflowNodeGraph setSize(int width, int height) {
|
|
||||||
this.size = new Size(width, height);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorkflowNodeGraph setStyle(String fill, String stroke, String icon) {
|
|
||||||
this.style = new Style(fill, stroke, icon);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorkflowNodeGraph setPosition(int x, int y) {
|
|
||||||
this.position = new Position(x, y);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorkflowNodeGraph configPorts(List<String> types) {
|
|
||||||
this.ports = new Ports();
|
|
||||||
Map<String, PortGroup> groups = new HashMap<>();
|
|
||||||
|
|
||||||
types.forEach(type -> {
|
|
||||||
PortGroup group = new PortGroup();
|
|
||||||
group.setPosition(type.equals("in") ? "left" : "right");
|
|
||||||
|
|
||||||
PortCircle circle = new PortCircle();
|
|
||||||
circle.setR(4);
|
|
||||||
circle.setFill("#ffffff");
|
|
||||||
circle.setStroke("#1890ff");
|
|
||||||
|
|
||||||
PortAttrs attrs = new PortAttrs();
|
|
||||||
attrs.setCircle(circle);
|
|
||||||
|
|
||||||
group.setAttrs(attrs);
|
|
||||||
groups.put(type, group);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.ports.setGroups(groups);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 节点大小配置
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class Size {
|
|
||||||
private int width;
|
|
||||||
|
|
||||||
private int height;
|
|
||||||
|
|
||||||
public Size() {
|
|
||||||
// 默认构造函数
|
|
||||||
}
|
|
||||||
|
|
||||||
public Size(int width, int height) {
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 节点位置配置
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class Position {
|
|
||||||
|
|
||||||
private int x;
|
|
||||||
|
|
||||||
private int y;
|
|
||||||
|
|
||||||
public Position() {
|
|
||||||
// 默认构造函数
|
|
||||||
}
|
|
||||||
|
|
||||||
public Position(int x, int y) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 节点样式配置
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class Style {
|
|
||||||
|
|
||||||
private String fill; // 填充颜色
|
|
||||||
|
|
||||||
private String stroke; // 边框颜色
|
|
||||||
|
|
||||||
private String icon; // 图标名称
|
|
||||||
|
|
||||||
private String iconColor; // 图标颜色
|
|
||||||
|
|
||||||
private int strokeWidth = 2;// 边框宽度
|
|
||||||
|
|
||||||
public Style() {
|
|
||||||
// 默认构造函数
|
|
||||||
}
|
|
||||||
|
|
||||||
public Style(String fill, String stroke, String icon) {
|
|
||||||
this.fill = fill;
|
|
||||||
this.stroke = stroke;
|
|
||||||
this.icon = icon;
|
|
||||||
this.iconColor = stroke;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 节点连接点配置
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class Ports {
|
|
||||||
private Map<String, PortGroup> groups;
|
|
||||||
|
|
||||||
public Ports() {
|
|
||||||
// 默认构造函数
|
|
||||||
this.groups = new HashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取端口类型列表
|
|
||||||
*
|
|
||||||
* @return 端口类型列表("in"/"out")
|
|
||||||
*/
|
|
||||||
public List<String> getTypes() {
|
|
||||||
if (groups == null) {
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
return new ArrayList<>(groups.keySet());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public static class PortGroup {
|
|
||||||
private String position;
|
|
||||||
|
|
||||||
private PortAttrs attrs;
|
|
||||||
|
|
||||||
public PortGroup() {
|
|
||||||
// 默认构造函数
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public static class PortAttrs {
|
|
||||||
private PortCircle circle;
|
|
||||||
|
|
||||||
public PortAttrs() {
|
|
||||||
// 默认构造函数
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public static class PortCircle {
|
|
||||||
|
|
||||||
private int r;
|
|
||||||
|
|
||||||
private String fill;
|
|
||||||
|
|
||||||
private String stroke;
|
|
||||||
|
|
||||||
private boolean magnet;
|
|
||||||
|
|
||||||
public PortCircle() {
|
|
||||||
// 默认构造函数
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -4,7 +4,6 @@ import com.fasterxml.jackson.databind.JsonNode;
|
|||||||
import com.qqchen.deploy.backend.framework.annotation.LogicDelete;
|
import com.qqchen.deploy.backend.framework.annotation.LogicDelete;
|
||||||
import com.qqchen.deploy.backend.framework.domain.Entity;
|
import com.qqchen.deploy.backend.framework.domain.Entity;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.node.uiVariables.NodeUiVariables;
|
import com.qqchen.deploy.backend.workflow.dto.definition.node.uiVariables.NodeUiVariables;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowNodeGraph;
|
|
||||||
import com.qqchen.deploy.backend.workflow.enums.NodeCategoryEnums;
|
import com.qqchen.deploy.backend.workflow.enums.NodeCategoryEnums;
|
||||||
import com.vladmihalcea.hibernate.type.json.JsonType;
|
import com.vladmihalcea.hibernate.type.json.JsonType;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|||||||
@ -7,16 +7,14 @@ import com.qqchen.deploy.backend.workflow.dto.definition.node.localVariables.Dep
|
|||||||
import com.qqchen.deploy.backend.workflow.dto.definition.node.localVariables.ScriptNodeLocalVariables;
|
import com.qqchen.deploy.backend.workflow.dto.definition.node.localVariables.ScriptNodeLocalVariables;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.DeployNodePanelVariables;
|
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.DeployNodePanelVariables;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.EndNodePanelVariables;
|
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.EndNodePanelVariables;
|
||||||
|
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.GatewayNodePanelVariables;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.ScriptNodePanelVariables;
|
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.ScriptNodePanelVariables;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.StartNodePanelVariables;
|
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.StartNodePanelVariables;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.node.uiVariables.NodeUiVariables;
|
import com.qqchen.deploy.backend.workflow.dto.definition.node.uiVariables.NodeUiVariables;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowNodeGraph;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工作流节点类型枚举
|
* 工作<EFBFBD><EFBFBD>节点类型枚举
|
||||||
* 定义了工作流中所有可用的节点类型及其UI配置
|
* 定义了工作流中所有可用的节点类型及其UI配置
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@ -38,12 +36,7 @@ public enum NodeTypeEnums {
|
|||||||
NodeUiVariables.class,
|
NodeUiVariables.class,
|
||||||
BpmnNodeTypeEnums.START_EVENT,
|
BpmnNodeTypeEnums.START_EVENT,
|
||||||
NodeCategoryEnums.EVENT,
|
NodeCategoryEnums.EVENT,
|
||||||
"工作流开始", // 节点简要描述
|
"工作流开始"
|
||||||
new WorkflowNodeGraph() // UI配置
|
|
||||||
.setShape("circle")
|
|
||||||
.setSize(40, 40)
|
|
||||||
.setStyle("#e8f7ff", "#1890ff", "play-circle")
|
|
||||||
.configPorts(Arrays.asList("out"))
|
|
||||||
),
|
),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,12 +55,7 @@ public enum NodeTypeEnums {
|
|||||||
NodeUiVariables.class,
|
NodeUiVariables.class,
|
||||||
BpmnNodeTypeEnums.END_EVENT,
|
BpmnNodeTypeEnums.END_EVENT,
|
||||||
NodeCategoryEnums.EVENT,
|
NodeCategoryEnums.EVENT,
|
||||||
"工作流结束",
|
"工作流结束"
|
||||||
new WorkflowNodeGraph()
|
|
||||||
.setShape("circle")
|
|
||||||
.setSize(40, 40)
|
|
||||||
.setStyle("#fff1f0", "#ff4d4f", "stop")
|
|
||||||
.configPorts(Arrays.asList("in"))
|
|
||||||
),
|
),
|
||||||
SCRIPT_NODE(
|
SCRIPT_NODE(
|
||||||
"SCRIPT_NODE",
|
"SCRIPT_NODE",
|
||||||
@ -78,12 +66,7 @@ public enum NodeTypeEnums {
|
|||||||
NodeUiVariables.class,
|
NodeUiVariables.class,
|
||||||
BpmnNodeTypeEnums.SERVICE_TASK,
|
BpmnNodeTypeEnums.SERVICE_TASK,
|
||||||
NodeCategoryEnums.TASK,
|
NodeCategoryEnums.TASK,
|
||||||
"脚本执行任务",
|
"脚本执行任务"
|
||||||
new WorkflowNodeGraph()
|
|
||||||
.setShape("rect")
|
|
||||||
.setSize(120, 60)
|
|
||||||
.setStyle("#ffffff", "#1890ff", "code")
|
|
||||||
.configPorts(Arrays.asList("in", "out"))
|
|
||||||
),
|
),
|
||||||
DEPLOY_NODE(
|
DEPLOY_NODE(
|
||||||
"DEPLOY_NODE",
|
"DEPLOY_NODE",
|
||||||
@ -94,8 +77,18 @@ public enum NodeTypeEnums {
|
|||||||
NodeUiVariables.class,
|
NodeUiVariables.class,
|
||||||
BpmnNodeTypeEnums.SERVICE_TASK,
|
BpmnNodeTypeEnums.SERVICE_TASK,
|
||||||
NodeCategoryEnums.TASK,
|
NodeCategoryEnums.TASK,
|
||||||
"构建任务",
|
"构建任务"
|
||||||
null
|
),
|
||||||
|
GATEWAY_NODE(
|
||||||
|
"GATEWAY_NODE",
|
||||||
|
"网关节点",
|
||||||
|
null,
|
||||||
|
GatewayNodePanelVariables.class,
|
||||||
|
null,
|
||||||
|
NodeUiVariables.class,
|
||||||
|
BpmnNodeTypeEnums.EXCLUSIVE_GATEWAY,
|
||||||
|
NodeCategoryEnums.GATEWAY,
|
||||||
|
"条件分支控制"
|
||||||
);
|
);
|
||||||
//
|
//
|
||||||
// /**
|
// /**
|
||||||
@ -250,8 +243,6 @@ public enum NodeTypeEnums {
|
|||||||
|
|
||||||
private final String description; // 节点详细描述
|
private final String description; // 节点详细描述
|
||||||
|
|
||||||
private final WorkflowNodeGraph uiConfig; // UI配置
|
|
||||||
|
|
||||||
NodeTypeEnums(
|
NodeTypeEnums(
|
||||||
String code,
|
String code,
|
||||||
String name,
|
String name,
|
||||||
@ -261,8 +252,8 @@ public enum NodeTypeEnums {
|
|||||||
Class<?> uiVariables,
|
Class<?> uiVariables,
|
||||||
BpmnNodeTypeEnums bpmnType,
|
BpmnNodeTypeEnums bpmnType,
|
||||||
NodeCategoryEnums category,
|
NodeCategoryEnums category,
|
||||||
String description,
|
String description
|
||||||
WorkflowNodeGraph uiConfig) {
|
) {
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.localVariables = localVariables;
|
this.localVariables = localVariables;
|
||||||
@ -272,7 +263,6 @@ public enum NodeTypeEnums {
|
|||||||
this.bpmnType = bpmnType;
|
this.bpmnType = bpmnType;
|
||||||
this.category = category;
|
this.category = category;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.uiConfig = uiConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.util;
|
package com.qqchen.deploy.backend.workflow.util;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants;
|
import com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionEdge;
|
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraphEdge;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraph;
|
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraph;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionNode;
|
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraphNode;
|
||||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
|
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.flowable.bpmn.BpmnAutoLayout;
|
import org.flowable.bpmn.BpmnAutoLayout;
|
||||||
@ -101,12 +101,12 @@ public class BpmnConverter {
|
|||||||
* @param process 流程定义对象
|
* @param process 流程定义对象
|
||||||
* @return 节点ID映射关系
|
* @return 节点ID映射关系
|
||||||
*/
|
*/
|
||||||
private Map<String, String> convertNodes(List<WorkflowDefinitionNode> nodes, Process process) {
|
private Map<String, String> convertNodes(List<WorkflowDefinitionGraphNode> nodes, Process process) {
|
||||||
// 步骤2.1:创建节点ID映射
|
// 步骤2.1:创建节点ID映射
|
||||||
Map<String, String> idMapping = new HashMap<>();
|
Map<String, String> idMapping = new HashMap<>();
|
||||||
|
|
||||||
// 步骤2.2:遍历并转换每个节点
|
// 步骤2.2:遍历并转换每个节点
|
||||||
for (WorkflowDefinitionNode node : nodes) {
|
for (WorkflowDefinitionGraphNode node : nodes) {
|
||||||
log.debug("转换节点: {}, 类型: {}", node.getNodeName(), node.getNodeCode());
|
log.debug("转换节点: {}, 类型: {}", node.getNodeName(), node.getNodeCode());
|
||||||
convertSingleNode(node, process, idMapping);
|
convertSingleNode(node, process, idMapping);
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ public class BpmnConverter {
|
|||||||
* @param process 流程定义对象
|
* @param process 流程定义对象
|
||||||
* @param idMapping 节点ID映射关系
|
* @param idMapping 节点ID映射关系
|
||||||
*/
|
*/
|
||||||
private void convertSingleNode(WorkflowDefinitionNode node, Process process, Map<String, String> idMapping) {
|
private void convertSingleNode(WorkflowDefinitionGraphNode node, Process process, Map<String, String> idMapping) {
|
||||||
try {
|
try {
|
||||||
// 步骤2.3:获取节点对应的BPMN元素类型
|
// 步骤2.3:获取节点对应的BPMN元素类型
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@ -158,7 +158,7 @@ public class BpmnConverter {
|
|||||||
* @param node 工作流节点定义
|
* @param node 工作流节点定义
|
||||||
* @param process 当前流程
|
* @param process 当前流程
|
||||||
*/
|
*/
|
||||||
private void configureFlowElement(FlowElement element, WorkflowDefinitionNode node, Process process) {
|
private void configureFlowElement(FlowElement element, WorkflowDefinitionGraphNode node, Process process) {
|
||||||
// 步骤1:创建基本的扩展元素
|
// 步骤1:创建基本的扩展元素
|
||||||
Map<String, List<ExtensionElement>> extensionElements = createBaseExtensionElements();
|
Map<String, List<ExtensionElement>> extensionElements = createBaseExtensionElements();
|
||||||
|
|
||||||
@ -200,7 +200,7 @@ public class BpmnConverter {
|
|||||||
* @param process 当前流程
|
* @param process 当前流程
|
||||||
* @param extensionElements 扩展元素
|
* @param extensionElements 扩展元素
|
||||||
*/
|
*/
|
||||||
private void configureServiceTask(ServiceTask serviceTask, WorkflowDefinitionNode node, Process process, Map<String, List<ExtensionElement>> extensionElements) {
|
private void configureServiceTask(ServiceTask serviceTask, WorkflowDefinitionGraphNode node, Process process, Map<String, List<ExtensionElement>> extensionElements) {
|
||||||
if (node.getLocalVariables() != null && node.getLocalVariables().has("delegate")) {
|
if (node.getLocalVariables() != null && node.getLocalVariables().has("delegate")) {
|
||||||
String delegate = node.getLocalVariables().get("delegate").asText();
|
String delegate = node.getLocalVariables().get("delegate").asText();
|
||||||
serviceTask.setImplementationType("delegateExpression");
|
serviceTask.setImplementationType("delegateExpression");
|
||||||
@ -233,7 +233,7 @@ public class BpmnConverter {
|
|||||||
* @param extensionElements 扩展元素
|
* @param extensionElements 扩展元素
|
||||||
* @param node 工作流节点定义
|
* @param node 工作流节点定义
|
||||||
*/
|
*/
|
||||||
private void addExecutionVariables(Map<String, List<ExtensionElement>> extensionElements, WorkflowDefinitionNode node) {
|
private void addExecutionVariables(Map<String, List<ExtensionElement>> extensionElements, WorkflowDefinitionGraphNode node) {
|
||||||
// 添加panelVariables变量
|
// 添加panelVariables变量
|
||||||
if (node.getPanelVariables() != null) {
|
if (node.getPanelVariables() != null) {
|
||||||
ExtensionElement fieldElement = new ExtensionElement();
|
ExtensionElement fieldElement = new ExtensionElement();
|
||||||
@ -422,8 +422,8 @@ public class BpmnConverter {
|
|||||||
* @param idMapping 节点ID映射
|
* @param idMapping 节点ID映射
|
||||||
* @param process 流程定义
|
* @param process 流程定义
|
||||||
*/
|
*/
|
||||||
private void convertEdgesToSequenceFlows(List<WorkflowDefinitionEdge> edges, Map<String, String> idMapping, Process process) {
|
private void convertEdgesToSequenceFlows(List<WorkflowDefinitionGraphEdge> edges, Map<String, String> idMapping, Process process) {
|
||||||
for (WorkflowDefinitionEdge edge : edges) {
|
for (WorkflowDefinitionGraphEdge edge : edges) {
|
||||||
log.debug("转换连线: from {} to {}", edge.getFrom(), edge.getTo());
|
log.debug("转换连线: from {} to {}", edge.getFrom(), edge.getTo());
|
||||||
|
|
||||||
SequenceFlow flow = new SequenceFlow();
|
SequenceFlow flow = new SequenceFlow();
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.util;
|
package com.qqchen.deploy.backend.workflow.util;
|
||||||
|
|
||||||
import com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants;
|
import com.qqchen.deploy.backend.workflow.constants.WorkFlowConstants;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionEdge;
|
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraphEdge;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraph;
|
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraph;
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionNode;
|
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowDefinitionGraphNode;
|
||||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
|
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.flowable.bpmn.BpmnAutoLayout;
|
import org.flowable.bpmn.BpmnAutoLayout;
|
||||||
@ -68,7 +68,7 @@ public class BpmnConverter1 {
|
|||||||
Map<String, String> idMapping = new HashMap<>();
|
Map<String, String> idMapping = new HashMap<>();
|
||||||
|
|
||||||
// 转换节点
|
// 转换节点
|
||||||
for (WorkflowDefinitionNode node : graph.getNodes()) {
|
for (WorkflowDefinitionGraphNode node : graph.getNodes()) {
|
||||||
log.debug("转换节点: {}, 类型: {}", node.getNodeName(), node.getNodeCode());
|
log.debug("转换节点: {}, 类型: {}", node.getNodeName(), node.getNodeCode());
|
||||||
|
|
||||||
// 通过NodeTypeEnums获取对应的BpmnTypeEnums中定义的实例类型
|
// 通过NodeTypeEnums获取对应的BpmnTypeEnums中定义的实例类型
|
||||||
@ -91,7 +91,7 @@ public class BpmnConverter1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 转换连线
|
// 转换连线
|
||||||
for (WorkflowDefinitionEdge edge : graph.getEdges()) {
|
for (WorkflowDefinitionGraphEdge edge : graph.getEdges()) {
|
||||||
log.debug("转换连线: from {} to {}", edge.getFrom(), edge.getTo());
|
log.debug("转换连线: from {} to {}", edge.getFrom(), edge.getTo());
|
||||||
|
|
||||||
SequenceFlow flow = new SequenceFlow();
|
SequenceFlow flow = new SequenceFlow();
|
||||||
@ -130,7 +130,7 @@ public class BpmnConverter1 {
|
|||||||
* @param node 工作流节点定义
|
* @param node 工作流节点定义
|
||||||
* @param process 当前流程
|
* @param process 当前流程
|
||||||
*/
|
*/
|
||||||
private void configureFlowElement(FlowElement element, WorkflowDefinitionNode node, Process process) {
|
private void configureFlowElement(FlowElement element, WorkflowDefinitionGraphNode node, Process process) {
|
||||||
// 为所有节点添加执行监听器
|
// 为所有节点添加执行监听器
|
||||||
Map<String, List<ExtensionElement>> extensionElements = new HashMap<>();
|
Map<String, List<ExtensionElement>> extensionElements = new HashMap<>();
|
||||||
List<ExtensionElement> executionListeners = new ArrayList<>();
|
List<ExtensionElement> executionListeners = new ArrayList<>();
|
||||||
|
|||||||
@ -1,396 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.util;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
||||||
import com.qqchen.deploy.backend.workflow.annotation.SchemaProperty;
|
|
||||||
import com.qqchen.deploy.backend.workflow.annotation.SchemaPropertyDataSource;
|
|
||||||
import com.qqchen.deploy.backend.workflow.annotation.SchemaPropertyDataSourceParam;
|
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.BaseNodePanelVariables;
|
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.EndNodePanelVariables;
|
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.ScriptNodePanelVariables;
|
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.node.panelVariables.StartNodePanelVariables;
|
|
||||||
import com.qqchen.deploy.backend.workflow.dto.definition.workflow.WorkflowNodeGraph;
|
|
||||||
import com.qqchen.deploy.backend.workflow.enums.NodeTypeEnums;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schema生成器
|
|
||||||
* 用于生成工作流节点的配置Schema和UI Schema
|
|
||||||
*/
|
|
||||||
public class SchemaGenerator {
|
|
||||||
private static final ObjectMapper mapper = new ObjectMapper();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取节点类型对应的配置类
|
|
||||||
*/
|
|
||||||
private static Class<?> getConfigClassForNodeType(NodeTypeEnums nodeType) {
|
|
||||||
switch (nodeType) {
|
|
||||||
case START_EVENT:
|
|
||||||
return StartNodePanelVariables.class;
|
|
||||||
case END_EVENT:
|
|
||||||
return EndNodePanelVariables.class;
|
|
||||||
case SCRIPT_NODE:
|
|
||||||
return ScriptNodePanelVariables.class;
|
|
||||||
// 其他节点类型的配置类
|
|
||||||
// case USER_TASK:
|
|
||||||
// case SERVICE_TASK:
|
|
||||||
// case EXCLUSIVE_GATEWAY:
|
|
||||||
// case PARALLEL_GATEWAY:
|
|
||||||
// case SUBPROCESS:
|
|
||||||
// case CALL_ACTIVITY:
|
|
||||||
// TODO: 为其他节点类型添加对应的配置类
|
|
||||||
// return BaseNodeConfig.class;
|
|
||||||
default:
|
|
||||||
return BaseNodePanelVariables.class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成所有节点类型的schema
|
|
||||||
*/
|
|
||||||
public static JsonNode generateAllNodeTypeSchemas() {
|
|
||||||
ArrayNode schemas = mapper.createArrayNode();
|
|
||||||
|
|
||||||
// 遍历所有节点类型
|
|
||||||
for (NodeTypeEnums nodeType : NodeTypeEnums.values()) {
|
|
||||||
// 获取节点类型对应的配置类
|
|
||||||
Class<?> configClass = getConfigClassForNodeType(nodeType);
|
|
||||||
// 生成该节点的schema
|
|
||||||
ObjectNode nodeSchema = generateNodeSchema(nodeType, configClass);
|
|
||||||
schemas.add(nodeSchema);
|
|
||||||
}
|
|
||||||
|
|
||||||
return schemas;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成节点schema
|
|
||||||
*/
|
|
||||||
private static ObjectNode generateNodeSchema(NodeTypeEnums nodeType, Class<?> configClass) {
|
|
||||||
ObjectNode node = mapper.createObjectNode();
|
|
||||||
|
|
||||||
// 设置基本信<EFBFBD><EFBFBD>
|
|
||||||
node.put("code", nodeType.getCode());
|
|
||||||
node.put("name", nodeType.getName());
|
|
||||||
// node.put("description", nodeType.getShortDesc());
|
|
||||||
|
|
||||||
// 添加详细信息
|
|
||||||
ObjectNode details = mapper.createObjectNode();
|
|
||||||
details.put("description", nodeType.getDescription());
|
|
||||||
ArrayNode features = mapper.createArrayNode();
|
|
||||||
// nodeType.getFeatures().forEach(features::add);
|
|
||||||
details.set("features", features);
|
|
||||||
ArrayNode scenarios = mapper.createArrayNode();
|
|
||||||
// nodeType.getScenarios().forEach(scenarios::add);
|
|
||||||
details.set("scenarios", scenarios);
|
|
||||||
node.set("details", details);
|
|
||||||
|
|
||||||
// 生成配置schema并设置到configSchema字段
|
|
||||||
ObjectNode configSchema = generateConfigSchema(configClass);
|
|
||||||
node.set("configSchema", configSchema);
|
|
||||||
|
|
||||||
// 生成UI schema并设置到uiSchema字段
|
|
||||||
ObjectNode uiSchema = generateUiSchema(nodeType);
|
|
||||||
node.set("uiSchema", uiSchema);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成UI Schema
|
|
||||||
* 包含节点的UI相关配置,如形状、大小、样式等
|
|
||||||
*/
|
|
||||||
private static ObjectNode generateUiSchema(NodeTypeEnums nodeType) {
|
|
||||||
ObjectNode uiSchema = mapper.createObjectNode();
|
|
||||||
WorkflowNodeGraph uiConfig = nodeType.getUiConfig();
|
|
||||||
|
|
||||||
// 设置基本形状和大小
|
|
||||||
uiSchema.put("shape", uiConfig.getShape());
|
|
||||||
ObjectNode size = mapper.createObjectNode();
|
|
||||||
size.put("width", uiConfig.getSize().getWidth());
|
|
||||||
size.put("height", uiConfig.getSize().getHeight());
|
|
||||||
uiSchema.set("size", size);
|
|
||||||
|
|
||||||
// 设置样式
|
|
||||||
ObjectNode style = mapper.createObjectNode();
|
|
||||||
style.put("fill", uiConfig.getStyle().getFill());
|
|
||||||
style.put("stroke", uiConfig.getStyle().getStroke());
|
|
||||||
style.put("strokeWidth", uiConfig.getStyle().getStrokeWidth());
|
|
||||||
style.put("icon", uiConfig.getStyle().getIcon());
|
|
||||||
style.put("iconColor", uiConfig.getStyle().getIconColor());
|
|
||||||
uiSchema.set("style", style);
|
|
||||||
|
|
||||||
// 设置连接点
|
|
||||||
ObjectNode ports = mapper.createObjectNode();
|
|
||||||
ObjectNode groups = mapper.createObjectNode();
|
|
||||||
uiConfig.getPorts().getGroups().forEach((key, group) -> {
|
|
||||||
ObjectNode groupNode = mapper.createObjectNode();
|
|
||||||
groupNode.put("position", group.getPosition());
|
|
||||||
|
|
||||||
ObjectNode attrs = mapper.createObjectNode();
|
|
||||||
ObjectNode circle = mapper.createObjectNode();
|
|
||||||
circle.put("r", group.getAttrs().getCircle().getR());
|
|
||||||
circle.put("fill", group.getAttrs().getCircle().getFill());
|
|
||||||
circle.put("stroke", group.getAttrs().getCircle().getStroke());
|
|
||||||
attrs.set("circle", circle);
|
|
||||||
|
|
||||||
groupNode.set("attrs", attrs);
|
|
||||||
groups.set(key, groupNode);
|
|
||||||
});
|
|
||||||
ports.set("groups", groups);
|
|
||||||
uiSchema.set("ports", ports);
|
|
||||||
|
|
||||||
return uiSchema;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据配置类生成schema
|
|
||||||
*/
|
|
||||||
private static ObjectNode generateConfigSchema(Class<?> configClass) {
|
|
||||||
ObjectNode schema = mapper.createObjectNode();
|
|
||||||
schema.put("type", "object");
|
|
||||||
|
|
||||||
// 创建一个有序的properties对象
|
|
||||||
ObjectNode properties = mapper.createObjectNode();
|
|
||||||
List<String> required = new ArrayList<>();
|
|
||||||
|
|
||||||
// 先处理基础字段(按指定顺序)
|
|
||||||
processBaseFields(properties, required, configClass);
|
|
||||||
|
|
||||||
// 处理其他字段
|
|
||||||
processRemainingFields(properties, required, configClass);
|
|
||||||
|
|
||||||
schema.set("properties", properties);
|
|
||||||
|
|
||||||
// 如果有必填字段,添加到schema中
|
|
||||||
if (!required.isEmpty()) {
|
|
||||||
ArrayNode requiredArray = mapper.createArrayNode();
|
|
||||||
required.forEach(requiredArray::add);
|
|
||||||
schema.set("required", requiredArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
return schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理基础字<EFBFBD><EFBFBD><EFBFBD>(code、name、description)
|
|
||||||
*/
|
|
||||||
private static void processBaseFields(ObjectNode properties, List<String> required, Class<?> configClass) {
|
|
||||||
String[] baseFields = {"code", "name", "description"};
|
|
||||||
Class<?> currentClass = configClass;
|
|
||||||
|
|
||||||
while (currentClass != null && !currentClass.equals(Object.class)) {
|
|
||||||
for (String fieldName : baseFields) {
|
|
||||||
try {
|
|
||||||
Field field = currentClass.getDeclaredField(fieldName);
|
|
||||||
SchemaProperty annotation = field.getAnnotation(SchemaProperty.class);
|
|
||||||
if (annotation != null && !properties.has(fieldName)) {
|
|
||||||
processField(properties, required, field, annotation);
|
|
||||||
}
|
|
||||||
} catch (NoSuchFieldException ignored) {
|
|
||||||
// 字段不在当前类中,继续查找父类
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentClass = currentClass.getSuperclass();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理剩余字段
|
|
||||||
*/
|
|
||||||
private static void processRemainingFields(ObjectNode properties, List<String> required, Class<?> configClass) {
|
|
||||||
Set<String> baseFields = Set.of("code", "name", "description");
|
|
||||||
Class<?> currentClass = configClass;
|
|
||||||
|
|
||||||
while (currentClass != null && !currentClass.equals(Object.class)) {
|
|
||||||
for (Field field : currentClass.getDeclaredFields()) {
|
|
||||||
String fieldName = field.getName();
|
|
||||||
if (!baseFields.contains(fieldName)) {
|
|
||||||
SchemaProperty annotation = field.getAnnotation(SchemaProperty.class);
|
|
||||||
if (annotation != null && !properties.has(fieldName)) {
|
|
||||||
processField(properties, required, field, annotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentClass = currentClass.getSuperclass();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理字段
|
|
||||||
*/
|
|
||||||
private static void processField(ObjectNode properties, List<String> required, Field field, SchemaProperty annotation) {
|
|
||||||
ObjectNode fieldSchema = mapper.createObjectNode();
|
|
||||||
Class<?> fieldType = field.getType();
|
|
||||||
|
|
||||||
// 设置字段类型
|
|
||||||
String jsonType = getJsonSchemaType(fieldType);
|
|
||||||
fieldSchema.put("type", jsonType);
|
|
||||||
|
|
||||||
// 设置基本属性
|
|
||||||
fieldSchema.put("title", annotation.title());
|
|
||||||
if (!annotation.description().isEmpty()) {
|
|
||||||
fieldSchema.put("description", annotation.description());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理hidden属性
|
|
||||||
if (annotation.hidden()) {
|
|
||||||
fieldSchema.put("hidden", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理数据源属性
|
|
||||||
SchemaPropertyDataSource dataSource = annotation.dataSource();
|
|
||||||
if (!dataSource.type().isEmpty()) {
|
|
||||||
ObjectNode dataSourceNode = fieldSchema.putObject("x-data-source");
|
|
||||||
dataSourceNode.put("type", dataSource.type());
|
|
||||||
|
|
||||||
if (!dataSource.url().isEmpty()) {
|
|
||||||
dataSourceNode.put("url", dataSource.url());
|
|
||||||
}
|
|
||||||
|
|
||||||
dataSourceNode.put("valueField", dataSource.valueField());
|
|
||||||
dataSourceNode.put("labelField", dataSource.labelField());
|
|
||||||
|
|
||||||
// 处理依赖字段
|
|
||||||
if (dataSource.dependsOn().length > 0) {
|
|
||||||
ArrayNode dependsOn = dataSourceNode.putArray("dependsOn");
|
|
||||||
for (String dep : dataSource.dependsOn()) {
|
|
||||||
dependsOn.add(dep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理参数
|
|
||||||
if (dataSource.params().length > 0) {
|
|
||||||
ObjectNode params = dataSourceNode.putObject("params");
|
|
||||||
for (SchemaPropertyDataSourceParam param : dataSource.params()) {
|
|
||||||
params.put(param.name(), param.value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理format
|
|
||||||
if (!annotation.format().isEmpty()) {
|
|
||||||
fieldSchema.put("format", annotation.format());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理默认值
|
|
||||||
if (!annotation.defaultValue().isEmpty()) {
|
|
||||||
setDefaultValue(fieldSchema, fieldType, annotation.defaultValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理数值范围
|
|
||||||
if (isNumberType(fieldType)) {
|
|
||||||
if (annotation.minimum() != Integer.MIN_VALUE) {
|
|
||||||
fieldSchema.put("minimum", annotation.minimum());
|
|
||||||
}
|
|
||||||
if (annotation.maximum() != Integer.MAX_VALUE) {
|
|
||||||
fieldSchema.put("maximum", annotation.maximum());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理枚举值
|
|
||||||
if (annotation.enumValues().length > 0) {
|
|
||||||
ArrayNode enumValues = fieldSchema.putArray("enum");
|
|
||||||
for (String value : annotation.enumValues()) {
|
|
||||||
enumValues.add(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果有枚举显示名称
|
|
||||||
if (annotation.enumNames().length > 0) {
|
|
||||||
ArrayNode enumNames = fieldSchema.putArray("enumNames");
|
|
||||||
for (String name : annotation.enumNames()) {
|
|
||||||
enumNames.add(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理数类型
|
|
||||||
if (jsonType.equals("array")) {
|
|
||||||
ObjectNode items = fieldSchema.putObject("items");
|
|
||||||
if (field.getType().isArray()) {
|
|
||||||
Class<?> componentType = field.getType().getComponentType();
|
|
||||||
items.put("type", getJsonSchemaType(componentType));
|
|
||||||
} else {
|
|
||||||
// 默认为字符串类型
|
|
||||||
items.put("type", "string");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理对象类型
|
|
||||||
if (jsonType.equals("object") && Map.class.isAssignableFrom(fieldType)) {
|
|
||||||
ObjectNode additionalProperties = fieldSchema.putObject("additionalProperties");
|
|
||||||
additionalProperties.put("type", "string");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果是必填字段,添加到required列表
|
|
||||||
if (annotation.required()) {
|
|
||||||
required.add(field.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
properties.set(field.getName(), fieldSchema);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置默认值(根据字段类型进行类型转换)
|
|
||||||
*/
|
|
||||||
private static void setDefaultValue(ObjectNode fieldSchema, Class<?> fieldType, String defaultValue) {
|
|
||||||
if (isNumberType(fieldType)) {
|
|
||||||
try {
|
|
||||||
if (fieldType == Integer.class || fieldType == int.class) {
|
|
||||||
fieldSchema.put("default", Integer.parseInt(defaultValue));
|
|
||||||
} else if (fieldType == Long.class || fieldType == long.class) {
|
|
||||||
fieldSchema.put("default", Long.parseLong(defaultValue));
|
|
||||||
} else if (fieldType == Double.class || fieldType == double.class) {
|
|
||||||
fieldSchema.put("default", Double.parseDouble(defaultValue));
|
|
||||||
} else if (fieldType == Float.class || fieldType == float.class) {
|
|
||||||
fieldSchema.put("default", Float.parseFloat(defaultValue));
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
// 如果转换失败,使用字符串形式
|
|
||||||
fieldSchema.put("default", defaultValue);
|
|
||||||
}
|
|
||||||
} else if (fieldType == Boolean.class || fieldType == boolean.class) {
|
|
||||||
fieldSchema.put("default", Boolean.parseBoolean(defaultValue));
|
|
||||||
} else {
|
|
||||||
fieldSchema.put("default", defaultValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断是否为数值类型
|
|
||||||
*/
|
|
||||||
private static boolean isNumberType(Class<?> type) {
|
|
||||||
return type == Integer.class || type == int.class ||
|
|
||||||
type == Long.class || type == long.class ||
|
|
||||||
type == Double.class || type == double.class ||
|
|
||||||
type == Float.class || type == float.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取JSON Schema类型
|
|
||||||
*/
|
|
||||||
private static String getJsonSchemaType(Class<?> type) {
|
|
||||||
if (type == String.class) {
|
|
||||||
return "string";
|
|
||||||
} else if (type == Integer.class || type == int.class || type == Long.class || type == long.class) {
|
|
||||||
return "integer";
|
|
||||||
} else if (type == Boolean.class || type == boolean.class) {
|
|
||||||
return "boolean";
|
|
||||||
} else if (type == Double.class || type == double.class || type == Float.class || type == float.class) {
|
|
||||||
return "number";
|
|
||||||
} else if (type.isArray() || List.class.isAssignableFrom(type)) {
|
|
||||||
return "array";
|
|
||||||
} else if (type.isEnum()) {
|
|
||||||
return "string";
|
|
||||||
} else {
|
|
||||||
return "object";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.util;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schema生成器的主类,用于测试和生成Schema
|
|
||||||
*/
|
|
||||||
public class SchemaGeneratorMain {
|
|
||||||
private static final ObjectMapper mapper = new ObjectMapper();
|
|
||||||
|
|
||||||
static {
|
|
||||||
mapper.enable(SerializationFeature.INDENT_OUTPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SchemaGeneratorMain() {
|
|
||||||
// 私有构造函数防止实例化
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
try {
|
|
||||||
// 生成所有节点类型的Schema
|
|
||||||
System.out.println("=== Node Type Schemas ===");
|
|
||||||
JsonNode schemas = SchemaGenerator.generateAllNodeTypeSchemas();
|
|
||||||
System.out.println(mapper.writeValueAsString(schemas));
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.err.println("生成Schema时发生错误:");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,143 +0,0 @@
|
|||||||
package com.qqchen.deploy.backend.workflow.util;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
class SchemaGeneratorTest {
|
|
||||||
private final ObjectMapper mapper = new ObjectMapper();
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testGenerateAllNodeTypeSchemas() throws Exception {
|
|
||||||
JsonNode schemas = SchemaGenerator.generateAllNodeTypeSchemas();
|
|
||||||
|
|
||||||
// 将生成的schema打印出来以便查看
|
|
||||||
System.out.println("Generated Schemas:");
|
|
||||||
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schemas));
|
|
||||||
|
|
||||||
// 验证基本结构
|
|
||||||
assertTrue(schemas.isObject());
|
|
||||||
assertTrue(schemas.has("START"));
|
|
||||||
assertTrue(schemas.has("SCRIPT"));
|
|
||||||
assertTrue(schemas.has("GIT_CLONE"));
|
|
||||||
assertTrue(schemas.has("TASK"));
|
|
||||||
assertTrue(schemas.has("EVENT"));
|
|
||||||
assertTrue(schemas.has("END"));
|
|
||||||
|
|
||||||
// 验证START节点
|
|
||||||
JsonNode startNode = schemas.get("START");
|
|
||||||
assertEquals("START", startNode.get("code").asText());
|
|
||||||
assertEquals("开始", startNode.get("name").asText());
|
|
||||||
assertEquals("开始节点", startNode.get("description").asText());
|
|
||||||
|
|
||||||
JsonNode startSchema = startNode.get("configSchema");
|
|
||||||
assertTrue(startSchema.has("properties"));
|
|
||||||
JsonNode startProps = startSchema.get("properties");
|
|
||||||
assertTrue(startProps.has("name"));
|
|
||||||
assertTrue(startProps.has("description"));
|
|
||||||
assertTrue(startProps.has("triggerType"));
|
|
||||||
assertTrue(startProps.has("formKey"));
|
|
||||||
assertTrue(startProps.has("initiator"));
|
|
||||||
|
|
||||||
// 验证SCRIPT节点
|
|
||||||
JsonNode scriptNode = schemas.get("SCRIPT");
|
|
||||||
assertEquals("SCRIPT", scriptNode.get("code").asText());
|
|
||||||
assertEquals("脚本执行", scriptNode.get("name").asText());
|
|
||||||
assertEquals("执行脚本任务", scriptNode.get("description").asText());
|
|
||||||
|
|
||||||
JsonNode scriptSchema = scriptNode.get("configSchema");
|
|
||||||
JsonNode scriptProps = scriptSchema.get("properties");
|
|
||||||
// 验证基本属性
|
|
||||||
assertTrue(scriptProps.has("taskType"));
|
|
||||||
assertTrue(scriptProps.has("taskName"));
|
|
||||||
assertTrue(scriptProps.has("description"));
|
|
||||||
// 验证任务相关属性
|
|
||||||
assertTrue(scriptProps.has("timeoutDuration"));
|
|
||||||
assertTrue(scriptProps.has("timeoutStrategy"));
|
|
||||||
assertTrue(scriptProps.has("retryTimes"));
|
|
||||||
assertTrue(scriptProps.has("retryInterval"));
|
|
||||||
assertTrue(scriptProps.has("retryStrategy"));
|
|
||||||
// 验证脚本特有属性
|
|
||||||
assertTrue(scriptProps.has("script"));
|
|
||||||
assertTrue(scriptProps.has("language"));
|
|
||||||
assertTrue(scriptProps.has("interpreter"));
|
|
||||||
assertTrue(scriptProps.has("workingDirectory"));
|
|
||||||
|
|
||||||
// 验证GIT_CLONE节点
|
|
||||||
JsonNode gitNode = schemas.get("GIT_CLONE");
|
|
||||||
assertEquals("GIT_CLONE", gitNode.get("code").asText());
|
|
||||||
assertEquals("Git克隆", gitNode.get("name").asText());
|
|
||||||
assertEquals("克隆Git仓库", gitNode.get("description").asText());
|
|
||||||
|
|
||||||
JsonNode gitSchema = gitNode.get("configSchema");
|
|
||||||
JsonNode gitProps = gitSchema.get("properties");
|
|
||||||
assertTrue(gitProps.has("taskType"));
|
|
||||||
assertTrue(gitProps.has("taskName"));
|
|
||||||
assertTrue(gitProps.has("description"));
|
|
||||||
assertTrue(gitProps.has("repositoryUrl"));
|
|
||||||
assertTrue(gitProps.has("ref"));
|
|
||||||
assertTrue(gitProps.has("targetDirectory"));
|
|
||||||
|
|
||||||
// 验证TASK节点
|
|
||||||
JsonNode taskNode = schemas.get("TASK");
|
|
||||||
assertEquals("TASK", taskNode.get("code").asText());
|
|
||||||
assertEquals("任务", taskNode.get("name").asText());
|
|
||||||
assertEquals("执行任务", taskNode.get("description").asText());
|
|
||||||
|
|
||||||
JsonNode taskSchema = taskNode.get("configSchema");
|
|
||||||
JsonNode taskProps = taskSchema.get("properties");
|
|
||||||
assertTrue(taskProps.has("taskType"));
|
|
||||||
assertTrue(taskProps.has("taskName"));
|
|
||||||
assertTrue(taskProps.has("description"));
|
|
||||||
assertTrue(taskProps.has("enabled"));
|
|
||||||
assertTrue(taskProps.has("priority"));
|
|
||||||
assertTrue(taskProps.has("timeoutDuration"));
|
|
||||||
assertTrue(taskProps.has("timeoutStrategy"));
|
|
||||||
assertTrue(taskProps.has("retryTimes"));
|
|
||||||
assertTrue(taskProps.has("retryInterval"));
|
|
||||||
assertTrue(taskProps.has("retryStrategy"));
|
|
||||||
assertTrue(taskProps.has("assignee"));
|
|
||||||
assertTrue(taskProps.has("form"));
|
|
||||||
assertTrue(taskProps.has("inputVariables"));
|
|
||||||
assertTrue(taskProps.has("outputVariables"));
|
|
||||||
assertTrue(taskProps.has("taskListeners"));
|
|
||||||
|
|
||||||
// 验证EVENT节点
|
|
||||||
JsonNode eventNode = schemas.get("EVENT");
|
|
||||||
assertEquals("EVENT", eventNode.get("code").asText());
|
|
||||||
assertEquals("事件", eventNode.get("name").asText());
|
|
||||||
assertEquals("事件节点", eventNode.get("description").asText());
|
|
||||||
|
|
||||||
JsonNode eventSchema = eventNode.get("configSchema");
|
|
||||||
JsonNode eventProps = eventSchema.get("properties");
|
|
||||||
assertTrue(eventProps.has("name"));
|
|
||||||
assertTrue(eventProps.has("description"));
|
|
||||||
assertTrue(eventProps.has("eventType"));
|
|
||||||
|
|
||||||
// 验证required字段
|
|
||||||
JsonNode eventRequired = eventSchema.get("required");
|
|
||||||
assertTrue(eventRequired.isArray());
|
|
||||||
assertTrue(eventRequired.toString().contains("name"));
|
|
||||||
assertTrue(eventRequired.toString().contains("eventType"));
|
|
||||||
|
|
||||||
// 验证END节点
|
|
||||||
JsonNode endNode = schemas.get("END");
|
|
||||||
assertEquals("END", endNode.get("code").asText());
|
|
||||||
assertEquals("结束", endNode.get("name").asText());
|
|
||||||
assertEquals("结束节点", endNode.get("description").asText());
|
|
||||||
|
|
||||||
JsonNode endSchema = endNode.get("configSchema");
|
|
||||||
JsonNode endProps = endSchema.get("properties");
|
|
||||||
assertTrue(endProps.has("name"));
|
|
||||||
assertTrue(endProps.has("description"));
|
|
||||||
assertTrue(endProps.has("status"));
|
|
||||||
assertTrue(endProps.has("reason"));
|
|
||||||
|
|
||||||
// 验证required字段
|
|
||||||
JsonNode endRequired = endSchema.get("required");
|
|
||||||
assertTrue(endRequired.isArray());
|
|
||||||
assertTrue(endRequired.toString().contains("name"));
|
|
||||||
assertTrue(endRequired.toString().contains("status"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user