项目有个需求需要写个类似 windows资源管理器的树结构。
一开始想偷懒到网上随便找段代码,可是找下来看了半天还没看懂。要是去一行一行的读源码去理解的话,就违背了偷懒的初衷,而且估计都满足不了需求~~于是DIY一个。
需求:
1)减轻数据库压力,访问一次数据库(只执行一条select * from 表名)便要读出所有树结构;
2)排序,目录要优先于结点显示在树形结构中,同级同种结点排序按填入的排序号大小来排序
3)有个界面可以随时增加、编辑、删除树的结点或目录。
于是花了一天时间把这个搞定了~~自我感觉还比较满意,因此把关键的代码贴上来共享下,有兴趣有经验的朋友请多教。
效果如下:
环境:webwork/spring/hibernate/extjs-json-tree
数据库表:
mid number Not null 目录id,编号,唯一
mname varchar2(30) Not null 目录名
pid number Not null 父目录id,顶级目录默认为0
pname String(30) 父目录名称
mtype char 是目录还是结点,'dir' or 'rpt'
leveidx number 同级目录中的排列顺序
state String(10) (一个业务字段,无关紧要)
reptid String(30) (一个业务字段,无关紧要)
bz String(100) (一个业务字段,无关紧要)
HibernateSynchronizer生成hbm.xml、DAO、pojo
web.xml中增加spring监听器将DAO自动注入至webwork的action
“界面可以随时增加、编辑、删除树的结点或目录”。就是一个普通的crud操作,地球人都会写,代码忽略。
EXTJS呈现,代码很短,就是请求一个action,返回一串json并解析该JSON为一棵树,不是关键,可以忽略。也将代码贴出来吧,AJAX请求的地址是sysrMenutreeAction!gettree.action
Ext.onReady(function(){
var loader = new Ext.tree.TreeLoader({url:"sysrMenutreeAction!gettree.action"});
loader.processResponse = function(response, node, callback){
var json = response.responseText;
try{
var json = eval("(" + json + ")");
node.beginUpdate();
var o = json["key"];
for(var i=0, len=o.length; i<len; i++){
var n = this.createNode(o[i]);
if(n){
node.appendChild(n);
}
}
node.endUpdate();
if(typeof callback == "function"){
callback(this,node);
}
}catch(e){
this.handleFailure(response);
}
}
var tree = new Ext.tree.TreePanel({
el : 'tree',
loader : loader,
border :false
});
var root = new Ext.tree.AsyncTreeNode({
id : '1',
text : "根结点"
});
tree.setRootNode(root);
tree.on("click", function(node){
top.mainFrame.location = "sysrMenutreeAction!getnode.action?node=" + node.id; //在主frame中显示结点的具体信息
});
tree.render();
});
上面请求的sysrMenutreeAction!gettree.action,在对应的action中对应的gettree()方法如下:
public String gettree() {
List<SysrMenutree> list = sysrMenutreeDAO.getSession()
.createQuery("from SysrMenutree ").list(); //执行查询,取得所有记录
Map<Integer, SysrMenutree> map = new HashMap<Integer, SysrMenutree>();
SysrMenutree root = null; //根结点
for (SysrMenutree treeNode : list) { //第一次循环,将结果集放到一个"Map键-值对"结构中,方便取出指定元素
map.put(treeNode.getId(), treeNode);
if(treeNode.getPid() == 0){
root = treeNode;
}
}
/*
第二次循环所有结点,将每个结点的子结点存入一个TreeSet中。
使用TreeSet比较关键,我的排序的代码全写在这个TreeSet的Comparator中,见下文
*/
for(SysrMenutree treeNode : list){
if(treeNode.getPid() != 0){
map.get(treeNode.getPid()).addChild(treeNode);
}
}
System.out.println(root.toJsonString());
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("application/x-json;charset=utf-8");
try {
PrintWriter out = response.getWriter();
if(root != null){
out.write("{key:[" + root.toJsonString() + "]}"); //向客户端写json。递归方法toJsonString()
}
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
return NONE;
}
关键的代码在pojo对象SysrMenutree中。如下:
public class SysrMenutree implements Comparable<SysrMenutree> {
//实现了Comparable接口
/*
........
省略pojo属性以及对应的getter/setter
*/
private Set<SysrMenutree> children = new TreeSet<SysrMenutree>(
new Comparator<SysrMenutree>() { //匿名内部类实现Comparator接口
public int compare(SysrMenutree o1, SysrMenutree o2) {
return -o1.compareTo(o2);
}
});
public void addChild(SysrMenutree node) {
children.add(node);
}
public String toJsonString() {
StringBuffer buf = new StringBuffer();
buf.append("{ id : " + getId() + ", text : '" + this.getMname()
+ "', ");
if (children.size() > 0) {
buf.append("children : [");
for (SysrMenutree node : children) {
buf.append(node.toJsonString() + ","); //对子结点递归
}
buf.deleteCharAt(buf.length() - 1);
buf.append("]}");
} else {
/*
如果不定义leaf=true,EXTJS就认为那是一个目录并以文件夹的图标显示。
但是如果没子结点,则会进入一个死循环。
因此在这里做特殊处理:
如果没有子结点,就设置leaf为true,但对数据库中标识为"dir"目录的结点,就指定显示图标为文件夹。
*/
if (this.getMtype().equals("dir")) {
buf.append("icon : 'folder.gif', ");
}
buf.append("leaf : true }");
}
return buf.toString();
}
public int compareTo(SysrMenutree o) { //Comparable接口具体实现
if (getMtype().equals(o.getMtype())) {
return this.getLeveidx() > o.getLeveidx() ? 1
: (this.getLeveidx() == o.getLeveidx() ? 0 : -1);
} else if (getMtype().equals("dir")) {
return 1;
} else {
return -1;
}
}
}

- 大小: 100.3 KB
分享到:
- 2009-07-08 15:35
- 浏览 4113
- 评论(8)
- 论坛回复 / 浏览 (8 / 7080)
- 查看更多
相关推荐
- 命名空间是Extjs中组织代码的一种方式,用于避免全局变量冲突。 - 使用`Ext.namespace`方法来定义命名空间。 - **Extjs OOP** - Extjs提供了一套面向对象的编程模型,支持类的继承、封装等特性。 - 通过`Ext....
- **触发器**:当某些特定事件(如INSERT、UPDATE、DELETE)发生时自动执行的一段代码。 - **存储过程**:预编译的SQL语句集合,可以接受输入参数,返回输出参数,增强SQL功能和灵活性。 - **事务管理**:确保数据...
在图书管理系统中,ExtJs可能被用来创建用户友好的、功能丰富的Web界面,包括表格、树形结构、分页、搜索等功能,提供良好的用户体验。 3. Ms-SQL:Microsoft SQL Server是一个关系型数据库管理系统,广泛应用于...
ExtAspNet - ExtJS based ASP.NET Controls with Full AJAX Support ExtAspNet是一组专业的Asp.net控件库,拥有原生的AJAX支持和丰富的UI效果, 目标是创建没有ViewState,没有JavaScript,没有CSS,没有...
--我们做了优化,现在要使一个Asp.net的按钮能够AJAX提交,你不需要做任何设置(PageManager的属性EnableAjax为true即可,这是默认属性)。 +PageManager的实例方法AddAjaxUpdateControl改名为...