概述
本示例是一个常见的产品目录树的演示。本示例链接如下:
准备工作
新建一工程producttree,并且配置好数据库,具体步骤参考3.1.2节。
开发步骤
添加Dataset
步骤1:添加一Common ViewModel,文件名为ProductTree。
步骤2:添加该ViewModel的实现,代码如下:
import java.util.List;
import com.bstek.dorado.data.Dataset;
import com.bstek.dorado.data.ParameterSet;
import com.bstek.dorado.data.Record;
import com.bstek.dorado.data.RecordIterator;
import com.bstek.dorado.data.db.DBStatement;
import com.bstek.dorado.utils.variant.VariantSet;
import com.bstek.dorado.view.DefaultViewModel;
/**
* ProductTreeViewModel
*/
public class ProductTreeViewModel extends DefaultViewModel {
protected void doUpdateData(ParameterSet parameters,
ParameterSet outParameters) throws Exception {
DBStatement stCategory = new DBStatement();
stCategory.setSql(DBStatement.SELECT, "category");
DBStatement stDelCategory = new DBStatement();
stDelCategory.setSql(DBStatement.DELETE, "category");
DBStatement stDelProduct = new DBStatement();
stDelProduct.setSql(DBStatement.DELETE, "product");
try {
Dataset datasetCategory = getDataset("datasetCategory");
RecordIterator iter = datasetCategory.recordIterator();
iter.setVisibility(Dataset.FILTER_DELETED);
while (iter.hasNext()) {
Record record = iter.nextRecord();
deleteChildCategory(record.getString("category_id"),
stCategory, stDelCategory, stDelProduct);
}
} finally {
stCategory.close();
stDelCategory.close();
stDelProduct.close();
}
super.doUpdateData(parameters, outParameters);
}
private void deleteChildCategory(String categoryId, DBStatement stCategory,
DBStatement stDelCategory, DBStatement stDelProduct)
throws Exception {
stCategory.parameters().setString("parent_id", categoryId);
List list = stCategory.queryForList();
int size = list.size();
for (int i = 0; i < size; i++) {
VariantSet category = (VariantSet) list.get(i);
deleteChildCategory(category.getString("category_id"), stCategory,
stDelCategory, stDelProduct);
}
stDelCategory.parameters().setString("category_id", categoryId);
stDelCategory.execute();
stDelProduct.parameters().setString("category_id", categoryId);
stDelProduct.execute();
}
}
步骤3:添加一CustomDataset,id设置为datasetRoot,添加两个字段,分别为category_id,category_name。
步骤4:为datasetRoot添加一Dataset Listener,代码如下:
import com.bstek.dorado.data.AbstractDatasetListener;
import com.bstek.dorado.data.Dataset;
/**
* ProductTree_datasetRootListener
*/
public class ProductTree_datasetRootListener extends AbstractDatasetListener {
public void afterLoadData(Dataset dataset) throws Exception {
dataset.insertRecord();
dataset.setString("category_id", "$null");
dataset.setString("category_name", "<产品目录>");
}
}
步骤5:添加一AutoSqlDataset,选择Category表,选择所有列,属性设置如下:
属性 | 值 |
|---|---|
id | datasetCategory |
originTable | category |
keyFields | category_id |
为AutoSqlDataset的Field的category_id和category_name添加"Vlidator-Required",添加位置如下图所示:

为AutoSqlDataset添加一BaseMatchRule,属性设置如下:
属性 | 值 |
|---|---|
level | 1 |
dataType | string |
value | :parent_id |
escapeEnabled | true |
table | category |
originField | parent_id |
operator | = |
为AutoSqlDataset添加一Parameter,属性设置如下:
属性 | 值 |
|---|---|
name | parent_id |
value | $null |
为datasetCategory的beforeDelete事件添加如下代码:
var category_id = parseInt(record.getValue("category_id"));
if (record.getString("parent_id") == "" && (category_id == 1 || category_id == 2 || category_id == 3)) {
return "处于演示数据的安全考虑,本例不允许您删除顶层的分类!";}
步骤6:添加一AutoSqlDataset,选择Product表,选择所有字段,属性设置如下:
属性 | 值 |
|---|---|
id | datasetProduct |
originTable | product |
keyFields | product_id |
为AutoSqlDataset的Field的product_id、category_id和product_name添加"Vlidator-Required"
为AutoSqlDataset添加三个BaseMatchRule,属性设置分别如下:
属性 | 值 |
|---|---|
level | 1 |
dataType | string |
value | :category_id |
escapeEnabled | true |
table | product |
originField | category_id |
operator | = |
属性 | 值 |
|---|---|
level | 1 |
dataType | string |
value | :product_id |
escapeEnabled | true |
table | product |
originField | product_id |
operator | = |
属性 | 值 |
|---|---|
level | 1 |
dataType | string |
value | :product_name |
escapeEnabled | true |
table | product |
originField | product_name |
operator | like |
添加DataTree
步骤1:添加一DataTree,属性设置如下:
属性 | 值 |
|---|---|
id | treeProduct |
height | 100% |
width | 100% |
draggable | true |
步骤2:为treeProduct添加一Simple Tree Level,属性设置如下:
属性 | 值 |
|---|---|
name | root |
dataset | datasetRoot |
labelField | category_name |
expanded | true |
步骤3:为root添加一Recursive Tree Level,属性设置如下:
属性 | 值 |
|---|---|
name | category |
dataset | datasetCategory |
recursiveKeyFields | category_id |
recursiveKeyParameters | parent_id |
labelField | category_name |
detailKeyParameters | parent_id |
masterKeyFields | category_id |
步骤4:为product添加一Simple Tree Level,属性设置如下:
属性 | 值 |
|---|---|
name | product |
dataset | datasetProduct |
masterKeyFields | category_id |
detailKeyParameters | category_id |
labelField | product_name |
hasChild | false |
步骤5:为treeProduct的beforeCurrentChange事件添加如下代码:
if (node.getLevel() == 1) {
return new AbortException();
}
为treeProduct的afterCurrentChange事件添加如下代码:
if (node == null) return;
if (node.getTreeLevel().getName() == "category") {
tabsetDetail.setCurrentTab("category");
}
else {
tabsetDetail.setCurrentTab("product");
}
为treeProduct的onDragOver事件添加如下代码:
var draggingLevel = draggingObject.getTreeLevel().getName();
var targetLevel = targetObject.getTreeLevel().getName();
if (draggingLevel == "category") {
return (targetLevel == "root" || targetLevel == "category");
}
else if (draggingLevel == "product") {
return (targetLevel == "category");
}
为treeProduct的onDragEnd事件添加如下代码:
var draggingLevel = draggingObject.getTreeLevel().getName();
var targetLevel = targetObject.getTreeLevel().getName();
var draggingRecord = draggingObject.getRecord();
var targetRecord = targetObject.getRecord();
if (draggingLevel == "category") {
if (targetLevel == "root") {
draggingRecord.setValue("parent_id", null);
}
else {
draggingRecord.setValue("parent_id", targetRecord.getValue("category_id"));
}
}
else if (draggingLevel == "product") {
draggingRecord.setValue("category_id", targetRecord.getValue("category_id"));
}
return true;
添加AutoForm和Button
步骤1:添加一AutoForm,属性设置如下:
属性 | 值 |
|---|---|
id | formCategory |
dataset | datasetCategory |
选中formCategory,点击字段生成按钮。
步骤2:添加一Button,属性设置如下:
属性 | 值 |
|---|---|
id | buttonAddCategory |
value | 添加分类 |
为buttonAddCategory的onClick事件添加如下代码:
if (!validateCurrentRecord()) return;
var record = datasetCategory.insertRecord();
var currentNode = treeProduct.getCurrentNode();
var parentNode = currentNode.getParent();
if (parentNode.getLevel() > 0) {
var parentRecord = parentNode.getRecord();
var parent_id = parentRecord.getValue("category_id");
if (parent_id == "$null") parent_id = null;
record.setValue("parent_id", parent_id);
}
var node = new RecordTreeNode(record, currentNode.getTreeLevel());
parentNode.addNode(node);
treeProduct.setCurrentNode(node);
步骤3:添加一Button,属性设置如下:
属性 | 值 |
|---|---|
id | buttonAddChildCategory |
value | 添加子分类 |
为buttonAddChildCategory的onClick事件添加如下代码:
if (!validateCurrentRecord()) return;
var currentNode = treeProduct.getCurrentNode();
treeProduct.expandNode(currentNode);
var record = datasetCategory.insertRecord();
var parentRecord = currentNode.getRecord();
record.setValue("parent_id", parentRecord.getValue("category_id"));
var node = new RecordTreeNode(record, currentNode.getTreeLevel());
currentNode.addNode(node);
treeProduct.setCurrentNode(node);
步骤4:添加一Button,属性设置如下:
属性 | 值 |
|---|---|
id | buttonDelCategory |
value | 删除分类 |
为buttonDelCategory的onClick事件添加如下代码:
if (confirm("确定要删除此产品分类以及其中的所有子分类和产品吗?")) {
datasetCategory.deleteRecord();
}
步骤5:添加一Button,属性设置如下:
属性 | 值 |
|---|---|
id | buttonAddChildProduct |
value | 添加子产品 |
为buttonAddChildProduct的onClick事件添加如下代码:
if (!validateCurrentRecord()) return;
var currentNode = treeProduct.getCurrentNode();
treeProduct.expandNode(currentNode);
var record = datasetProduct.insertRecord();
var parentRecord = currentNode.getRecord();
record.setValue("category_id", parentRecord.getValue("category_id"));
var node = new RecordTreeNode(record, currentNode.getTreeLevel().getTreeLevel("product"));
currentNode.addNode(node);
treeProduct.setCurrentNode(node);
步骤6:添加一AutoForm,属性设置如下:
属性 | 值 |
|---|---|
id | formProduct |
dataset | datasetProduct |
选中formProduct,点击字段生成按钮。
步骤7:添加一Button,属性设置如下:
属性 | 值 |
|---|---|
id | buttonAddProduct |
value | 添加产品 |
为buttonAddProduct的onClick事件添加如下代码:
if (!validateCurrentRecord()) return;
var record = datasetProduct.insertRecord();
var currentNode = treeProduct.getCurrentNode();
var parentNode = currentNode.getParent();
var parentRecord = parentNode.getRecord();
record.setValue("category_id", parentRecord.getValue("category_id"));
var node = new RecordTreeNode(record, currentNode.getTreeLevel());
parentNode.addNode(node);
treeProduct.setCurrentNode(node);
步骤8:添加一Button,属性设置如下:
属性 | 值 |
|---|---|
id | buttonDelProduct |
value | 删除产品 |
为buttonDelProduct的onClick事件添加如下代码:
if (confirm("确定要删除此产品吗?")) {
datasetProduct.deleteRecord();
}
步骤9:为View的function添加如下代码:
function validateCurrentRecord() {
if (tabsetDetail.getCurrentTab().getName() == "category") {
return datasetCategory.postRecord();
}
else {
return datasetProduct.postRecord();
}
}
为View的onLoad事件添加如下代码:
var current = datasetCategory.getCurrent();
if (current != null) {
var node = treeProduct.findNodeByRecord(current);
if (node != null) treeProduct.setCurrentNode(node);
}
为View的onUnLoad事件添加如下代码:
if (commandSave.isDirty()) {
if (confirm("本页面中有未保存的数据.\n您希望在离开之前对这些数据进行保存吗?")) {
commandSave.execute();
}
}
添加Command和Button
步骤1:添加一UpdateCommand,id设置为commandSave。
选中commandSave,为其添加两个DatasetInfo,分别为datasetCategory、datasetProduct。
步骤2:添加一Button,属性设置如下:
属性 | 值 |
|---|---|
id | buttonSave |
command | commandSave |
value | 保存所有修改 |
创建Jsp页面
生成Jsp页面以后再编辑一下布局,最后结果如下:
<%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib uri="http://www.bstek.com/dorado" prefix="d" %> <html> <head> </head> <body style="margin: 0; overflow: hidden"> <d:View config="ProductTree"> <d:Layout type="border"> <d:Pane position="center"> <d:SplitPanel id="splitpanel1" orientation="horizontal" width="100%" height="100%" showButtons="true"> <d:DataTree id="treeProduct" /> <d:Splitter /> <d:TabSet id="tabsetDetail" showFrame="false"> <d:Tab name="category" visible="false" padding="12"> <d:Layout type="Hflow" height="30"> <d:Pane> <d:Button id="buttonAddCategory" /> </d:Pane> <d:Pane> <d:Button id="buttonAddChildCategory" /> </d:Pane> <d:Pane> <d:Button id="buttonDelCategory" /> </d:Pane> <d:Pane> <d:Button id="buttonAddChildProduct" /> </d:Pane> </d:Layout> <d:AutoForm id="formCategory" /> </d:Tab> <d:Tab name="product" visible="false" padding="12"> <d:Layout type="Hflow" height="30"> <d:Pane> <d:Button id="buttonAddProduct" /> </d:Pane> <d:Pane> <d:Button id="buttonDelProduct" /> </d:Pane> </d:Layout> <d:AutoForm id="formProduct" /> </d:Tab> </d:TabSet> </d:SplitPanel> </d:Pane> <d:Pane position="bottom" align ="right" padding="6" style="background-color: #f0f0f0"> <d:Button id="buttonSave" /> </d:Pane> </d:Layout> </d:View> </body> </html>
查看运行效果
启动服务器后,浏览效果如下:

点击左边不同的节点,可以在右侧对该节点进行操作。
知识点
本示例的知识点为DataTree部分。关于DataTree可以参考《dorado 5 组件详解 1.1》第二部分的B部分的第2部分。