在研究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>