feat: 对象重新整理, 架构重新设计, 支持自定义节点给予外部系统使用
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
package com.metis.domain.bo;
|
package com.metis.domain.bo;
|
||||||
|
|
||||||
import com.metis.enums.YesOrNoEnum;
|
import com.metis.enums.YesOrNoEnum;
|
||||||
import com.metis.flow.domain.bo.Graph;
|
import com.metis.flow.domain.bo.GraphBO;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -13,7 +13,7 @@ public class ProcessBo {
|
|||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
private Graph graph;
|
private GraphBO graph;
|
||||||
|
|
||||||
private YesOrNoEnum defaultUse;
|
private YesOrNoEnum defaultUse;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package com.metis.facade;
|
package com.metis.facade;
|
||||||
|
|
||||||
import com.metis.domain.bo.ProcessBo;
|
import com.metis.domain.bo.ProcessBo;
|
||||||
import com.metis.flow.domain.entity.App;
|
import com.metis.flow.convert.GraphConvert;
|
||||||
import com.metis.flow.domain.bo.CreateApp;
|
import com.metis.flow.domain.bo.CreateApp;
|
||||||
import com.metis.flow.domain.bo.UpdateApp;
|
import com.metis.flow.domain.bo.UpdateApp;
|
||||||
|
import com.metis.flow.domain.entity.App;
|
||||||
|
import com.metis.flow.domain.entity.base.Graph;
|
||||||
import com.metis.flow.engine.AppEngineService;
|
import com.metis.flow.engine.AppEngineService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -22,9 +24,10 @@ public class ProcessDefinitionFacade {
|
|||||||
* @param processBo 过程业务对象
|
* @param processBo 过程业务对象
|
||||||
*/
|
*/
|
||||||
public Long create(ProcessBo processBo) {
|
public Long create(ProcessBo processBo) {
|
||||||
|
Graph graph = GraphConvert.INSTANCE.toEntity(processBo.getGraph());
|
||||||
CreateApp createApp = CreateApp.builder()
|
CreateApp createApp = CreateApp.builder()
|
||||||
.name(processBo.getName())
|
.name(processBo.getName())
|
||||||
.graph(processBo.getGraph())
|
.graph(graph)
|
||||||
.build();
|
.build();
|
||||||
App app = appEngineService.create(createApp);
|
App app = appEngineService.create(createApp);
|
||||||
return app.getWorkflowId();
|
return app.getWorkflowId();
|
||||||
@@ -35,11 +38,12 @@ public class ProcessDefinitionFacade {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void update(ProcessBo processBo) {
|
public void update(ProcessBo processBo) {
|
||||||
|
Graph graph = GraphConvert.INSTANCE.toEntity(processBo.getGraph());
|
||||||
appEngineService.update(UpdateApp.builder()
|
appEngineService.update(UpdateApp.builder()
|
||||||
.defaultUse(processBo.getDefaultUse())
|
.defaultUse(processBo.getDefaultUse())
|
||||||
.appId(processBo.getAppId())
|
.appId(processBo.getAppId())
|
||||||
.name(processBo.getName())
|
.name(processBo.getName())
|
||||||
.graph(processBo.getGraph())
|
.graph(graph)
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public interface BaseAppConvert {
|
|||||||
* @return {@link App }
|
* @return {@link App }
|
||||||
*/
|
*/
|
||||||
@Mappings({
|
@Mappings({
|
||||||
@Mapping(target = "graph", expression = "java(com.alibaba.fastjson2.JSON.parseObject(baseApp.getGraphJson(), com.metis.flow.domain.bo.Graph.class))"),
|
@Mapping(target = "graph", expression = "java(com.alibaba.fastjson2.JSON.parseObject(baseApp.getGraphJson(), com.metis.flow.domain.entity.base.Graph.class))"),
|
||||||
@Mapping(target = "workflowId", source = "id")
|
@Mapping(target = "workflowId", source = "id")
|
||||||
})
|
})
|
||||||
App toApp(BaseApp baseApp);
|
App toApp(BaseApp baseApp);
|
||||||
|
|||||||
17
src/main/java/com/metis/flow/convert/GraphConvert.java
Normal file
17
src/main/java/com/metis/flow/convert/GraphConvert.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package com.metis.flow.convert;
|
||||||
|
|
||||||
|
|
||||||
|
import com.metis.flow.domain.bo.GraphBO;
|
||||||
|
import com.metis.flow.domain.entity.base.Graph;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface GraphConvert {
|
||||||
|
|
||||||
|
GraphConvert INSTANCE = Mappers.getMapper(GraphConvert.class);
|
||||||
|
|
||||||
|
|
||||||
|
Graph toEntity(GraphBO graph);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.metis.flow.domain.bo;
|
package com.metis.flow.domain.bo;
|
||||||
|
|
||||||
|
import com.metis.flow.domain.entity.base.Graph;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.metis.flow.domain.bo;
|
package com.metis.flow.domain.bo;
|
||||||
|
|
||||||
|
import com.metis.flow.domain.entity.base.Graph;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|||||||
66
src/main/java/com/metis/flow/domain/bo/EdgeBO.java
Normal file
66
src/main/java/com/metis/flow/domain/bo/EdgeBO.java
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package com.metis.flow.domain.bo;
|
||||||
|
|
||||||
|
import com.metis.flow.enums.EdgeType;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class EdgeBO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 唯一标识符
|
||||||
|
*/
|
||||||
|
@NotNull(message = "唯一标识符不能为空")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签
|
||||||
|
*/
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点类型
|
||||||
|
*/
|
||||||
|
@NotNull(message = "线类型不能为空")
|
||||||
|
private EdgeType type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 源节点ID,对应节点id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "源节点ID不能为空")
|
||||||
|
private Long source;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 目标节点ID,对应节点id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "目标节点ID不能为空")
|
||||||
|
private Long target;
|
||||||
|
/**
|
||||||
|
* 源句柄id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "源句柄ID不能为空")
|
||||||
|
private Long sourceHandle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 目标句柄id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "目标句柄ID不能为空")
|
||||||
|
private Long targetHandle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 边是否动画true/false
|
||||||
|
*/
|
||||||
|
private Boolean animated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始标志
|
||||||
|
*/
|
||||||
|
private String markerStart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束标记
|
||||||
|
*/
|
||||||
|
private String markerEnd;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package com.metis.flow.domain.bo;
|
|
||||||
|
|
||||||
import com.metis.flow.domain.entity.base.Edge;
|
|
||||||
import com.metis.flow.domain.entity.base.Node;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import jakarta.validation.constraints.Size;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class Graph {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 边缘
|
|
||||||
*/
|
|
||||||
@Valid
|
|
||||||
@NotNull(message = "连线不能为空")
|
|
||||||
private List<Edge> edges;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 节点
|
|
||||||
*/
|
|
||||||
@Valid
|
|
||||||
@NotNull(message = "节点不能为空")
|
|
||||||
@Size(min = 1, message = "节点不能为空")
|
|
||||||
private List<Node> nodes;
|
|
||||||
}
|
|
||||||
43
src/main/java/com/metis/flow/domain/bo/GraphBO.java
Normal file
43
src/main/java/com/metis/flow/domain/bo/GraphBO.java
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package com.metis.flow.domain.bo;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class GraphBO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 边缘
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotEmpty(message = "连线不能为空")
|
||||||
|
private List<EdgeBO> edges;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotEmpty(message = "节点不能为空")
|
||||||
|
private List<NodeBO> nodes;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 位置
|
||||||
|
*/
|
||||||
|
private List<Double> position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变焦
|
||||||
|
*/
|
||||||
|
private Double zoom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视窗
|
||||||
|
*/
|
||||||
|
private ViewportBo viewport;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
36
src/main/java/com/metis/flow/domain/bo/HandleBO.java
Normal file
36
src/main/java/com/metis/flow/domain/bo/HandleBO.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package com.metis.flow.domain.bo;
|
||||||
|
|
||||||
|
import com.metis.flow.enums.HandleType;
|
||||||
|
import com.metis.flow.enums.PositionType;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 句柄对象
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class HandleBO {
|
||||||
|
/**
|
||||||
|
* 句柄id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "句柄id不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 句柄类型
|
||||||
|
*/
|
||||||
|
@NotNull(message = "句柄类型不能为空")
|
||||||
|
private HandleType type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 句柄位置
|
||||||
|
*/
|
||||||
|
@NotNull(message = "句柄位置不能为空")
|
||||||
|
private PositionType position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否可以连接
|
||||||
|
*/
|
||||||
|
@NotNull(message = "是否可以连接不能为空")
|
||||||
|
private Boolean connectable;
|
||||||
|
}
|
||||||
60
src/main/java/com/metis/flow/domain/bo/NodeBO.java
Normal file
60
src/main/java/com/metis/flow/domain/bo/NodeBO.java
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package com.metis.flow.domain.bo;
|
||||||
|
|
||||||
|
import com.metis.flow.enums.NodeType;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class NodeBO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "节点id不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
@NotNull(message = "节点类型不能为空")
|
||||||
|
private NodeType type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义类型
|
||||||
|
*/
|
||||||
|
private String customType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 位置
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotNull(message = "节点位置不能为空")
|
||||||
|
private PositionBO position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务数据
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotNull(message = "节点业务数据不能为空")
|
||||||
|
private NodeDataBO data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 宽度
|
||||||
|
*/
|
||||||
|
// @NotNull(message = "节点宽度不能为空")
|
||||||
|
private Integer width;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高度
|
||||||
|
*/
|
||||||
|
// @NotNull(message = "节点高度不能为空")
|
||||||
|
private Integer height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点是否选中
|
||||||
|
*/
|
||||||
|
private Boolean selected;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
45
src/main/java/com/metis/flow/domain/bo/NodeDataBO.java
Normal file
45
src/main/java/com/metis/flow/domain/bo/NodeDataBO.java
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package com.metis.flow.domain.bo;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.metis.flow.enums.PositionType;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class NodeDataBO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "标签不能为空")
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图标
|
||||||
|
*/
|
||||||
|
private String icon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工具栏位置
|
||||||
|
*/
|
||||||
|
private PositionType toolbarPosition;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置
|
||||||
|
*/
|
||||||
|
private JSONObject config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 句柄列表
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotEmpty(message = "句柄列表不能为空")
|
||||||
|
private List<HandleBO> handles;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
20
src/main/java/com/metis/flow/domain/bo/PositionBO.java
Normal file
20
src/main/java/com/metis/flow/domain/bo/PositionBO.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package com.metis.flow.domain.bo;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PositionBO {
|
||||||
|
/**
|
||||||
|
* x坐标
|
||||||
|
*/
|
||||||
|
@NotNull(message = "x坐标不能为空")
|
||||||
|
private Double x;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* y坐标
|
||||||
|
*/
|
||||||
|
@NotNull(message = "y坐标不能为空")
|
||||||
|
private Double y;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.metis.flow.domain.bo;
|
package com.metis.flow.domain.bo;
|
||||||
|
|
||||||
import com.metis.enums.YesOrNoEnum;
|
import com.metis.enums.YesOrNoEnum;
|
||||||
|
import com.metis.flow.domain.entity.base.Graph;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|||||||
10
src/main/java/com/metis/flow/domain/bo/ViewportBo.java
Normal file
10
src/main/java/com/metis/flow/domain/bo/ViewportBo.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package com.metis.flow.domain.bo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ViewportBo {
|
||||||
|
private Double x;
|
||||||
|
private Double y;
|
||||||
|
private Double zoom;
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ package com.metis.flow.domain.entity;
|
|||||||
|
|
||||||
|
|
||||||
import com.metis.enums.YesOrNoEnum;
|
import com.metis.enums.YesOrNoEnum;
|
||||||
import com.metis.flow.domain.bo.Graph;
|
import com.metis.flow.domain.entity.base.Graph;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|||||||
52
src/main/java/com/metis/flow/domain/entity/GraphDemo.java
Normal file
52
src/main/java/com/metis/flow/domain/entity/GraphDemo.java
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package com.metis.flow.domain.entity;
|
||||||
|
|
||||||
|
import com.metis.flow.domain.entity.base.Edge;
|
||||||
|
import com.metis.flow.domain.entity.base.Node;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class GraphDemo {
|
||||||
|
private Map<Long, Node> nodes = new HashMap<>();
|
||||||
|
private Map<Long, List<Long>> adjacencyList = new HashMap<>();
|
||||||
|
|
||||||
|
public void addNode(Node node) {
|
||||||
|
nodes.put(node.getId(), node);
|
||||||
|
adjacencyList.put(node.getId(), new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addEdge(Edge edge) {
|
||||||
|
adjacencyList.get(edge.getSource())
|
||||||
|
.add(edge.getTarget());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Node> topologicalSort() {
|
||||||
|
List<Node> sortedNodes = new ArrayList<>();
|
||||||
|
Set<Long> visited = new HashSet<>();
|
||||||
|
Set<Long> visiting = new HashSet<>();
|
||||||
|
|
||||||
|
for (Long nodeId : nodes.keySet()) {
|
||||||
|
if (!visited.contains(nodeId)) {
|
||||||
|
dfs(nodeId, visited, visiting, sortedNodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.reverse(sortedNodes);
|
||||||
|
return sortedNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dfs(Long nodeId, Set<Long> visited, Set<Long> visiting, List<Node> sortedNodes) {
|
||||||
|
if (visiting.contains(nodeId)) {
|
||||||
|
throw new IllegalStateException("Cycle detected in the graph");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!visited.contains(nodeId)) {
|
||||||
|
visiting.add(nodeId);
|
||||||
|
for (Long neighbor : adjacencyList.get(nodeId)) {
|
||||||
|
dfs(neighbor, visited, visiting, sortedNodes);
|
||||||
|
}
|
||||||
|
visiting.remove(nodeId);
|
||||||
|
visited.add(nodeId);
|
||||||
|
sortedNodes.add(nodes.get(nodeId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/main/java/com/metis/flow/domain/entity/base/Graph.java
Normal file
43
src/main/java/com/metis/flow/domain/entity/base/Graph.java
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package com.metis.flow.domain.entity.base;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class Graph {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 边缘
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotEmpty(message = "连线不能为空")
|
||||||
|
private List<Edge> edges;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotEmpty(message = "节点不能为空")
|
||||||
|
private List<Node> nodes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 位置
|
||||||
|
*/
|
||||||
|
private List<Double> position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变焦
|
||||||
|
*/
|
||||||
|
private Double zoom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视窗
|
||||||
|
*/
|
||||||
|
private Viewport viewport;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,16 +1,11 @@
|
|||||||
package com.metis.flow.domain.entity.base;
|
package com.metis.flow.domain.entity.base;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
import com.metis.flow.enums.NodeType;
|
import com.metis.flow.enums.NodeType;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class Node {
|
public class Node {
|
||||||
|
|
||||||
@@ -26,6 +21,8 @@ public class Node {
|
|||||||
@NotNull(message = "节点类型不能为空")
|
@NotNull(message = "节点类型不能为空")
|
||||||
private NodeType type;
|
private NodeType type;
|
||||||
|
|
||||||
|
private String customType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 位置
|
* 位置
|
||||||
*/
|
*/
|
||||||
@@ -58,20 +55,31 @@ public class Node {
|
|||||||
private Boolean selected;
|
private Boolean selected;
|
||||||
|
|
||||||
|
|
||||||
@JsonIgnore
|
private Class<?> configClass;
|
||||||
public Map<Long, Handle> getHandleMap() {
|
|
||||||
if (CollUtil.isEmpty(data.getHandles())) {
|
|
||||||
return Map.of();
|
|
||||||
}
|
|
||||||
return data.getHandles().stream().collect(Collectors.toMap(Handle::getId, handle -> handle));
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
|
/**
|
||||||
|
* 获取配置
|
||||||
|
*
|
||||||
|
* @return {@link T }
|
||||||
|
*/
|
||||||
public <T> T getConfig() {
|
public <T> T getConfig() {
|
||||||
if (ObjectUtil.isNull(data.getConfig())) {
|
if (ObjectUtil.isNull(data.getConfig())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (T) data.getConfig().to(type.getConfigClass());
|
return (T) data.getConfig().to(configClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置配置类
|
||||||
|
*
|
||||||
|
* @param configClass 配置类
|
||||||
|
*/
|
||||||
|
public <T> void setConfigClass(Class<T> configClass) {
|
||||||
|
if (ObjectUtil.isNotNull(this.configClass)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.configClass = configClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package com.metis.flow.domain.entity.base;
|
||||||
|
|
||||||
|
public abstract class NodeConfig {
|
||||||
|
}
|
||||||
@@ -4,8 +4,7 @@ import com.alibaba.fastjson2.JSONObject;
|
|||||||
import com.metis.flow.enums.PositionType;
|
import com.metis.flow.enums.PositionType;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import jakarta.validation.constraints.Size;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -30,8 +29,6 @@ public class NodeData {
|
|||||||
private PositionType toolbarPosition;
|
private PositionType toolbarPosition;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 配置
|
* 配置
|
||||||
*/
|
*/
|
||||||
@@ -41,8 +38,7 @@ public class NodeData {
|
|||||||
* 句柄列表
|
* 句柄列表
|
||||||
*/
|
*/
|
||||||
@Valid
|
@Valid
|
||||||
@NotNull(message = "句柄列表不能为空")
|
@NotEmpty(message = "句柄列表不能为空")
|
||||||
@Size(min = 1, message = "句柄列表不能为空")
|
|
||||||
private List<Handle> handles;
|
private List<Handle> handles;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.metis.flow.domain.entity.base;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class Viewport {
|
||||||
|
private Double x;
|
||||||
|
private Double y;
|
||||||
|
private Double zoom;
|
||||||
|
}
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
package com.metis.flow.domain.entity.config.node;
|
package com.metis.flow.domain.entity.config.node;
|
||||||
|
|
||||||
|
import com.metis.flow.domain.entity.base.NodeConfig;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class DocumentExtractorNodeConfig {
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class DocumentExtractorNodeConfig extends NodeConfig {
|
||||||
|
|
||||||
@NotBlank(message = "文件类型不能为空")
|
@NotBlank(message = "文件类型不能为空")
|
||||||
private String fileType;
|
private String fileType;
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.metis.flow.domain.entity.config.node;
|
||||||
|
|
||||||
|
import com.metis.flow.domain.entity.base.NodeConfig;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class EndNodeConfig extends NodeConfig {
|
||||||
|
}
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
package com.metis.flow.domain.entity.config.node;
|
package com.metis.flow.domain.entity.config.node;
|
||||||
|
|
||||||
|
import com.metis.flow.domain.entity.base.NodeConfig;
|
||||||
import com.metis.flow.domain.entity.base.NodeVariable;
|
import com.metis.flow.domain.entity.base.NodeVariable;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class StartNodeConfig {
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class StartNodeConfig extends NodeConfig {
|
||||||
|
|
||||||
@Valid
|
@Valid
|
||||||
private List<NodeVariable> variables;
|
private List<NodeVariable> variables;
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
package com.metis.flow.engine.impl;
|
package com.metis.flow.engine.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.IdUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.metis.flow.domain.bo.Graph;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.metis.flow.domain.context.RunningContext;
|
import com.metis.flow.domain.context.RunningContext;
|
||||||
import com.metis.flow.domain.context.RunningResult;
|
import com.metis.flow.domain.context.RunningResult;
|
||||||
import com.metis.flow.domain.context.SysContext;
|
import com.metis.flow.domain.context.SysContext;
|
||||||
import com.metis.flow.domain.entity.App;
|
import com.metis.flow.domain.entity.App;
|
||||||
import com.metis.flow.domain.entity.base.Edge;
|
import com.metis.flow.domain.entity.base.Edge;
|
||||||
|
import com.metis.flow.domain.entity.base.Graph;
|
||||||
import com.metis.flow.domain.entity.base.Node;
|
import com.metis.flow.domain.entity.base.Node;
|
||||||
import com.metis.flow.engine.AppEngineService;
|
import com.metis.flow.engine.AppEngineService;
|
||||||
import com.metis.flow.engine.AppFlowEngineRunnerService;
|
import com.metis.flow.engine.AppFlowEngineRunnerService;
|
||||||
@@ -16,13 +18,13 @@ import com.metis.flow.enums.NodeType;
|
|||||||
import com.metis.flow.runner.FlowRunningContext;
|
import com.metis.flow.runner.FlowRunningContext;
|
||||||
import com.metis.flow.runner.NodeRunner;
|
import com.metis.flow.runner.NodeRunner;
|
||||||
import com.metis.flow.runner.RunnerResult;
|
import com.metis.flow.runner.RunnerResult;
|
||||||
import com.metis.flow.runner.factory.RunnerFactory;
|
import com.metis.flow.runner.factory.NodeRunnerFactory;
|
||||||
|
import com.metis.utils.GenericInterfacesUtils;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -38,7 +40,6 @@ public class AppFlowEngineRunnerServiceImpl implements AppFlowEngineRunnerServic
|
|||||||
public RunnerResult running(FlowRunningContext context) {
|
public RunnerResult running(FlowRunningContext context) {
|
||||||
App app = getApp(context);
|
App app = getApp(context);
|
||||||
// todo 构建运行实例, 并将运行实例放入上下文
|
// todo 构建运行实例, 并将运行实例放入上下文
|
||||||
|
|
||||||
Long instanceId = IdUtil.getSnowflakeNextId();
|
Long instanceId = IdUtil.getSnowflakeNextId();
|
||||||
// 构建系统上下文信息
|
// 构建系统上下文信息
|
||||||
SysContext sysContext = SysContext.builder()
|
SysContext sysContext = SysContext.builder()
|
||||||
@@ -55,21 +56,18 @@ public class AppFlowEngineRunnerServiceImpl implements AppFlowEngineRunnerServic
|
|||||||
.collect(Collectors.toMap(Node::getId, Function.identity()));
|
.collect(Collectors.toMap(Node::getId, Function.identity()));
|
||||||
Map<Long, List<Edge>> edgeMap = graph.getEdges().stream()
|
Map<Long, List<Edge>> edgeMap = graph.getEdges().stream()
|
||||||
.collect(Collectors.groupingBy(Edge::getSource));
|
.collect(Collectors.groupingBy(Edge::getSource));
|
||||||
// 获取到开始节点
|
Set<Node> readyRunningNode = new HashSet<>();
|
||||||
Node runningNode = graph.getNodes().stream().filter(node -> node.getType() == NodeType.START)
|
|
||||||
.findFirst().orElse(null);
|
|
||||||
// 开始节点为空,则表示数据存在异常
|
|
||||||
Assert.isTrue(ObjectUtil.isNotNull(runningNode), "流程图不存在开始节点");
|
|
||||||
while (ObjectUtil.isNotNull(runningNode)) {
|
|
||||||
NodeRunner nodeRunner = RunnerFactory.get(runningNode.getType());
|
|
||||||
// 获取到返回结果
|
|
||||||
RunningResult result = nodeRunner.run(runningContext, runningNode, edgeMap.get(runningNode.getId()));
|
|
||||||
if (ObjectUtil.isNotNull(result.getNodeContext())) {
|
|
||||||
runningContext.addNodeRunningContext(runningNode.getId(), result.getNodeContext());
|
|
||||||
}
|
|
||||||
runningNode = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 获取到开始节点
|
||||||
|
// 开始节点为空,则表示数据存在异常
|
||||||
|
Assert.isTrue(ObjectUtil.isNotNull(readyRunningNode), "流程图不存在开始节点");
|
||||||
|
while (CollUtil.isNotEmpty(readyRunningNode)) {
|
||||||
|
// todo 出现多个节点同时运行, 需要找到他们最终运行的聚合节点, 前期默认只有一条线路运行, 不支持并行流程
|
||||||
|
doRunning(readyRunningNode, edgeMap, runningContext);
|
||||||
|
|
||||||
|
|
||||||
|
readyRunningNode = null;
|
||||||
|
}
|
||||||
|
|
||||||
return RunnerResult.builder()
|
return RunnerResult.builder()
|
||||||
.content("你他妈的!")
|
.content("你他妈的!")
|
||||||
@@ -78,6 +76,49 @@ public class AppFlowEngineRunnerServiceImpl implements AppFlowEngineRunnerServic
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void doRunning(Set<Node> readyRunningNode, Map<Long, List<Edge>> edgeMap, RunningContext runningContext) {
|
||||||
|
Set<Long> nextRunningNodeId = new HashSet<>();
|
||||||
|
for (Node runningNode : readyRunningNode) {
|
||||||
|
// 当前节点接下来的连接线信息
|
||||||
|
List<Edge> edges = edgeMap.getOrDefault(runningNode.getId(), new ArrayList<>());
|
||||||
|
// 执行
|
||||||
|
NodeRunner nodeRunner = getNodeRunner(runningNode);
|
||||||
|
runningNode.setConfigClass(GenericInterfacesUtils.getClass(nodeRunner));
|
||||||
|
// 获取到返回结果
|
||||||
|
RunningResult result = nodeRunner.run(runningContext, runningNode, edges);
|
||||||
|
// 节点执行结果参数放入上下文中
|
||||||
|
if (ObjectUtil.isNotNull(result.getNodeContext())) {
|
||||||
|
runningContext.addNodeRunningContext(runningNode.getId(), result.getNodeContext());
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(result.getNextRunNodeId())) {
|
||||||
|
nextRunningNodeId.addAll(result.getNextRunNodeId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private RunningResult doRunning(RunningContext runningContext, Node node, List<Edge> edges) {
|
||||||
|
NodeRunner nodeRunner = getNodeRunner(node);
|
||||||
|
node.setConfigClass(GenericInterfacesUtils.getClass(nodeRunner));
|
||||||
|
// 获取到返回结果
|
||||||
|
return nodeRunner.run(runningContext, node, edges);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取节点运行程序
|
||||||
|
*
|
||||||
|
* @param node 节点
|
||||||
|
* @return {@link NodeRunner }
|
||||||
|
*/
|
||||||
|
private NodeRunner getNodeRunner(Node node) {
|
||||||
|
if (NodeType.CUSTOM_NODE.equals(node.getType())) {
|
||||||
|
Assert.isTrue(StrUtil.isNotBlank(node.getCustomType()), "自定义节点类型不能为空");
|
||||||
|
return NodeRunnerFactory.getCustom(node.getCustomType());
|
||||||
|
}
|
||||||
|
return NodeRunnerFactory.get(node.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取到应用程序信息
|
* 获取到应用程序信息
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ package com.metis.flow.enums;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
import com.metis.flow.domain.entity.config.node.DocumentExtractorNodeConfig;
|
|
||||||
import com.metis.flow.domain.entity.config.node.StartNodeConfig;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@@ -13,9 +11,10 @@ import java.util.Arrays;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum NodeType {
|
public enum NodeType {
|
||||||
|
|
||||||
START(1, "start", "开始", StartNodeConfig.class),
|
START(1, "start", "开始"),
|
||||||
END(2, "end", "结束", Object.class),
|
END(2, "end", "结束"),
|
||||||
DOCUMENT_EXTRACTOR(3, "document-extractor", "文档提取器", DocumentExtractorNodeConfig.class);
|
DOCUMENT_EXTRACTOR(3, "document-extractor", "文档提取器"),
|
||||||
|
CUSTOM_NODE(4, "Custom-Node", "自定义节点");
|
||||||
|
|
||||||
|
|
||||||
private final Integer code;
|
private final Integer code;
|
||||||
@@ -25,7 +24,7 @@ public enum NodeType {
|
|||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
private final Class<?> configClass;
|
// private final Class<?> configClass;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
33
src/main/java/com/metis/flow/runner/CustomNodeRunner.java
Normal file
33
src/main/java/com/metis/flow/runner/CustomNodeRunner.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package com.metis.flow.runner;
|
||||||
|
|
||||||
|
import com.metis.flow.domain.entity.base.NodeConfig;
|
||||||
|
import com.metis.flow.enums.NodeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义节点运行器
|
||||||
|
*
|
||||||
|
* @author clay
|
||||||
|
* @date 2025/04/20
|
||||||
|
*/
|
||||||
|
public interface CustomNodeRunner<T extends NodeConfig> extends NodeRunner<T> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取自定义节点的节点类型
|
||||||
|
*
|
||||||
|
* @return {@link String }
|
||||||
|
*/
|
||||||
|
String getCustomNodeType();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 得到类型
|
||||||
|
*
|
||||||
|
* @return {@link NodeType }
|
||||||
|
*/
|
||||||
|
default NodeType getType() {
|
||||||
|
return NodeType.CUSTOM_NODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,11 +4,18 @@ import com.metis.flow.domain.context.RunningContext;
|
|||||||
import com.metis.flow.domain.context.RunningResult;
|
import com.metis.flow.domain.context.RunningResult;
|
||||||
import com.metis.flow.domain.entity.base.Edge;
|
import com.metis.flow.domain.entity.base.Edge;
|
||||||
import com.metis.flow.domain.entity.base.Node;
|
import com.metis.flow.domain.entity.base.Node;
|
||||||
|
import com.metis.flow.domain.entity.base.NodeConfig;
|
||||||
import com.metis.flow.enums.NodeType;
|
import com.metis.flow.enums.NodeType;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface NodeRunner {
|
/**
|
||||||
|
* 内置节点运行器
|
||||||
|
*
|
||||||
|
* @author clay
|
||||||
|
* @date 2025/04/20
|
||||||
|
*/
|
||||||
|
public interface NodeRunner<T extends NodeConfig> {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,7 +23,7 @@ public interface NodeRunner {
|
|||||||
*
|
*
|
||||||
* @param context 上下文
|
* @param context 上下文
|
||||||
* @param node 节点配置信息
|
* @param node 节点配置信息
|
||||||
* @param edges
|
* @param edges 当前接下来的连线信息, 一些特殊节点需要节点内部判断下一个运行节点
|
||||||
* @return {@link RunningContext }
|
* @return {@link RunningContext }
|
||||||
*/
|
*/
|
||||||
RunningResult run(RunningContext context, Node node, List<Edge> edges);
|
RunningResult run(RunningContext context, Node node, List<Edge> edges);
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package com.metis.flow.runner.factory;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import com.metis.flow.enums.NodeType;
|
||||||
|
import com.metis.flow.runner.CustomNodeRunner;
|
||||||
|
import com.metis.flow.runner.NodeRunner;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public final class NodeRunnerFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内置节点运行器
|
||||||
|
*/
|
||||||
|
private static final Map<NodeType, NodeRunner> NODE_MAP = new ConcurrentHashMap<>(8);
|
||||||
|
/**
|
||||||
|
* 自定义节点映射
|
||||||
|
*/
|
||||||
|
private static final Map<String, NodeRunner> CUSTOM_NODE_MAP = new ConcurrentHashMap<>(8);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册
|
||||||
|
*
|
||||||
|
* @param runner 跑步者
|
||||||
|
*/
|
||||||
|
static void register(NodeRunner runner) {
|
||||||
|
NODE_MAP.put(runner.getType(), runner);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 得到
|
||||||
|
*
|
||||||
|
* @param type 类型
|
||||||
|
* @return {@link NodeRunner }
|
||||||
|
*/
|
||||||
|
public static NodeRunner get(NodeType type) {
|
||||||
|
return NODE_MAP.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册自定义节点
|
||||||
|
*
|
||||||
|
* @param runner 跑步者
|
||||||
|
*/
|
||||||
|
static void registerCustom(CustomNodeRunner runner) {
|
||||||
|
Assert.isTrue(!CUSTOM_NODE_MAP.containsKey(runner.getCustomNodeType()), "已存在类型:{}, class:{}的运行器", runner.getCustomNodeType(), runner.getClass());
|
||||||
|
CUSTOM_NODE_MAP.put(runner.getCustomNodeType(), runner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 得到自定义节点运行器
|
||||||
|
*
|
||||||
|
* @param type 类型
|
||||||
|
* @return {@link NodeRunner }
|
||||||
|
*/
|
||||||
|
public static NodeRunner getCustom(String type) {
|
||||||
|
return CUSTOM_NODE_MAP.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package com.metis.flow.runner.factory;
|
|
||||||
|
|
||||||
import com.metis.flow.enums.NodeType;
|
|
||||||
import com.metis.flow.runner.NodeRunner;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
public class RunnerFactory {
|
|
||||||
|
|
||||||
private static final Map<NodeType, NodeRunner> MAP = new ConcurrentHashMap<>(8);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 注册
|
|
||||||
*
|
|
||||||
* @param runner 跑步者
|
|
||||||
*/
|
|
||||||
public static void register(NodeRunner runner) {
|
|
||||||
MAP.put(runner.getType(), runner);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 得到
|
|
||||||
*
|
|
||||||
* @param type 类型
|
|
||||||
* @return {@link NodeRunner }
|
|
||||||
*/
|
|
||||||
public static NodeRunner get(NodeType type) {
|
|
||||||
return MAP.get(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.metis.flow.runner;
|
package com.metis.flow.runner.factory;
|
||||||
|
|
||||||
import com.metis.flow.runner.factory.RunnerFactory;
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import com.metis.flow.enums.NodeType;
|
||||||
|
import com.metis.flow.runner.CustomNodeRunner;
|
||||||
|
import com.metis.flow.runner.NodeRunner;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
@@ -19,9 +22,16 @@ public class RunnerInitialize implements ApplicationContextAware {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||||
|
|
||||||
Map<String, NodeRunner> runnerMap = applicationContext.getBeansOfType(NodeRunner.class);
|
Map<String, NodeRunner> runnerMap = applicationContext.getBeansOfType(NodeRunner.class);
|
||||||
runnerMap.forEach((k, v) -> {
|
|
||||||
RunnerFactory.register(v);
|
runnerMap.forEach((runnerBeanName, runner) -> {
|
||||||
|
if (NodeType.CUSTOM_NODE.equals(runner.getType())) {
|
||||||
|
Assert.isTrue(runner instanceof CustomNodeRunner, "自定义节点必须实现CustomNodeRunner接口");
|
||||||
|
NodeRunnerFactory.registerCustom((CustomNodeRunner) runner);
|
||||||
|
} else {
|
||||||
|
NodeRunnerFactory.register(runner);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5,6 +5,7 @@ import com.metis.flow.domain.context.RunningContext;
|
|||||||
import com.metis.flow.domain.context.RunningResult;
|
import com.metis.flow.domain.context.RunningResult;
|
||||||
import com.metis.flow.domain.entity.base.Edge;
|
import com.metis.flow.domain.entity.base.Edge;
|
||||||
import com.metis.flow.domain.entity.base.Node;
|
import com.metis.flow.domain.entity.base.Node;
|
||||||
|
import com.metis.flow.domain.entity.config.node.EndNodeConfig;
|
||||||
import com.metis.flow.enums.NodeType;
|
import com.metis.flow.enums.NodeType;
|
||||||
import com.metis.flow.runner.NodeRunner;
|
import com.metis.flow.runner.NodeRunner;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -14,7 +15,7 @@ import java.util.List;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class EndNodeRunner implements NodeRunner {
|
public class EndNodeRunner implements NodeRunner<EndNodeConfig> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RunningResult run(RunningContext context, Node node, List<Edge> edges) {
|
public RunningResult run(RunningContext context, Node node, List<Edge> edges) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class StartNodeRunner implements NodeRunner {
|
public class StartNodeRunner implements NodeRunner<StartNodeConfig> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RunningResult run(RunningContext context, Node node, List<Edge> edges) {
|
public RunningResult run(RunningContext context, Node node, List<Edge> edges) {
|
||||||
@@ -46,6 +46,7 @@ public class StartNodeRunner implements NodeRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NodeType getType() {
|
public NodeType getType() {
|
||||||
return NodeType.START;
|
return NodeType.START;
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.metis.flow.validator;
|
||||||
|
|
||||||
|
import com.metis.flow.domain.entity.base.NodeConfig;
|
||||||
|
import com.metis.flow.enums.NodeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义节点验证器
|
||||||
|
*
|
||||||
|
* @author clay
|
||||||
|
* @date 2025/04/20
|
||||||
|
*/
|
||||||
|
public interface CustomNodeValidator<T extends NodeConfig> extends NodeValidator<T> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取自定义节点的节点类型
|
||||||
|
*
|
||||||
|
* @return {@link String }
|
||||||
|
*/
|
||||||
|
String getCustomNodeType();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 得到类型
|
||||||
|
*
|
||||||
|
* @return {@link NodeType }
|
||||||
|
*/
|
||||||
|
default NodeType getType() {
|
||||||
|
return NodeType.CUSTOM_NODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,11 +2,12 @@ package com.metis.flow.validator;
|
|||||||
|
|
||||||
import com.metis.flow.domain.entity.base.Edge;
|
import com.metis.flow.domain.entity.base.Edge;
|
||||||
import com.metis.flow.domain.entity.base.Node;
|
import com.metis.flow.domain.entity.base.Node;
|
||||||
|
import com.metis.flow.domain.entity.base.NodeConfig;
|
||||||
import com.metis.flow.enums.NodeType;
|
import com.metis.flow.enums.NodeType;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface NodeValidator {
|
public interface NodeValidator<T extends NodeConfig> {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
package com.metis.flow.validator;
|
|
||||||
|
|
||||||
|
|
||||||
import com.metis.flow.validator.factory.EdgeValidatorFactory;
|
|
||||||
import com.metis.flow.validator.factory.NodeValidatorFactory;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.ApplicationContextAware;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class ValidatorInitialize implements ApplicationContextAware {
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
|
|
||||||
Map<String, EdgeValidator> edgeMap = applicationContext.getBeansOfType(EdgeValidator.class);
|
|
||||||
|
|
||||||
edgeMap.forEach((k, v) -> {
|
|
||||||
EdgeValidatorFactory.register(v);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
Map<String, NodeValidator> nodeMap = applicationContext.getBeansOfType(NodeValidator.class);
|
|
||||||
nodeMap.forEach((k, v) -> {
|
|
||||||
NodeValidatorFactory.register(v);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,23 +1,33 @@
|
|||||||
package com.metis.flow.validator.factory;
|
package com.metis.flow.validator.factory;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
import com.metis.flow.enums.NodeType;
|
import com.metis.flow.enums.NodeType;
|
||||||
|
import com.metis.flow.validator.CustomNodeValidator;
|
||||||
import com.metis.flow.validator.NodeValidator;
|
import com.metis.flow.validator.NodeValidator;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
|
||||||
public class NodeValidatorFactory {
|
public final class NodeValidatorFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内置节点验证器
|
||||||
|
*/
|
||||||
|
private static final Map<NodeType, NodeValidator> NODE_MAP = new ConcurrentHashMap<>(8);
|
||||||
|
/**
|
||||||
|
* 自定义节点验证器
|
||||||
|
*/
|
||||||
|
private static final Map<String, NodeValidator> CUSTOM_NODE_MAP = new ConcurrentHashMap<>(8);
|
||||||
|
|
||||||
private static final Map<NodeType, NodeValidator> MAP = new ConcurrentHashMap<>(8);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册
|
* 注册
|
||||||
*
|
*
|
||||||
* @param validator 验证器
|
* @param validator 验证器
|
||||||
*/
|
*/
|
||||||
public static void register(NodeValidator validator) {
|
static void register(NodeValidator validator) {
|
||||||
MAP.put(validator.getType(), validator);
|
NODE_MAP.put(validator.getType(), validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,7 +37,19 @@ public class NodeValidatorFactory {
|
|||||||
* @return {@link NodeValidator }
|
* @return {@link NodeValidator }
|
||||||
*/
|
*/
|
||||||
public static NodeValidator get(NodeType type) {
|
public static NodeValidator get(NodeType type) {
|
||||||
return MAP.get(type);
|
return NODE_MAP.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param validator 验证器
|
||||||
|
*/
|
||||||
|
static void registerCustom(CustomNodeValidator validator) {
|
||||||
|
Assert.isTrue(!CUSTOM_NODE_MAP.containsKey(validator.getCustomNodeType()), "已存在类型:{}, class:{}的验证器", validator.getCustomNodeType(), validator.getClass());
|
||||||
|
CUSTOM_NODE_MAP.put(validator.getCustomNodeType(), validator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NodeValidator getCustom(String type) {
|
||||||
|
return CUSTOM_NODE_MAP.get(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.metis.flow.validator.factory;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import com.metis.flow.enums.NodeType;
|
||||||
|
import com.metis.flow.validator.CustomNodeValidator;
|
||||||
|
import com.metis.flow.validator.EdgeValidator;
|
||||||
|
import com.metis.flow.validator.NodeValidator;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ValidatorInitialize implements ApplicationContextAware {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
|
||||||
|
|
||||||
|
Map<String, EdgeValidator> edgeMap = applicationContext.getBeansOfType(EdgeValidator.class);
|
||||||
|
|
||||||
|
edgeMap.forEach((edgeValidatorBeanName, edgeValidator) -> {
|
||||||
|
EdgeValidatorFactory.register(edgeValidator);
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String, NodeValidator> nodeMap = applicationContext.getBeansOfType(NodeValidator.class);
|
||||||
|
|
||||||
|
nodeMap.forEach((nodeValidatorBeanName, nodeValidator) -> {
|
||||||
|
if (NodeType.CUSTOM_NODE.equals(nodeValidator.getType())) {
|
||||||
|
Assert.isTrue(nodeValidator instanceof CustomNodeValidator, "自定义节点必须实现CustomNodeValidator接口");
|
||||||
|
NodeValidatorFactory.registerCustom((CustomNodeValidator) nodeValidator);
|
||||||
|
} else {
|
||||||
|
NodeValidatorFactory.register(nodeValidator);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,15 +3,17 @@ package com.metis.flow.validator.impl;
|
|||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.metis.flow.domain.bo.BuildApp;
|
import com.metis.flow.domain.bo.BuildApp;
|
||||||
import com.metis.flow.domain.bo.Graph;
|
|
||||||
import com.metis.flow.domain.entity.base.Edge;
|
import com.metis.flow.domain.entity.base.Edge;
|
||||||
|
import com.metis.flow.domain.entity.base.Graph;
|
||||||
import com.metis.flow.domain.entity.base.Node;
|
import com.metis.flow.domain.entity.base.Node;
|
||||||
import com.metis.flow.enums.EdgeType;
|
import com.metis.flow.enums.EdgeType;
|
||||||
import com.metis.flow.enums.NodeType;
|
import com.metis.flow.enums.NodeType;
|
||||||
import com.metis.flow.validator.*;
|
import com.metis.flow.validator.*;
|
||||||
import com.metis.flow.validator.factory.EdgeValidatorFactory;
|
import com.metis.flow.validator.factory.EdgeValidatorFactory;
|
||||||
import com.metis.flow.validator.factory.NodeValidatorFactory;
|
import com.metis.flow.validator.factory.NodeValidatorFactory;
|
||||||
|
import com.metis.utils.GenericInterfacesUtils;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -28,16 +30,16 @@ public class ValidatorServiceImpl implements ValidatorService {
|
|||||||
private final ValidatorCodeService validatorCodeService;
|
private final ValidatorCodeService validatorCodeService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate(BuildApp graph) {
|
public void validate(BuildApp buildApp) {
|
||||||
// validation 编程式校验
|
// validation 编程式校验
|
||||||
validatorCodeService.validateThrow(graph);
|
validatorCodeService.validateThrow(buildApp);
|
||||||
Graph model = graph.getGraph();
|
Graph graph = buildApp.getGraph();
|
||||||
// 节点参数校验
|
// 节点参数校验
|
||||||
validateNode(model.getNodes());
|
validateNode(graph.getNodes());
|
||||||
// 线参数校验
|
// 线参数校验
|
||||||
validateEdge(model.getEdges());
|
validateEdge(graph.getEdges());
|
||||||
// 关系验证
|
// 关系验证
|
||||||
validateRelation(model.getNodes(), model.getEdges());
|
validateRelation(graph.getNodes(), graph.getEdges());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -50,7 +52,8 @@ public class ValidatorServiceImpl implements ValidatorService {
|
|||||||
List<String> errorMessage = new ArrayList<>();
|
List<String> errorMessage = new ArrayList<>();
|
||||||
for (Node node : nodes) {
|
for (Node node : nodes) {
|
||||||
NodeType type = node.getType();
|
NodeType type = node.getType();
|
||||||
NodeValidator validator = NodeValidatorFactory.get(type);
|
NodeValidator validator = getNodeValidator(node);
|
||||||
|
node.setConfigClass(GenericInterfacesUtils.getClass(validator));
|
||||||
// 节点校验器
|
// 节点校验器
|
||||||
Assert.isTrue(ObjectUtil.isNotNull(validator), "无:{}类型的节点校验器", type.getName());
|
Assert.isTrue(ObjectUtil.isNotNull(validator), "无:{}类型的节点校验器", type.getName());
|
||||||
ValidatorResult result = validator.validateValue(node);
|
ValidatorResult result = validator.validateValue(node);
|
||||||
@@ -237,7 +240,7 @@ public class ValidatorServiceImpl implements ValidatorService {
|
|||||||
Map<Long, List<Edge>> targetMap = edges.stream().collect(Collectors.groupingBy(Edge::getTarget));
|
Map<Long, List<Edge>> targetMap = edges.stream().collect(Collectors.groupingBy(Edge::getTarget));
|
||||||
|
|
||||||
for (Node node : nodes) {
|
for (Node node : nodes) {
|
||||||
NodeValidator validator = NodeValidatorFactory.get(node.getType());
|
NodeValidator validator = getNodeValidator(node);
|
||||||
// 获取当前节点的 source 和 target
|
// 获取当前节点的 source 和 target
|
||||||
List<Edge> sources = targetMap.getOrDefault(node.getId(), new ArrayList<>());
|
List<Edge> sources = targetMap.getOrDefault(node.getId(), new ArrayList<>());
|
||||||
List<Edge> targets = sourceMap.getOrDefault(node.getId(), new ArrayList<>());
|
List<Edge> targets = sourceMap.getOrDefault(node.getId(), new ArrayList<>());
|
||||||
@@ -247,4 +250,19 @@ public class ValidatorServiceImpl implements ValidatorService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取节点验证器
|
||||||
|
*
|
||||||
|
* @param node 节点
|
||||||
|
* @return {@link NodeValidator }
|
||||||
|
*/
|
||||||
|
private NodeValidator getNodeValidator(Node node) {
|
||||||
|
if (NodeType.CUSTOM_NODE.equals(node.getType())) {
|
||||||
|
Assert.isTrue(StrUtil.isNotBlank(node.getCustomType()), "自定义节点类型不能为空");
|
||||||
|
return NodeValidatorFactory.getCustom(node.getCustomType());
|
||||||
|
}
|
||||||
|
return NodeValidatorFactory.get(node.getType());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import java.util.List;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class DocumentExtractorNodeValidator implements NodeValidator {
|
public class DocumentExtractorNodeValidator implements NodeValidator<DocumentExtractorNodeConfig> {
|
||||||
private final ValidatorCodeService validatorCodeService;
|
private final ValidatorCodeService validatorCodeService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.metis.flow.validator.impl.node;
|
|||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import com.metis.flow.domain.entity.base.Edge;
|
import com.metis.flow.domain.entity.base.Edge;
|
||||||
import com.metis.flow.domain.entity.base.Node;
|
import com.metis.flow.domain.entity.base.Node;
|
||||||
|
import com.metis.flow.domain.entity.config.node.EndNodeConfig;
|
||||||
import com.metis.flow.enums.NodeType;
|
import com.metis.flow.enums.NodeType;
|
||||||
import com.metis.flow.validator.NodeValidator;
|
import com.metis.flow.validator.NodeValidator;
|
||||||
import com.metis.flow.validator.ValidatorResult;
|
import com.metis.flow.validator.ValidatorResult;
|
||||||
@@ -15,7 +16,7 @@ import java.util.List;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class EndNodeValidator implements NodeValidator {
|
public class EndNodeValidator implements NodeValidator<EndNodeConfig> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import java.util.List;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class StartNodeValidator implements NodeValidator {
|
public class StartNodeValidator implements NodeValidator<StartNodeConfig> {
|
||||||
|
|
||||||
private final ValidatorCodeService validatorCodeService;
|
private final ValidatorCodeService validatorCodeService;
|
||||||
|
|
||||||
|
|||||||
25
src/main/java/com/metis/utils/GenericInterfacesUtils.java
Normal file
25
src/main/java/com/metis/utils/GenericInterfacesUtils.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package com.metis.utils;
|
||||||
|
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
public class GenericInterfacesUtils {
|
||||||
|
|
||||||
|
|
||||||
|
public static <T> Class<T> getClass(Object object) {
|
||||||
|
|
||||||
|
Type[] genericInterfaces = object.getClass().getGenericInterfaces();
|
||||||
|
for (Type genericInterface : genericInterfaces) {
|
||||||
|
if (genericInterface instanceof ParameterizedType) {
|
||||||
|
ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
|
||||||
|
Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
||||||
|
if (typeArguments.length > 0) {
|
||||||
|
return (Class<T>) typeArguments[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("无法获取泛型类型");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user