用友NC57 基础

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sir_jun/article/details/44627791
模式化开发的开发步骤


1.4 利用开发模型编写界面代码:
1.4.1 编写界面初始化控制器,设置VO类名,菜单按钮,单据类型等
public class TestManageControl
extends AbstractManageController {
/**单据类型*/
private String m_sBillType = "88";
/**单据VO信息*/
private String[] m_billVoNames =
new String[] {
TestBillVO.class.getName(),
TestheadVO.class.getName(),
TestbodyVO.class.getName()};
….
/**
 * 获得BusinessAction种类(BD\PF)。
 */
public int getBusinessActionType()
{
return nc.ui.trade.businessaction.IBusinessActionType.BD;
}


/**
 * 返回录入的列表的动作数组。
 * 具体的参见IBillButton
 */
public int[] getListButtonAry() {
return new int[]{
// IBillButton.Busitype,
IBillButton.Add,
IBillButton.Query,
IBillButton.Edit,
IBillButton.Del,
IBillButton.Action,
IBillButton.Ass,
IBillButton.File,
IBillButton.Card,
IBillButton.Print,
IBillButton.Refresh
};
}


1.4.2 编写主界面类
public class TestBillManageUI extends BillManageUI {




* 实例化界面初始控制器
*/
protected AbstractManageController createController() {
return new TestManageControl();
}


/**
 * 初始化UI界面的数据。
 * 创建日期:(2004-02-28 15:17:23)
 */
protected void initSelfData() {

       String strWhere = " isnull(dr,0)=0";


        SuperVO[] queryVos =
                new nc.vo.pub.SuperVO[0];
        try {
            queryVos = getBusiDelegator().queryHeadAllData(getUIControl().getBillType(), strWhere);




            //清空缓冲数据
            getBufferData().clear();
            if (queryVos != null && queryVos.length != 0) {
                for (int i = 0; i < queryVos.length; i++) {
                    AggregatedValueObject aVo =
                            (AggregatedValueObject) Class
                            .forName(getUIControl().getBillVoName()[0])
                            .newInstance();
                    aVo.setParentVO(queryVos[i]);
                    getBufferData().addVOToBuffer(aVo);
                }
                setListHeadData(queryVos);
                getBufferData().setCurrentRow(0);
                setBillOperate(IBillOperate.OP_NOTEDIT);
            } else {
                setListHeadData(queryVos);
                getBufferData().setCurrentRow(-1);
                setBillOperate(IBillOperate.OP_INIT);
            }


        } catch (Exception e) {
            e.printStackTrace();  //
        }
}
}


这样基本上完成了界面的编程。在运行程序前我们还要做一些设置。
















UI界面中树的使用


单个VO类构造树
一、 树数据的准备,即编写TreeData类
目前支持两种方法构造树:
1、 按编码,即vo中的编码体现了节点的上下级关系,TreeData类需要实现接口nc.ui.trade.pub.IVOTreeDataByCode,实现其中的四个方法。下面举例说明。
public nc.vo.pub.SuperVO[] getTreeVO() {//取树数据VOs
nc.vo.pm.pm0101.BdProjecttypeVO[] treeVOs  = null;
nc.ui.trade.bsdelegate.BusinessDelegator business = new nc.ui.trade.bsdelegate.BusinessDelegator();//取得业务代理,通过它访问数据库
try{
treeVOs  =
(nc.vo.pm.pm0101.BdProjecttypeVO[])business.queryByCondition(
nc.vo.pm.pm0101.BdProjecttypeVO.class,
null);//查询出VOs
}catch(java.lang.Exception e){}
return treeVOs;
}
public String getCodeFieldName() {//返回vo中用于构造树的编码属性
return "vcode";
}
public String getCodeRule() {//返回编码规则
return "/2/2/2/";
}
public String getShowFieldName() {//返回vo中需要作为树节点显示的那个vo属性
return "vname";
}
2、 按ID,即vo中有一属性指明该vo的上级节点,TreeData类需要实现接口nc.ui.trade.pub.IVOTreeDataByCode,实现如下四个方法:
public nc.vo.pub.SuperVO[] getTreeVO() //同上
public String getIDFieldName() {//返回vo的ID属性
return "pk_project";
}
public String getParentIDFieldName() {//返回vo的上级ID
return "fk_projtype";
}
public String getShowFieldName() {//返回vo中用于显示的属性
return "vname";
}
二、 UI类中的处理
UI类需要继承自nc.ui.trade.treecard.BillTreeCardUI,重载其中的方法createTreeData()返回步骤一中TreeData类的实例。如下:
protected nc.ui.trade.pub.IVOTreeData createTreeData() {
return new TreeDataProjectTypeByCode();
}
当选中树中的节点,默认的行为是载UI界面的右面显示节点的vo数据,可以通过重载方法public  boolean afterTreeSelected(VOTreeNode node)实现。
三、 Controller类中的处理
Controller类需要实现nc.ui.trade.treecard.ITreeCardController接口,实现如下与树相关的方法,如果UI类的右侧为单表或单卡,还要实现ISingleController接口。
public boolean isAutoManageTree() {//当数据变化后,是否需要自动更改树,
return true;                 //如:vo被删除后,对应的节点自动删除
}
public boolean isChildTree() {//是否把树放在表体的左面,返回false将把树放在整个UI
return false;           //的左侧
}
public boolean isTableTree() {//是否支持"表树",即表中嵌套树,关于表树另文介绍
return false;
}
public boolean isSingleDetail() {//ISingleController中的方法=true单表体,=false单表头。
return true;
}
四、 VO类中的处理
如果UI类右侧是主子表,则需在子表VO类中的方法中返回子表vo中的主表ID,如:
public java.lang.String getParentPKFieldName() {
return  "pk_forecastversion";
}






多个VO类构造树
按步骤一构造多个TreeData类,其它步骤同上,仅需重载UI类的afterInit(),添加如下代码方法:
public void afterInit() throws java.lang.Exception{
/*其它初始化*/
TreeDataProjectByID tdProject = new TreeDataProjectByID();
TreeDataForecastVersionByID tdVersion = new TreeDataForecastVersionByID();
insertNodeToTree(tdProject);
addBufferData(tdProject.getTreeVO());
insertNodeToTree(tdVersion);
addBufferData(tdVersion.getTreeVO());
/*其它初始化*/


}




















单据左树右多子表卡片使用说明
一. 界面效果图:
 


二. UI包中的类:
1.必要的类:
UI类:继承nc.ui.trade.treecard.MultiChildBillTreeCardUI;
Controller类:实现nc.ui.trade.treecard.ItreeCardController;
对于单表体,必须实现nc.ui.trade.bill.IsingleController;
BusinessDelegator类:继承nc.ui.trade.bsdelegate.BDBusinessDelegator;
TreeData类:对于按编码构造树的,实现nc.ui.trade.pub.IVOTreeDataByCode;
对于按id、parentid构造树的,实现nc.ui.trade.pub.IVOTreeDataByID;


2.可要的类:
EventHandler类:继承nc.ui.trade.treecard.TreeCardEventHandler;


三. VO包中的类:
数据VO类:继承nc.vo.pub.SuperVO;
聚合BillVO类:继承nc.vo.trade.pub.HYBillVO;实现nc.vo.pub.pf.IgetBusiDataForFlow、nc.vo.trade.pub.IexAggVO;


四. 需覆盖的方法:
1. UI类:
(1) public void afterEdit(nc.ui.pub.bill.BillEditEvent e);
如果需要动态构造树,需在此方法中调用createBillTree(IVOTreeData treeData)方法;
(2) public void afterTreeSelected(VOTreeNode node);
如果需要对选择的树节点进行操作,需覆盖此方法;
(3) protected BusinessDelegator createBusinessDelegator();
返回自己的BusinessDelegator;
(4) protected nc.ui.trade.bill.ICardController createController();
返回自己的Controller;
(5) protected nc.ui.trade.card.CardEventHandler createEventHandler();
如果有自己的EventHandler,则将之返回;
(6) protected nc.ui.trade.pub.IVOTreeData createTreeData();
返回自己的TreeData;
2. Controller类:
(1) public String getBillType();
返回单据类型;
(2) public java.lang.String[] getBillVoName();
返回多子表单据VO信息;
****注意:数组中VO的顺序需按照页签的顺序;另如果无表头,则将数组中表头VO位置处填入第一个页签的VO;
(3) public int getBusinessActionType();
根据单据是否走系统平台返回nc.ui.trade.businessaction.IBusinessActionType.PLATFORM或BD(如果是单表体,则必须返回BD);
(4) public int[] getCardButtonAry();
返回UI界面按钮数组;
(5) public String getChildPkField();
(6) public String getPkField();
(7) public boolean isChildTree();
左树是否在子Panel上,是则返回true,否则返回false;默认为false;
(8) public boolean isSingleDetail();
是否单表体,=true单表体,=false单表头;
3. BusinessDelegator类:
(1) public Hashtable loadChildDataAry(String[] tableCodes, String key);
多子表必须覆盖此方法,填如下内容:


//取得各子表VO数组
SuperVO[] vos =
(SuperVO []) queryByCondition(SuperVO.class,null);
//将过滤数据放入HAS
Hashtable dataHas = new Hashtable();
//按照顺序放到哈希表中
for (int i = 0; i < tableCodes.length; i++)
if (tableCodes[i].equals("tableCodei")) {
if (vos!=null) dataHas.put(tableCodes[i], vos);
}
}
//返回
return dataHas;
4. TreeData类:
对于按编码构造树的:
(1) public String getCodeFieldName();
返回编码字段名;
(2) public String getCodeRule();
返回编码规则;
(3) public String getShowFieldName();
返回树节点显示字段名;
(4) public nc.vo.pub.SuperVO[] getTreeVO();
返回构造树的SuperVO[];
对于按id、parentid构造树的:
(1) public String getIDFieldName();
返回ID字段名;
(2) public String getParentIDFieldName() ;
返回ParentID字段名;
(3) public String getShowFieldName();
返回树节点显示字段名;
(4) public nc.vo.pub.SuperVO[] getTreeVO();
返回构造树的SuperVO[];
5. 聚合BillVO类:
加成员变量:private HashMap hmChildVOs = new HashMap();
(1) public nc.vo.pub.CircularlyAccessibleValueObject[] getAllChildrenVO;
方法体中加:
ArrayList al=new ArrayList();
for (int i = 0; i < getTableCodes().length; i++){
CircularlyAccessibleValueObject[] cvos=getTableVO(getTableCodes()[i]);
if (cvos != null)
al.addAll(Arrays.asList(cvos));
}
return (SuperVO[])al.toArray(new SuperVO[0]);
(2) public String getDefaultTableCode();
方法体中加:return getTableCodes()[0];
(3) public java.lang.String[] getTableCodes();
返回子表tableCode数组;
(4) public java.lang.String[] getTableNames();
返回子表tableName数组;
(5) public nc.vo.pub.CircularlyAccessibleValueObject[] getTableVO(String tableCode)
方法体中加:
return (CircularlyAccessibleValueObject[])hmChildVOs.get(tableCode);
(6) public void setTableVO(String tableCode, nc.vo.pub.CircularlyAccessibleValueObject[] values);
方法体中加:hmChildVOs.put(tableCode, values);
五. 例程详见nc.ui.pm.pm060101、nc.vo.pm.pm060101;


































模式化开发相关的一些问题


闫长海 (2004.6.22)
1.1 关于动作执行前后的业务规则处理
1、 执行前处理:可以通过注册单据动作的执行前处理类来实现,注册单据时注册一个实现IUIBeforeProcAction的类来实现。
2、 执行后处理:只适用于基于平台的模式化开发,动作的返回值可以实现IUIAfterProcAction接口,系统会利用此接口自动处理动作执行后的业务规则处理。
当然也可以重载EventHandler,实现要处理的相应方法,比如Save方法,先写检查再调用基类的实现。如果想自己实现业务逻辑时可以完全自己编写。但不建议这样做。


1.2 后台业务逻辑检查
可以通过userObj来实现。实现AbstractBillUI中的setUserObject(java.lang.Object newObject) 生成UserObj来传递检查类。这个UserObj没有太多的约束,如果自己实现业务逻辑,UserObj的格式或接口可以自己来约定。这个对象可以从界面传递到后台。
如果用基础数据的默认业务逻辑,那么有这么几个接口:
IBDGetCheckClass:实现接口得到一个业务检查类名,那么这业务检查类应实现IBDBusicheck接口。
IRetCurrentDataAfterSave:是一个标志性的接口,保存后是否返回数据。
1.3 关于树模型构造
树模型构造有两种方式:
1. 根据ID关联来构造树模型。可以通过实现IVOTreeDataByID接口来实现,他返回一个树VO数组及关联关系等信息,界面模型能自动构造生成树。
2. 根据Code编码来构造树模型。可以通过实现IVOTreeDataByCode接口来实现,他返回一个树VO数组及code编码规则。
1.4 关于业务逻辑处理的返回值
1. 基于基础数据的处理,一般返回AggregatedValueObject数据
2. 基于平台的处理,返回对象的处理更多一些,一般返回值也是AggregatedValueObject数据,但实现一些相关的接口可以会产生一些不同的处理:IworkFlowRet, IprocActionRetObject, PFUtilActionVO,若返回对象实现了这些接口则系统会做相应的处理。
1.5 关于业务锁处理
系统会自动处理业务锁。


















字段唯一性校验组件使用说明
2004/02/18 李金巧






类简要描述:
1) 接口类nc.vo.mphtest.pub.IuniqueFieldCheck
? 方法:public ArrayList getFieldArray();
说明:
用于判断唯一性的字段Key的集合;
举例:FieldList = 
{
{"pk_corp", "itemCode"},
{"pk_corp", "itemName"},
{"pk_corp", "pk_cumandoc", "pk_invmandoc"}
}
{"pk_corp", "itemCode"}中,"pk_corp"&"itemCode"在数据库中唯一;
分别对三个数组进行校验
? 方法:public ArrayList getNameArray();
说明:
用于判断唯一性的字段中文名称,用于提示信息
举例:nameList = 
{
{"公司", "编码"},
{"公司", "名称"},
{"公司", "供应商", "存货"}
}
? 方法:public boolean isDetail();
说明:
是否表体Y-表体;N-表头
? 方法:public boolean isSingleTable();
说明:
是否单表Y-单表;N-主子表
2) 后台实现类:nc.bs.mphtest.pub.MphPubDMO
? 方法:public void isExistCurrentRecord(HYBillVO billVO, String checkClassName)
说明:
billVO为需要校验的数据VO
String为实现接口nc.vo.mphtest.pub.IuniqueFieldCheck的类名称;


使用说明:
1) 实现接口nc.vo.mphtest.pub.IuniqueFieldCheck,在接口中定义需要校验的VO的唯一性字段信息、单表信息等;
2) 在后台校验类中需要唯一性校验的地方调用nc.bs.mphtest.pub.MphPubDMO的相应方法;
例:在成本项目档案的保存校验中,需要调用该方法,则:


/**
 * 作者:李金巧 
 * 功能:成本项目后台校验类
 * 日期:(2004-2-17 13:26:33)
 */
public class CostItemBusiCheck implements nc.bs.trade.business.IBDBusiCheck,IBDACTION {
public void check(int intBdAction, AggregatedValueObject vo, Object userObj) throws Exception {
if(vo == null || vo.getChildrenVO() == null || vo.getChildrenVO().length <= 0) return;

CostitemVO item = (CostitemVO)vo.getChildrenVO()[0];

switch (intBdAction){
case this.DELETE:
onCheckDelete(item);
case this.SAVE:
onCheckSave((nc.vo.trade.pub.HYBillVO)vo);
}
}


/**
 * 作者:李金巧
 * 功能:VO保存前的校验:编码、名称不可重复,使用公共组件
 * 日期:(2004-2-17 13:31:03)
 * 修改日期,修改人,修改原因,注释标志:
 * 
 */
public boolean onCheckSave(nc.vo.trade.pub.HYBillVO vo) throws Exception {

boolean flag = true;
try{
MphPubDMO dmo = new MphPubDMO(); 
dmo.isExistCurrentRecord(vo,CostitemVO.class.getName());
}
catch(Exception e){
if(e instanceof BusinessException || e instanceof RemoteException){
throw e;
}
else throw new BusinessException("判断成本项目可否保存出错!");
}
return flag;
}


















单表体在启动之后就加载所有数据的处理方法:


1. 在UI中写一个方法进行数据的初始化,注:该方法不能在initSelfData()中调用,应当在UI构造子中调用;
2. 数据初始化过程:
查询所有数据->构造聚合VO并加载数据到该聚合VO->加载数据到缓冲(BufferData)->设置当前行
3. 初始化数据样例:
private void initializeData() {
try {
//查询所有数据
String strWhere = " isnull(dr,0)=0 ";
SuperVO[] vos = getBusiDelegator().queryByCondition(MphSingledocVO.class,strWhere);

HYBillVO billVO = new HYBillVO();

//加载数据到单据
billVO.setChildrenVO(vos);

//加载数据到缓冲
if (getBufferData().isVOBufferEmpty())
getBufferData().addVOToBuffer(billVO);//加载
else
getBufferData().setCurrentVO(billVO);//更新


//设置当前行 
getBufferData().setCurrentRow(0);
} catch (Exception e) {
e.printStackTrace();
}
}






















利用单据工厂制作单据的几点体会
★ 一张单据UI的制作过程在PPT"如何制作一张单据"中有详细说明。在出版组的重构中,要求所有单据模板和查询模板均用以前的,所以PPT说明中前15步工作都不必做,可以直接从第16步开始做起。


★ 在代码中可以没有BS和VO,但必须有UI。


★ UI层中的类
1. UI层中至少必须有一个界面类(各种界面继承相应的UI类)和一个控制类(实现相应的接口)。
2. 如需在单据动作中增加一些数据处理,则需增加一个事件处理类(继承nc.ui.trade.card.CardEventHandler),在该类中可以根据具体要求覆盖父类的所有事件处理方法(onBoSave,onBoLineAdd等)。
3. 如需定制自己的查询对话框,则需增加一个查询对话框类(继承nc.ui.trade.query.HYQueryDLG),可以在该类中实现各种条件筛选和初始化,此外还需在BS端增加一个DMO(继承nc.bs.trade.business.HYSuperDMO 实现nc.bs.pub.pf.IqueryData和nc.bs.pub.pf.IQueryData2 )。注:在调试环境中使用查询模板时,务必在nc.ui.trade.base.AbstractBillUI._getModuleCode()中返回各自的节点号。


★ VO层中的处理
VO必须通过运行nc.code.seed.v2.CodeSeed自动生成(继承自SuperVO),生成VO之后还须继承nc.vo.trade.pub.HYBillVO创建一个聚合VO,在该聚合VO中无需做任何处理。


★ 控制类中需要进行的修改:
1.public java.lang.String getBillType() {
return "S4";//返回单据类型
}
2.public java.lang.String[] getBillVoName() {
return new String[]{nc.vo.mphtest.indirectcost.IndirectcostBillVO.class.getName(),
nc.vo.mphtest.indirectcost.IndirectcostVO.class.getName(),
nc.vo.mphtest.indirectcost.IndirectcostVO.class.getName()};
}//返回VO名称


   3.public int getBusinessActionType() {
return nc.ui.trade.businessaction.IBusinessActionType.BD;
} //获得BusinessAction种类,基础档案返回BD,走平台单据返回PF


public int[] getCardButtonAry() {
return new int[]{
IBillButton.Edit,
IBillButton.Line,
IBillButton.Save,
IBillButton.Cancel,
IBillButton.Query,
IBillButton.Print,
};
} //返回录入的卡片动作数组


4.public java.lang.String getChildPkField() {
return "pk_indirectcost"; //返回单据子表主键
}


5.public boolean isSingleDetail() {
return true; //返回true为单表体,返回false为单表头
}


★ 在界面类中,需要在setDefaultData()中进行数据的初始化,包括界面数据的初始化和BufferData的初始化。界面的初始化和前台数据校验均在该类中进行。


★ 如果增加了控制类和事件处理类,则需覆盖界面类中的方法createController()和createEventHandler(),分别返回自己创建的控制类和事件处理类。


★ 如果增加了查询对话框,则需在自己的事件处理类中覆盖方法createQueryUI(),返回增加的查询对话框。


★ BillListUI的使用
1. BillListUI适用于表头和表体均为列表形式,但表头列表行数据不可编辑的使用环境。
2. 用户的xxUI继承nc.ui.trade.list. BillListUI;
3. 用户的xxController实现nc.ui.trade.bill.IlistController和nc.ui.trade.bill.IsingleController两个接口;
4. xxController类中的方法getChildPkField()和getPkField()分别返回子表主键和主表主键,注意实现。
5. xxController实现IsingleController接口而继承的方法isSingleDetail(),注意返回true,即为单表体形式。
6. 子表VO的方法getParentPKFieldName()返回主表外键,注意实现该方法,否则选中主表的某行,无法在子表显示相应的数据。


★ 前台校验(动作执行前处理)的步骤:
1. 在UI中继承BeforeActionCHK创建前台校验类;
2. 在UI中实现接口IcheckRules创建前台校验规则类;
3. 在客户化-二次开发工具-单据类型管理中注册校验类(将前台校验类名填入对应节点的"单据的动作执行前类"中。
4. 在校验规则类中编写自己的规则。


★ 后台校验的步骤:
1. 在VO中实现接口IBDGetCheckClass(只对BD), Serializable创建后台校验中间类;
2. 在BS端实现接口IBDBusiCheck, IBDACTION创建后台校验类,在该类的check方法中进行动作执行前后台校验处理;
3. 在校验中间类的getCheckClass方法中返回BS端校验类的完整路径名称;
4. 在UI类中重载方法getUserObject,返回校验中间类的完成路径名称。


★ 调用查询模板的步骤:
1. 在UI端继承HYQueryDLG创建自己的查询对话框(只有必要时才需创建),可在方法getWhereSQL()中构造自己的Where子句;
2. 在事件处理类中重载方法createQueryUI()并返回自己创建的查询对话框类的一个实例;
3. 如果是在调试环境中运行,则须在nc.ui.trade.base.AbstractBillUI._getModuleCode()中返回节点编号。


★ 对于单表体来说,如果不希望点击保存按钮后读出数据库中所有记录则须在后台校验中间类(即UI类中getUserObject()方法返回的类)中实现接口IretCurrentDataAfterSave(该接口没有方法,其作用相当于一个开关)。
★ 如果想要隐藏列表界面的表体,只需将pub_billtemplet中的options值设为空即可。如果要在代码中控制,则用如下代码:
getBillListPanel().getBodyUIPanel().setVisible(false);


★ 节点Title不在getTitle()中定义,现在直接返回pub_billtemplet中字段bill_templetcaption的值。
★ 前后台字段是否为空校验无需自己实现,统一在befortActionCHK中用公共校验工具校验。


★ UI界面的初始化可以用原来的,在initSelfData()中调用即可。


★ 如果需要对保存前的VO进行加工,则需重载getChangedVOFromUI()
可在该方法中对VO进行加工。


★ 后台校验必须统一在后台校验类中进行。

猜你喜欢

转载自blog.csdn.net/sir_jun/article/details/44627791