feat: 文档解析器demo
This commit is contained in:
@@ -1,17 +1,25 @@
|
|||||||
package com.metis.controller;
|
package com.metis.controller;
|
||||||
|
|
||||||
|
import com.metis.flow.domain.bo.BuildApp;
|
||||||
|
import com.metis.flow.validator.ValidatorService;
|
||||||
import com.metis.result.Result;
|
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.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/test")
|
@RequestMapping("/test")
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class TestController {
|
public class TestController {
|
||||||
|
|
||||||
|
|
||||||
@GetMapping
|
private final ValidatorService validatorService;
|
||||||
public Result<String> test() {
|
|
||||||
|
@PostMapping
|
||||||
|
public Result<String> test(@RequestBody BuildApp app) {
|
||||||
|
validatorService.validate(app);
|
||||||
return Result.ok("测试成功");
|
return Result.ok("测试成功");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.metis.flow.domain.entity.base;
|
|||||||
import com.alibaba.fastjson2.JSONObject;
|
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.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import jakarta.validation.constraints.Size;
|
import jakarta.validation.constraints.Size;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -15,6 +16,7 @@ public class NodeData {
|
|||||||
/**
|
/**
|
||||||
* 标签
|
* 标签
|
||||||
*/
|
*/
|
||||||
|
@NotBlank(message = "标签不能为空")
|
||||||
private String label;
|
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.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
|
import com.metis.flow.domain.entity.config.node.DocumentExtractorNodeConfig;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@ public enum NodeType {
|
|||||||
|
|
||||||
START(1, "start", "开始", Object.class),
|
START(1, "start", "开始", Object.class),
|
||||||
END(2, "end", "结束", 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.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.EdgeValidator;
|
import com.metis.flow.validator.*;
|
||||||
import com.metis.flow.validator.NodeValidator;
|
|
||||||
import com.metis.flow.validator.ValidatorResult;
|
|
||||||
import com.metis.flow.validator.ValidatorService;
|
|
||||||
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 jakarta.validation.ConstraintViolation;
|
|
||||||
import jakarta.validation.Validator;
|
|
||||||
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.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.function.Function;
|
||||||
import java.util.Set;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ValidatorServiceImpl implements ValidatorService {
|
public class ValidatorServiceImpl implements ValidatorService {
|
||||||
|
|
||||||
private final Validator globalValidator;
|
private final ValidatorCodeService validatorCodeService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate(BuildApp graph) {
|
public void validate(BuildApp graph) {
|
||||||
// validation 编程式校验
|
// validation 编程式校验
|
||||||
Set<ConstraintViolation<BuildApp>> validates = globalValidator.validate(graph);
|
validatorCodeService.validateThrow(graph);
|
||||||
if (CollUtil.isNotEmpty(validates)) {
|
|
||||||
List<String> errorMessage = validates.stream()
|
|
||||||
.map(ConstraintViolation::getMessage).toList();
|
|
||||||
throw new RuntimeException(String.join(",", errorMessage));
|
|
||||||
}
|
|
||||||
|
|
||||||
Graph model = graph.getGraph();
|
Graph model = graph.getGraph();
|
||||||
// 节点参数校验
|
// 节点参数校验
|
||||||
validateNode(model.getNodes());
|
validateNode(model.getNodes());
|
||||||
@@ -78,7 +67,7 @@ public class ValidatorServiceImpl implements ValidatorService {
|
|||||||
/**
|
/**
|
||||||
* 验证边缘
|
* 验证边缘
|
||||||
*
|
*
|
||||||
* @param edges
|
* @param edges 线
|
||||||
*/
|
*/
|
||||||
private void validateEdge(List<Edge> edges) {
|
private void validateEdge(List<Edge> edges) {
|
||||||
List<String> errorMessage = new ArrayList<>();
|
List<String> errorMessage = new ArrayList<>();
|
||||||
@@ -105,7 +94,81 @@ public class ValidatorServiceImpl implements ValidatorService {
|
|||||||
* @param edges 边缘
|
* @param edges 边缘
|
||||||
*/
|
*/
|
||||||
private void validateRelation(List<Node> nodes, List<Edge> 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.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;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class EndNodeValidator implements NodeValidator {
|
public class EndNodeValidator implements NodeValidator {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValidatorResult validate(Node node) {
|
public ValidatorResult validate(Node node) {
|
||||||
return ValidatorResult.valid();
|
return ValidatorResult.valid();
|
||||||
|
|||||||
Reference in New Issue
Block a user