递归树在日常开发中非常常见,如本例就以系统的菜单作为展现数据,用树的形式展现出来。
由于DataSet的面向对象,以及DataType支持继承等特性,使得我们使用DataTree控件展现一个复杂结构和不同数据来源的数据都很轻松。
准备Java层的数据服务
本例为了展示树,我们在com.bstek.dorado.sample下的Main.java类中定义了两个方法:
@DataProvider public Collection<ExampleCategory> getCategories(Long parentCategoryId) { return exampleCategoryDao.find("from ExampleCategory where categoryId=" + parentCategoryId + " order by sortFlag"); } @DataProvider @SuppressWarnings("unchecked") public Collection getExamplesByCategoryId(Long categoryId) throws Exception { return exampleDao.find("select e " + "from Example e, CategoryExampleRelation r " + "where e.id = r.exampleId and r.categoryId = " + categoryId + " order by r.sortFlag"); }
getCategories
这个方法是根据父Category的ID获取子Category列表
getExamplesByCategoryId
这个方法根据分类id获取Example对象列表
其数据库接口通过查询的SQL已经可以很清楚看出其逻辑关系,此处不再贴出.
以上两个方法都通过"@DataProvider"标识,便于暴露给客户端,向客户端提供数据。
定义DataType
为便于树的开发,我们在范例的视图模型中定义一个复合的DataType:CategoryNode,其定义如下:
<DataType name="CategoryNode" parent="BaseExampleCategory"> <Reference name="categories" dataType="[CategoryNode]" dataProvider="main#getCategories" parameter="$${this.id}" /> <Reference name="examples" dataType="[BaseExample]" dataProvider="main#getExamplesByCategoryId" parameter="$${this.id}" /> </DataType>
其中定义了两个较为复杂的reference属性:
categories:是一个CategoryNode组合的数组对象,其数据来自"main#getCategories";
examples:是一个BaseExample组合的数组对象,其数据来自"main#getExamplesByCategoryId";
注意这两个reference设置中parameter的设置:
$${this.id}
这是动态EL表达式的用法,在本例的用意是以当前CategoryNode的id属性作为两个reference的dataProvider调用时的参数传入。
定义DataSet
定义好CategoryNode之后,我们定义dsCategories:
<DataSet id="dsCategories" dataType="[CategoryNode]" dataProvider="main#getCategories" />
通过这种定义方式,当我们拿到dsCategories中的一个CategoryNode对象时,其categories属性就是一个子的CategoryNode集合;同时所属这个Category的Example集合就会自动初始化到examples中。
定义DataTree
经过上面的准备之后,现在我们再来定义DataTree:
<DataTree id="treeExamples" dataSet="dsCategories" width="300" height="400"> <BindingConfigs> <BindingConfig childrenProperty="categories" labelProperty="label" recursive="true" icon=">images/folder.gif"> <BindingConfig childrenProperty="examples" labelProperty="label" icon=">images/file.gif" /> </BindingConfig> </BindingConfigs> </DataTree>
treeExamples绑定了dsCategories对象,并通过BindingConfig定义节点属性。
childrenProperty属性
childrenProperty="categories"
表示子节点通过CategoryNode的categories获取
childrenProperty="examples"
表示子节点通过CategoryNode的examples获取
labelProperty属性
表示树节点初始化时,默认以树节点所绑定对象的哪个属性(本例为label)作为节点标题显示。
本例相关DataType(src/models/SampleCenter.model.xml)都定义了label属性:
<DataType name="BaseExampleCategory" parent="CommonEntity" matchType="com.bstek.dorado.sample.entity.ExampleCategory"> <PropertyDef name="label" label="标题" required="true" /> <PropertyDef name="icon" label="图标" /> </DataType> <DataType name="BaseExample" parent="CommonEntity" matchType="com.bstek.dorado.sample.entity.Example"> <PropertyDef name="label" label="标题" required="true" /> <PropertyDef name="icon" label="图标" /> </DataType>
recursive属性
该属性是用来定义是否一个递归的BindingConfig,如果递归则内部会继续按照如下的规则加载树节点:
<BindingConfig childrenProperty="categories" labelProperty="label" recursive="true" icon=">images/folder.gif"> <BindingConfig childrenProperty="examples" labelProperty="label" icon=">images/file.gif" /> </BindingConfig>