NC开发流程一览表说明.docx
《NC开发流程一览表说明.docx》由会员分享,可在线阅读,更多相关《NC开发流程一览表说明.docx(35页珍藏版)》请在冰豆网上搜索。
NC开发流程一览表说明
单表体的卡片型单据制作
单表体的单据:
指装载界面数据的聚合VO表头为空,只存在一组表体VO。
UI工厂设计了接口ISingleController,单表体单据界面控制类应实现此接口,并实现isSingleDetail方法。
前期准备:
单据注册,模板初始化等等,在构造好类框架后要修改界面控制类。
1.注册单据类型
2.注册VO对象如下:
publicString[]getBillVoName(){
ReturnnewString[]{
};
}
publicStringgetPKField(){
Return“pk_sample”;
}
publicStringgetChildPKField(){
Return“pk_sample”;
}
注意此时的表头,表体的VO类一致。
3.是否走平台
publicintgetBusinessActionType(){
R
}
4.注册按钮
publicint[]getCardButtonAry(){
Returnnewint[]{
IBillButton.Query,
IBillButton.Add,
IBillButton.Edit,
IBillButton.Line,
IBillButton.Save,
IBillButton.Cancel,
IBillButton.Refresh,
};
}
最重要的一步,实现isSingleDetail方法。
publicBooleanisSingleDetail(){//单表体明细
//单表体
Returntrue;
}
ISingleController用来支持单表头或单表体的单据,因此,当isSingleDetail方法返回true时,单据为单表体;当返回false时,单据为但表头。
单表头的卡片型单据制作
除了显示有很大差异外,单表头于单表体的唯一区别在于isSingleDetail方法的返回值。
另外,在单表头界面增加浏览按钮和去掉行操作按钮。
虚拟主子表的卡片型单据制作
虚拟主子表单据:
指的是那种数据来源于一张表,却根据(自定义的)特定规则虚拟主子表的结构,将一部分放到表头,剩下的字段放到表体的单据。
它通常用于数据的分组,即把数据根据(自定义的)特定字段的值进行分组。
字段值相等的数据自然的被归为一类,然后,把特定字段放到表头显示,属于它的一组数据在表体列表显示,形成了标准主子表的结构。
由于数据分组的特定规则取决于业务,因此UI工厂无法做缺省的实现。
但加载数据库数据一般都在查询时完成,所以可以定制查询事件的行为,这需要为单据创建按钮事件处理器,并重载查询时基类调用的方法。
加载数据的步骤如下:
1.第一步,与前面的步骤一样,并配置好界面控制器类。
2.在UI类重载按钮事件处理器类的方法,如下:
ProtectedCardEventHandlercreateEventHandler(){
ReturnnewSampleCardEventHandle(this.getUIControl());
}
3.构造按钮事件处理器类,重载onBoQuery方法。
如下:
ProtectedvoidonBoQuery()throwsException{
UIDialogquerydialog=getQueryUI();
If(querydialog.showModel())==(INormalQuery)querydialog;
StringstrWhere=query.getWhereSql();
If(strWhere==null)
strWhere=”1=1”;
strWhere=”(”+strWhere+”)and(isnull(dr,0)=0)”;
//将查询对话框条件加到整个查询条件后
If(getHeadCondition()!
=null)
strWhere=strWhere+”and”+getHeadCondition();
//查询数据表数据
SuperVO[]queryVos=getBusinessAction().queryHeadAllData(
Class.forName(getUIController().getBillVoName()[1]),
getUIController().getBillType(),
strWhere);
//清空缓冲数据
getBUfferData().clear();
if(queryVos==null||queryVos.length==0){
getBillUI().setBillOperate(IBillOperate.OP_INIT);
getBufferData().setCurrentRow(-1);
}else{
//根据规则将数据进行分组
AggregatedValueObject[]bills=createBillVOs(queryVos);
getBillUI().setBillOperate(IBillOperate.OP_NOTEDIT);
getBufferData().setCurrentRow(0);
}
}
/**
*对一组VO数据进行分类
*
*@param待分类的VO数据
*@return分类的结果
*/
PrivateAggregatedValueObject[]//聚合值对象数据
createBillVOs(CircularlyAccessibleValueObject[]vos){//循环获得值对象数组
if(vos==null||vos.length==0)
returnnull;
//按照年度,月度将数据分组
HashMaptmpMap=Hashlize.hashlizeObjects(vos,newVOHashKeyAdapter(newString[]{“vyear”,”vmonth”}));
AggregatedValueObject[]bills=newAggregatedValueObject[tmpMap.size()];
Inti=0;
Iteratorit=tmpMap.keySet().iterator()
For(;it.hasNext();i++){
Objectkey=it.next();
ArrayListal=(ArrayList)tmpMap.get(key);
B
//设置表头数据
bill[i].setChildrenVO(
(SuperVO[]).toArray(newSuperVO[0]));
}
Returnbills;
}
对数据增,删,改的控制
因为是虚拟主子表的数据结构,它在进行数据的操作时需要额外的控制。
这个问题的本质是在将前台数据写回后台时,需将前台的主子表结构还原为单表结构。
1.数据修改时的控制,这包括新增和编辑
在编辑(行操作)完毕,点击保存按钮。
程序会从界面取得被修改的数据,这些数据被标志成新增,删除,修改等状态,提交给后台处理。
对于真正的主子表,表头数据和标题数据会分别存储到对应的表中,但对于虚拟主子表的单据,主表数据加上字表数据的一行才构成数据表中的一行记录。
这个问题的解决方法如下:
在获取界面VO时做控制,方法是重载UI类重载基类的getChangedVOFramUI方法:
PublicAggregateValueObjectgetChangeVOFromUI()ThrowsException
{
AggregatedValueObjectvo=super.getChangedVOFromUI();
If(vo!
=null){
//将聚合VO的主表设为空
Vo.setParentVO(null);
}
Returnvo;
}
通过将聚合VO的主表舍为空,后台不会再处理主表的数据。
在编辑时,将需要存储的主表数据放到字表中。
这需要控制行操作的行为,方法是时间处理器重载基类的行操作方法:
/**
*增行方法
*/
P
Super.onBoLineAdd();
addDefaultData();
}
/**
*粘贴行的方法
*/
ProtectedvoidonBoLinePaste()throwsException{
Super.onBoLinePaste();
addDefaultData();
}
/**
*插入行方法
*/
ProtectedvoidonBoLineIns()throwsException{
super.onBoLineIns();
addDefaultData();
}
/**
*将表头数据放到表体中
*/
PrivatevoidaddDefaultData()throwsException{
IntcurrentBodyrow=getBillCardPanelWrapper().getBillCardPanel().getBillTable().getSelectedRow();
Objectvyear=getBillCardPanelWrapper().getBillCardPanel().getHeadItem(“vyear”).getValue();
getBillCardPanelWrapper().getBillCardPanel().setBodyValueAt(vyear,currentBodyrow,”vyear”);
Objectvmonth=getBillCardPanelWrapper().getBillCardPanel().getHeadItem(“vmonth”).getValue();
getBillCardPanelWrapper().getBillCardPanel().setBodyValueAt(vmonth,currentBodyrow,”vmonth”);
}
可以看到,在每个意在更新数据的行操作方法中,都会调用将表头相关数据放到表体当前操作行的方法。
控制保存后否再次查询数据库,以取得数据库最新数据。
对于真正的主子表,在数据库更新数据后重新查询一下最新数据并向前台返回,是具有意义的,并且根据表头数据的主键即可获得表头数据和表体数据。
而虚拟主子表,如前所述,数据的组织在UI端完成,后台没有足够的信息区查询和组织数据。
因此,此时只能向前台返回当前的数据。
UI工厂使用IRetCurrentDataAfterSave借口做此标志,如果UI类的getUserObject方法返回的对象实现了此接口,则在保存后部重新读取数据库。
我们加了一个RetCurrentDataAfterSaveImpl类,让它实现IRetCurrentDataAfterSave接口。
如:
PublicObjectgetUserObject(){
ReturnnewRetCurrentDataAfterSaveImpl();
}
需要注意的是:
从程序健壮性考虑,我们应该加一些前台校验类,依照前面介绍,我们创建前台校验类,并在单据类型中注册。
3.对数据的删除控制
这需要让事件处理器重载基类的onBoDelete方法,如:
ProtectedvoidonBoDelete()throwsException{
If(MessageDialog.showYesNoDlg(
getBillUI(),”档案删除”,”是否确认删除该基本档案?
”)!
=UIDialog.ID_YES)
return;
AggregateValueObjectmodelVo=getBufferData().getCurrentVO();
//将聚合VO的表头设为空
modelVo.setParentVo(null);
getBusinesssAction().delete(
modelVo,
getBillUI()._getDate().toString(),
getBillUI.getUserObject());
getBufferData().removeCurrentRow();
if(getBufferData().getVOBufferSize()==0)
getBillUI().setBillOperate(IBillOperate.OP_INIT);
else
getBillUI().setBillOperate(IBillOperate.OP_NOTEDIT);
}
注:
删除单据时,并不涉及到界面的数据,因此只需控制BillUIBuffer中的缓存的当前VO。
多子表卡片型单据
多子表单据在界面显示上通常是表头+多页签的表体,每一个页签代表一个子表。
在UI工厂中,这种单据得到了抽象,主要从以下两个角度:
1.对UI显示界面的抽象。
多子表单据的UI类不使用BillCardUI做基类,而是继承与一个新的UI基类,MultiChildBillCardUI,它封装了多个页签的界面显示。
2.对VO数据的抽象。
在NC应用中,主子表数据存储在聚合VO中,它支持一个主表+一个子表的结构,但是,这种结构不适合于多子表的情况。
因此,UI工厂设计了接口IExAggVO,需要装载多子表数据的聚合VO类,应该实现此接口,并实现它的关键方法。
制作多子表单据的步骤
定义多子表VO
多子表Vo是聚合VO,同事又像一个装载多个字表数据的容器,因此它必然继承自AggregatedValueObject的类层次,又实现多子表VO的接口,IExAggVO,具体如下:
P
//用来装载多子表数据的hashmap
PrivateHashMaphmChildVOs=newHashMap();
/**
*返回各个子表的编码
*必须与单据模板的页签编码对应
*/
P
ReturnnewString[]{“sample_table1”,”sample_table2”};
}
/**
*返回各个子表的中文名称
*创建日期:
(01-3-2017:
36:
56)
*/
P
ReturnnewString[]{“字表一”,”字表二”};
}
/**
*取得所有子表的所有VO对象
*/
PublicCircularlyAccessibleValueObject[]getAllChildrenVO()
{
ArrayLIstall=newArrayList();
For(inti=0;iCircularlyAccessibleValueObject[]cvos=getTableVO(getTableCodes()[i]);
If(cvos!
=null)
all.addAll(Arrays.asList(cvos));
}
Return(SuperVO[])all.toArray(newSuperVO[0]);
}
/**
*返回某个字表的VO数组。
*/
PublicCircularlyAccessibleValueObject[]
getTableVO(StringtableCode){
return(CircularlyAccessibleValueObject[])
hmChildVOs.get(tableCode);
}
/**
*为特定子表设置VO数据
*/
PublicvoidsetTableVO()(StringtableCode,CircularlyAccessibleValueObject[]vos){
hmChildVOs.put(tableCode,vos);
}
/**
*缺省的页签编码
*/
PublicStringgetDefaultTableCode(){
ReturngetTableCodes()[0];
}
P
{
Returnnull;
}
P
returnnull;
}
P
Returnnull;
}
}
代码的解释:
HYBillVO类是UI工厂定义的继承自AggregatedValueObject的类。
它实现了AggregatedValueObject的抽象方法。
返回的子表编码必须与单据模板定义的页签编码一致,这样数据才能正确显示。
2.定义单据界面控制类
需要重点强调的是以下代码
publicString[]getBillVoName(){
returnnewString[]{
//聚合VO
//主表
//子表一
//子表二
};
}
3.定义事件处理类
如果没有特殊的按钮事件处理,现在暂时可以不创建
4.定义业务代理类
对于多子表的单据,一定要创建业务代理类并重载loadChildDataAry方法如下所示:
PublicclassSampleCardDelegatorextendsBDBusinessDelegator{
/**
*取得不同表体页签的数据
*/
P
//根据主表主键,取得子表一的数据
SampleBodyVO[]AVOs=(SampleBodyVO[])queryByCondition(SampleBodyVO.class,”pk_sample=’”+key+”’andisnull(dr,0)=0”);
//根据主表主键,取得子表二的数据
SampleBody_BVO[]BVOs=(SampleBody_BVO[])queryByCondition(SampleBody_BVO.class,”pk_sample=’”+key+”’andisnull(dr,0)=0”);
//将查询数据放入hashtable并返回
HashtabledataHashTable=newHashtable();
If(AVOs!
=null&&AVOs.length>0){
dataHashTable.put(tableCodes[0],AVOs);//将查询的数据子表一的数据放入hashtable
}
If(BVOs!
=null&&BVOs.length>0){
dataHashTable.put(tableCodes[1],BVOs);//将查询的数据子表二的数据放入hashtable
}
ReturndataHashTable;
}
}
5.定义单据UI类
创建一个继承MultiChildBillCardUI类的单据UI类,并关联上先前创建的界面控制类,业务代理类:
/**
*关联上界面控制类
*/
ProtectedICardControllercreateController(){
ReturnnewSampleCardController();
}
/**
*关联上业务代理类
*/
ProtectedBusinessDelegatorcreateBusinessDelegator(){
ReturnnewSampleCardDelegator();
}
如何制作列表型单据
列表型单据统一的界面基类是ListCardUI,统一的事件处理基类是ListEventHandler,统一的界面控制接口为IListController。
对于数据表满足真正的主子表结构的单据,要开发单表头,单表体,多子表的单据非常简单,只是在类的继承关系上有所不同,因此在制作列表型单据时,绝大部分过程都可以仿照卡片型单据的制作。
标准的列表型单据和卡片型单据相比,不同之处是:
列表型单据的控制器实现IListController接口,并且应该把按钮的设置实现在getListButtonAry方法中,如:
Publicint[]getListButtonAry(){
Returnnewint[]{
IBillButton.Query,
IBillButton.Edit,
IBillButton.Line,
IBillButton.Save,
IBillButton.Cancel,
IBillButton.Refresh,
};
}
与多子表的卡片单据相比,有两个不同:
1.多子表列表型单据的UI类继承自MultiChildlistUI类;
2.多子表列表型单据的界面控制类实现IListController接口。
需要注意的是:
列表型单据也应该创建自己的业务代理类,负责加载多页签的数据。
单表头和单表体的列表型单据:
因为列表界面的表头和表体都是由列表组成的,所以单表头和单表体对于列表型单据在界面显示上是一致的。
UI工厂定义了ISingleController接口来指定单据时单表头还是单表体,因此,如果单据的界面控制类实现ISingleController接口,辅之以配套的单据模板,就可以实现单列表的界面。
需要注意的是:
1.列表型单据不支持新增,而卡片型单据可以新增.2.就是列表型单据支持UI初始化时自动加载数据,而卡片型单据要初始化时自动加载,只能在构造函数中调用数据加载的方法。
虚拟主子表的列表型单据:
制作虚拟主子表的列表型单据,基本策略和办法还是和卡片型单据一样。
因为列表型单据在UI初始化时可以调用加载单据数据的方法。
BillListUI初始化时调用initBillData方法加载单据数据因此我们在UI子类重载此方法:
/**
*初始化时加载单据数据
*/
ProtectedvoidinitBillData(StringstrWhere)throwsException{
If(strWhere==null)
strWhere=”1=1”;
strWhere=“(“+strWhere+”)and(isnull(dr,0)=0)”;
SuperVO[]queryVos=getBusiDelegator().queryHeadAllData(Class.forName(getUIControl().getBillVoName()[1]),getUIControl().getBillTye(),strWhere);
//清空缓冲数据
getBufferData().clear();
if(queryVos==null||query.length==0){
setBillOperate(IBillOPerate.OP_INIT);
setListHeadData(queryVos);
getBufferData().setCurrentRow(-1);
}else{
//将VO数据分组
AggregatedValueObject[]bills=createBillVOs(queryVos);
getBufferData().addVOsToBuffer(bills);
//将表头数据加到表头的列表中
setListHeadData(getBufferData(