以前在项目须要实现一个功能——将xml文件映射成实体,而后对映射的实体进行逻辑处理,最后保存到数据库中;因为xml结构的数据是结构化的数据,因此须要保证保存的数据具备正确的主外键关联。以下所示,是一个须要保存到数据库的xml文件。当映射成对应的实体school和student的时候,咱们须要知道“school-one”下面有哪些学生,“school-two”下面有哪些学生,这个时候想到了使用树形结构来保存实体,让实体之间依然存在关联关系。java
<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>
复制代码
如下是树形工具类的实现,包含了树形节点类和树形结构类,因为代码中注释已经比较全面,因此不作过多的说明。node
每个节点对应一个实体,节点包含了实体信息,为了保证明体之间的关联关系,须要留有父节点信息,全部的子节点信息。由此推断出,节点的主要成员有git
为了方便操做,我还多增长了id和pid(parent id),以及节点类型(nodeType)。对id的相关操做我并无添加,若是须要能够自行添加。github
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里面包含了以下的一些经常使用操做:数据库
代码以下apache
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) {
//从当前父节点移除sNode
sNode.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,看看可否构造出想要的结构,测试类代码以下。dom
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中其余的一些方法这里就不在一一测试了。测试