出家如初,成佛有余

Struts2 Tree标签的使用

Posted in Uncategorized by chuanliang on 2008/04/01

  在项目中有很多地方使用了树形结构,主要有几个地方:素材和软件等软件资源表,人员权限的权限资源表、人员权限的角色,套餐及产品包,现以类别表为例,说明树形结构的数据库存储、利用Struts2 中dojo的Tree标签来完成前端展现。

1、 数据库结构

CREATE TABLE `oss_category` (
  `category_id` int(11) NOT NULL auto_increment,
  `parent_id` int(11) default '-1',
  `level` smallint(6) default NULL ,
  `is_leaf` tinyint(1) default NULL,
  `category_title` varchar(100) default NULL,
  `category_name` varchar(100) default NULL,
  `category_code` varchar(100) default NULL,
  `category_type` varchar(30) default NULL,
  `image` varchar(255) default NULL,
  `status` varchar(20) default NULL,
  `creator` varchar(50) default NULL,
  `create_date` datetime default NULL,
  `modify_user` varchar(50) default NULL,
  `modify_date` datetime default NULL,
  `description` text,
  PRIMARY KEY  (`category_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=gbk;

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

测试数据:

INSERT INTO `oss_category` VALUES ('1', '-1', '1', '0', 'root', 'root', 'root', 'product_type', null, '1', null, null, null, null, null);
INSERT INTO `oss_category` VALUES ('2', '1', '2', '0', '<input type='checkbox' name='product_type1'  id='product_type1'  /><b>product_type1</b>', 'product_type1', 'product_type1', 'product_type', null, '1', null, null, null, null, null);
INSERT INTO `oss_category` VALUES ('3', '1', '2', '0', '<input type='checkbox' name='product_type2' id='product_type2'  class='treeCheckBox'/><b>product_typ', 'product_type2', 'product_type2', 'product_type', null, '1', null, null, null, null, null);
INSERT INTO `oss_category` VALUES ('4', '3', '3', '0', '<input type='checkbox' name='product_type21'  id='product_type21'  /><b>product_type21</b>', 'product_type21', 'product_type21', 'product_type', null, '1', null, null, null, null, null);
INSERT INTO `oss_category` VALUES ('5', '2', '3', '0', '<input type='checkbox' name='product_type11'  id='product_type11'  /><b>product_type11</b>', 'product_type11', 'product_type11', 'product_type', null, '1', null, null, null, null, null);
INSERT INTO `oss_category` VALUES ('6', '5', '4', '1', '<input type='checkbox' name='product_type111'  id='product_type111'  /><b>product_type111</b>', 'product_type111', 'product_type111', 'product_type', null, '1', null, null, null, null, null);
INSERT INTO `oss_category` VALUES ('7', '3', '2', '0', '<input type='checkbox' name='product_type22'  id='product_type22'  /><b>product_type22</b>', 'product_type22', 'product_type22', 'product_type', null, '1', null, null, null, null, null);
INSERT INTO `oss_category` VALUES ('8', '2', '3', '0', '<input type='checkbox' name='product_type12'  id='product_type12'  /><b>product_type12</b>', 'product_type12', 'product_type12', 'product_type', null, '1', null, null, null, null, null);
INSERT INTO `oss_category` VALUES ('9', '4', '4', '1', '<input type='checkbox' name='product_type211'  id='product_type211'  /><b>product_type211</b>', 'product_type211', 'product_type211', 'product_type', null, '1', null, null, null, null, null);
INSERT INTO `oss_category` VALUES ('10', '7', '4', '1', '<input type='checkbox' name='product_type221'  id='product_type221'  /><b>product_type221</b>', 'product_type221', 'product_type221', 'product_type', null, '1', null, null, null, null, null);

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

注意:

  • 为了支持在树形结构的节点前有checkbox框,需要在树形结构的title(对应s:tree中的nodeTitleProperty)前增加checkbox树形,因此在数据库中category_title字段的格式采用如上的形式,例如:

<input type=’checkbox’ name=’product_type1′  id=’product_type1′  /><b>product_type1</b>

  • 对于有序的树形结构,为了标识left和right,可以增加ordering字段,或者采用类似嵌套树的结构,例如
CREATE TABLE nested_category (
 category_id INT AUTO_INCREMENT PRIMARY KEY,
 name VARCHAR(20) NOT NULL,
 lft INT NOT NULL,
 rgt INT NOT NULL
);
但采用嵌套树的方式,在变动一个节点时候需要对相关的节点进行更新,不是很适合。但效率较高。可以参看:
http://dev.mysql.com/tech-resources/articles/hierarchical-data.html
http://www.sitepoint.com/print/hierarchical-data-database
  • mysql对树形结构没有原生的支持,Oracle和DB2可以支持,Oracle通过CONNECT BY,DB2通过With方式。

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

2、Model层

OssCategory.java

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

直接用myeclipse生成后,增加了如下内容:

    private OssCategory[] childCategories;
    private OssCategory parentCategory;

    public OssCategory[] getChildCategories() {
        return childCategories;
    }

    public void setChildCategories(OssCategory[] childCategories) {
        this.childCategories = childCategories;
    }

    public OssCategory getParentCategory() {
        return parentCategory;
    }

    public void setParentCategory(OssCategory parentCategory) {
        this.parentCategory = parentCategory;
    }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

3、DAO层

OssCategoryDAO.java

直接用myeclipse生成,没有调优,增加如下内容:

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

    public OssCategory[] getAllCategory() {
        ArrayList<OssCategory> resultList=new ArrayList<OssCategory>();
        String queryString="from OssCategory as category where category.parentId=1";
        List<OssCategory> queryList =getHibernateTemplate().find(queryString);
        Iterator iterator=queryList.iterator();
        while(iterator.hasNext()){
            OssCategory ossCategory=(OssCategory)iterator.next();
            OssCategory[] childrenArray=getChildCategoriesById(ossCategory.getCategoryId());
            logger.debug("getAllCategory() - OssCategory[] childrenList=" + childrenArray.length);
            ossCategory.setChildCategories(childrenArray);
            resultList.add(ossCategory);

        }

        OssCategory[] resultArray=(OssCategory[])resultList.toArray(new OssCategory[resultList.size()]);
        return resultArray;

    }

    public OssCategory[] getChildCategoriesById(int categoryId) {
        String queryString="from OssCategory as category where category.parentId="+categoryId;
        List<OssCategory> queryList =getHibernateTemplate().find(queryString);
        logger.debug("getChildCategoriesById(int) - List<OssCategory> queryList=" + queryList.size());
        ArrayList<OssCategory> resultList=new ArrayList<OssCategory>();
        Iterator iterator=queryList.iterator();
        while(iterator.hasNext()){
            OssCategory ossCategory=(OssCategory)iterator.next();
            OssCategory[] childrenList=getChildCategoriesById(ossCategory.getCategoryId());
            logger.debug("getChildCategoriesById(int) - OssCategory[] childrenList=" + childrenList+"parentid is "+categoryId); //$NON-NLS-1$
            ossCategory.setChildCategories(childrenList);
            resultList.add(ossCategory);

        }
        OssCategory[] resultArray=(OssCategory[])resultList.toArray(new OssCategory[resultList.size()]);
        return resultArray;
    }
注意:
  •  getAllCategory和getChildCategoriesById采用了递归调用方式,应该可以一次性取出指定节点的所有子节点到结果集合List,然后对List在内存中进行遍历,但比较麻烦,先采用此种方式。
  •  struts2的tree应该支持List,而不一定要采用数组方式,只不过没有测试
 

4、Service层

TreeService.java

有些方法尚未实现

package com.mobilesoft.framework.tree.service;

import java.util.List;
import java.util.Set;

import com.mobilesoft.framework.tree.model.OssCategory;

public interface TreeService {


    /**
     * @return 获取下级子节点
     */
  //  public Set getChildren(int rootId);

    /**
     * @return 递归指定级别的所有子节点
     *      
     */
  //  public Set getChildrenByLevel(int rootId,int level);


    /**
     * @return 获取指定类型的所有子节点
     * @param type:节点的类型
     * @param levle:节点相对于所属类型的节点的级别 -1表示获取所属类型的根节点的所有级别的子节点
     */
 //   public Set getChildrenByType( String type,int level);

    /**
     * @return 获取指定根节点的所有子节点
     */
    public OssCategory[]  getAllCategory();

}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

TreeServiceImpl.java

 

package com.mobilesoft.framework.tree.service.impl;

import java.util.List;
import java.util.Set;

import com.mobilesoft.framework.tree.dao.hibernate.OssCategoryDAO;
import com.mobilesoft.framework.tree.model.OssCategory;
import com.mobilesoft.framework.tree.service.TreeService;

public class TreeServiceImpl implements TreeService {
    OssCategoryDAO ossCategoryDAO;
    public Set getChildren(int rootId) {
        // TODO Auto-generated method stub
        return null;
    }

    public Set getLevelChildren(int rootId, int level) {
        // TODO Auto-generated method stub
        return null;
    }

    public OssCategory[]   getAllCategory(){
        return ossCategoryDAO.getAllCategory();
    }
    public OssCategoryDAO getOssCategoryDAO() {
        return ossCategoryDAO;
    }

    public void setOssCategoryDAO(OssCategoryDAO ossCategoryDAO) {
        this.ossCategoryDAO = ossCategoryDAO;
    }

}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

5、Action层

package com.mobilesoft.esales.webapp.action;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;

import com.mobilesoft.framework.tree.model.FileWrapper;
import com.mobilesoft.framework.tree.model.OssCategory;
import com.mobilesoft.framework.tree.service.TreeService;

public class TreeAction extends BaseAction {
    /**
     * Logger for this class
     */
    private static final Logger logger = Logger.getLogger(TreeAction.class);

    private OssCategory root;
    private TreeService treeService;
    private FileWrapper fileroot;

    public String execute() {
        root = new OssCategory();
        root.setCategoryId(new Integer(1));
        root.setParentId(-1);
        root.setCategoryTitle("Root");
        root.setCategoryName("Root");
        OssCategory[] childCategories = treeService.getAllCategory();

        root.setChildCategories(childCategories);
        visitTree(childCategories);
        getRequest().setAttribute("root", root);
        // fileroot = new FileWrapper(getSession().getServletContext().getRealPath("/"));
        return SUCCESS;
    }

    public String treeWithCheckbox() {
        Map map = getRequest().getParameterMap();
        logger.fatal("the tree map");
        Set set = map.entrySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();

            logger.fatal("the tree key is: " + entry.getKey() + " ,and value is: "
                    + entry.getValue());
        }

        return SUCCESS;
    }

    public TreeService getTreeService() {
        return treeService;
    }

    public void setTreeService(TreeService treeService) {
        this.treeService = treeService;
    }


    public OssCategory getRoot() {
        return root;
    }

    public void setRoot(OssCategory root) {
        this.root = root;
    }

    public void visitTree(OssCategory[] tree) {

        for (int i = 0; i < tree.length; i++) {
            OssCategory node = (OssCategory) tree[i];
            logger.fatal("visitTree:The treenode parentid is :"
                    + node.getParentId() + " ,treenode id is "
                    + node.getCategoryId() + ",and the treenode name is "
                    + node.getCategoryName());
            visitTree(node.getChildCategories());
        }

    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

6、页面

treetest.jsp

<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ page language="java" errorPage="/error.jsp" pageEncoding="GBK" contentType="text/html;charset=GBK" %>
<html>
<head>
    <title>tag list</title>
    <%@ include file="/common/meta.jsp" %>

<style>
    .treeCheckBox {
        height: 14px;
        margin: 0px;
        padding: 0px;
        border: 1px;
        vertical-align: middle;
    }
</style>
<s:head theme="ajax" debug="true" />
</head>
<body >


<script type="text/javascript">
function treeNodeSelected(arg) {
    //alert("id["+arg.source.widgetId+"], name["+ arg.source.title+ "] selected");
}

function treeNodeExpanded(arg) {
    //alert("id["+arg.source.widgetId+"], name["+ arg.source.title+ "] expanded");
}

function treeNodeCollapsed(arg) {
    //alert("id["+arg.source.widgetId+"], name["+ arg.source.title+ "] collapsed");
}

dojo.addOnLoad(function() {
    var t = dojo.widget.byId('root');
    dojo.event.topic.subscribe(t.eventNames.expand, treeNodeExpanded);
    dojo.event.topic.subscribe(t.eventNames.collapse, treeNodeCollapsed);

    var s = t.selector;


});

</script>

<s:form name="form1" action="treeWithCheckbox">
<div style="float:left; margin-right: 50px;" >
<s:tree
    theme="ajax"
    id="root"
    rootNode="#request.root"
    childCollectionProperty="childCategories"
    nodeIdProperty="categoryId"
    nodeTitleProperty="categoryTitle"
    treeSelectedTopic="treeSelected">
</s:tree>
</div>

<div style="float:left; margin-right: 50px;">
<s:submit/>
</div>
</s:form>


</body>
</html>
 

注意:

  • 在s:tree中不能使用label标签,使用后树形结构出不来。
  • childCollectionProperty=”childCategories”对应Category.java中的
    private OssCategory[] childCategories;
    
    public OssCategory[] getChildCategories() {
        return childCategories;
    }
    
    public void setChildCategories(OssCategory[] childCategories) {
        this.childCategories = childCategories;
    }
    

    .csharpcode, .csharpcode pre
    {
    font-size: small;
    color: black;
    font-family: consolas, “Courier New”, courier, monospace;
    background-color: #ffffff;
    /*white-space: pre;*/
    }
    .csharpcode pre { margin: 0em; }
    .csharpcode .rem { color: #008000; }
    .csharpcode .kwrd { color: #0000ff; }
    .csharpcode .str { color: #006080; }
    .csharpcode .op { color: #0000c0; }
    .csharpcode .preproc { color: #cc6633; }
    .csharpcode .asp { background-color: #ffff00; }
    .csharpcode .html { color: #800000; }
    .csharpcode .attr { color: #ff0000; }
    .csharpcode .alt
    {
    background-color: #f4f4f4;
    width: 100%;
    margin: 0em;
    }
    .csharpcode .lnum { color: #606060; }

  • nodeIdProperty=”categoryId”和nodeTitleProperty=”categoryTitle” 对应OssCategory[] childCategories中每一个Category的categoryId和categoryTitle

  • rootNode=”#request.root”,采用rootNode=”root”方式好像取不到数据,按理说应该可以通过ognl自动调用getRoot方法得到

  • 结果提交后,根据对应checkbox的name的on属性来判断是否选中,因此在数据库中对节点的命名需要有一定规则,以便方便选择

尚需要完善的地方:

  • 增加对下拉框树形结构实现的支持,以处理项目中大量诸如产品类型、资源类型等类型。

在实现上,为了避免由于浏览器兼容性问题,在形式上是树形结构,实际上就是从字典表(目前树形结构仍然采用oss_category作为字典表)动态取出数据,然后拼凑成字符串形式展现,例如:

<select>
    <option value="1">1</option>
    <option value="11">&nbsp;&nbsp;|-11</option>
    <option value="12">&nbsp;&nbsp;|-12</option>
    <option value="2">2</option>
    <option value="21">&nbsp;&nbsp;|-21</option>
    <option value="22">&nbsp;&nbsp;|-22</option>
</select>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

  • 进一步优化递归算法,一次性从数据库取出需要的数据,在内存中完成树形结构的构造,避免对数据库的查询,在目前情况下,采用递归方式问题也不大。
  • 由于Struts2.0采用dojo来实现其标签,尽管dojo与jquery相比较很重,但由于与Struts2.0较好支持,在架构统一上和使用上还是较为方便的,因此有空需要研究一下dojo库。

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

7、参考资料

http://www.ajaxtree.com/

http://struts.apache.org/2.x/docs/tree.html

http://ait.web.psi.ch/js/dojo/tests/widget/tree/

http://exjava.spaces.live.com/blog/cns!A43FBDAF9245A0BC!199.entry

http://www.stack.be/~roel/blog/archives/the-dojo-tree-control-for-beginners-part-1/

http://www.stack.be/~roel/blog/archives/the-dojo-tree-control-for-beginners-part-2

http://www.codepencil.com/index.php/struts2-dojo-dynamic-tree/

http://dojotoolkit.org/book/dojo-book-0-9/part-2-dijit/advanced-editing-and-display/tree

 

Technorati 标签: ,,,,
Tagged with: , , , ,

No Responses Yet

Subscribe to comments with RSS.

  1. aaa said, on 2008/08/07 at 15:10

    hao thank you!!!

  2. oozoh said, on 2009/08/24 at 15:16

    非常感谢楼主的分享。收藏了。

  3. BadGirl76 said, on 2009/10/22 at 23:20

    Mark,It’s not Google’s fault that there’s not a proper app. ,

  4. hw said, on 2009/11/02 at 15:06

    代码写的够烂

  5. 新建文件夹 said, on 2009/11/20 at 10:45

    有问题:

    Expression stack.findValue(parameters.nodeTitleProperty) is undefined on line 23, column 48 in template/ajax/treenode-include.ftl.
    The problematic instruction:
    ———-
    ==> ${stack.findValue(parameters.nodeTitleProperty)} [on line 23, column 46 in template/ajax/treenode-include.ftl]
    in include “/${parameters.templateDir}/ajax/treenode-include.ftl” [on line 124, column 5 in template/ajax/tree.ftl]
    ———-

    Java backtrace for programmers:
    ———-
    freemarker.core.InvalidReferenceException: Expression stack.findValue(parameters.nodeTitleProperty) is undefined on line 23, column 48 in template/ajax/treenode-include.ftl.
    at freemarker.core.TemplateObject.assertNonNull(TemplateObject.java:124)
    at freemarker.core.Expression.getStringValue(Expression.java:118)
    at freemarker.core.Expression.getStringValue(Expression.java:93)
    at freemarker.core.DollarVariable.accept(DollarVariable.java:76)
    at freemarker.core.Environment.visit(Environment.java:208)
    at freemarker.core.MixedContent.accept(MixedContent.java:92)
    at freemarker.core.Environment.visit(Environment.java:208)
    at freemarker.core.Environment.include(Environment.java:1477)
    at freemarker.core.Include.accept(Include.java:169)
    at freemarker.core.Environment.visit(Environment.java:208)
    at freemarker.core.MixedContent.accept(MixedContent.java:92)

    ….(省略更多堆栈信息)

    怎么解决呢?


发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: