阅读原文请访问我的博客BrightLoong's Blog

之前在项目需要实现一个功能——将xml文件映射成实体,然后对映射的实体进行逻辑处理,最后保存到数据库中;由于xml结构的数据是结构化的数据,所以需要保证保存的数据具有正确的主外键关联。如下所示,是一个需要保存到数据库的xml文件。当映射成对应的实体school和student的时候,我们需要知道“school-one”下面有哪些学生,“school-two”下面有哪些学生,这个时候想到了使用树形结构来保存实体,让实体之间依然存在关联关系。

<school-inf><msg>2017-10-1XX省学校信息总汇</msg><schools><school><name>school-one</name><students><student>Jack</student><student>Rose</student><student>Jon</student></students></school><school><name>school-two</name><students><student>Bob</student><student>Alisa</student></students></school></schools>
</school-inf>
复制代码

树形工具

以下是树形工具类的实现,包含了树形节点类和树形结构类,由于代码中注释已经比较全面,所以不做过多的说明。

树形节点类BeanTreeNode.java

每一个节点对应一个实体,节点包含了实体信息,为了保证实体之间的关联关系,需要留有父节点信息,所有的子节点信息。由此推断出,节点的主要成员有

  • 父节点信息
  • 所有子节点信息
  • 当前实体信息

为了方便操作,我还多增加了id和pid(parent id),以及节点类型(nodeType)。对id的相关操作我并没有添加,如果需要可以自行添加。

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;/*** 实体树形结构点* BeanTreeNode* @author BrightLoong* @version 1.0**/
public class BeanTreeNode {/**标识id*/private String id;/**父id标识,为了方便获取冗余出来*/private String pid;/**父节点*/private BeanTreeNode parentNode;/**节点类型*/private String nodeType;/**节点值*/private Object bean;/**子节点*/private List<BeanTreeNode> childNodes;/*** @param parentNode* @param nodeType* @param bean* @param childNodes*/public BeanTreeNode(BeanTreeNode parentNode, String nodeType, Object bean) {this.parentNode = parentNode;this.nodeType = nodeType;this.bean = bean;this.childNodes = new ArrayList<BeanTreeNode>();this.id = UUID.randomUUID().toString().replaceAll("-", "");if (parentNode != null) {this.pid = parentNode.getId();}}/*** @return the nodeType*/public String getNodeType() {return nodeType;}/*** @param nodeType the nodeType to set*/public void setNodeType(String nodeType) {this.nodeType = nodeType;}/*** @return the parentNode*/public BeanTreeNode getParentNode() {return parentNode;}/*** @param parentNode the parentNode to set*/public void setParentNode(BeanTreeNode parentNode) {this.parentNode = parentNode;}/*** @return the bean*/public Object getBean() {return bean;}/*** @param bean the bean to set*/public void setBean(Object bean) {this.bean = bean;}/*** @return the childNodes*/public List<BeanTreeNode> getChildNodes() {return childNodes;}/*** @param childNodes the childNodes to set*/public void setChildNodes(List<BeanTreeNode> childNodes) {this.childNodes = childNodes;}/*** @return the id*/public String getId() {return id;}/*** @param id the id to set*/public void setId(String id) {this.id = id;}/*** @return the pid*/public String getPid() {return pid;}/*** @param pid the pid to set*/public void setPid(String pid) {this.pid = pid;}/*** 是否具有子节点* @return true or false*/public boolean haveChild() {return !CollectionUtils.isEmpty(childNodes);}
}
复制代码

树形结构类BeanTree.java

BeanTree.java里面包含了如下的一些常用操作:

  • 返回根节点
  • 返回最后添加节点
  • 判断是否具有子节点
  • 添加节点
  • 移动节点到其他节点下
  • 获取对应nodeType的所有节点或实体
  • 根据实体获取节点
  • 获取父节点
  • 转化为map结构

代码如下

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import org.apache.commons.collections.CollectionUtils;/*** 实体树形结构* BeanTree* @author BrightLoong* @version 1.0**/
public class BeanTree {/**根节点*/private BeanTreeNode root;/*** 最新添加的节点*/private BeanTreeNode currentNode;/*** @return the currentNode*/public BeanTreeNode getCurrentNode() {return currentNode;}/*** @return the root*/public BeanTreeNode getRoot() {return root;}/*** 判断节点是否有子节点.* @param node 要判断的节点* @return true or false*/public boolean haveChild(BeanTreeNode node) {return CollectionUtils.isEmpty(node.getChildNodes());}/*** 在父节点上面添加节点,并返回天添加的节点.* @param parentNode 父节点* @param bean 要添加的bean* @param nodeType 节点类型* @return 返回包含bean的节点*/public BeanTreeNode addNode(BeanTreeNode parentNode, Object bean, String nodeType) {BeanTreeNode node;if (bean == null) {return null;}//如果没有父节点说明为root根节点if (parentNode == null) {node = root = new BeanTreeNode(null, nodeType, bean);} else {//创建子节点,并添加到父节点上node = new BeanTreeNode(parentNode, nodeType, bean);parentNode.getChildNodes().add(node);}currentNode = node;return node;}/*** 将当期bean-sBean,以及sBean下的子Bean,挂到dBean下* @param sBean 源Bean* @param dBean 目的父Bean*/public void removeTo(Object sBean, Object dBean) {BeanTreeNode sNode = getNodeByBean(sBean);BeanTreeNode dNode = getNodeByBean(dBean);removeTo(sNode, dNode);}/*** 将当期node-sNode,以及sNode下的子Node,挂到dNode下* @param sNode 源node* @param dNode 目的父node*/public void removeTo(BeanTreeNode sNode, BeanTreeNode dNode) {//从当前父节点移除sNodesNode.getParentNode().getChildNodes().remove(sNode);//将sNode移到dNode下dNode.getChildNodes().add(sNode);//修改sNode的父Id和父节点sNode.setPid(dNode.getId());sNode.setParentNode(dNode);}/*** 获取父bean.* @param bean 子bean* @return 返回父bean*/public Object getParentBean(Object bean) {return getNodeByBean(bean).getParentNode().getBean();}/*** 根据传入的bean获取bean下面对应类型的子bean.* @param bean 当前bean* @param nodeType 节点类型* @return 子bean的集合*/public List<Object> getBeanListByBeanAndNodeType(Object bean, String nodeType) {BeanTreeNode node = getNodeByBean(bean);return getBeanListByNodeType(node, nodeType);}/*** 根据传入的bean获取包含bean的Node节点* @param node 当前node* @param bean 要查找的bean* @return node节点*/public BeanTreeNode getNodeByBean(BeanTreeNode node, Object bean) {BeanTreeNode resultNode = null;if (node.getBean().equals(bean)) {resultNode = node;return resultNode;} else {for (BeanTreeNode tempNode : node.getChildNodes()) {resultNode = getNodeByBean(tempNode, bean);if (resultNode != null) {break;}}}return resultNode;}/*** 根据传入的bean获取root节点下包含bean的Node节点* @param bean 要查找的bean* @return node节点*/public BeanTreeNode getNodeByBean(Object bean) {return getNodeByBean(root, bean);}/*** 根据节点类型返回当前节点下对应节点类型的bean的list集合.* 默认如果当前节点满足类型,那么当前节点不会存在相同类型的子节点* @param node 当前节点* @param nodeType 节点类型* @return*/@SuppressWarnings("unchecked")public <T> List<T> getBeanListByNodeType(BeanTreeNode node, String nodeType) {List<T> beanList = new ArrayList<T>();if (node.getNodeType().equals(nodeType)) {beanList.add((T)node.getBean());} else {for (BeanTreeNode tempNode : node.getChildNodes()) {beanList.addAll((Collection<? extends T>) getBeanListByNodeType(tempNode, nodeType));}}return beanList;}/*** 根据节点类型返回根节点下对应节点类型的bean的list集合.* @param nodeType 节点类型* @return*/public <T> List<T> getBeanListByNodeType(String nodeType) {return getBeanListByNodeType(root, nodeType);}/*** 从root节点开始获取对应nodeType的node.* @param nodeType 节点类型* @return nodeType类型的节点集合*/public List<BeanTreeNode> getNodeListByNodeType(String nodeType) {return getNodeListByNodeType(root, nodeType);}/*** 从node节点开始获取对应nodeType的node.* @param node node节点* @param nodeType 节点类型* @return nodeType类型的节点集合*/public List<BeanTreeNode> getNodeListByNodeType(BeanTreeNode node, String nodeType) {List<BeanTreeNode> nodeList = new ArrayList<BeanTreeNode>();if(node==null){return nodeList;  }if (nodeType.equals(node.getNodeType())) {nodeList.add(node);} else {for (BeanTreeNode tempNode : node.getChildNodes()) {nodeList.addAll(getNodeListByNodeType(tempNode, nodeType));  }}return nodeList;}/*** 将树形结构转化为map.* @return*/public Map<String, List<Object>> toMap() {return toMap(root);}/*** 将对应节点及其子节点转化为map.* @param node 树节点* @return 转化后的map*/public Map<String, List<Object>> toMap(BeanTreeNode node) {Map<String, List<Object>> map = new HashMap<String, List<Object>>();toMap(node, map);return map;}/*** 根据传入的nodeType删除对应的节点以及其所有子节点.* @param nodeType*/public void delNodeByNodeType(String nodeType) {delNodeByNodeType(root, nodeType);}/*** 删除node节点下,类型为nodeType的节点和所有子节点* @param node* @param nodeType*/public void delNodeByNodeType(BeanTreeNode node, String nodeType) {List<BeanTreeNode> nodeList = getNodeListByNodeType(node, nodeType);for (BeanTreeNode beanTreeNode : nodeList) {beanTreeNode.getParentNode().getChildNodes().remove(beanTreeNode);}}/*** 从树结构里面删除bean和相关node.* @param bean bean*/public void delNodeByBean(Object bean) {BeanTreeNode node = getNodeByBean(bean);BeanTreeNode parentNode = node.getParentNode();List<BeanTreeNode> childNodes = parentNode.getChildNodes();Iterator<BeanTreeNode> it = childNodes.iterator();while (it.hasNext()) {BeanTreeNode beanTreeNode = it.next();if (node == beanTreeNode) {it.remove();}}}/*** 根据class返回对应的beanList.* @param cls class* @return beanList*/public <T> List<Object> getBeanListByClass(Class<T> cls) {return getBeanListByClass(root, cls);}/*** 根据class返回对应的beanList.* @param node 节点* @param cls class* @return beanList*/public <T> List<Object> getBeanListByClass(BeanTreeNode node, Class<T> cls) {List<Object> beanList = new ArrayList<Object>();Object bean = node.getBean();if (cls.isAssignableFrom(bean.getClass())) {beanList.add(bean);}List<BeanTreeNode> childNodes = node.getChildNodes();for (BeanTreeNode beanTreeNode : childNodes) {beanList.addAll(getBeanListByClass(beanTreeNode, cls));}return beanList;}/*** 将对应节点及其子节点转化为map.* @param node 树节点* @param map 用来保存结果的map*/private void toMap(BeanTreeNode node, Map<String, List<Object>> map) {String key = node.getNodeType();Object bean = node.getBean();if (map.containsKey(key)) {map.get(key).add(bean);} else {List<Object> list = new ArrayList<Object>();list.add(bean);map.put(key, list);}for (BeanTreeNode tempNode : node.getChildNodes()) {toMap(tempNode, map);}}
}
复制代码

测试树形工具

使用上面的xml进行测试,这里就不再做xml映射,假设存在上面xml所示的所有实体,“school-one”和“school-two”以及5个student,看看能否构造出想要的结构,测试类代码如下。

class SchoolInf {private String msg;public SchoolInf(String msg) {this.msg = msg;}
}class Student {private String name;public Student(String name) {this.name = name;}
}class School {private String name;public School(String name) {this.name = name;}
}public class Test {public static void main(String[] args) {SchoolInf schoolInf = new SchoolInf("2017-10-1XX省学校信息总汇");School school_one = new School("school-one");School school_two = new School("school-two");Student Jack = new Student("Jack");Student Rose = new Student("Rose");Student Jon = new Student("Jon");Student Bob = new Student("Bob");Student Alisa = new Student("Alisa");BeanTree tree = new BeanTree();BeanTreeNode root = tree.addNode(null, schoolInf, "root");BeanTreeNode school_node1 = tree.addNode(root, school_one, "school");BeanTreeNode school_node2 = tree.addNode(root, school_two, "school");tree.addNode(school_node1, Jack, "root");tree.addNode(school_node1, Rose, "root");tree.addNode(school_node1, Jon, "root");tree.addNode(school_node2, Bob, "root");tree.addNode(school_node2, Alisa, "root");System.out.println("end");}
}复制代码

我们通过调试观察树结构变量“tree”的值如下:

可以看出来能够构造出正确的结构,BeanTree中其他的一些方法这里就不在一一测试了。

更新记录

  • 2018/1/10,在BeanTree中添加更多的操作方法。

转载于:https://juejin.im/post/5add8ea8518825670e5cab3f

使用树形结构保存实体相关推荐

  1. 树形结构tree工具类

    说明:下面用到了lombox插件,和hutool工具包,这两个自行百度 TreeBean.class  用来封装树形结构的实体类 import lombok.AllArgsConstructor; i ...

  2. 后台数据转树形结构返回前台

    前台向后台请求数据时可能会希望能得到一个树结构的数据结构,方便我们前台获取和使用,也能使得数据结构清晰.这时候需要,后台将数据转化为树形结构.整体思路为: 1. 定义树形结构的实体类 2. 新建工具类 ...

  3. mysql 树形结构_结合RBAC模型讲解权限管理系统需求及表结构创建

    结合RBAC模型讲解权限管理系统需求及表结构创建 在本号之前的文章中,已经为大家介绍了很多关于Spring Security的使用方法,也介绍了RBAC的基于角色权限控制模型.但是很多朋友虽然已经理解 ...

  4. Java后端递归构建树形结构

    记录:在Java后台利用递归思路进行构建树形结构数据,返回给前端,能以下拉菜单等形式进行展示. 简明:为了简化代码,引入Lombok的Jar包,可省略实体类set().get()方法. <dep ...

  5. 软件工程应用与实践(2)——知识图谱树形结构获取

    2021SC@SDUSC 目录 一.知识图谱的结构 二.前端代码 2.1 对axios请求的封装 2.2 树形控件代码及其分析 三.后端代码 3.1 树形结构对应的实体类 3.2 填充知识树的过程 3 ...

  6. Java8 Stream流递归,几行代码搞定遍历树形结构

    欢迎关注方志朋的博客,回复"666"获面试宝典 可能平常会遇到一些需求,比如构建菜单,构建树形结构,数据库一般就使用父id来表示,为了降低数据库的查询压力,我们可以使用Java8中 ...

  7. 浅谈树形结构的特性和应用(上):多叉树,红黑树,堆,Trie树,B树,B+树......

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 上篇文章我们主要介绍了线性数据结构,本篇233酱带大家看看 无所不 ...

  8. SpringBoot+JsTree实现在编辑时能选择树形结构并获取选中的ID

    场景 SpringBoot+Jquery+jsTree实现页面树型结构: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/90897 ...

  9. Java实现返回的数据为树形结构

    1.实体类为: id:主键 name:名字 parent_id:父id grade:等级 根据list中的实体类数据返回树形结构,代码如下: public class TSystemTreeUtil ...

最新文章

  1. 【错误记录】Groovy 函数参数动态类型报错 ( Caught: groovy.lang.MissingMethodException: No signature of method )
  2. Linux C下实现线程池
  3. InnoDB与MyISAM等存储引擎对比
  4. java 分号 转义_java – 正则表达式和转义和未转义的分隔符
  5. el-input 输入框类型;只能输入数字的输入框;保留两位小数输入框;只能输入正整数和0的输入框;手机号正则校验;车牌号码正则校验
  6. STM32——DMA
  7. vb6.0企业版id_国网公司十八项反措(2018版)开关设备专题解读
  8. box-sizing的属性值
  9. 汉诺塔游戏玩法介绍(攻略和编程实现)
  10. NLPCC2021.10.14
  11. vue 脚手架 elementUi element-ui 兼容 ie 360 急速/兼容模式 完美处理
  12. 在Word指定页插入页码
  13. Linux下异步IO(libaio)的使用以及性能
  14. C++进阶_Effective_C++第三版(六) 继承与面向对象设计 Inheritance and Object-Oriented Design
  15. 数据库 和html的交互
  16. 60个实用的Android框架
  17. MyMPC·暴风影音 Unicode 4.10.07 简体中文版
  18. Android新功能用户指引UserGuide
  19. 【每日新闻】看清小米生态链,再说它值多少钱 | 工信部:二月份查处“黑广播”违法犯罪案件206起
  20. 用户画像从入门到挖坑

热门文章

  1. Win10系列:JavaScript动画2
  2. mongodb3 分片集群平滑迁移
  3. SQLServer查看存储过程的方法
  4. DOMContentLoaded 与onload区别以及使用
  5. Linux下tcpdump用法
  6. 解决vim没有颜色的办法
  7. Java 重写(Override)与重载(Overload)
  8. Python链接MySQL
  9. Sql server Insert执行的秘密(下) 带外键的INSERT分析
  10. CentOS6.5下Gunicorn+Django+nginx部署的过程