package com.*.util.generator;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.jsoup.helper.StringUtil;
import com.*.common.model.AtlasNavigationVO;
import com.*.common.model.RelationShipVO;
// TODO 资产类型可变的时候,考虑类型的处理
// TODO Graphviz并发问题
/**
* 图谱导航Graphviz文件生成,转dot类
*
* @since Test
* @author brian
*
*/
public class GraphvizDotGenerator {
// 本地dot.exe路径
private static String graphviz2xdot = "e:/graphviz/bin/dot.exe";
//gv文件路径
private String gvout;
//生成的图形文件路径
private String gvdotout;
//输出文件格式
private String outformat;
//有向图,还是无向图
private boolean undirected;
//要进行绘图的关系
private Map<String,List<AtlasNavigationVO>> relationsmap;
private BufferedWriter bw;
private static final String[] colorTable = new String[]{
"antiquewhite","aqua","aquamarine",
"bisque","blanchedalmond","blue",
"blueviolet","brown","burlywood","cadetblue","chartreuse",
"chocolate","coral","cornflowerblue","crimson",
"cyan","darkcyan","darkgoldenrod","darkgray",
"darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen",
"darkorange","darkorchid","darkred","darksalmon","darkseagreen",
"darkslategray","darkslategrey","darkturquoise","darkviolet",
"deeppink","deepskyblue","dimgray","dimgrey","dodgerblue",
"firebrick","forestgreen","fuchsia",
"gold","goldenrod","gray","grey",
"green","greenyellow","hotpink","indianred",
"indigo","khaki","lavender","lavenderblush",
"lawngreen","lemonchiffon","lightblue","lightcoral",
"lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink",
"lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey",
"lightsteelblue","lime","limegreen",
"magenta","maroon","mediumaquamarine","mediumorchid",
"mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise",
"mediumvioletred","moccasin",
"navajowhite","olive","olivedrab",
"orange","orangered","orchid","palegoldenrod","palegreen",
"paleturquoise","palevioletred","peachpuff","peru",
"pink","plum","powderblue","purple","red",
"rosybrown","royalblue","saddlebrown","salmon","sandybrown",
"seagreen","sienna","silver","skyblue",
"slateblue","slategray","slategrey","springgreen",
"steelblue","tan","teal","thistle","tomato",
"turquoise","violet","wheat",
"yellow","yellowgreen"
};
private static final int colorNumber = colorTable.length;
private Random colorRnd = new Random();
//分类节点颜色表
private static Map<String,String> nodeColors = new HashMap<String, String>();
private static Map<String,String> edgeColors = new HashMap<String,String>();
public GraphvizDotGenerator(String gvout, String gvdotout, String outformat, Map<String,List<AtlasNavigationVO>> assets) throws Exception{
this.gvout = gvout;
this.gvdotout = gvdotout;
this.outformat = outformat;
this.relationsmap = assets;
FileOutputStream fos = new FileOutputStream(gvout);
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
//fw = new FileWriter(gvout,"UTF-8");
bw = new BufferedWriter(osw);
}
public void generate() throws Exception{
generateHeader();
generateGroupNodes();
generateVirtualGroupRelations();
generateRelations();
generateFoot();
generateDotFile();
}
protected void generateGroupRelation() throws Exception{
Set keys = relationsmap.keySet();
Object[] keyarray = keys.toArray();
generateClusterStart(null);
for (int i = 0; i < keyarray.length; i++) {
generateCategoryNode((String)keyarray[i]);
}
for (int i = 1; i < keyarray.length; i++) {
String pre = (String)keyarray[i - 1];
String cur = (String)keyarray[i];
String relstr = String.format("%s%s%s [style=invis]\n", pre, getDirection(), cur);
bw.write(relstr);
}
generateClusterEnd();
}
/**
* 生成基本信息,头部文字
* @throws Exception
*/
protected void generateHeader() throws Exception {
String digraph = "digraph atlas {\n";
String header="rankdir=LR;\nlabeljust=l\n";
String graph = "graph [ranksep=1.0 splines=true overlap=false charset=\"UTF-8\"]\n";
String edge = "edge [dir=none labeldistance=3]\n";
String node = "node [shape=ellipse style=filled fontname=SimSun width=0.5 label=\"\"]\n";
bw.write(digraph);
bw.write(header);
bw.write(graph);
bw.write(edge);
bw.write(node);
generateGroupRelation();
node = "node [shape=rectangle style=\"rounded,filled\" fontname=SimSun width=0.5 label=\"\",href=\"javascript:parent.click_node('\\N')\"]\n";
bw.write(node);
}
/**
* 生成左边成组的节点
* 研发技术[ label = 研发技术]
* @throws Exception
*/
protected void generateCategoryNode(String category) throws Exception {
String color = nextNodeColor(category);
//nodeColors.put(category, color);
String categorynode = String.format("%s[ color=%2$s label = \"%1$s\"]\n", category, color);
bw.write(categorynode);
}
/**
* 生成右边结果的节点
* XML数据库技术[ label = a0]
* @throws Exception
*/
protected void generateAssetNode(String category, String assetid, String asset) throws Exception {
String color = nodeColors.get(category);
String label = asset;
if(label.length() > 10){
label = label.substring(0, 10);
}
String assetnode = String.format("%s[ label = \"%s\" color=%s]\n", assetid, label, color);
bw.write(assetnode);
}
/**
* 生成每种类型的组节点,
* @throws Exception
*/
protected void generateGroupNodes() throws Exception {
Integer i = 0;
for (String key : relationsmap.keySet()) {
i++;
generateClusterStart(i.toString());
//generateCategoryNode(key);在头部同一生成即可
List<AtlasNavigationVO> relations = relationsmap.get(key);
//生成虚拟联系,保证其在同一水平上
generateVirtualRelation(i.toString(), relations);
for(AtlasNavigationVO avo: relations){
generateAssetNode(key, getAtlasId(avo), avo.getName());
}
generateClusterEnd();
}
}
/**
* 生成一个关系,根据传入的两个asset进行关联
* 方正畅流45商业版->XML数据库技术 [color=brown]
* @throws Exception
*/
protected void generateRelation(String category, String startAsset, String endAsset) throws Exception {
//String color = edgeColors.get(category);
String color = nextEdgeColor(category);
String relationnode = String.format("%s %s %s[ color = %s penwidth=1.5]\n", startAsset, getDirection(), endAsset, color);
bw.write(relationnode);
}
/**
* 生成所有关系
* @throws Exception
*/
protected void generateRelations() throws Exception {
//生成一固定字符串,用于布局时不调整rank
bw.write("edge[constraint=false]\n");
for (String key : relationsmap.keySet()) {
//edgeColors.put(key, nextColor());
List<AtlasNavigationVO> relations = relationsmap.get(key);
for(AtlasNavigationVO avo: relations){
List<RelationShipVO> relation = avo.getRelatedasset();
if(relation != null){
for(RelationShipVO rel: relation){
generateRelation(key, getAtlasId(avo), getAtlasId(rel));
}
}
}
}
}
/**
* 生成gv分块开始
* @param clusterName 子图名称
* @throws Exception
*/
protected void generateClusterStart(String clusterName) throws Exception {
String cluster = "{\n";
if(!StringUtil.isBlank(clusterName)){
cluster = "subgraph cluster" + clusterName.trim() + cluster;
cluster += "color=none\n";
}
bw.write(cluster);
bw.write("rank=same\n");
}
/**
* 生成gv分块结束
* @throws Exception
*/
protected void generateClusterEnd() throws Exception {
bw.write("}\n");
}
/*
* 生成组到每组第一个节点的虚拟联系
*/
private void generateVirtualGroupRelations() throws Exception {
for (String key : relationsmap.keySet()) {
List<AtlasNavigationVO> relations = relationsmap.get(key);
String relation = String.format("%s%s%s[style=invis]\n", key, this.getDirection(), getAtlasId(relations.get(0)));
bw.write(relation);
}
}
/**
* 生成每组数据水平之间的虚拟联系
* @param weight 虚拟水平数据的重量,如1,2,3,
* @param relations 每组group的数据,比如解决方案所有节点
* @throws Exception
*/
private void generateVirtualRelation(String weight,
List<AtlasNavigationVO> relations) throws Exception {
StringBuilder relation = new StringBuilder();
int relsize = relations.size();
if(relsize >= 2){
for (int i = 0; i < relsize - 1; i++) {
relation.append(getAtlasId(relations.get(i)));
relation.append(this.getDirection());
}
relation.append(getAtlasId(relations.get(relsize - 1)));
relation.append("[style=invis weight=");
relation.append(weight);
relation.append("]\n");
bw.write(relation.toString());
}
}
protected String getAtlasId(String id){
return "abc_" + id;
}
protected String getAtlasId(AtlasNavigationVO avo){
return getAtlasId(avo.getId());
}
protected String getAtlasId(RelationShipVO rvo){
return getAtlasId(rvo.getAssetId());
}
/**
* 生成结束
* @throws Exception
*/
protected void generateFoot() throws Exception {
generateClusterEnd();
bw.flush();
bw.close();
}
protected String getDirection(){
String direction = "->";
if(!this.undirected){
direction = "->";
}
return direction;
}
protected void generateDotFile() throws Exception {
//生成svg用于页面显示,png用于下载
Process proc = new ProcessBuilder(graphviz2xdot, gvout, "-T" + outformat, "-o", gvdotout).start();
wait(proc);
}
private void wait(Process process) throws Exception{
InputStream in=process.getInputStream();
byte[] re=new byte[1024];
while (in.read(re)!= -1) {
System.out.println(new String(re));
}
in.close();
InputStream err=process.getErrorStream();
while (err.read(re)!= -1) {
System.out.println(new String(re));
}
err.close();
}
protected String nextNodeColor(String key){
String cateColor = nodeColors.get(key);
if (StringUtils.isBlank(cateColor)) {
String color = colorTable[colorRnd.nextInt(colorNumber)];
nodeColors.put(key, color);
return color;
}else {
return cateColor;
}
}
protected String nextEdgeColor(String key){
String edgeColor = edgeColors.get(key);
if (StringUtils.isBlank(edgeColor)) {
String color = colorTable[colorRnd.nextInt(colorNumber)];
edgeColors.put(key, color);
return color;
}else {
return edgeColor;
}
}
// 测试本地Graphviz转xdot
public static void main(String[] args) throws Exception {
Map<String,List<AtlasNavigationVO>> relationsmap = new HashMap<String,List<AtlasNavigationVO>>();
new HashSet();
new Random();
List<AtlasNavigationVO> list1 = new ArrayList<AtlasNavigationVO>();
AtlasNavigationVO avo1 = new AtlasNavigationVO();
avo1.setName("p0");
List<RelationShipVO> rlist1 = new ArrayList<RelationShipVO>();
RelationShipVO ro1 = new RelationShipVO();
ro1.setAssetName("s1");
rlist1.add(ro1);
avo1.setRelatedasset(rlist1);
list1.add(avo1);
relationsmap.put("产品", list1);
// List<AtlasNavigationVO> list2 = new ArrayList<AtlasNavigationVO>();
// AtlasNavigationVO avo2 = new AtlasNavigationVO();
// avo2.setName("p1");
// List<RelationShipVO> rlist2 = new ArrayList<RelationShipVO>();
// RelationShipVO ro2 = new RelationShipVO();
// ro2.setAssetName("s1");
// rlist2.add(ro2);
// avo2.setRelatedasset(rlist2);
// list2.add(avo2);
// relationsmap.put("产品", list2);
//
// List<AtlasNavigationVO> list3 = new ArrayList<AtlasNavigationVO>();
// AtlasNavigationVO avo3 = new AtlasNavigationVO();
// avo3.setName("s1");
// List<RelationShipVO> rlist3 = new ArrayList<RelationShipVO>();
// RelationShipVO ro3 = new RelationShipVO();
// ro3.setAssetName("p0");
// rlist3.add(ro3);
// avo3.setRelatedasset(rlist3);
// list3.add(avo3);
// relationsmap.put("解决方案", list3);
//
GraphvizDotGenerator gdg = new GraphvizDotGenerator("d:/out.gv", "d:/out.dot", "svg", relationsmap);
gdg.generate();
}
}
图谱导航Graphviz文件生成,转dot类
最新推荐文章于 2026-02-27 12:26:22 发布
这个Java类用于生成Graphviz的dot文件,实现图谱导航。它处理资产关系,创建有向或无向图,并使用颜色映射。类中包含用于生成头、组节点、关系和文件的函数,支持输出SVG和PNG格式。

426

被折叠的 条评论
为什么被折叠?



