?在研究ExtJS Tree动态构建时,按照ExtJS推进的方法是通过TreeLoader加载数据,加载的数据的格式是JSON。在ExtJS的例子check-tree.html中,直接利用后端的check-nodes.json来构建,但是在实际的工程中,有很多是根据不确定的数据内容来构建Tree的。
??? 在Java开发的Web中利用Struts实现后端的servlet,可以提供相应的json格式,实现ExtJS Tree的动态构建。在网上搜索相应的技术文章是,发现利用jsp作为中间转换的例子,url:http://www.blogjava.net/usherlight/archive/2008/02/19/180590.html,觉得不是很理想,在struts2中引入了plugin的机制,有现成的struts-json-plugin包,如何利用action直接通过Ext.Tree.TreeLoader直接加载Tree的数据,在上述文章中,指出:
?"最近尝试用extjs来展示树状菜单。着实花了一番功夫。树状菜单的菜单项需要动态加载,而目前版本的extjs中只支持JSON格式的数据。查了一些资料,决定使用struts2的json-plugin。首先按照例子做了一个,但是结果就是不成功,界面上只出来了一个js中生成的root节点,不能加载从后台生成的数据。研究后发现是数据格式有问题。使用json-plugin生成的数据格式如下:
{"cls":"folder","id":10,"leaf":false,"children":[{"cls":"file","id":11,"leaf":true,"children":null,"text":"S600"},{"cls":"file","id":12,"leaf":true,"children":null,"text":"SLK200"}],"text":"Benz"}
而extjs需要的数据格式如下:
[{"cls":"folder","id":10,"leaf":false,"children":[{"cls":"file","id":11,"leaf":true,"children":null,"text":"S600"},{"cls":"file","id":12,"leaf":true,"children":null,"text":"SLK200"}],"text":"Benz"}]
区别很小,就只相差最外面的两个方括号。但是少了这两个方括号,在json中,含义迥然不同,前者表示一个对象,而后者表示一个数组。而extjs中 tree的dataloader需要的数据必须是一个数组。而这样的数据格式是json-plugin自动生成的,无法改变。所以,我最后放弃了json -plugin,转而使用json-lib来解决这个问题。"
在struts-json-plugin中返回的数据的确有这个问题,经过仔细分析,在struts-json-plugin的配置中是可以解决这个问题的,通过wrapPrefix和wrapSuffix设置,可以解决上面的问题,struts config文件中的设置如下:
- <package?name="test"?extends="json-default"?>??
- ????????????<action?name="menu"?class="com.struts2.action.Menu">??
- ????????<result?name="success"?type="json">??
- ????????????<param?name="excludeNullProperties">true</param>??
- ????????????<param?name="noCache">true</param>??
- ????????????<param?name="wrapPrefix">[</param>??
- ????????????<param?name="wrapSuffix">]</param>??
- ????????</result>??
- ????</action>??
- </package>??
<package name="test" extends="json-default" > <action name="menu" class="com.struts2.action.Menu"> <result name="success" type="json"> <param name="excludeNullProperties">true</param> <param name="noCache">true</param> <param name="wrapPrefix">[</param> <param name="wrapSuffix">]</param> </result> </action> </package>
?action的实现类Menu的代码如下:
- package?com.struts2.action; ??
- ??
- import?java.util.ArrayList; ??
- import?java.util.List; ??
- ??
- public?class?Menu?{ ??
- ????private?int?id; ??
- ????private?String?text; ??
- ????private?boolean?leaf; ??
- ????private?String?cls; ??
- ????private?List<Menu>?children; ??
- ??
- ????public?String?execute()?throws?Exception?{ ??
- ????????//?TODO?Auto-generated?method?stub ??
- ????????this.id?=1; ??
- ????????this.text="text"; ??
- ????????this.leaf=false; ??
- ????????this.cls?="cls"; ??
- ????????this.children?=?new?ArrayList<Menu>(); ??
- ????????Menu?benz?=?new?Menu(); ??
- ????????benz.setText("Benz"); ??
- ????????benz.setCls("folder"); ??
- ????????benz.setLeaf(true); ??
- ????????benz.setId(10); ??
- ??
- ????????this.children.add(benz); ??
- ??
- ????????return?"success"; ??
- ????} ??
- ????public?int?getId()?{ ??
- ????????return?id; ??
- ????} ??
- ????public?void?setId(int?id)?{ ??
- ????????this.id?=?id; ??
- ????} ??
- ????public?String?getText()?{ ??
- ????????return?text; ??
- ????} ??
- ????public?void?setText(String?text)?{ ??
- ????????this.text?=?text; ??
- ????} ??
- ????public?boolean?isLeaf()?{ ??
- ????????return?leaf; ??
- ????} ??
- ????public?void?setLeaf(boolean?leaf)?{ ??
- ????????this.leaf?=?leaf; ??
- ????} ??
- ????public?String?getCls()?{ ??
- ????????return?cls; ??
- ????} ??
- ????public?void?setCls(String?cls)?{ ??
- ????????this.cls?=?cls; ??
- ????} ??
- ????public?List<Menu>?getChildren()?{ ??
- ????????return?children; ??
- ????} ??
- ????public?void?setChildren(List<Menu>?children)?{ ??
- ????????this.children?=?children; ??
- ????} ??
- }??
package com.struts2.action; import java.util.ArrayList; import java.util.List; public class Menu { private int id; private String text; private boolean leaf; private String cls; private List<Menu> children; public String execute() throws Exception { // TODO Auto-generated method stub this.id =1; this.text="text"; this.leaf=false; this.cls ="cls"; this.children = new ArrayList<Menu>(); Menu benz = new Menu(); benz.setText("Benz"); benz.setCls("folder"); benz.setLeaf(true); benz.setId(10); this.children.add(benz); return "success"; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getText() { return text; } public void setText(String text) { this.text = text; } public boolean isLeaf() { return leaf; } public void setLeaf(boolean leaf) { this.leaf = leaf; } public String getCls() { return cls; } public void setCls(String cls) { this.cls = cls; } public List<Menu> getChildren() { return children; } public void setChildren(List<Menu> children) { this.children = children; } }
?
利用ExtJS自带的例子check-tree.js,把原来的dataUrl修改为自己实现的struts的Url:
- /*! ?
- ?*?Ext?JS?Library?3.2.0 ?
- ?*?Copyright(c)?2006-2010?Ext?JS,?Inc. ?
- ?*?licensing@extjs.com ?
- ?*?http://www.extjs.com/license ?
- ?*/??
- ??
- Ext.onReady(function(){ ??
- ????var?tree?=?new?Ext.tree.TreePanel({ ??
- ????????renderTo:'tree-div', ??
- ????????title:?'My?Task?List', ??
- ????????height:?300, ??
- ????????width:?400, ??
- ????????useArrows:true, ??
- ????????autoScroll:true, ??
- ????????animate:true, ??
- ????????enableDD:true, ??
- ????????containerScroll:?true, ??
- ????????rootVisible:?false, ??
- ????????frame:?true, ??
- ????????root:?{ ??
- ????????????nodeType:?'async'??
- ????????}, ??
- ??
- ????????//?auto?create?TreeLoader ??
- ????????dataUrl:?'http://localhost:8080/Stock3th/menu.action', ??
- ??
- ????????listeners:?{ ??
- ????????????'checkchange':?function(node,?checked){ ??
- ????????????????if(checked){ ??
- ????????????????????node.getUI().addClass('complete'); ??
- ????????????????}else{ ??
- ????????????????????node.getUI().removeClass('complete'); ??
- ????????????????} ??
- ????????????} ??
- ????????}, ??
- ??
- ????????buttons:?[{ ??
- ????????????text:?'Get?Completed?Tasks', ??
- ????????????handler:?function(){ ??
- ????????????????var?msg?=?'',?selNodes?=?tree.getChecked(); ??
- ????????????????Ext.each(selNodes,?function(node){ ??
- ????????????????????if(msg.length?>?0){ ??
- ????????????????????????msg?+=?',?'; ??
- ????????????????????} ??
- ????????????????????msg?+=?node.text; ??
- ????????????????}); ??
- ????????????????Ext.Msg.show({ ??
- ????????????????????title:?'Completed?Tasks', ??
- ????????????????????msg:?msg.length?>?0???msg?:?'None', ??
- ????????????????????icon:?Ext.Msg.INFO, ??
- ????????????????????minWidth:?200, ??
- ????????????????????buttons:?Ext.Msg.OK ??
- ????????????????}); ??
- ????????????} ??
- ????????}] ??
- ????}); ??
- ??
- ????tree.getRootNode().expand(true); ??
- });??
/*! * Ext JS Library 3.2.0 * Copyright(c) 2006-2010 Ext JS, Inc. * licensing@extjs.com * http://www.extjs.com/license */ Ext.onReady(function(){ var tree = new Ext.tree.TreePanel({ renderTo:'tree-div', title: 'My Task List', height: 300, width: 400, useArrows:true, autoScroll:true, animate:true, enableDD:true, containerScroll: true, rootVisible: false, frame: true, root: { nodeType: 'async' }, // auto create TreeLoader dataUrl: 'http://localhost:8080/Stock3th/menu.action', listeners: { 'checkchange': function(node, checked){ if(checked){ node.getUI().addClass('complete'); }else{ node.getUI().removeClass('complete'); } } }, buttons: [{ text: 'Get Completed Tasks', handler: function(){ var msg = '', selNodes = tree.getChecked(); Ext.each(selNodes, function(node){ if(msg.length > 0){ msg += ', '; } msg += node.text; }); Ext.Msg.show({ title: 'Completed Tasks', msg: msg.length > 0 ? msg : 'None', icon: Ext.Msg.INFO, minWidth: 200, buttons: Ext.Msg.OK }); } }] }); tree.getRootNode().expand(true); });
?则可以生成所需要的Tree了。我用的各种资源的版本为:ExtJS3.2.0,Struts2.2.1,所需要的支持jar配置文件pom.xml如下:
- <?xml?version="1.0"?encoding="UTF-8"?>??
- ????<!-- ??
- ????????/*?*?$Id:?pom.xml?821140?2009-10-02?19:46:07Z?wesw?$?*?*?Licensed?to ??
- ????????the?Apache?Software?Foundation?(ASF)?under?one?*?or?more?contributor ??
- ????????license?agreements.?See?the?NOTICE?file?*?distributed?with?this?work ??
- ????????for?additional?information?*?regarding?copyright?ownership.?The?ASF ??
- ????????licenses?this?file?*?to?you?under?the?Apache?License,?Version?2.0?(the ??
- ????????*?"License");?you?may?not?use?this?file?except?in?compliance?*?with ??
- ????????the?License.?You?may?obtain?a?copy?of?the?License?at?*?* ??
- ????????http://www.apache.org/licenses/LICENSE-2.0?*?*?Unless?required?by ??
- ????????applicable?law?or?agreed?to?in?writing,?*?software?distributed?under ??
- ????????the?License?is?distributed?on?an?*?"AS?IS"?BASIS,?WITHOUT?WARRANTIES ??
- ????????OR?CONDITIONS?OF?ANY?*?KIND,?either?express?or?implied.?See?the ??
- ????????License?for?the?*?specific?language?governing?permissions?and ??
- ????????limitations?*?under?the?License.?*/ ??
- ????-->??
- <project?xmlns="http://maven.apache.org/POM/4.0.0"?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"??
- ????xsi:schemaLocation="http://maven.apache.org/POM/4.0.0?http://maven.apache.org/maven-v4_0_0.xsd">??
- ????<modelVersion>4.0.0</modelVersion>??
- ??
- ????<artifactId>org.tkxing.stock</artifactId>??
- ????<groupId>stock3th</groupId>??
- ????<version>3.0</version>??
- ??
- ????<properties>??
- ????????<struts2-version>2.2.1</struts2-version>??
- ????</properties>??
- ??
- ????<dependencies>??
- ????????<dependency>??
- ????????????<groupId>org.apache.struts</groupId>??
- ????????????<artifactId>struts2-core</artifactId>??
- ????????????<version>2.2.1</version>??
- ????????</dependency>??
- ????????<dependency>??
- ????????????<groupId>org.apache.struts</groupId>??
- ????????????<artifactId>struts2-json-plugin</artifactId>??
- ????????????<version>2.2.1</version>??
- ????????</dependency>??
- ????????<dependency>??
- ????????????<groupId>commons-logging</groupId>??
- ????????????<artifactId>commons-logging</artifactId>??
- ????????????<version>1.1.1</version>??
- ????????</dependency>??
- ????????<dependency>??
- ????????????<groupId>org.apache</groupId>??
- ????????????<artifactId>log4j</artifactId>??
- ????????????<version>2.1.8</version>??
- ????????</dependency>??
- ????????<dependency>??
- ????????????<groupId>javassist</groupId>??
- ????????????<artifactId>javassist</artifactId>??
- ????????????<version>3.9.0.GA</version>??
- ????????</dependency>??
- ??
- ????????<dependency>??
- ????????????<groupId>commons-lang</groupId>??
- ????????????<artifactId>commons-lang</artifactId>??
- ????????????<version>2.4</version>??
- ????????</dependency>??
- ??
- ????????<dependency>??
- ????????????<groupId>commons-collections</groupId>??
- ????????????<artifactId>commons-collections</artifactId>??
- ????????????<version>3.2.1</version>??
- ????????</dependency>??
- ??
- ????????<dependency>??
- ????????????<groupId>commons-beanutils</groupId>??
- ????????????<artifactId>commons-beanutils</artifactId>??
- ????????????<version>1.7.0</version>??
- ????????</dependency>??
- ??
- ????????<dependency>??
- ????????????<groupId>net.sf.ezmorph</groupId>??
- ????????????<artifactId>ezmorph</artifactId>??
- ????????????<version>1.0.6</version>??
- ????????</dependency>??
- ??
- ????</dependencies>??
- </project>??
String jsonStr="{" +
"'text': 'To Do'," +
"'cls': 'folder'," +
"'expanded': true," +
"'children': [" +
"{" +
"'text': 'Go jogging'," +
"'leaf': true," +
"'checked': true" +
" }," +
"{" +
"'text': 'Take a nap'," +
"'leaf': true," +
"'checked': false" +
"}," +
" {" +
"'text': 'Climb Everest'," +
"'leaf': true," +
"'checked': false" +
"}" +
"]" +
"}" ;
返回的: ["{'text': 'To Do','cls': 'folder','expanded': true,'children': [{'text': 'Go jogging','leaf': true,'checked': true },{'text': 'Take a nap','leaf': true,'checked': false}, {'text': 'Climb Everest','leaf': true,'checked': false}]}"] 怎么去掉双引号 …… 谢谢!