Dorado 9 : 递归树(sample-center)

递归树在日常开发中非常常见,如本例就以系统的菜单作为展现数据,用树的形式展现出来。
由于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>