feat: 文档解析器demo
This commit is contained in:
@@ -1,17 +1,25 @@
|
||||
package com.metis.controller;
|
||||
|
||||
import com.metis.flow.domain.bo.BuildApp;
|
||||
import com.metis.flow.validator.ValidatorService;
|
||||
import com.metis.result.Result;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/test")
|
||||
@RequiredArgsConstructor
|
||||
public class TestController {
|
||||
|
||||
|
||||
@GetMapping
|
||||
public Result<String> test() {
|
||||
private final ValidatorService validatorService;
|
||||
|
||||
@PostMapping
|
||||
public Result<String> test(@RequestBody BuildApp app) {
|
||||
validatorService.validate(app);
|
||||
return Result.ok("测试成功");
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.metis.flow.domain.entity.base;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.metis.flow.enums.PositionType;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
@@ -15,6 +16,7 @@ public class NodeData {
|
||||
/**
|
||||
* 标签
|
||||
*/
|
||||
@NotBlank(message = "标签不能为空")
|
||||
private String label;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.metis.flow.domain.entity.config.node;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DocumentExtractorNodeConfig {
|
||||
|
||||
@NotBlank(message = "文件类型不能为空")
|
||||
private String fileType;
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package com.metis.flow.domain.entity.config;
|
||||
@@ -2,6 +2,7 @@ package com.metis.flow.enums;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import com.metis.flow.domain.entity.config.node.DocumentExtractorNodeConfig;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -13,6 +14,7 @@ public enum NodeType {
|
||||
|
||||
START(1, "start", "开始", Object.class),
|
||||
END(2, "end", "结束", Object.class),
|
||||
DOCUMENT_EXTRACTOR(3, "document-extractor", "文档提取器", DocumentExtractorNodeConfig.class)
|
||||
|
||||
;
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.metis.flow.validator;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.Validator;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ValidatorCodeService {
|
||||
|
||||
private final Validator globalValidator;
|
||||
|
||||
/**
|
||||
* 验证, 出现校验未通过则抛出异常
|
||||
*
|
||||
* @param validObject 有效对象
|
||||
*/
|
||||
public <T> void validateThrow(T validObject) {
|
||||
// validation 编程式校验
|
||||
Set<ConstraintViolation<T>> validates = globalValidator.validate(validObject);
|
||||
if (CollUtil.isNotEmpty(validates)) {
|
||||
List<String> errorMessage = validates.stream()
|
||||
.map(ConstraintViolation::getMessage).toList();
|
||||
throw new RuntimeException(String.join(",", errorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证错误信息
|
||||
*
|
||||
* @param validObject 有效对象
|
||||
* @return {@link String }
|
||||
*/
|
||||
public <T> String validateErrorMsg(T validObject) {
|
||||
// validation 编程式校验
|
||||
Set<ConstraintViolation<T>> validates = globalValidator.validate(validObject);
|
||||
if (CollUtil.isNotEmpty(validates)) {
|
||||
List<String> errorMessage = validates.stream()
|
||||
.map(ConstraintViolation::getMessage).toList();
|
||||
return String.join(",", errorMessage);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 验证
|
||||
*
|
||||
* @param validObject 有效对象
|
||||
* @return boolean
|
||||
*/
|
||||
public <T> boolean validate(T validObject) {
|
||||
// validation 编程式校验
|
||||
Set<ConstraintViolation<T>> validates = globalValidator.validate(validObject);
|
||||
return CollUtil.isEmpty(validates);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,39 +9,28 @@ import com.metis.flow.domain.entity.base.Edge;
|
||||
import com.metis.flow.domain.entity.base.Node;
|
||||
import com.metis.flow.enums.EdgeType;
|
||||
import com.metis.flow.enums.NodeType;
|
||||
import com.metis.flow.validator.EdgeValidator;
|
||||
import com.metis.flow.validator.NodeValidator;
|
||||
import com.metis.flow.validator.ValidatorResult;
|
||||
import com.metis.flow.validator.ValidatorService;
|
||||
import com.metis.flow.validator.*;
|
||||
import com.metis.flow.validator.factory.EdgeValidatorFactory;
|
||||
import com.metis.flow.validator.factory.NodeValidatorFactory;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.Validator;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ValidatorServiceImpl implements ValidatorService {
|
||||
|
||||
private final Validator globalValidator;
|
||||
private final ValidatorCodeService validatorCodeService;
|
||||
|
||||
@Override
|
||||
public void validate(BuildApp graph) {
|
||||
// validation 编程式校验
|
||||
Set<ConstraintViolation<BuildApp>> validates = globalValidator.validate(graph);
|
||||
if (CollUtil.isNotEmpty(validates)) {
|
||||
List<String> errorMessage = validates.stream()
|
||||
.map(ConstraintViolation::getMessage).toList();
|
||||
throw new RuntimeException(String.join(",", errorMessage));
|
||||
}
|
||||
|
||||
validatorCodeService.validateThrow(graph);
|
||||
Graph model = graph.getGraph();
|
||||
// 节点参数校验
|
||||
validateNode(model.getNodes());
|
||||
@@ -78,7 +67,7 @@ public class ValidatorServiceImpl implements ValidatorService {
|
||||
/**
|
||||
* 验证边缘
|
||||
*
|
||||
* @param edges
|
||||
* @param edges 线
|
||||
*/
|
||||
private void validateEdge(List<Edge> edges) {
|
||||
List<String> errorMessage = new ArrayList<>();
|
||||
@@ -105,7 +94,81 @@ public class ValidatorServiceImpl implements ValidatorService {
|
||||
* @param edges 边缘
|
||||
*/
|
||||
private void validateRelation(List<Node> nodes, List<Edge> edges) {
|
||||
// 1. 检查线是否连接有效节点
|
||||
validateEdgeConnections(nodes, edges);
|
||||
|
||||
// 2. 检查是否存在环结构
|
||||
validateCycle(nodes, edges);
|
||||
|
||||
// 3. 检查是否存在孤立节点
|
||||
validateIsolatedNodes(nodes, edges);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查线是否连接有效节点
|
||||
*/
|
||||
private void validateEdgeConnections(List<Node> nodes, List<Edge> edges) {
|
||||
Map<String, Node> nodeMap = nodes.stream().collect(Collectors.toMap(Node::getId, Function.identity()));
|
||||
for (Edge edge : edges) {
|
||||
String source = edge.getSource();
|
||||
String target = edge.getTarget();
|
||||
Assert.isTrue(nodeMap.containsKey(source), "边 {} 的源节点 {} 不存在", edge.getLabel(), source);
|
||||
Assert.isTrue(nodeMap.containsKey(target), "边 {} 的目标节点 {} 不存在", edge.getLabel(), target);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否存在环结构
|
||||
*/
|
||||
private void validateCycle(List<Node> nodes, List<Edge> edges) {
|
||||
Map<String, List<String>> adjacencyList = buildAdjacencyList(edges);
|
||||
for (Node node : nodes) {
|
||||
if (hasCycle(node.getId(), adjacencyList, new HashSet<>())) {
|
||||
throw new IllegalArgumentException("图中存在环结构,起始节点: " + node.getData().getLabel());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否存在孤立节点
|
||||
*/
|
||||
private void validateIsolatedNodes(List<Node> nodes, List<Edge> edges) {
|
||||
Set<String> connectedNodes = new HashSet<>();
|
||||
for (Edge edge : edges) {
|
||||
connectedNodes.add(edge.getSource());
|
||||
connectedNodes.add(edge.getTarget());
|
||||
}
|
||||
for (Node node : nodes) {
|
||||
Assert.isTrue(connectedNodes.contains(node.getId()), "节点 {} 是孤立节点,未与任何边连接", node.getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建邻接表
|
||||
*/
|
||||
private Map<String, List<String>> buildAdjacencyList(List<Edge> edges) {
|
||||
Map<String, List<String>> adjacencyList = new HashMap<>();
|
||||
for (Edge edge : edges) {
|
||||
adjacencyList.computeIfAbsent(edge.getSource(), k -> new ArrayList<>()).add(edge.getTarget());
|
||||
}
|
||||
return adjacencyList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 深度优先搜索(DFS)检查环
|
||||
*/
|
||||
private boolean hasCycle(String nodeId, Map<String, List<String>> adjacencyList, Set<String> visited) {
|
||||
if (visited.contains(nodeId)) {
|
||||
return true; // 发现环
|
||||
}
|
||||
visited.add(nodeId);
|
||||
for (String neighbor : adjacencyList.getOrDefault(nodeId, new ArrayList<>())) {
|
||||
if (hasCycle(neighbor, adjacencyList, visited)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
visited.remove(nodeId);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.metis.flow.validator.impl.node;
|
||||
|
||||
import com.metis.flow.domain.entity.base.Node;
|
||||
import com.metis.flow.domain.entity.config.node.DocumentExtractorNodeConfig;
|
||||
import com.metis.flow.enums.NodeType;
|
||||
import com.metis.flow.validator.NodeValidator;
|
||||
import com.metis.flow.validator.ValidatorCodeService;
|
||||
import com.metis.flow.validator.ValidatorResult;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DocumentExtractorNodeValidator implements NodeValidator {
|
||||
private final ValidatorCodeService validatorCodeService;
|
||||
|
||||
@Override
|
||||
public ValidatorResult validate(Node node) {
|
||||
DocumentExtractorNodeConfig config = node.getConfig();
|
||||
validatorCodeService.validateThrow(config);
|
||||
// 业务检查未通过
|
||||
return ValidatorResult.invalid("业务报错");
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeType getType() {
|
||||
return NodeType.DOCUMENT_EXTRACTOR;
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,17 @@ import com.metis.flow.domain.entity.base.Node;
|
||||
import com.metis.flow.enums.NodeType;
|
||||
import com.metis.flow.validator.NodeValidator;
|
||||
import com.metis.flow.validator.ValidatorResult;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class EndNodeValidator implements NodeValidator {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public ValidatorResult validate(Node node) {
|
||||
return ValidatorResult.valid();
|
||||
|
||||
Reference in New Issue
Block a user