You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

114 lines
4.6 KiB
Java

package com.supervision.handler.graph;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import com.supervision.ngbatis.dao.CommonQueryDao;
import com.supervision.ngbatis.domain.tag.Condition;
import com.supervision.ngbatis.domain.tag.ProcessCondition;
import lombok.extern.slf4j.Slf4j;
import org.jgrapht.Graph;
import org.jgrapht.GraphPath;
import org.jgrapht.alg.shortestpath.AllDirectedPaths;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.builder.GraphTypeBuilder;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 寻找判断节点的链条
*/
@Slf4j
@Component
public class FindConditionPathHandler {
@Resource
private CommonQueryDao commonQueryDao;
/**
* 根据某个办理条件节点,寻找所有路径,以用来判断是否符合
* @param itemLeafId 叶子节点的ID
* @return 所有路径
*/
public List<List<Condition>> findConditionPath(String itemLeafId) {
// 首先根据叶子节点,找到条件节点
ProcessCondition conditionVertexByLeafVertex = commonQueryDao.findConditionVertexByLeafVertex(itemLeafId);
if (ObjUtil.isEmpty(conditionVertexByLeafVertex)){
return new ArrayList<>();
}
// 构建一个图,用这个图来找属性结构
Graph<Condition, DefaultEdge> jGraph = buildJGraph();
// 定位终点的vertexId
Set<Condition> finalVertexSet = new HashSet<>();
// 从条件节点processConditionVid开始探索下一级节点列表,使用GO语句
List<Condition> sourceConditionList = commonQueryDao.findNextConditionByConditionEdge(conditionVertexByLeafVertex.getId());
// 如果没有任何绑定的条件节点,
if (CollUtil.isEmpty(sourceConditionList)) {
// TODO 如果没有任何绑定的条件节点,这里咋整?暂定返回一个空的集合
return new ArrayList<>();
}
for (Condition sourceVertex : sourceConditionList) {
jGraph.addVertex(sourceVertex);
}
// 下面开始使用递归,开始持续的找下级节点(递归增加次数限制,最多100次)
int recursionCount = 0;
recursionFindNext(sourceConditionList, jGraph, finalVertexSet, recursionCount);
// 根据图去找所有的路径
return findAllPath(jGraph, new HashSet<>(sourceConditionList), finalVertexSet);
}
private void recursionFindNext(List<Condition> sourceIdList, Graph<Condition, DefaultEdge> jGraph, Set<Condition> finalVertexSet, int recursionCount) {
// 防止死循环出现无限递归
if (recursionCount > 100) {
return;
}
recursionCount++;
for (Condition source : sourceIdList) {
List<Condition> nextVertxList = commonQueryDao.findNextConditionByConditionEdge(source.getId());
if (CollUtil.isNotEmpty(nextVertxList)) {
for (Condition nextVertex : nextVertxList) {
jGraph.addVertex(nextVertex);
jGraph.addEdge(nextVertex, nextVertex);
}
recursionFindNext(nextVertxList, jGraph, finalVertexSet, recursionCount);
} else {
finalVertexSet.add(source);
}
}
}
private Graph<Condition, DefaultEdge> buildJGraph() {
// 创建一个树形结构
return GraphTypeBuilder
.directed()
.allowingMultipleEdges(false)
.allowingSelfLoops(false)
.edgeClass(DefaultEdge.class)
.vertexClass(Condition.class)
.weighted(false)
.buildGraph();
}
private List<List<Condition>> findAllPath(Graph<Condition, DefaultEdge> graph, Set<Condition> sourceSet, Set<Condition> targetIdSet) {
// 使用深度优先遍历来获取所有路径
AllDirectedPaths<Condition, DefaultEdge> directedPaths = new AllDirectedPaths<>(graph);
// 根据一个起始点和终止节点,开始找所有的路径
List<GraphPath<Condition, DefaultEdge>> allPaths = directedPaths.getAllPaths(sourceSet, targetIdSet, true, 100);
// 将所有判断的路径汇聚起来
List<List<Condition>> paths = new ArrayList<>();
for (GraphPath<Condition, DefaultEdge> path : allPaths) {
List<Condition> vertexList = path.getVertexList();
if (CollUtil.isNotEmpty(vertexList)) {
paths.add(vertexList);
}
}
return paths;
}
}