EAS-BOS应用框架编程指南
应用框架在业务对象层建立了一些典型业务对象,可用做设计人员建立自己的业务对象的超类。这些用做超类的业务对象,既定义了对象属性,也提供了业务方法。例如,层次数据的超类TreeBase在数据保存时会自动维护level、isLeaf和longNumber的正确性。
1.1. 类体系
1.2. 所有业务对象超类CoreBase
属性
方法
1.3. 普通业务对象超类ObjectBase
属性
方法
常见问题
1.问:Creator、CreateTime、LastUpdateUser、LastUpdateTime作用和意义?
答:所在普通业务对象的基本属性,由基类来维护,业务对象不能用作其他用途。
1.4. 基础资料超类DataBase
属性
方法
注:【名称与编码】检查方法都是需要根据业务要求进行调用的,应用框架本身不调用。
常见问题
1.问:为何继承自DataBase的类没有自动进行名称及编码的检查?
答:没办法统一检查机制,可能由于检查的条件不一样,如科目表使用全局的检查,就可直接调用如上的方法来完成。
2.问:编码规则如何起作用?
答:编码规则在DataBase类起作用。从DataBase继承的类如果定义了编码规则就会自动由基类来完成,子类不需要关心。
1.5. 层次数据超类TreeBase
属性
因为超类中定义的关系无法实例化,所以TreeBase并未定义parent关联属性。要求在子类中自行建立这个表示指向父节点的关联属性,并且约定属性名一定是parent。
方法
常见问题
1.问:isLeaf、level、longNumber由基类处理吗?
答:是的。父类自动维护,子类不需要进行干预。
2.问:检查编码重复的注意事项。
答:原则:输入项必须完整,生成项可以没有,如level,isLeaf,longnumber等,传递给基类的值要求有id,number,name,description。
1.6. 单据超类BillBase(单据头)
属性
方法
可选的方法:
1.protected SystemEnum getOwnedSys():定义单据所属的系统。通常情况下一种单据所属的系统是
确定的,可以在单据对象的扩展属性予以定义。超类负责处理这种情况。对于一种类型的单据被实例化到不同系统的情况,可以增加实体属性,并重载这个方法。
常见问题
1.问:单据生成凭证的处理?
答:校验是否已经生成过凭证,如果已经生成过则抛异常。
2.问:单据关联关系处理。
答:处理所有的分录关联。分为暂存与提交两类。
1.7. 单据超类BillEntryBase(单据体)
属性
常见问题
1.8. 通用设计方法
1.8.1.业务数据状态管理
业务数据状态属于数据的附加描述属性,表达业务数据经过的处理过程,例如:是否已生效、是否已审核,并据此进行相应的逻辑控制。业务数据状态根据业务数据的不同类型会有不同组合,例如:基础资料中可能只有是否生效状态,而单据中会有是否已审核及是否已关闭等状态。
在应用架构中会抽象业务数据中存在的状态种类,并在超类体系里固化对某些通用状态的处理逻辑。
状态配置表
下表列出了所有已知的数据状态属性,这些属性将作为基础的状态属性供定义具体的业务对象时选择使用。
说明:
1、属性对应的数据类型都是相应的枚举类型,类型为Int。字段的数据类型也使用Int。
2、在com.kingdee.eas.framework包中定义了枚举类型供使用。
使用方法
所有基础的状态属性被定义于配置表中,已集成于BOS Studio中。如果业务对象要使用某个状态属性,可方便地选取即可。
单据状态
单据状态往往是由多个基础状态属性组合后对外的统一表现形式。以订单处理为例,可能表现为六种状态:
在内部处理中,实际上选择了三个基础的状态属性来实现控制逻辑:作废状态、完成状态和关闭状态。控制逻辑的规则是:
从编程的方便性考虑,推荐为单据状态定义自己的枚举,并为值对象增加一个getBillStatus方法。该方法通过计算基本属性的取值而得到对应的单据状态。需要注意的是,设置单据状态的操作仍将操作基本状
态属性,并且在设置某个状态属性时可能需要根据控制逻辑同时设置其它属性。
UI层提供数据的展现方式与客户端控制逻辑。
2.1. 通用设计方法
2.1.1.数据绑定
数据绑定主要分为两种类型:查询类界面的数据绑定和编辑类界面的数据绑定。
对于查询类界面,数据绑定是一个从Query对象到KDTable的单向过程。通常在设计期定义完绑定关系后,不会在代码中再关注绑定问题。相关方法是:
1.由KDTable的setFormatXML方法完成列的定义
2.由KDTable的putBindContents传递绑定关系
3.在KDTalbe的doRequestRowSet事件中完成数据的获取与显示
对于编辑类界面,由loadFields和storeFields方法定义了Entity对象与界面控件双向的绑定关系。如果对象是聚合类型的数据(例如单据)并选择KDTable显示单据体,则进一步由loadLineFields和storeLineFields定义了单据行与KDTable的绑定关系。如果在BOS Studio中定义绑定关系,那么这些方法会由BOS自动生成。
注意:不管是完全不使用BOS Studio来定义绑定关系,还是只有部分控件使用BOS Studio定义了绑定关系,你都需要重载这些方法,并通过手工编码来把所有绑定关系补充完整。这是因为超类依赖于这些方法来管理绑定关系。
示例:
假设币别编辑界面没有为isoCode在设计期定义绑定关系,那么需要补充定义:
public void loadFields()
{
super.loadFields();
// editData允许强类型访问
txtIsoCode.setText(editData.getIsoCode());
}
public void storeFields()
{
super.storeFields();
editData.setIsoCode(txtIsoCode.getText());
}
2.1.2.UI元素的使能控制
对UI元素进行使能控制有两种方法:一是利用setOprtState方法,二是利用checkActionStatus方法。
在BOS的UI设计器中,可以利用状态编辑视图定义各种状态下控件的使能情况。BOS会自动生成反映满足这种定义的setOprtState方法。当然,也可以不用BOS的定义能力而重载后完全自行编码,尤其是在需要定义更多逻辑时:例如控件的使能可能需要检查当OprtState处于某种状态时,某些数据是否同时符合要求。
而checkActionStatus方法会在按钮的事件响应完毕后被调用,作为一种推荐的检查控件使能的统一位置。checkActionStatus的调用频率比较高,故检查逻辑最好比较简单。
注意:这种方式与UI的OprtState没有关系,视为对OprtState机制的一种补充。
2.1.
3.UILoadListener
应用框架提供一种扩展机制,允许在加载UI对象和注销UI对象时加入自定义的处理逻辑。
public interface IUILoadListener extends EventListener
{
public void load(UILoadEvent e);
public void unload(UILoadEvent e);
}
例如,想实现用户监控功能,可以按如下步骤进行:
1.在BOS Studio中定义UI对象的扩展属性。此处定义功能编号和功能描述。
2.编写IUILoadListener的实现类,在load事件中访问UI元数据,获取扩展属性中定义的信息,注
册用户监控信息;在unload事件中访问UI元数据,获取扩展属性中定义的信息,注销用户监控信息。
2.2. 序时簿类UI
序时簿是EAS规范地展现数据的方式,提供查询过滤的能力,并可打开维护数据的编辑类界面。序时簿使用查询对象来执行查询,使用KDTable来展现数据。
2.2.1.类体系
2.2.2.通用基类UI
完成了通用职责处理,在此,进行了权限、License、网络控制的通用处理。
2.2.
3.普通序时簿类UI
从CoreUI继承下来。下图是一个普通的序时簿界面的样例。
截图。
类方法介绍
普通序时簿类UI从com.kingdee.eas.framework.client.ListUI继承。通过BOS Studio完成UI对象的创建、更改继承Query对象的类型以及KDTable控件绑定等。
必须重载的方法:
1.protected abstract String getEditUIName():指示关联的编辑UI对象名
示例:
protected String getEditUIName()
{
return “com.kingdee.eas.basedata.assistant.client.CurrencyEditUI”;
}
2.protected abstract IObjectBase getBizInterface():获取列表对应实体的业务接口,以便调用业务
方法。要求实体必须从ObjectBase及其子类派生。
示例:
protected IObjectBase getBizInterface()
{
return CurrencyFactory.getRemoteInstance();
}
可选的方法:
1.protected void prepareUIContext(UIContext uiContext, java.awt.event.ActionEvent e):允许构
造传递给EditUI的UIContext。利用这个方法,你可以加入需要的任何对象并传递给EditUI。
示例:
protected void prepareUIContext(UIContext uiContext, java.awt.event.ActionEvent e)
{
// 检查是否按下新建按钮
if (e.getSource() == btnAddNew)
uiContext.put(“myObject”, null);
else
uiContext.pub(“myObject”, getMyObject());
}
2.protected String getEditUIModal():产生编辑UI的方式,缺省是Dialog方式。可以重载这个方法,
指定其它的模式。
示例:
protected String getEditUIModal()
{
return UIFactoryName.EDITWIN;
}
3.protected boolean initDefaultFilter():设置默认过滤条件。该方法被onLoad调用。
4.protected void refresh(ActionEvent e):界面刷新方法。通过传递的参数e可以知道触发事件源。在
ListUI的缺省实现中,refresh是靠调用execQuery把数据重新获取一遍来达到刷新的效果的。派生类可以依据实际情况来定义更合理的刷新策略。
5.protected String getKeyFieldName():获取KDTable中的主键列名称,供编辑/删除时获取主键用。默
认值为"id"。
注意:BOS自动生成KDTable的列时,使用的是query对象名.id的形式,与超类中约定并不一致。要么在设计期将列名修改,要么在重载该方法返回正确的列名。
常见问题
1.问:序时簿界面打开时会自动查询并显示所有的数据,我想加入一个过滤条件应该怎么做?
答:重载initDefaultFilter方法,为mainQuery对象(类型是EntityViewInfo)增加过滤条件(filterItem)。也可弹出一个对话框(例如通用查询对话框),让用户指定过滤条件。
2.问:我增加了一个按钮,想在执行完毕的时候刷新一下列表,该怎么做?
答:在actionPerformed方法最后一行加调用exceQuery()的代码即可。
3.问:我增加了一个按钮,想在执行前先检查列表是否有选中的行,该怎么做?
答:在actionPerformed方法第一行加调用checkSelected()的代码即可。该方法在检查到没有选中的行时,会弹出对话框提示用户,并且不再继续执行actionPerformed方法中后面的代码。
4.问:如何得到选中行的主键值?
答:使用getSelectedKeyValue方法即可
2.2.4.带通用查询的序时簿类UI
界面样式。
超类为CommonQueryListUI,从ListUI继承。在超类基础上增加了对通用查询对话框的管理。
类方法介绍
带通用查询的序时簿类UI从https://www.wendangku.net/doc/c42304697.html,monQueryListUI继承。
可选的方法:
1.protected void prepareCommonQueryParam(CommonQueryParam param):在该方法中定义要传递给通用
查询对话框的参数。超类的该方法已经把查询对象放到了param中,通常可不必再重载。如果有特别的需要,则按通用查询对话框的要求进行设置。
示例(用一个自己编写的过滤页面替换掉通用过滤页面):
protected void prepareCommonQueryParam(CommonQueryParam param)
{
super.prepareCommonQueryParam(param);
param.setShowFilter(false); // 不显示通用过滤页面
param.addPanel(new MyQueryPanel()); // 加入自己的过滤页面
}
常见问题
1.问:打开带通用查询的序时簿类UI,缺省会弹出通用查询对话框,我怎么调整这个行为?
答:超类使用getDefaultFilterInited()方法来判定UI是否已设置了缺省的filter。当没有设置时,就会弹出通用查询对话框。你可以重载initDefaultFilter方法,设置缺省的filter并返回true(不设置filter也没有关系,主要是返回true即可)。
2.2.5.单据序时簿类UI
超类为BillListUI,从CommonQueryListUI继承。在超类基础上增加了对单据通用操作的处理。
2.2.6.层次数据序时簿类UI
超类为TreeListUI,从ListUI继承。在超类基础上,增加了一个KDTree,以管理层次数据。除支持在KDTable中展现数据的编辑外(该能力从ListUI继承),还支持Tree本身的编辑(典型如地址簿分类的编辑)。
类方法介绍
层次数据序时簿类UI从com.kingdee.eas.framework.client.TreeListUI继承。通过BOS Studio完成UI对象的创建、更改继承Query对象的类型以及处理控件绑定等。KDTree上每个节点的类型为KDTreeNode 类型。
必须重载的abstract方法:
1.protected abstract String getQueryFieldName():点击树上节点时形成过滤条件时的字段,例如地址
簿序时簿界面右边的地址列表要依据左边Tree上选中的地址分类而刷新,此处则返回Address.class即可。
2.protected abstract ITreeBase getTreeInterface():获取层次数据实体的业务接口,以便调用业务方
法。要求实体必须从TreeBase及其子类派生。
可选的方法:
1.protected void buildTreeFilter():构造查询子节点数据的过滤条件。在TreeListUI中默认实现为在
EntityViewInfo中添加一个getQueryFieldName()=treeNodeInfo的过滤条件,即查询对象的某个属性关联到Tree节点所代表的对象。超类认为这种查询条件是是最常见的情况,例如地址簿对象有一个属性指向关联的地址簿分组对象。该默认实现依赖于getQueryFieldName纯虚方法。如果你需要构造的查询条件不是这种形式,则需要重载本方法自行设定过滤条件。
示例:
protected void buildTreeFilter()
{
KDTreeNode treeNode = (KDTreeNode)treeMain.getLastSelectedPathComponent();
AddressClassInfo info = (AddressClassInfo)treeNode.getUserObject();
// 清空并加入自己的过滤条件(通讯地址包含被选中地址簿分类的名称=>仅示意而已)
FilterItemCollection items = mainQuery.getFilter().getFilterItems();
items.clear();
items().add(new FilterItemInfo ("postalAddress",info.getClassName(),CompareType.LIKE))
}
2.protected String getGroupEditUIName():指示Tree关联的类别编辑UI对象名,如果界面需要实现类
别编辑,则需要重载该方法。
3.protected String getGroupEditUIModal():与ListUI类似,表示产生类别编辑UI的方式。
4.protected void prepareGroupUIContext(UIContext uiContext, ActionEvent e):类似于ListUI对关
联EditUI的处理方式,允许构造传递给GroupEditUI的UIContext。超类默认对于新增类别,传入了当前选中的节点对象(默认为是新增节点的父节点,通过UIContext.PARENTNODE传递)。
5.protected String getRootName():定义一个虚拟根节点的显示名称,默认返回null,即不需要虚拟根
节点。此时,所有节点都依据实际的数据构造,可能会有多个一级节点。继承类可以重载,定义虚拟根结点。
示例(地址簿序时簿需要定义一个虚的根节点):
protected String getRootName()
{
return "地址分类";
}
6.protected void initTree():初始化构造Tree。一般情况下请不要重载这个方法,除非你决定用自己的
ITreeBuilder接口的实现类替换掉超类默认提供的LNTreeBuilder。
7.protected ILNTreeNodeCtrl getLNTreeNodeCtrl():返回与LNTreeBuilder配合使用的ILNTreeNodeCtrl
实现类。超类提供默认的实现类DefaultLNTreeNodeCtrl。在特定情况下需要重载,例如菜单树需要根据权限进行过滤而不是仅根据longnumber过滤时。
常见问题
1.问:如何启用TreeListUI对Tree分组的编辑能力?
答:首先将分组编辑相关的按钮Visible属性设置为true,然后重载getGroupEditUIName方法指示关联的编辑UI对象名。
2.问:如何获得选中节点?如何获得选中节点的主键值?
答:使用getSelectedNode获得选中节点所对应的对象。为方便获取主键值,提供了getSelectedNodeKeyValue方法。
Tree的构造机制及如何扩展?
树的构造由ITreeBuidler接口定义。主要的方法是:
●public JTree buildTree(JTree tree):构建树,若传入tree为null,则新建树。
●public void refreshTreeNode(KDTreeNode treeNode):重新取数,刷新节点。
针对EAS处理层次数据采用长编码(longnumber)的情况,应用框架提供了LNTreeBuilder这个特定实现类。与此配合,又定义了ILNTreeNodeCtrl接口和该接口的实现类DefaultLNTreeNodeCtrl。
1.LNTreeBuilder:实现ITreeBuilder接口,提供树的构建能力。
2.ILNTreeNodeCtrl接口:根据父结点信息,获取指定层次子孙结点信息。主要的方法是:
●public AbstractObjectCollection getChildren(TreeBaseInfo parentNodeInfo, int level):获
取指定结点的指定级次的子孙结点。若parent==null,则获取从1到指定级次的结点。
3.DefaultLNTreeNodeCtrl:实现ILNTreeNodeCtrl接口,完成根据longnumber获取下级节点数据的能力。
如果有不基于longnumber方式的层次数据,可通过实现ITreeBuilder接口予以扩展。
2.2.7.带拥有者的层次数据序时簿类UI
超类为ComboTreeListUI,从TreeListUI继承。
2.2.8.带分类的层次数据序时簿UI
超类为TreeDetailListUI,从ListUI继承。
类方法介绍
层次数据序时簿类UI从com.kingdee.eas.framework.client.TreeListUI继承。通过BOS Studio完成UI对象的创建、更改继承Query对象的类型以及处理控件绑定等。KDTree上每个节点的类型为KDTreeNode 类型。
必须重载的abstract方法:
1.protected abstract String getQueryFieldName():点击树上节点时形成过滤条件时的字段,例如地址
簿序时簿界面右边的地址列表要依据左边Tree上选中的地址分类而刷新,此处则返回Address.class即可。
2.protected abstract ITreeBase getTreeInterface():获取层次数据实体的业务接口,以便调用业务方
法。要求实体必须从TreeBase及其子类派生。
3.protected abstract String getGroupEditUIName():关联的类别编辑UI对象名,如果界面需要实现类
别编辑,则需要重载该方法。
可选的方法:
参考层次数据序时簿类UI。
2.2.9.带拥有者和分类的层次数据序时簿UI
超类为ComboTreeDetailListUI,从TreeDetalListUI继承。
2.3. 编辑类UI
2.3.1.类体系
2.3.2.普通编辑类UI
超类为EditUI,从CoreUI继承。EditUI支持实体对象的编辑,提供新增、删除、提交、暂存、作废数据、放弃作废、打印及上一条、下一条等功能。EditUI支持的实体对象必须从ObjectBase及其子类继承。
类方法介绍
普通编辑类UI从com.kingdee.eas.framework.client.EditUI继承。通过BOS Studio完成UI对象的创建、更改继承Entity对象的类型以及处理控件绑定等。
必须重载的方法:
1.protected IObjectValue createNewData():新建业务对象,并设置初始值。
示例:
protected IObjectValue createNewData()
{
CurrencyInfo info = new CurrencyInfo();
// 设定初值
info.setCreator(sysContext.getOperator());
info.setIsoCode(defaultIsoCode);
info.setSign(defaultSign);
return info;
}
2.protected abstract IObjectBase getBizInterface():获取实体对象的业务接口,供调用后台方法使
用。
示例:
protected IObjectBase getBizInterface()
{
return CurrencyFactory.getRemoteInstance();
}
可选的方法:
1.protected void verifyInput () throws Exception:校验输入的合法性。可以直接检查空或范围等条
件,也可以调用服务端提供的校验方法。可使用SysUtil.abort方法中断操作流程,并视情况弹出提示框及设置输入焦点。
示例:
protected void verifyInput() throws Exception
{
if (isNull(txtNum.getText())) {
MsgBox.showWarning(“编号不能为空”);
txtNum.requestFocus();
SysUtil.abort();
}
// 可能抛出异常但无须捕获,最外层有缺省的异常处理器
getBizInterface().checkNameDup(editData);
// …其它检查代码
}
2.loadFields/storeFields:作用请参考前面通用设计方法的说明。
3.getMessageIcon()/getMessageBgcolor()/getMessageText()设置状态栏提示图标、背景色、提示文
字。
示例:
protected Icon getMessageIcon()
{
return SHOW_MESSAGE_ICON_DEFAULT;
}
protected Color getMessageBgcolor()
{
return new Color(0x0F , 0x88 , 0x28);
}
protected String getMessageText()
{
return SHOW_MESSAGE_TEXT_OK;
}
4.showSaveSuccess/showSubmitSuccess子类可重载这些处理方式。默认情况下,如果有状态栏则使
用状态栏处理,如果保存成功则绿色背景闪烁三次;否则使用消息对话框显示。
示例:
protected void showSaveSuccess()
{
MsgBox.ShowInfo(“success!”);
}
常见问题
2.3.3.单据编辑类UI
超类为BillEditUI,从EditUI继承。BillEditUI支持单据对象的编辑,除继承了EditUI的能力外,还可处理单据行的新增和删除。BillEditUI支持的实体对象必须从BillBase及其子类继承。
类方法介绍
单据编辑类UI从com.kingdee.eas.framework.client.BillEditUI继承。通过BOS Studio完成UI对象的创建、更改继承Entity对象的类型以及处理控件绑定等。
必须重载的方法:
1.protected IObjectValue createNewDetailData():新建单据行,并设置初始值。
示例:
protected IObjectValue createNewDetailData()
{
VoucherEntryInfo info = new VoucherEntryInfo();
// 设定初值
info.setCreator(sysContext.getOperator());
info.setXXX…
return info;
}
可选的方法:
1.loadLineFields/storeLineFields:数据绑定方法,针对单据行。若不能利用BOS Studio在设计期全部
定义好绑定关系,则需要编码完成。
2.protected void afterAddLine(IObjectValue lineData):通知方法,允许在增加单据行后做相关处理。
protected void afterAddLine(IObjectValue lineData)
{
// 计算合计值并显示
calcTotalAmount();
}
3.protected void afterRemoveLine(IObjectValue lineData ):通知方法,允许在删除单据行后做相关
处理。
4.protected void afterSelectLine(IObjectValue lineData ):通知方法,允许在选中单据行后做相关
处理。
常见问题
3.1. 实体对象的迁移
在BOS Studio设计器中,完成如下工作:
1.找到要修改的实体对象,打开编辑视图
2.选择合适的超类实体对象作为父实体对象。例如,对于币别对象,应选择从DataBase继承。
3.将超类中已经定义的属性需要去掉。例如,对于币别对象,应将超类中已经定义的id、number和
name属性去掉。
4.重新发布数据表
对于从TreeBase派生的层次数据对象,要注意:
1.因为超类中定义的关系无法实例化,所以TreeBase并未定义parent关联属性。要求在子类中自行
建立这个表示指向父节点的关联属性,并且约定属性名一定是parent。
3.2. UI对象的迁移
UI对象需要重新生成。可以同时打开老的UI对象和新的UI对象,把控件拷贝过来。相关处理代码若超类已提供处理则废弃,否则拷贝过来并做适当修改。