Java一个表树形结构大类数据,java 把DataTable数据部类转换为树形结构(多叉树)...

java 把DataTable数据类型转换为树形结构(多叉树)

问题分析:一个关系数据库的表,如图所示:

可以看到后面四个字段:Country,Province,City,Street 具有逻辑上的从属结构,现在要把这种数据搞成一个树形结构,如图所示:

不是原来的数据转换而成的,大致就是这个意思,可以想象成,dataTable里面相同的数据进行单元格合并,然后找到所有的从根到叶子节点的路径,就算完成任务。JS里面似乎有很多插件可以实现,但Java中我暂时还没找到,没办法只能自己写了。从结构上看,应该是一个多叉多级树形结构,所以在转换的时候必须具备一定的灵活性,节点的层级也要分明。

首先定义一个node类,描述节点:

public class Node {

private String id;

private String pId;

private String text;

private Map nodeValue;

private String path;

public Node() {

}

public Node(String id,String pId,String text,String path){

this.id = id;

this.pId = pId;

this.text = text;

this.path = path;

}

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public String getpId() {

return pId;

}

public void setpId(String pId) {

this.pId = pId;

}

public String getText() {

return text;

}

public void setText(String text) {

this.text = text;

}

public Map getNodeValue() {

return nodeValue;

}

public void setNodeValue(Map nodeValue) {

this.nodeValue = nodeValue;

}

public String getPath() {

return path;

}

public void setPath(String path) {

this.path = path;

}

@Override

public String toString() {

String str = "";

if(this.nodeValue!=null){

Set> entrySet = this.nodeValue.entrySet();

for (Entry entry : entrySet) {

str+=entry.getKey()+"="+entry.getValue();

}

}

return str;

}

}

简单说明一下设计初衷:

1,id和pid就不说了,明眼人一眼就看穿了。text表示的是节点当前显示内容。

2,nodeValue是Map结构,包含从当前节点到根节点的text,比如:三级节点City=QingDao的nodeValue包含说明什么呢?答案:{city=QingDao,province=ShanDong,country=China}

3,path属性表示节点的地址,或者叫做路径,用来标识某个节点是否已存在,样式举例:/China/ShanDong/QingDao

看具体实现类:

public class MultiTree {

private List nodeList;

private Node rootNode;

public List getNodeList() {

return nodeList;

}

public void setNodeList(List nodeList) {

this.nodeList = nodeList;

}

public MultiTree() {

init();

}

public MultiTree(List nodeList, Node rootNode) {

this();

if (nodeList != null) {

this.nodeList = nodeList;

}

if (rootNode != null) {

this.rootNode = rootNode;

}

}

private void init() {

nodeList = new ArrayList();

rootNode = new Node("0", "-1", "0", "/");

}

/**

* 把DataTable数据转换为DataTree,保证path唯一

* @param listMaps

* @param args

*/

public void convertListMapToTree(List> listMaps,

String... args) {

Object value = null;

String path = "";

Node pNode = null;

Node node = null;

Map nodeValue = new HashMap();

nodeList.add(rootNode);

for (Map map : listMaps) {

path = "";

pNode = getRoot();

for (int i = 0;i < args.length;i++) {

String key = args[i];

value = map.get(key);

path += "/" + value;

node = findNodeByPath(path);

if (node == null) {

node = new Node(IdGenerator.uuidGenerator(), pNode.getId(),

String.valueOf(value), path);

if(i==args.length-1){

nodeValue = map;

}else{

nodeValue = getNodeValueByPath(path,args);

}

node.setNodeValue(nodeValue);

nodeList.add(node);

} else {

pNode = node;

}

}

}

}

/**

* 根据node path node应该有nodeValue

* nodeValue 应该包含父节点的Text,而不应该包含子节点的text,叶子节点应该包含所有的值

* @param path

* @param args

* @return

*/

private Map getNodeValueByPath(String path, String[] args) {

Map nodeValue = new HashMap();

String[] values = path.split("/");

for (int i = 1;i < values.length;i++) {

nodeValue.put(args[i-1], values[i]);

}

return nodeValue;

}

public Node getRoot() {

return rootNode;

}

/**

* 某个节点的所有子节点

* @param pNode

* @return

*/

public List getChildNodes(Node pNode) {

List childNodes = new ArrayList();

if (pNode == null || pNode.getId() == null) {

return childNodes;

}

for (Node node : nodeList) {

if (pNode.getId().equals(node.getpId())) {

childNodes.add(node);

}

}

return childNodes;

}

/**

* 根据path查找node是否存在(因path唯一)

* @param path

* @return 找到node返回,否则返回null

*/

public Node findNodeByPath(String path) {

for (Node node : nodeList) {

if (path.equals(node.getPath())) {

return node;

}

}

return null;

}

/**

* 从某个节点开始进行深度度递归遍历

* @param pNode

*/

public void recursionTraversal(Node pNode){

List childNodes = getChildNodes(pNode);

for (Node node : childNodes) {

System.out.println(node.toString());

if(getChildNodes(node).size()>0){

recursionTraversal(node);

}

}

}

}

此类的核心方法是:  convertListMapToTree 参数,是数据源和节点的字段名称。

调用方式:

tree.convertListMapToTree(listMaps, "COUNTRY","PROVINCE","CITY","STREET");

执行结果:

/

/China

/China/HeBei

/China/HeBei/BaoDing

/China/HeBei/BaoDing/street1

/China/HeBei/HengShui

/China/HeBei/HengShui/street1

/China/ShanDong

/China/ShanDong/Jian

/China/ShanDong/Jian/street1

/China/ShanDong/QingDao

/China/ShanDong/QingDao/street1

/China/ShanDong/YanTai

/China/ShanDong/YanTai/street1

/Japan

/Japan/JiuZhou

/Japan/JiuZhou/ChangQi

/Japan/JiuZhou/ChangQi/street2

/America

/America/California

/America/California/Los Angeles

/America/California/Los Angeles/street3

/England

/England/Norwich

/England/Norwich/Any

/England/Norwich/Any/street4

此处有几个点需要注意:

1,字段名称参数传递的顺序就是节点的层级顺序,从高到低,若是写错,则结果不准确。

2,一定要有一个根节点,这是树形结构的必备,程序中已给出默认根节点,也给出了自定义的接口。

3,本程序中,nodeValue中只包含(叶子节点除外)从当前节点到根节点的字段值,叶子节点包含所有的字段值,比如本例,叶子节点中也包含ID=1这样的数据,虽然没有被应用到节点层级中。

4,判断path是否存在是关键一步,如果该步骤不能准确,则整个程序就以失败告终。

不足之处:

很多地方都在全局查找,效率较低,期待后续改进。

你可能感兴趣的:(Java一个表树形结构大类数据)