java樹形結構

zhyp29發表於2016-05-08
我們的目標是:完成以下形態的樹狀.
--管理
---高階管理員
----增加
----刪除
----修改
---普通管理員
----增加
 
 
 
一、建表
/**
--樹形選單
   節點編號
   節點名稱
   節點連結址
   些節點父節點
   是否最底節點
    節點排序(一般用在同級節點上)
   節點說明 
*/
 
drop table EPTreeTable
create table EPTreeTable
(
  TreeNodeId int identity(1,1) constraint pk_TreeNode primary key,
  TreeNodeName varchar(50) not null,
  TreeNodeLink varchar(100) ,
  TreeNodeFatherId int default 0, --0 為最高層
  TreeNodeIsBottom bit default 1, --1 為底層 0為非底層
  TreeNodeCompositor int default 1, -- 預設排在最後面
  TreeNodeExplain varchar(200)
)
 
 
二、JAVA程式碼
(1)TO物件
 
/**
 * @author fangbiao
 * 用於對映父級選單TO物件
 */
public class ParentResourcePojo {
 /**
  * 節點編號
  */
 private int  treeNodeId;
 /**
  * 節點名稱
  */
 private String  treeNodeName;
 /**
  * 父節點
  */
 private int  treeParentNodeId;
 /**
  * @return treeNodeName
  */
 public String getTreeNodeName() {
  return treeNodeName;
 }
 /**
  * @param treeNodeName 要設定的 treeNodeName
  */
 public void setTreeNodeName(String treeNodeName) {
  this.treeNodeName = treeNodeName;
 }
 /**
  * @return treeParentNodeId
  */
 public int getTreeParentNodeId() {
  return treeParentNodeId;
 }
 /**
  * @param treeParentNodeId 要設定的 treeParentNodeId
  */
 public void setTreeParentNodeId(int treeParentNodeId) {
  this.treeParentNodeId = treeParentNodeId;
 }
 /**
  * @return treeNodeId
  */
 public int getTreeNodeId() {
  return treeNodeId;
 }
 /**
  * @param treeNodeId 要設定的 treeNodeId
  */
 public void setTreeNodeId(int treeNodeId) {
  this.treeNodeId = treeNodeId;
 }
}
 
(2)樹形組合

 /**
  * 獲取節點選擇列表資訊
  * @return
  */
 public List getResourceList(){
  if(resourceList.size() == 0) {
   //獲取高階的父節點
   resourceList = doTurnParentToTree(itbs.getTopParentResource());
  }
  return resourceList;
 }

 private int num =2;
 private int tempTotalChildren ;
 private boolean temp = false;
 private int tempParent; //每次遞迴節點的父節點
 /**
  * 對父級列表進行樹排
  * @param prp
  * @return
  */
 private synchronized List doTurnParentToTree(ParentResourcePojo prp){
  if(prp == null)
   return null;
  List list = getChildrenList(prp);
     
  //分線
  tempParent = prp.getTreeParentNodeId();
  
  String str = "";
  if(tempParent == 0){
   resourceList.add("-"+prp.getTreeNodeName()));
  }else{
   resourceList.add(prp.getTreeNodeName()));
//每棵樹的節點數目
   tempTotalChildren = list.size();
   
  }
  Iterator iterator = list.iterator();
  while(iterator.hasNext()){
   ParentResourcePojo treePojo = (ParentResourcePojo)iterator.next();

   if(tempParent != 0){
    if( tempParent treePojo.getTreeParentNodeId()){
     num -=1;
     temp = false;
    }else if( tempParent == treePojo.getTreeParentNodeId() ){
     if(tempTotalChildren ==0)
      temp = false;
     else
      temp = true;
    }
   
   }
   for(int i=0;i<num str resourcelist list allparenttreelist="null;" int flag="0;" getallparenttreelist null itbs.getrrcresource prp getchildrenlist listlength="list.size();" newreturnlist="new" arraylist leavelist="new" i="0;i&lt;listLength;i++){" prpojo=" " treepojotreeparantnodeid="prPojo.getTreeParentNodeId();" tptreenodeid="prp.getTreeNodeId();" public class actionbo private string id parentid level menutypeid menutype name url integer sort description commandname date created recordoperationflag userid> actionBOs;


public ActionBO() {
super();
}


public ActionBO(Action action) {
this.id = action.getId();
this.parentId = action.getParentId();
this.name = action.getName();
this.level = action.getLevel();
this.menuTypeId = action.getMenuTypeId();
this.menuType = action.getMenuType();
this.url = action.getUrl();
this.sort = action.getSort();
this.description = action.getDescription();
this.recordOperationFlag = action.getRecordOperationFlag();
this.created = action.getCreated();
this.commandName = action.getCommandName();
}


public ActionBO(String id, String parentId, String level,
String menuTypeId, String menuType, String name, String url,
Integer sort, String description, String commandName, Date created,
String recordOperationFlag, String userId, List<actionbo> actionBOs) {
super();
this.id = id;
this.parentId = parentId;
this.level = level;
this.menuTypeId = menuTypeId;
this.menuType = menuType;
this.name = name;
this.url = url;
this.sort = sort;
this.description = description;
this.commandName = commandName;
this.created = created;
this.recordOperationFlag = recordOperationFlag;
this.userId = userId;
this.actionBOs = actionBOs;
}

}

public class Action {

private String id;
private String parentId;
private String level;
private String menuTypeId;
private String menuType;
private String name;
private String url;
private Integer sort;
private String description;
private String commandName;
private Date created;
private String recordOperationFlag;

public Action() {
super();
}
public Action(String id, String parentId, String level, String menuTypeId,
String menuType, String name, String url, Integer sort,
String description, String commandName, Date created,
String recordOperationFlag) {
super();
this.id = id;
this.parentId = parentId;
this.level = level;
this.menuTypeId = menuTypeId;
this.menuType = menuType;
this.name = name;
this.url = url;
this.sort = sort;
this.description = description;
this.commandName = commandName;
this.created = created;
this.recordOperationFlag = recordOperationFlag;
}


public Action(JSONObject object) {
this.id = object.getString("id");
this.parentId = StringUtils.isEmpty(object.getString("parentId")) ? null : object.getString("parentId");
this.level = object.getString("level");
this.menuTypeId = object.getString("menuTypeId");
this.menuType = object.getString("menuType");
this.name = object.getString("name");
this.url = object.getString("url");
this.sort = object.getInteger("sort");
this.description = object.getString("description");
this.commandName = object.getString("commandName");
this.created = object.getDate("created");
this.recordOperationFlag = object.getString("recordOperationFlag");
}

}

主要方法:
@Override
public List<actionbo> findAll(){
List<actionbo> actionBOs = new ArrayList<actionbo>();
List<action> actions = actionDao.findAll();


for (Action Action : actions) {
if (StringUtils.isEmpty(Action.getParentId())) {
ActionBO actionBO = new ActionBO(Action);
setChildNode(actionBO, actions);
actionBOs.add(actionBO);
}
}
return actionBOs;
}


/**
* 設定樹的子節點
*
* @param actionBO
* @param actions
*/
private void setChildNode(ActionBO actionBO, List<action> actions) {
List<actionbo> actionBOs = new ArrayList<actionbo>();
for (Action Action : actions) {
if (!actionBO.getId().equals(Action.getId())
&amp;&amp; actionBO.getId().equals(Action.getParentId())) {
ActionBO actionBo = new ActionBO(Action);
if (isParent(actions, actionBo)) {
setChildNode(actionBo, actions);
}
actionBOs.add(actionBo);
}
}
actionBO.setActionBOs(actionBOs);
}


/**
* 是否為父節點
*
* @param actions
* @param actionBo
* @return
*/
private boolean isParent(List<action> actions, ActionBO actionBo) {
boolean isParent = false;
for (Action Action : actions) {
if (!actionBo.getId().equals(Action.getId())
&amp;&amp; actionBo.getId().equals(Action.getParentId())) {
isParent = true;
break;
}
}
return isParent;
}

使用遞迴演算法結合資料庫解析成java樹形結構

1、準備表結構及對應的表資料
a、表結構:

create table TB_TREE
(
CID NUMBER not null,
CNAME VARCHAR2(50),
PID NUMBER //父節點
)
b、表資料:


insert into tb_tree (CID, CNAME, PID) values (1, '中國', 0);
insert into tb_tree (CID, CNAME, PID) values (2, '北京市', 1);
insert into tb_tree (CID, CNAME, PID) values (3, '廣東省', 1);
insert into tb_tree (CID, CNAME, PID) values (4, '上海市', 1);
insert into tb_tree (CID, CNAME, PID) values (5, '廣州市', 3);
insert into tb_tree (CID, CNAME, PID) values (6, '深圳市', 3);
insert into tb_tree (CID, CNAME, PID) values (7, '海珠區', 5);
insert into tb_tree (CID, CNAME, PID) values (8, '天河區', 5);
insert into tb_tree (CID, CNAME, PID) values (9, '福田區', 6);
insert into tb_tree (CID, CNAME, PID) values (10, '南山區', 6);
insert into tb_tree (CID, CNAME, PID) values (11, '密雲縣', 2);
insert into tb_tree (CID, CNAME, PID) values (12, '浦東', 4);

2、TreeNode物件,對應tb_tree


public class TreeNode implements Serializable {
private Integer cid;
private String cname;
private Integer pid;
private List nodes = new ArrayList();
 
public TreeNode() {
}
 
//getter、setter省略
}

3、測試資料


public class TreeNodeTest {
@Test
public void loadTree() throws Exception{
System.out.println(JsonUtils.javaToJson(recursiveTree(1)));
}
 
/**
* 遞迴演算法解析成樹形結構
*
* @param cid
* @return
* @author jiqinlin
*/
public TreeNode recursiveTree(int cid) {
//根據cid獲取節點物件(SELECT * FROM tb_tree t WHERE t.cid=?)
TreeNode node = personService.getreeNode(cid);
//查詢cid下的所有子節點(SELECT * FROM tb_tree t WHERE t.pid=?)
List childTreeNodes = personService.queryTreeNode(cid);
//遍歷子節點
for(TreeNode child : childTreeNodes){
TreeNode n = recursiveTree(child.getCid()); //遞迴
node.getNodes().add(n);
}
 
return node;
}
}

輸出的json格式如下:


{
    "cid": 1,
    "nodes": [
        {
            "cid": 2,
            "nodes": [
                {
                    "cid": 11,
                    "nodes": [
                         
                    ],
                    "cname": "密雲縣",
                    "pid": 2
                }
            ],
            "cname": "北京市",
            "pid": 1
        },
        {
            "cid": 3,
            "nodes": [
                {
                    "cid": 5,
                    "nodes": [
                        {
                            "cid": 7,
                            "nodes": [
                                 
                            ],
                            "cname": "海珠區",
                            "pid": 5
                        },
                        {
                            "cid": 8,
                            "nodes": [
                                 
                            ],
                            "cname": "天河區",
                            "pid": 5
                        }
                    ],
                    "cname": "廣州市",
                    "pid": 3
                },
                {
                    "cid": 6,
                    "nodes": [
                        {
                            "cid": 9,
                            "nodes": [
                                 
                            ],
                            "cname": "福田區",
                            "pid": 6
                        },
                        {
                            "cid": 10,
                            "nodes": [
                                 
                            ],
                            "cname": "南山區",
                            "pid": 6
                        }
                    ],
                    "cname": "深圳市",
                    "pid": 3
                }
            ],
            "cname": "廣東省",
            "pid": 1
        },
        {
            "cid": 4,
            "nodes": [
                {
                    "cid": 12,
                    "nodes": [
                         
                    ],
                    "cname": "浦東",
                    "pid": 4
                }
            ],
            "cname": "上海市",
            "pid": 1
        }
    ],
    "cname": "中國",
    "pid": 0
}


樹節點類:
package cn.com.tree;

public class Node {
private Integer id;
private Integer parentId;
private String name;
private String link;

public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getParentId() {
return parentId;
}
public void setParentId(Integer parentId) {
this.parentId = parentId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
}
輸出樹形選單類:
package cn.com.tree;

import java.util.ArrayList;
import java.util.List;

public class Tree {
private StringBuffer html = new StringBuffer();
private List<node> nodes;

public Tree(List<node> nodes){
this.nodes = nodes;
}

public String buildTree(){
html.append("<ul>");
for (Node node : nodes) {
Integer id = node.getId();
if (node.getParentId() == null) {
html.append("\r\n<li id='" + id + "'>" + node.getName()+ "</li>");
build(node);
}
}
html.append("\r\n</ul>");
return html.toString();
}

private void build(Node node){
List<node> children = getChildren(node);
if (!children.isEmpty()) {
html.append("\r\n<ul>");
for (Node child : children) {
Integer id = child.getId();
html.append("\r\n<li id='" + id + "'>" + child.getName()+ "</li>");
build(child);
}
html.append("\r\n</ul>");
}
}

private List<node> getChildren(Node node){
List<node> children = new ArrayList<node>();
Integer id = node.getId();
for (Node child : nodes) {
if (id.equals(child.getParentId())) {
children.add(child);
}
}
return children;
}
}
測試類:
package zzj.test;

import java.util.ArrayList;
import java.util.List;

import cn.com.tree.Node;
import cn.com.tree.Tree;


public class Test {

/**
* @param args
*/
public static void main(String[] args) {
List<node> nodes = new ArrayList<node>();

Node node1 = new Node();
node1.setId(1);
node1.setName("node1");
node1.setParentId(null);
node1.setLink(null);
nodes.add(node1);

Node node11 = new Node();
node11.setId(11);
node11.setName("node11");
node11.setParentId(1);
node11.setLink(null);
nodes.add(node11);

Node node111 = new Node();
node111.setId(111);
node111.setName("node111");
node111.setParentId(11);
node111.setLink(null);
nodes.add(node111);

Node node12 = new Node();
node12.setId(12);
node12.setName("node12");
node12.setParentId(1);
node12.setLink(null);
nodes.add(node12);

Node node2 = new Node();
node2.setId(2);
node2.setName("node2");
node2.setParentId(null);
node2.setLink(null);
nodes.add(node2);

Node node21 = new Node();
node21.setId(21);
node21.setName("node21");
node21.setParentId(2);
node21.setLink(null);
nodes.add(node21);

Node node3 = new Node();
node3.setId(3);
node3.setName("node3");
node3.setParentId(null);
node3.setLink(null);
nodes.add(node3);

Tree tree = new Tree(nodes);
System.out.println(tree.buildTree());
}
}
輸出:
<ul>
<li id="1">node1</li>
<ul>
<li id="11">node11</li>
<ul>
<li id="111">node111</li>
</ul>
<li id="12">node12</li>
</ul>
<li id="2">node2</li>
<ul>
<li id="21">node21</li>
</ul>
<li id="3">node3</li>
</ul>


三、原始碼實現(Java語言版)

實現這樣一顆樹,需要設計三個類:樹類(MultipleTree.java)、節點類(Node.java)、孩子列表類(Children.java);為了方便演示,還需要構造一些假的層次資料,因此還需要建一個構造假資料的類(VirtualDataGenerator.java),以下程式碼拷貝出來之後可直接執行測試:
 
Java程式碼  
package test;  
  
import java.util.ArrayList;  
import java.util.Comparator;  
import java.util.HashMap;  
import java.util.Iterator;  
import java.util.List;  
import java.util.Map;  
import java.util.Set;  
import java.util.Collections;  
  
/** 
 * 多叉樹類 
*/  
public class MultipleTree {  
 public static void main(String[] args) {  
  // 讀取層次資料結果集列表   
  List dataList = VirtualDataGenerator.getVirtualResult();    
    
  // 節點列表(雜湊表,用於臨時儲存節點物件)  
  HashMap nodeList = new HashMap();  
  // 根節點  
  Node root = null;  
  // 根據結果集構造節點列表(存入雜湊表)  
  for (Iterator it = dataList.iterator(); it.hasNext();) {  
   Map dataRecord = (Map) it.next();  
   Node node = new Node();  
   node.id = (String) dataRecord.get("id");  
   node.text = (String) dataRecord.get("text");  
   node.parentId = (String) dataRecord.get("parentId");  
   nodeList.put(node.id, node);  
  }  
  // 構造無序的多叉樹  
  Set entrySet = nodeList.entrySet();  
  for (Iterator it = entrySet.iterator(); it.hasNext();) {  
   Node node = (Node) ((Map.Entry) it.next()).getValue();  
   if (node.parentId == null || node.parentId.equals("")) {  
    root = node;  
   } else {  
    ((Node) nodeList.get(node.parentId)).addChild(node);  
   }  
  }  
  // 輸出無序的樹形選單的JSON字串  
  System.out.println(root.toString());     
  // 對多叉樹進行橫向排序  
  root.sortChildren();  
  // 輸出有序的樹形選單的JSON字串  
  System.out.println(root.toString());   
    
  // 程式輸出結果如下(無序的樹形選單)(格式化後的結果):    
  //  {  
  //   id : '100000',   
  //   text : '廊坊銀行總行',   
  //   children : [  
  //     {  
  //     id : '110000',   
  //     text : '廊坊分行',   
  //     children : [  
  //       {  
  //       id : '113000',   
  //       text : '廊坊銀行開發區支行',   
  //       leaf : true  
  //       },  
  //       {  
  //       id : '111000',   
  //       text : '廊坊銀行金光道支行',   
  //       leaf : true  
  //       },  
  //       {  
  //       id : '112000',   
  //       text : '廊坊銀行解放道支行',   
  //       children : [  
  //         {  
  //         id : '112200',   
  //         text : '廊坊銀行三大街支行',   
  //         leaf : true  
  //         },  
  //         {  
  //         id : '112100',   
  //         text : '廊坊銀行廣陽道支行',   
  //         leaf : true  
  //         }  
  //       ]  
  //       }  
  //     ]  
  //     }  
  //   ]  
  //  }  
  
  // 程式輸出結果如下(有序的樹形選單)(格式化後的結果):  
  //  {  
  //   id : '100000',   
  //   text : '廊坊銀行總行',   
  //   children : [  
  //     {  
  //     id : '110000',   
  //     text : '廊坊分行',   
  //     children : [  
  //       {  
  //       id : '111000',   
  //       text : '廊坊銀行金光道支行',   
  //       leaf : true  
  //       },  
  //       {  
  //       id : '112000',   
  //       text : '廊坊銀行解放道支行',   
  //       children : [  
  //         {  
  //         id : '112100',   
  //         text : '廊坊銀行廣陽道支行',   
  //         leaf : true  
  //         },  
  //         {  
  //         id : '112200',   
  //         text : '廊坊銀行三大街支行',   
  //         leaf : true  
  //         }  
  //       ]  
  //       },  
  //       {  
  //       id : '113000',   
  //       text : '廊坊銀行開發區支行',   
  //       leaf : true  
  //       }  
  //     ]  
  //     }  
  //   ]  
  //  }    
    
 }  
     
}  
  
  
/** 
* 節點類 
*/  
class Node {  
 /** 
  * 節點編號 
  */  
 public String id;  
 /** 
  * 節點內容 
  */  
 public String text;  
 /** 
  * 父節點編號 
  */  
 public String parentId;  
 /** 
  * 孩子節點列表 
  */  
 private Children children = new Children();  
   
 // 先序遍歷,拼接JSON字串  
 public String toString() {    
  String result = "{"  
   + "id : '" + id + "'"  
   + ", text : '" + text + "'";  
    
  if (children != null &amp;&amp; children.getSize() != 0) {  
   result += ", children : " + children.toString();  
  } else {  
   result += ", leaf : true";  
  }  
      
  return result + "}";  
 }  
   
 // 兄弟節點橫向排序  
 public void sortChildren() {  
  if (children != null &amp;&amp; children.getSize() != 0) {  
   children.sortChildren();  
  }  
 }  
   
 // 新增孩子節點  
 public void addChild(Node node) {  
  this.children.addChild(node);  
 }  
}  
  
/** 
* 孩子列表類 
*/  
class Children {  
 private List list = new ArrayList();  
   
 public int getSize() {  
  return list.size();  
 }  
   
 public void addChild(Node node) {  
  list.add(node);  
 }  
   
 // 拼接孩子節點的JSON字串  
 public String toString() {  
  String result = "[";    
  for (Iterator it = list.iterator(); it.hasNext();) {  
   result += ((Node) it.next()).toString();  
   result += ",";  
  }  
  result = result.substring(0, result.length() - 1);  
  result += "]";  
  return result;  
 }  
   
 // 孩子節點排序  
 public void sortChildren() {  
  // 對本層節點進行排序  
  // 可根據不同的排序屬性,傳入不同的比較器,這裡傳入ID比較器  
  Collections.sort(list, new NodeIDComparator());  
  // 對每個節點的下一層節點進行排序  
  for (Iterator it = list.iterator(); it.hasNext();) {  
   ((Node) it.next()).sortChildren();  
  }  
 }  
}  
  
/** 
 * 節點比較器 
 */  
class NodeIDComparator implements Comparator {  
 // 按照節點編號比較  
 public int compare(Object o1, Object o2) {  
  int j1 = Integer.parseInt(((Node)o1).id);  
     int j2 = Integer.parseInt(((Node)o2).id);  
     return (j1   
  <menugroup>  
     <menu>    
     </menu>  
     <menu>    
     </menu>  
     <menugroup>  
       <menu>     
       </menu>  
       <menu>     
       </menu>  
     </menugroup>  
  </menugroup>  
  
 
 
(2)UL - LI 層次結構
 
Html程式碼  
<ul>  
 <li>廊坊銀行總行</li>  
 <ul>  
  <li>廊坊分行</li>  
  <ul>  
    <li>廊坊銀行開發區支行</li>       
     <li>廊坊銀行解放道支行</li>  
     <ul>  
      <li>廊坊銀行三大街支行</li>  
      <li>廊坊銀行廣陽道支行</li>  
     </ul>   
    <li>廊坊銀行金光道支行</li>  
  </ul>   
 </ul>   
</ul>   
 
 
(3)TABLE層次結構
 
Html程式碼  
<table>  
<tr><td>廊坊銀行總行</td></tr>  
<tr><td>  廊坊分行</td></tr>  
<tr><td>    廊坊銀行開發區支行</td></tr>  
<tr><td>    廊坊銀行解放道支行</td></tr>  
<tr><td>      廊坊銀行三大街支行</td></tr>  
<tr><td>      廊坊銀行廣陽道支行</td></tr>  
<tr><td>    廊坊銀行金光道支行</td></tr>  
</table>  
 
 
另外對TreeGrid樹形表格也有一定的價值:
   1、  一次性構造樹形表格,實現資料分級展示
   2、  通過更換比較器,實現對不同表格列的全排序(全排序指的是對所有頁的資料進行排序,而不是隻對當前頁的資料排序)
   3、  實現對樹形表格的完整分頁(每次分頁時,只取固定數目的第一層節點,之後呼叫toString方法,展示出完 整條數的分級資料)


</node></node></node></node></node></node></node></node></action></actionbo></actionbo></action></action></actionbo></actionbo></actionbo></actionbo></num>

相關文章