树的动态生成和一般的静态书是不一样的。因为动态树中所有的结点或者部分节点不是固定的,可能会随时随着数据库中或者文件中的数据而动态的变动。对于一般的静态树,我们只需要在jsp页面中包含js代码就可以了。那么动态树就需要javabean的支持了。
主要文件
TreeNote.java :树的结点类。
TreeBuilder.java :树的构造器。
ShowTree.java :为了减少页面中的java语句,我们在这里构造生成树需要的html代码。
BuildyourTree.java :在这里构造你的树。你也可以写自己的方法,这里只是个例子。
下面一个一个文件的来看:
TreeNote.java
package cn.edu.ouc.jwc.zysb.tree;
import java.util.*;
import cn.edu.ouc.jwc.util.*;
/**
*
/**
* 节点的Id,生成对象时此Id会被自动生成.
*/
private String Id = null;
/**
* 描述节点在树中的位置.必须准许一定的格式.其格式规则如下:
* 1.根节点值为"root";
* 2.其他节点的值为"root secondLevelparameter thirdLevelParameter ... thisLevelParameter".
* 举例我要添加专业节点其location内容如下: "root yh zhuanye",其中yh为这个专业所属院的parameter,zhuanye为本专业的parameter.
*/
private String location = null;
/**
* 节点名字.要显示在页面上的东东.就是每个节点上显示的名字.
*/
private String name = null;
/**
* 每个节点对应的URL.
*/
private String URL = null;
/**
* 也就是本层的参数,代表本层,将要添加到location的末尾中.
*/
private String parameter = null;
/**
* 容器包装其所有的孩子节点.
*/
private ArrayList children = new ArrayList();
public TreeNote() {
Id = IDGenerator.getID();
}
public TreeNote(int seed) {
Id = IDGenerator.getID(seed);
}
public TreeNote(String name) {
Id = IDGenerator.getID();
this.name = name;
}
public TreeNote(String name, int seed) {
Id = IDGenerator.getID(seed);
this.name = name;
}
public String getId() {
return Id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getURL() {
return URL;
}
public void setURL(String URL) {
this.URL = URL;
}
public void setLocation(String location) {
this.location = location;
}
public String getLocation() {
return location;
}
public ArrayList getChildren() {
return children;
}
public void setChildren(ArrayList children) {
this.children = children;
}
public String getParameter() {
return parameter;
}
public void setParameter(String parameter) {
this.parameter = parameter;
}
/**
* 返回孩子的数目.
*
* @return 孩子的数目,无孩子为"0".
*/
public int getChildNum() {
return children.size();
}
/**
* 增加一个孩子.
*
* @param child TreeNote.
*/
public void addChild(TreeNote child) {
children.add(child);
}
/**
* 根据索引得到一个孩子.
*
* @param index 从"0"开始的索引."0"代表第一个孩子.
* @return TreeNote
*/
public TreeNote getChild(int index) {
return (TreeNote) children.get(index);
}
}
Title: 教务处工程-专业识别
*
*
Description:树的节点对象
*
*
Copyright: Copyright (c) 2004
*
*
Company: 中国海洋大学教务处
*
*
创建日期: 2004.4.17
*
*
修改日期: 2004.4.17
* @author IPlinger
* @version 1.0
*/
public class TreeNote {
注释我应该已经写的很清楚了,自己看吧。其中需要一个IDGenerator.getID()的辅助方法ID产生器,这里我给出这个源码,当然你也可以自己写呀
IDGenerator.java
package cn.edu.ouc.jwc.util;
import java.net.*;
/**
*
/**
* a single static metod which generates a unique id based on hostname and
* time.Id=hostname+time.
*
return Id;
}
/**
* a single static metod which generates a unique id based on hostname and
* time and seed.Id=hostname+time+seed.
*
此方法的引入无非是为了避免上一方法的缺点,但注意传入的seed在生成一系列id时务必是不同的;比如可以传入循环中的"i".
* @param seed
* @return String 一般为主机名+当前时间(毫秒)+seed;如果找不到主机明就为UnknownHost加当前时间+seed;
*/
public static String getID(int seed) {
String Id = null;
try {
Id = InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException ue) {
Id = "UnknownHost";
}
Id = Id + System.currentTimeMillis() + String.valueOf(seed);
return Id;
}
}
注意 如果id连续产生可能会产生相同的Id,务必谨慎!
* @return String 一般为主机名加当前时间(毫秒);如果找不到主机明就为UnknownHost加当前时间;
*/
public static String getID() {
String Id = null;
try {
Id = InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException ue) {
Id = "UnknownHost";
}
Id = Id + System.currentTimeMillis();
名称: 教务处工程-专业识别
*
*
描述: This class has a single static metod which generates a unique id based on hostname and time.
*
*
版权: Copyright (c) 2004
*
*
单位: 中国海洋大学教务处
*
创建日期: 2004.4.8
*
修改日期: 2004.4.8
* @author IPlinger
* @version 1.0
*/
public class IDGenerator {
下面是TreeBuilder类
TreeBuilder.java
package cn.edu.ouc.jwc.zysb.tree;
import java.util.*;
import org.apache.log4j.*;
/**
*
/**
* 给定一个parent节点和一个child节点,判断这个child节点是否属于这个parent.
*
* @param parent parent节点.
* @param child child节点.
* @return true 所给的两个节点父子关系正确.
* false 所给的两个节点不存在指定的父子关系.
*/
private boolean isChild(TreeNote parent, TreeNote child) {
if (parent == null) {
//logger.error("treeNote parent null!!!");
throw new NullPointerException();
}
if (child != null &&
findNoteByParam(parent.getChildren(), child.getParameter()) != null) {
return true;
}
return false;
}
/**
* 在树中找出所给节点的双亲节点.
*
* @param treeNote
* @return TreeNote 如果没有找到返回null.
*/
private TreeNote locateParentNote(TreeNote treeNote) {
String location = treeNote.getLocation();
if (location != null) {
TreeNote locatedNote = root; //当前定位到的节点;初始时为根节点;
StringTokenizer loc = new StringTokenizer(location);
int locNum = loc.countTokens();
if (loc.nextToken().equals("root") && locNum > 1) {
//第一层为"root",最后一层为自己,所以i从0开始,循环locNum-2遍;
for (int i = 0; i < locNum - 2; i++) {
locatedNote = findNoteByParam(locatedNote.getChildren(),
loc.nextToken());
if (locatedNote == null) {
break;
}
}
if (locatedNote != null) {
return locatedNote;
}
}
}
return null;
}
/**
* 向树中添加一个节点.
*
* @param treeNote 待添加节点对象.
* @return ture 添加成功.
* false
* 添加失败.可能是找不到这个节点的parent节点或着这个节点已经存在!
*/
public boolean treeNoteAdd(TreeNote treeNote) {
if (treeNote == null) {
//logger.error("the size of treeNote is null!!!");
throw new NullPointerException();
}
TreeNote parentNote = locateParentNote(treeNote);
if (parentNote != null && !isChild(parentNote, treeNote)) {
parentNote.getChildren().add(treeNote);
return true;
}
//logger.error("treeNote " + treeNote.getName() + "have not parents or is existent! can't be added!!");
return false;
}
/**
* 把以ArrayList容器装载的一系列节点添加到树.
*
* @param treeNoteList 装入一系列TreeNote的ArrayList.
*/
public void ArrayListAdd(ArrayList treeNoteList) {
int noteNum = treeNoteList.size();
if (noteNum == 0) {
//logger.error("the size of treeNoteList is zero!!!");
throw new NullPointerException();
}
for (int i = 0; i < noteNum; i++) {
treeNoteAdd( (TreeNote) treeNoteList.get(i));
}
}
/**
* 从所给的存放TreeNote的容器中找到一个其parameter为所给值的节点.
*
* @param locNote ArrayList.
* @param parameter String.
* @return 如果能找到多个则只返回一个TreeNote,其位置在容器中最靠前.找不到则返回null.
*/
private TreeNote findNoteByParam(ArrayList locNote, String parameter) {
if (parameter == null) {
//logger.error("the parameter is null!!!");
throw new NullPointerException();
}
TreeNote noteTemp = null;
int num = locNote.size();
for (int i = 0; i < num; i++) {
noteTemp = (TreeNote) locNote.get(i);
if (noteTemp.getParameter().equals(parameter)) {
return noteTemp;
}
}
return null;
}
//测试用
public static void main(String[] args) {
TreeBuilder myTree = new TreeBuilder();
TreeNote testson = new TreeNote("son");
testson.setLocation("root test");
testson.setParameter("test");
myTree.root.addChild(testson);
TreeNote test = new TreeNote("son");
test.setLocation("root test");
System.out.println(myTree.isChild(myTree.root, test));
}
}
Title: 教务处工程-专业识别
*
*
Description: 树构建器对象.自动生成root节点.包含构建树用的一切方法.
*
*
Copyright: Copyright (c) 2004
*
*
Company: 中国海洋大学教务处
* @author IPlinger
* @version 1.0 2004.4.17
*/
public class TreeBuilder {
public TreeNote root = new TreeNote("root");
//public static Logger logger = Logger.getLogger(TreeBuilder.class); //生成记录器;
public TreeBuilder() {
root.setLocation("root");
root.setParameter("root");
}
不知道你们主要了吗?添加节点要根据location来添加,它就相当于这里节点的地址,指明它在整棵树的那个位置。location其他解释看TreeNote.java中的注释。
ShowTree.java
package cn.edu.ouc.jwc.zysb.tree;
import java.util.*;
import org.apache.log4j.*;
public class ShowTree {
//public static Logger logger = Logger.getLogger(ShowTree.class);
private TreeNote temp = null;
private StringBuffer buf = new StringBuffer();
/**
* 包装treeHTMLGenerator(ArrayList chiildren)方法
*
* @param children children 开始传入root节点的孩子
* @return String 生成的HTML代码
*/
public String HTMLGenerator(TreeNote root) {
return treeHTMLGenerator(root.getChildren());
}
/**
* 产生树的HTML代码,为递归程序.
*
* @param children 开始传入root节点的孩子
* @return 生成的HTML代码
*/
private String treeHTMLGenerator(ArrayList children) {
buf.append(" <>/n");
int size = children.size();
for (int i = 0; i < size; i++) {
temp = (TreeNote) children.get(i);
if (temp.getChildNum() != 0) { //如果这个节点有孩子..
buf.append(" <>/n");
if (temp.getURL() != null) {
buf.append(
" temp.getId() + "').style){display=display=='none'?'':'none';this.style.backgroundImage=display!='none'?'url(image/e.gif)':'url(image/c.gif)'}/">
temp.getURL() + //通过URL管理器得到URL
"?location=" + temp.getLocation() + "/" target=/"mainFrame/">" +
temp.getName() + " <>/n"); //页面上显示节点的名字
}
else {
buf.append(
" temp.getId() + "').style){display=display=='none'?'':'none';this.style.backgroundImage=display!='none'?'url(image/e.gif)':'url(image/c.gif)'}/">
" +
temp.getName() + " <>/n");
}
buf.append("
<>/n");
buf.append(" <>/n");
buf.append(" "/" style=/"display:none/">/n");
treeHTMLGenerator(temp.getChildren());
buf.append(" <>/n");
buf.append("
<>/n");
}
else { //这个节点没有孩子...
buf.append(" <>/n");
if (temp.getURL() != null) {
buf.append(
" temp.getURL() +
"?location=" + temp.getLocation() + "/" target=/"mainFrame/">" +
temp.getName() + " <>/n");
}
else {
buf.append(" " +
temp.getName() + " <>/n");
}
buf.append("
<>/n");
}
}
buf.append(" /n");
return buf.toString();
}
}
这个类避免了在页面中嵌入过多的java代码,我们用递归来生成树的html代码。所以你要对树的显示效果的修改就要修改这里的代码。当然css用的好的人可以用css解决。不是很方便,可是我也找不到好的方法了:)。也希望大家能多提意见呀。
下面给出要显示树的jsp页面中需要的js和css代码。
function findObj(theObj, theDoc)
{
var p, i, foundObj;
if(!theDoc) theDoc = document;
if( (p = theObj.indexOf("?")) > 0 && parent.frames.length)
{
theDoc = parent.frames[theObj.substring(p+1)].document;
theObj = theObj.substring(0,p);
}
if(!(foundObj = theDoc[theObj]) && theDoc.all) foundObj = theDoc.all[theObj];
for (i=0; !foundObj && i < theDoc.forms.length; i++)
foundObj = theDoc.forms[i][theObj];
for(i=0; !foundObj && theDoc.layers && i < theDoc.layers.length; i++)
foundObj = findObj(theObj,theDoc.layers[i].document);
if(!foundObj && document.getElementById) foundObj = document.getElementById(theObj);
return foundObj;
}
.folder { BACKGROUND-POSITION: left 50%; PADDING-LEFT: 20px; FONT-SIZE: 12px; BACKGROUND-IMAGE: url(image/e.gif); CURSOR: hand; BACKGROUND-REPEAT: no-repeat; FONT-FAMILY: "Verdana", "Arial", "Helvetica", "sans-serif" } .collapsedFolder { BACKGROUND-POSITION: left 50%; PADDING-LEFT: 20px; FONT-SIZE: 12px; BACKGROUND-IMAGE: url(image/c.gif); CURSOR: hand; BACKGROUND-REPEAT: no-repeat; FONT-FAMILY: "Verdana", "Arial", "Helvetica", "sans-serif" } .submenu { PADDING-LEFT: 18px } .iefile { BACKGROUND-POSITION: left 50%; PADDING-LEFT: 20px; FONT-SIZE: 12px; BACKGROUND-IMAGE: url(image/f.gif); BACKGROUND-REPEAT: no-repeat; FONT-FAMILY: "Verdana", "Arial", "Helvetica", "sans-serif" }
这些css你都需要根据你的需求来订制。也可以自己加入新的。
下面我们用BuildYourTree.java这个类,来建造我们的树。
BuildYourTree.java
package cn.edu.ouc.jwc.zysb.tree;
import cn.edu.ouc.jwc.zysb.data.*;
/**
*
/**
* 建造你自己的树.用于教学计划的维护.
*
* @return 你所建造树的根节点.
*/
public TreeNote buildMaintaiTree() {
YearPlanData yearplan = new YearPlanData(); //加入第一层"计划学年".
myTree.ArrayListAdd(yearplan.buildTreeNotes());
InstituteData institute = new InstituteData(); //第二层"学院".
myTree.ArrayListAdd(institute.buildTreeNotes());
SpecialityData speciality = new SpecialityData(); //第三层"专业".
myTree.ArrayListAdd(speciality.buildTreeNotes("Speciality.jsp"));
LevelData level = new LevelData(); //第四层"层次".
myTree.ArrayListAdd(level.buildTreeNotes("Level.jsp"));
return myTree.root;
}
/**
* 建造你自己的树.用于教学计划的察看.
*
* @return 你所建造树的根节点.
*/
public TreeNote buildViewTree() {
YearPlanData yearplan = new YearPlanData(); //加入第一层"计划学年".
myTree.ArrayListAdd(yearplan.buildTreeNotes());
InstituteData institute = new InstituteData(); //第二层"学院".
myTree.ArrayListAdd(institute.buildTreeNotes());
SpecialityData speciality = new SpecialityData(); //第三层"专业".
myTree.ArrayListAdd(speciality.buildTreeNotes("SpecialityView.jsp"));
LevelData level = new LevelData(); //第四层"层次".
myTree.ArrayListAdd(level.buildTreeNotes("LevelView.jsp"));
return myTree.root;
}
}
Title: 教务处工程-专业识别
*
*
Description: 在这里用TreeBuilder对象建造你自己的树
*
*
Copyright: Copyright (c) 2004
*
*
Company:
* @author IPlinger
* @version 1.0
*/
public class BuildYourTree {
TreeBuilder myTree = new TreeBuilder();
这里只是我的实现,我用两个方法生成了我需要的两棵树。这里可以写你自己的方法。我们在构造树的时候是一层一层的往树中添加的。而每层中的节点的位置时根据每个节点location 这个参数决定的。关于buildTreeNotes()方法,你们可以有自己的实现。下面给出我的一个实现。我的这些节点信息是在数据库中得到的。
/**
* 先调用getAllSpecialityData()得到含所有专业对象的容器,再把所有Speciality对象转换成
* TreeNote对象,并装入ArrayList容器
*
* @return 生成的TreeNote容器,如果没有则返回空容器。
*/
public ArrayList buildTreeNotes(String noteURL) {
ArrayList allSpecialityData = getAllSpecialityData();
ArrayList result = new ArrayList();
for (int i = 0, n = allSpecialityData.size(); i < n; i++) {
Speciality temp = (Speciality) allSpecialityData.get(i);
TreeNote note = new TreeNote(temp.getSpecialityName(), i);
note.setURL(URLManager.makeDocumentURL(noteURL)); //加入连接
note.setParameter(temp.getSpecialityId()); //加入本节点的属性
note.setLocation("root " + temp.getYearPlan() + " " + temp.getInstituteId() + " " +
temp.getSpecialityId()); //节点位置
result.add(note); //加入容器
}
return result;
}
/**
* 从数据库中得到所有的专业信息.
*
* @return ArrayList 包含所有Speciality对象的容器,如果没有返回空容器;
*/
public ArrayList getAllSpecialityData() {...}