Skip to end of metadata
Go to start of metadata

下载

MoonDataset(自定义Dataset实践) v1.0.doc
MoonDataset工程文件.rar

目录

前言
名词
目标
扩展
初始化
两个功能
数据查询
字段集
查询动作
数据提交
字段集
提交动作
工具类
com.bstek.dorado.common.fileloader.FileLoader
com.bstek.dorado.utils.xml.XmlFactory
效果图
在Studio中添加MoonDataset
配置MoonDataset
自动生成字段
页面效果

前言

目前自定义Dataset的权威文档是Benny编写的《自定义Dataset的步骤-Benny-v10-20070903》,总结其中的步骤如下:
1. 为了在项目运行期间可以使用自定义的Dataset1. 将自定义Dataset打jar包放到项目的WEB-INF/lib下。
2. 编写view-datasets.xml放到项目的%doradohome%下。
2. 为了让studio为我们提供可视化的配置自定义Dataset功能。
1. 将自定义Dataset打jar包放到studio/lib下。
2. 编写user-view-rules.xml放到studio/config下。

名词

名称

含义

MoonDataset

本文谈论的自定义数据集。

OrigDataset

原始数据集,即被MoonDataset引用的数据集。

View配置文件

指View的XML定义文件,名字以.view.xml为后缀。

dataset节点

指View配置文件中表示dataset的XML节点。


目标

允许一个View引用在其他View中定义的Dataset,使用时与直接定义在自身View中的Dataset具有相同的效果。即:

  1. MoonDataset可以不定义字段而使用/合并OrigDataset的字段。
  2. MoonDataset可以不定义Parameters而使用OrigDataset的Parameters。
  3. MoonDataset可以不定义Properties而使用OrigDataset的Properties。
  4. MoonDataset可以不定义Event而使用OrigDataset的Event。

扩展

MoonDataset继承了com.bstek.dorado.view.data.CustomDataset。根据自身的功能目标需要定义3个属性:

名称

类型

含义

origViewModelConfig

String

OrigDataset所在的View配置文件。

origDatasetId

String

原始数据集ID,即被引用的Dataset的ID。

appendFields

boolean

合并字段?

初始化

任何类型的Dataset都有init()方法,通过继承com.bstek.dorado.view.data.DatasetSupport的该方法完成初始化的工作,API说明如下:

public void init(DoradoContext context,
XmlNode node)
throws java.lang.Exception
根据一个XML节点对象自动配置本Dataset。
Parameters:
context - DoradoContext
node - XmlNode
Throws:
java.lang.Exception

参数说明如下:

  1. XmlNode node – View配置文件中的dataset节点。
  2. DoradoContext context – 通常来说实例化dataset只需要node参数就足够了,那么context参数的作用可能是为了解决I18N问题。

功能说明如下:

1. 将node的所有attribute的值通过setXxx方法设置到dataset的属性中。
2. 如果配置了listener,则初始化监听器。
3. 根据dataset/masterlink节点初始化主从关系。
4. 根据dataset/fields/field节点初始化字段集。
5. 根据dataset/parameters/parameter节点初始化参数集。
6. 根据dataset/properties/property节点初始化属性集。

  1. 根据dataset/events/event节点初始化EventHandlers。


那么MoonDataset除了完成上面的工作外,还要初始化OrigDataset。相关方法如下:

public void init(DoradoContext context, XmlNode xmlNode) throws Exception {
super.init(context, xmlNode);
initOrigDataset();//初始化源Dataset
initSelfEventHandlers();
//将源Dataset的EventHandler合并到MoonDataset中
}

/**
* 初始化源Dataset
*
* @throws Exception
*/
protected void initOrigDataset() throws Exception {
XmlNode xmlNode = new XmlTool().getDatasetXmlNode(config
.getOrigViewModelConfig(), config.getOrigDatasetId());
ViewModel viewModel = this.getViewModel();
origDataset = (new DefaultDatasetFactory()).createDataset(viewModel,
xmlNode.getAttribute("type"), DEFAULT_MOON_PREFIX
+ this.getId());
origDataset.init(DoradoContext.getContext(), xmlNode);

Class c = this.getObjectClazz();
if (c != null) {
origDataset.setObjectClazz(c);
} else {
this.setObjectClazz(origDataset.getObjectClazz());
}
}

/**
* 将源Dataset的EventHandler合并到MoonDataset中
*/
private void initSelfEventHandlers() {
if (state == ViewModel.STATE_VIEW) {
Iterator i = origDataset.eventHandlers().entrySet().iterator();
EventHandler eventHandler = null;
String eventName = null;
Map.Entry entry = null;
while (i.hasNext()) {
entry = (Map.Entry) i.next();
eventHandler = (EventHandler) entry.getValue();
eventName = (String) entry.getKey();
if (this.getEventHandler(eventName) == null) {
this.addEventHandler(eventHandler);
}
}
}
}

说明:

1. super.init(context, xmlNode);此时MoonDataset初始化了自身的属性,并且origViewModelConfig与origDatasetId已经得到了View配置的值,但origDataset还没有初始化。
2. initOrigDataset();
初始化origDataset,依据为origViewModelConfig与origDatasetId的值。此时也调用了origDataset的init()方法。

  1. initSelfEventHandlers();初始化MoonDataset的EventHandler,合并MoonDataset与origDataset的EventHandler。


两个功能

Dataset的两大功能是:数据查询与数据提交,所以自定义Dataset的终极目标就是实现这两个功能。

数据查询

需要继承com.bstek.dorado.data.DatasetSupport类的doLoad方法,API如下:

protected abstract void doLoad(boolean createFields,
boolean loadData)
throws java.lang.Exception
根据已设定的条件读取外部数据.
Parameters:
createFields - 是否要执行自动创建字段的操作
loadData - 是否要装载数据
Throws:
java.lang.Exception

根据API的说明我们知道在这个方法体中我们要注意两点:

  1. 根据createField的布尔值控制生成dataset字段集的方式。
  2. 根据loadData的布尔值控制是否加载数据。

所以会出现下面的代码:

if(createFields){
... ...//自动生成字段
}
if(loadDada){
... ...//加载数据
}


字段集

在MoonDataset中是通过void syncFieldSet (boolean createFields)方法完成字段的同步功能的,规则如下:

  1. 如果appendFields为true,则合并MoonDataset和OrigDataset的字段集合。
  2. 否则OrigDataset以MoonDataset定义的字段集合为准。

代码如下:

/**
* 同步MoonDataset与源Dataset的字段集
*
* @param createFields
* @throws Exception
*/
private void syncFieldSet(boolean createFields) throws Exception {
if (createFields) {
this.createFieldsFromObjectClazz();
}

syncFieldSet4OrigDataset();//将源Dataset的字段合并到MoonDataset中
syncFieldSet2OrigDataset(); //将MoonDataset的字段集给origDataset
}
/**
* 将源Dataset的字段合并到MoonDataset中
*/
private void syncFieldSet4OrigDataset () {
FieldSet fs = this.fieldSet();
FieldSet ofs = origDataset.fieldSet();
Field f;
// how to appendField ?
switch (state) {
case ViewModel.STATE_DESIGN:
for (int i = 0; i < ofs.getCount(); i++) {
try {
f = ofs.getField(info);
if (!(f instanceof DummyField)) {
fs.addField(f);
}
} catch (DuplicateKeyException e) {
}
}
break;
case ViewModel.STATE_VIEW:
case ViewModel.STATE_SERVICE:
case ViewModel.STATE_REPORT:
if (config.isAppendFields()) {
for (int i = 0; i < ofs.getCount(); i++) {
try {
f = ofs.getField(info);
if (!(f instanceof DummyField)
&& !(f instanceof ViewDummyField)) {
fs.addField(f);
} else {
DummyField vdf = this.addDummyField(f.getName());
vdf.setDataType(f.getDataType());
vdf.setDefaultValue(vdf.getDefaultValue());
vdf.setProperty(f.getProperty());
vdf.setDefaultValue(f.getLabel());
vdf.setNullable(f.isNullable());
}
} catch (DuplicateKeyException e) {
}
}
}
break;
}
}
/**
* 将MoonDataset的字段集给源Dataset
*
* @throws Exception
*/
private void syncFieldSet2OrigDataset() throws Exception {
if (state != ViewModel.STATE_DESIGN) {
Field f;
FieldSet fs = this.fieldSet();
origDataset.setFieldSet(fs);
if (origDataset instanceof DatasetWrapper) {
Dataset ds = ((DatasetWrapper) origDataset).getWrappedDataset();
FieldSet ofs = ds.fieldSet();
FieldSet nfs = new FieldSet();

for (int i = 0, size = fs.getCount(); i < size; i++) {
f = fs.getField(info);
f = ofs.removeField(f.getName());
if (f != null) {
nfs.addField(f);
}
}

ds.setFieldSet(nfs);
}
}
}

其中createFieldsFromObjectClazz()的API说明如下,来自com.bstek.dorado.data.DatasetSupport类:

public void createFieldsFromObjectClazz()
自动利用反射将objectClazz中包含的属性映射成Dataset的字段.
此方法将自动为Dataset添加字段对象.
Specified by:
createFieldsFromObjectClazz in interface Dataset

合并fieldset的两大步骤:

  1. 将OrigDataset的FieldSet合并到MoonDataset的FieldSet中。
  2. 把MoonDataset的FieldSet给OrigDataset。


注:在syncFieldSet4OrigDataset()方法中,

  1. 当state为ViewModel.STATE_DESIGN时表明在处理Studio发送自动生成字段的请求,由于目前Studio不支持生成DummyField,所以此处将这种字段过滤掉了,否则会将DummyField按照Field的方式传递给Studio,这样OrigDataset的DummyField到了MoonDataset中就变成一般的字段了。
  2. 当state为ViewModel.STATE_VIEW或ViewModel.STATE_SERVICE或ViewModel.STATE_REPORT时只需要合并MoonDataset与OrigDatset的字段集。
  3. 这里没有对state为ViewModel.STATE_UPDATING情景做处理,原因是在服务器端处理UpdateCommand请求时,被提交的Dataset的字段以客户端的为准,并一同提交的服务器端。


查询动作

由于MoonDataset是利用origDataset完成查询功能,所以与此相关的依据都要传递给origDataset,包括: pageSize、pageIndex、parameters、properties。MoonDataset的查询动作的代码如下:

/**
* 加载数据的动作
*
* @param createFields
* 是否创建字段
* @param loadData
* 是否加载数据
*/
protected void doLoad(boolean createFields, boolean loadData)
throws Exception {
syncFieldSet(createFields);
if (loadData) {
int pageSize;
if ((pageSize = this.getPageSize()) >= 0) {// $$ Not caution.
origDataset.setPageSize(pageSize);
}
origDataset.setPageIndex(this.getPageIndex());

origDataset.parameters().assign(this.parameters());
origDataset.properties().assign(this.properties());

origDataset.load(loadData);
RecordSet rs = origDataset.recordSet();
this.setRecordSet(rs);

this.setPageSize(origDataset.getPageSize());
this.setPageIndex(origDataset.getPageIndex());
this.setPossibleRecordCount(origDataset.getPossibleRecordCount());
this.setPageCount(origDataset.getPageCount());

this.parameters().assign(origDataset.parameters());
this.properties().assign(origDataset.properties());
}
}

其中用到了com.bstek.dorado.utils.variant.VariantSet的assing()方法,API说明如下:

public void assign(VariantSet variants)
将本集合中的所有数据全部指派到给定的另一个集合中.
Parameters:
variants - VariantSet


数据提交

需要继承com.bstek.dorado.data.DatasetSupport的doUpdate方法,API说明如下:

protected abstract void doUpdate()
throws java.lang.Exception
把用户对Dataset中数据的操作更新到外部数据中.
Throws:
java.lang.Exception


字段集

数据提交时也会涉及到字段集的问题,所以此时syncFieldSet ()方法也会被调用,描述同数据查询。

提交动作

通常提交动作会涉及与数据库的交互,而MoonDataset则需要调用origDataset的update()方法,另外也同样涉及parameters与properties问题,MoonDataset的doUpdate方法代码如下:

protected void doUpdate() throws Exception {
/*
* @1.before update.
*/
// parameters && properties
origDataset.parameters().assign(this.parameters());
origDataset.properties().assign(this.properties());
/*
* @2.update
*/
origDataset.setRecordSet(this.recordSet());
origDataset.update();
this.setRecordSet(origDataset.recordSet());
/*
* @3.after update
*/
// parameters && properties
this.parameters().assign(origDataset.parameters());
this.properties().assign(origDataset.properties());
}

工具类

com.bstek.dorado.common.fileloader.FileLoader

文件加载器。目前Dorado中两种常见的FileLoader是:
1. com.bstek.dorado.common.fileloader.ResourceFileLoader – 针对存放在classpath中的资源加载器。
2. com.bstek.dorado.common.fileloader.PathFileLoader – 针对绝对路径资源的加载器。
注:决定Dorado使用哪种FileLoader加载资源的是决策者是com.bstek.dorado.common.fileloader.FileLoaderFactory,依据为%webroot%\WEB-INF\dorado.properties。

com.bstek.dorado.utils.xml.XmlFactory

XML解析对象的工厂类。屏蔽了解析XML使用的底层解析器,目前支持JDOM9、JDOM10、DOM4J,详情见Dorado安装目录下的support/jaxen/readme.txt。摘录如下:

dorado中自带的JDOM版本为JDOM 9(也被称为JDOM 0.9)。
如果您的部署环境中必须使用JDOM 10(也被称为JDOM 1.0), 那么请将dorado自带的jdom.jar替换为您所使用的版本,此时dorado可自动适配JDOM 9或JDOM 10。但是dorado使用的第三方工具包jaxen.jar却无法自动进行此类适配,因此您还需要手工用此处的JDOM10/jaxen.jar覆盖原先自带的同名文件。
注: dorado中默认使用的jaxen.jar(即安装目录中的/lib/thirdparty/jaxen.jar)是适用与JDOM 9的版本。

另外,dorado除可自适应JDOM 9和JDOM 10之外也可以自动适配DOM4j。如果您的希望dorado使用DOM4j作为XML解析器,那么请删除部署环境中的jdom.jar。此时dorado将自动尝试适配DOM4j。

注:某些应用服务器的运行是依赖于JDOM 的,如WebLogic、JBOSS等。在这种情况下您可能无法从部署环境中移除JDOM。

效果图

在Studio中添加MoonDataset

配置MoonDataset

自动生成字段

页面效果

Labels
  • No labels