1. 程式人生 > >用友NC57 基礎

用友NC57 基礎

模式化開發的開發步驟


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進行加工。


★ 後臺校驗必須統一在後臺校驗類中進行。