★ 用Java实现目录树

磁盘文件、XML文档和SQL中的表(有一定要求)都可以生成目录树。
此代码可以任意使用修改,如有修改、建议或发现错误,请发信到flyxxxxx@163.com,谢谢。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;

/**
?* 目录树.

?* 提供由其它对象生成目录树的支持。

?* 如磁盘目录:Tree t=Tree.getTree(new java.io.File("D:/"),new FileContainer());

?* XML文件:Document doc=...

?* Tree t=Tree.getTree(doc,new DocumentContainer());

?* 如果有File或Document以外的对象要生成目录树,请实现{@link TreeNode}或{@link Container}接口。
?* 对于SQL中的表,建议字段要求id(标识)、parentId(上级目录标识),其它字段自定,然后对查询到的每一
?* 条记录生成一个实现TreeNode接口的对象。
?* 如果实现了TreeNode接口:

?*?? class Group implements TreeNode{}

?*?? Group[] groups=...

?*?? Tree t=Tree.getTree(groups,0);//其中0为根结点的ID
,并且groups不要求是同一对象,只要它们都实现了
?* 接口TreeNode,并且ID不同,这样可以在生成目录树的过程中根据对象类型自行处理。
?*

Copyright: Copyright (c) 2004


?*


?* @author flyxxxxx
?* @version 1.0
?*/
final public class Tree
??? extends Node
{
? /**
?? * 结点最大标识
?? */
? private static int maxId = 0;

? private Tree()
? {
??? super(getMaxId(), null);
? }

? private Tree(int id)
? {
??? super(id, null);
??? maxId = id++;
? }

? private static int getMaxId()
? {
??? return maxId++;
? }

? /**
?? * 创建空目录树.
?? * @return Tree 空目录树
?? */
? public static Tree getTree()
? {
??? return new Tree();
? }

? /**
?? * 向目录树添加一个结点.
?? * 目录树中所有结点的类型最好是相同的。
?? * @param parent Node 父结点
?? * @param value Object 结点的值
?? * @return Node 添加的结点
?? */
? public Node addNode(Node parent, Object value)
? {
??? Node rs = new Node(getMaxId(), parent);
??? rs.setValue(value);
??? return rs;
? }

? /**
?? * 创建目录树.
?? * 如果对象实现了接口{@link Container},可以通过此方法加入目录树。

?? * 通过此方法创建的目录树,所有结点的ID由系统生成。obj将直接做为根结点,对根结点调用方法
?? * {@link Node#getValue()}将得到obj。

?? * @param obj Object 目录树的根结点
?? * @param container Container 得到对象的子对象的接口
?? * @return Tree 目录树
?? */
? public static Tree getTree(Object obj, Container container)
? {
??? Tree rs = new Tree();
??? rs.setValue(obj);
??? Object[] o = container.getChilds(obj);
??? for (int i = 0; i < o.length; i++)
??? {
????? addNode(rs, o[i], container);
??? }
??? return rs;
? }

? private static void addNode(Node n, Object obj, Container container)
? {
??? Node node = new Node(getMaxId(), n);
??? node.setValue(obj);
??? Object[] o = container.getChilds(obj);
??? for (int i = 0; i < o.length; i++)
??? {
????? addNode(node, o[i], container);
??? }
? }

? /**
?? * 创建目录树.
?? * 如果对象实现了接口{@link Container},可以通过此方法加入目录树。

?? * 通过此方法创建的目录树,所有结点的ID由系统生成,对根结点调用方法{@link Node#getValue()}
?? * 将得到null。

?? * obj数组中的每一个,将直接做为根结点的直接子结点。
?? * @param obj Object 目录树的根结点的直接子结点.
?? * @param container Container 得到对象的子对象的接口
?? * @return Tree 目录树
?? */
? public static Tree getTree(Object obj[], Container container)
? {
??? Tree rs = new Tree();
??? for (int i = 0; i < obj.length; i++)
??? {
????? addNode(rs, obj[i], container);
??? }
??? return rs;
? }

? /**
?? * 创建目录树.
?? * 只要一组对象实现接口{@link TreeNode},并且每个对象的ID不同,就可以将它们加入目录树。

?? * 通过此方法得到的目录树,它的根结点ID值为rootId,其它结点的值为实现接口TreeNode的对象的ID。

?? * 如果treeNode中包含了根结点,根结点的值可以通过方法{@link Node#getValue()}得到,返之得到的是null。

?? * treeNode可以没有顺序,但父结点的ID一定大于子结点的。
?? * @param treeNode TreeNode[] 构成目录树的结点
?? * @param rootId int 根结点的ID
?? * @return Tree 创建目录树
?? */
? public static Tree getTree(TreeNode[] treeNode, int rootId)
? {
??? Tree rs = new Tree(rootId);
??? ArrayList list = new ArrayList();
??? for (int i = 0; i < treeNode.length; i++)
??? {
????? list.add(treeNode[i]);
??? }
??? Collections.sort(list, new Compare()); //排序
??? Node last = rs;
??? for (int i = 0; i < treeNode.length; i++)
??? {
????? TreeNode tnode = (TreeNode) list.get(i);
????? if (i == 0 && tnode.getId() == rootId)
????? { //是否根结点
??????? rs.setValue(tnode);
????? }
????? else
????? {
??????? Node parent = null; //寻找父结点
??????? if ( ( (TreeNode) last.getValue()).getId() == tnode.getParentId())
??????? {
????????? parent = last;
??????? }
??????? else
??????? {
????????? parent = rs.getNode(tnode.getParentId());
??????? }
??????? if (parent == null)
??????? { //未找到
????????? throw new NullPointerException("Node " + tnode.getParentId() +
???????????????????????????????????????? " not found.");
??????? }
??????? else
??????? { //找到
????????? Node n = new Node(tnode.getId(), parent);
????????? n.setValue(tnode);
????????? last = parent;
??????? }
????? }
??? }
??? return rs;
? }

? /**
?? * 从目录树中查找标识为id的结点.
?? * @param id String 结点标识
?? * @return Node 标识为id的结点(未找到返回null)
?? */
? public Node getNode(int id)
? {
??? if (id == getId())
??? {
????? return this;
??? }
??? return getNode(getChilds(), id);
? }

? private static Node getNode(Iterator it, int id)
? { //查找结点
??? while (it.hasNext())
??? {
????? Node n = (Node) it.next();
????? if (n.getId() == id)
????? {
??????? return n;
????? }
????? if (n.getChildsNumber() > 0)
????? {
??????? n = getNode(n.getChilds(), id);
??????? if (n != null)
??????? {
????????? return n;
??????? }
????? }
??? }
??? return null;
? }

? /**
?? * 对目录树进行排序
?? * @param com Comparator 排序接口
?? */
? public void sort(Comparator com)
? {
??? sort(childs, com);
? }

? private void sort(ArrayList childs, Comparator com)
? { //对子结点排序
??? Collections.sort(childs, com);
??? for (int i = 0; i < childs.size(); i++)
??? {
????? Node n = (Node) childs.get(i);
????? if (n.getChildsNumber() > 1)
????? {
??????? sort(n.childs, com);
????? }
??? }
? }

? /**
?? * 得到满足条件的结点列表.
?? * @param filter NodeFilter 结点过滤器
?? * @return Iterator 结点列表(存储Node对象)
?? */
? public Iterator getNodeList(NodeFilter filter)
? {
??? ArrayList rs = new ArrayList();
??? getNodeList(childs, filter, rs);
??? return rs.iterator();
? }

? private void getNodeList(ArrayList childs, NodeFilter filter,
?????????????????????????? ArrayList rs)
? { //检索满足条件的结点
??? for (int i = 0; i < childs.size(); i++)
??? {
????? Node n = (Node) childs.get(i);
????? if (filter.accept(n))
????? {
??????? rs.add(n);
????? }
????? if (n.hasChilds())
????? {
??????? getNodeList(n.childs, filter, rs);
????? }
??? }
? }

}

class Compare
??? implements Comparator //对结点按ID排序
{
? public Compare()
? {}

? public int compare(Object obj1, Object obj2)
? {
??? int id1 = ( (TreeNode) obj1).getId();
??? int id2 = ( (TreeNode) obj2).getId();
??? return id1 - id2;
? }
}

import java.util.ArrayList;
import java.util.Iterator;

/**
?* 目录树的一个结点.

?* 它的主要属性有结点标识、父结点、它在目录树中的层次(根结点为0)、结点的值、子结点。
?*

Copyright: Copyright (c) 2004


?* @author flyxxxxx
?* @version 1.0
?*/
public class Node
{
? private int id;
? private Node parent;
? private int level;
? private Object value;
? protected ArrayList childs = new ArrayList();

? /**
?? * 构造方法
?? * @param id int 结点ID
?? * @param parent Node 父结点
?? */
? Node(int id, Node parent)
? {
??? this.id = id;
??? if (parent != null)
??? {
????? this.parent = parent;
????? parent.childs.add(this);
????? this.level = parent.getLevel() + 1;
??? }
??? else
??? {
????? level = 0;
??? }
? }

? /**
?? * 得到结点ID.
?? * @return int 结点ID
?? */
? public int getId()
? {
??? return id;
? }

? /**
?? * 得到结点在目录树中的层次.
?? * 其中根结点为0,根结点的子结点为1,依次类推
?? * @return int 结点在目录树中的层次
?? */
? final public int getLevel()
? {
??? return level;
? }

? /**
?? * 得到结点的值.
?? * 也就是TreeNode接口所引用的对象
?? * @return Object 结点的值
?? */
? final public Object getValue()
? {
??? return value;
? }

? /**
?? * 设定结点的值.
?? */
? final void setValue(Object value)
? {
??? this.value = value;
? }

? /**
?? * 得到子结点列表.
?? * Iterator中存储的是Node对象
?? * @return Iterator 子结点列表
?? */
? final public Iterator getChilds()
? {
??? return childs.iterator();
? }

? /**
?? * 得到子结点数量.
?? * @return int 子结点数量
?? */
? final public int getChildsNumber()
? {
??? return childs.size();
? }

? /**
?? * 是否有子结点.
?? * @return boolean 有子结点返回true
?? */
? final public boolean hasChilds()
? {
??? return childs.size() > 0;
? }

? /**
?? * 得到父结点.
?? * 如果结点为根结点,返回null
?? * @return Node 父结点
?? */
? final public Node getParent()
? {
??? return parent;
? }

? /**
?? * 得到第level级父结点.
?? * @param level int 父结点的层次(level大于等于0,小于此结点的层次)
?? * @return Node 第level级父结点
?? */
? final public Node getParent(int level)
? {
??? if (level < 0 || level >= this.level)
??? {
????? throw new ArrayIndexOutOfBoundsException("level is error.");
??? }
??? Node n = parent;
??? for (int i = 1; i < level; i++)
??? {
????? n = n.getParent();
??? }
??? return n;
? }

? /**
?? * 得到结点在同级结点的相对位置.
?? * @return int 结点在同级结点的相对位置
?? */
? final public int getPosition()
? {
??? if (parent == null)
??? {
????? return 0;
??? }
??? return parent.childs.indexOf(this);
? }

? /**
?? * 结点是否是同级结点的最后一个.
?? * @return boolean 是返回true
?? */
? final public boolean isLast()
? {
??? if (parent == null)
??? {
????? return true;
??? }
??? return getPosition() == parent.childs.size() - 1;
? }

? /**
?? * 结点是否同级结点的第一个.
?? * @return boolean 是返回true
?? */
? final public boolean isFirst()
? {
??? return getPosition() == 0;
? }

? /**
?? * 得到目录树中下一个结点.
?? * 如果此结点是目录树最后一个结点则返回null
?? * @return Node 下一个结点
?? */
? final public Node getNext()
? {
??? if (childs.size() > 0)
??? {
????? return (Node) childs.get(0);
??? }
??? Node n = parent;
??? while (n != null)
??? {
????? Node node = n.getNextSibling();
????? if (node != null)
????? {
??????? return node;
????? }
????? n = n.getParent();
??? }
??? return null;
? }

? /**
?? * 得到下一个同级结点.
?? * 没有下一个同级结点返回null
?? * @return Node 下一个同级结点
?? */
? final public Node getNextSibling()
? {
??? if (parent == null)
??? {
????? return null;
??? }
??? int k = getPosition();
??? if (k == parent.getChildsNumber() - 1)
??? {
????? return null;
??? }
??? return (Node) parent.childs.get(k + 1);
? }

? /**
?? * 得到前一个同级结点.
?? * 没有前一个同级结点返回null
?? * @return Node 前一个同级结点
?? */
? final public Node getPreviousSibling()
? {
??? int k = getPosition();
??? if (k == 0)
??? {
????? return null;
??? }
??? return (Node) parent.childs.get(k - 1);
? }

? /**
?? * 得到前一个结点.
?? * 根结点的前一个结点为null
?? * @return Node 前一个结点
?? */
? final public Node getPrevious()
? {
??? Node n = getPreviousSibling();
??? if (n != null)
??? {
????? return n;
??? }
??? return parent;
? }

}

/**
?* 结点过滤接口.

* 此接口用于从目录树中查找符合一定条件的结点。

?*

Copyright: Copyright (c) 2004


?* @author flyxxxxx
?* @version 1.0
?*/
public interface NodeFilter
{
? /**
?? * 判断结点是否满足一定条件.
?? * @param n Node 要判断的结点
?? * @return boolean 满足条件返回true
?? */
? public boolean accept(Node n);
}

/**
?* 目录树的一个结点.

?* 要将一组对象转化为目录树,它必须实现此接口或{@link Container}接口。

?* 通过实现此接口的目录树,目录树的每个结点的标识等于实现此接口的相应对象的标识。

?* 一个结点最重要的属性是它的标识和它上级目录的标识。

?*

Copyright: Copyright (c) 2004


?* @author flyxxxxx
?* @version 1.0
?*/

public interface TreeNode
{

? /**
?? * 得到此结点的标识
?? * @return String 结点的标识
?? */
? public int getId();

? /**
?? * 得到父结点的标识
?? * @return String 父结点的标识
?? */
? public int getParentId();

}
/**
?* 容器接口.

?* 要将一组或一个对象转化为目录树,它必须实现此接口或{@link TreeNode}接口。

?* 容器能够包含子结点,它通过方法{@link #getChilds(java.lang.Object)}得到一个对象的子结点。

?* 目录树中的每一个结点的值将引用这个容器所指向的对象,也就是说:通过调用方法
?* {@link Node#getValue()}将得到这个对象。

?* 如:Tree t=Tree.getTree(new File("D:/"),new FileContainer());

?* 在t中的每个结点,对它调用方法{@link Node#getValue()}都将得到一个File对象。

?*

Copyright: Copyright (c) 2004


?*


?* @author flyxxxxx
?* @version 1.0
?*/
public interface Container
{
? /**
?? * 得到将对象的所有子对象.
?? * @param obj Object 父对象
?? * @return Object[] 子对象列表
?? */
? public Object[] getChilds(Object obj);
}

import java.util.ArrayList;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;

/**
?* XML文档容器.

?* 将一个XML文件转化为目录树,此目录树中的每个结点将对应XML文件中的一个Element,也就是Document
?* 结点对应目录树的根结点,依次类推。

?* 目录树的每个结点的值({@link Node#getValue()}均为Element,结点的ID由系统产生,根结点为0。

?* 使用方法:Tree t=new Tree(Document document,new DocumentContainer());

?*     其中document为XML文档元素。

?*

Copyright: Copyright (c) 2004


?*


?* @author flyxxxxx
?* @version 1.0
?*/
final public class DocumentContainer
??? implements Container
{
? /**
?? * XML文档容器构造方法
?? */
? public DocumentContainer()
? {
? }

? /**
?? * 得到将对象的所有子对象.
?? * @param obj Object 父对象(类型Element)
?? * @return Object[] 子对象列表(类型Element[])
?? */
? public Object[] getChilds(Object obj)
? {
??? if (obj instanceof Element)
??? {
????? ArrayList rs = new ArrayList();
????? NodeList list = ( (Element) obj).getChildNodes();
????? for (int i = 0; i < list.getLength(); i++)
????? {
??????? Node n = list.item(i);
??????? if (n.getNodeType() == Node.ELEMENT_NODE)
??????? {
????????? rs.add(n);
??????? }
????? }
????? return rs.toArray();
??? }
??? throw new IllegalArgumentException(
??????? "Required param type is org.w3c.dom.Element.");
? }
}

import java.io.FileFilter;
import java.io.File;

/**
?* 文件容器.

?* 将一个磁盘目录转化为目录树,此目录树中的每个结点将对应磁盘中的一个目录或文件。

?* 目录树的每个结点的值({@link Node#getValue()}均为File,结点的ID由系统产生,根结点为0。

?* 使用方法:Tree t=new Tree(File f,new FileContainer());

?*

Copyright: Copyright (c) 2004


?*


?* @author flyxxxxx
?* @version 1.0

?*/
final public class FileContainer
??? implements Container
{
? private FileFilter filter;

? /**
?? * 默认容器构造方法
?? */
? public FileContainer()
? {
? }

? /**
?? * 带文件过滤器的构造方法.
?? * 通过此方法,将目录树中不会有不满足条件的目录或文件
?? * @param filter FileFilter 文件过滤器
?? */
? public FileContainer(FileFilter filter)
? {
??? this.filter = filter;
? }

? /**
?? * 得到将对象的所有子对象.
?? * @param obj Object 父对象(类型File)
?? * @return Object[] 子对象列表(类型File[])
?? */
? public Object[] getChilds(Object obj)
? {
??? if (obj instanceof File)
??? {
????? File f = (File) obj;
????? if (f.isFile())
????? {
??????? return new Object[0];
????? }
????? if (filter == null)
????? {
??????? return f.listFiles();
????? }
????? else
????? {
??????? return f.listFiles(filter);
????? }
??? }
??? throw new IllegalArgumentException("Required param type is java.io.File.");
? }

}

?

JSP部分参考

<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="..."%>//未导入包
<%!
static Hashtable images=new Hashtable();
static Hashtable actions=new Hashtable();
static String script;
static {
??? images.put("IMAGE_PLUS", "images/plus.gif");
??? images.put("IMAGE_PLUS_LAST", "images/pluslast.gif");
??? images.put("IMAGE_MINUS", "images/minus.gif");
??? images.put("IMAGE_MINUS_LAST", "images/minuslast.gif");
??? images.put("IMAGE_MIDBLK", "images/midblk.gif");
??? images.put("IMAGE_BLANK", "images/blank.gif");
??? images.put("IMAGE_LASTBLK", "images/lastblk.gif");
??? images.put("IMAGE_LINE", "images/line.gif");
??? images.put("IMAGE_FOLDER", "images/folder.gif");
??? images.put("IMAGES_FOLDER_OPEN","images/folderopen.gif");
??? StringBuffer sc=new StringBuffer("<script type=/"text/javascript/">/r/n");
??? Iterator imgs=images.values().iterator();
??? int k=0;
??? while(imgs.hasNext()){
????? sc.append("var image"+k+"=new Image();/r/n");
????? sc.append("image"+k+".src=/""+(String)imgs.next()+"/";/r/n");
????? k++;
??? }
??? sc.append("</script>/r/n");
??? script=sc.toString();
??? actions.put("CLICK_FOLDER","clickFolder");
??? actions.put("CLICK_DOCUMENT","clickDocument");
??? actions.put("CLICK_FOLDER_IMG","openFolder");
??? actions.put("MOUSEOVER","overMouse");
??? actions.put("MOUSEOUT","outMouse");
}

? void paintChilds(Iterator childs,Writer w) throws IOException{
??? while(childs.hasNext()){
????? paintNode((Node)childs.next(),w);
??? }
? }

? void paintNode(Node n,Writer w) throws IOException{
??? w.write("


























");??? int level=n.getLevel();??? int id=n.getId();??? Node parent=null;??? String name=((File)n.getValue()).getName();??? boolean last=false;??? for(int i=level-1;i>0;i--){????? parent=n.getParent(i);????? last=parent.isLast();????? w.write("
????????????? (String) images.get(last ? "IMAGE_BLANK":"IMAGE_LINE" ) +
????????????? "/" border=/"0/">
");??? }??? last=n.isLast();??? if(n.hasChilds()){????? w.write("
??((String)actions.get("CLICK_FOLDER_IMG")+"(document,"+id+")")+"/">??????????????? (String) images.get(last ? "IMAGE_PLUS_LAST" : "IMAGE_PLUS") +
??????????????? "/" border=/"0/">
");??? }??? else {????? w.write("
????????????? (String) images.get(last ? "IMAGE_MINUS_LAST" : "IMAGE_MINUS") +
????????????? "/" border=/"0/">
");??? }??? w.write("
??????????? (String) images.get("IMAGE_FOLDER") + "/" border=/"0/">
");??? if(n.hasChilds()){????? w.write("
?(String)actions.get("CLICK_FOLDER")+"(document,"+id+"),"+
?(String)actions.get("CLICK_FOLDER_IMG")+"(document,"+id+")"+"/">" +
?name + "
");??? }??? else{????? w.write("
?(String)actions.get("CLICK_FOLDER")+"(document,"+id+")"+"/">" +
?? name + "
");??? }??? w.write(" ");
??? if (n.hasChilds()) {
????? w.write("
");
????? paintChilds(n.getChilds(), w);
????? w.write("
");
??? }
??? w.flush();
? }


%>


<BR>tree<BR>

<%=script%>
<script type="text/javascript">
function changeColor(doc,k){
? var old=doc.thisForm.selectedNode.value;
? if(old!=k){
??? if(old!=""){
????? doc.all("td"+old).style.backgroundColor=doc.thisForm.bgColor.value;
??? }
??? doc.all("td"+k).style.backgroundColor=doc.thisForm.selectedColor.value;
??? doc.thisForm.selectedNode.value=k;
? }
}
function clickDocument(doc,k){
? changeColor(doc,k);
? alert("Click document "+doc.all("td"+k).innerText+".");
}
function openFolder(doc,k){
? var o=doc.all("div"+k);
? if(o.style.display=="none"){
??? o.style.display="block";
? }
? else{
??? o.style.display="none";
? }
? replaceImg(doc,k);
? var k=0;
? while((o=o.parentElement)!=doc&&o!=null){
??? k=o.id.indexOf("div");
??? if(k!=-1){
????? if(o.style.display=="none"){
??????? o.style.display="block";
?replaceImg(doc,o.id.substring(k));
????? }
??? }
? }
}
function clickFolder(doc,k){
? changeColor(doc,k);
? alert("Click folder "+doc.all("td"+k).innerText+".");
}
function replaceImg(doc,k){

}
</script>


<%
out.flush();
File f=new File(this.getServletConfig().getServletContext().getRealPath("/tree")).getParentFile();
Tree t=Tree.getTree(f,new FileContainer());
paintChilds(t.getChilds(),response.getWriter());
%>


?
?
?




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值