EBS 11.5.10.2
創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括伊通網(wǎng)站建設(shè)、伊通網(wǎng)站制作、伊通網(wǎng)頁(yè)制作以及伊通網(wǎng)絡(luò)營(yíng)銷(xiāo)策劃等。多年來(lái),我們專(zhuān)注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,伊通網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶(hù)以成都為中心已經(jīng)輻射到伊通省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶(hù)的支持與信任!
需求
下圖是Oracle標(biāo)準(zhǔn)頁(yè)面,有一個(gè)簡(jiǎn)單的開(kāi)發(fā)需求,當(dāng)Expense Template等于“管理費(fèi)用”時(shí),Approver的LOV輸入框默認(rèn)為“XXX”,并且LOV只讀,不能進(jìn)行選擇。
分析
這個(gè)看似極其簡(jiǎn)單的開(kāi)發(fā),其背后所隱藏的技術(shù)知識(shí)卻是不那么簡(jiǎn)單的。
當(dāng)Expense Template選擇為“管理費(fèi)用”時(shí),Approver LOV輸入框只讀,這里牽涉到的開(kāi)發(fā)基本為給Expense Template加上FireAction的功能,
然后在Expense Template的Value Change事件中去修改Approver LOV的只讀屬性。
因?yàn)殚_(kāi)發(fā)規(guī)范是不允許直接修改Oracle的代碼,所以此開(kāi)發(fā)將通過(guò)集成標(biāo)準(zhǔn)的控制器類(lèi),在客戶(hù)化的控制器類(lèi)中實(shí)現(xiàn)添加Expense Template的FireAction功能,和修改Approver LOV只讀屬性,
然后通過(guò)個(gè)性化,將控制器類(lèi)替換成客戶(hù)化的控制器類(lèi)。
技術(shù)要點(diǎn)
1,修改Approver LOV的只讀屬性
剛剛進(jìn)行OAF開(kāi)發(fā)的開(kāi)發(fā)人員可能覺(jué)得這是很簡(jiǎn)單的事,只要在客戶(hù)化的控制器類(lèi)的processFormRequest()方法中調(diào)用以下代碼:
OAMessageLovInputBean lovBean = (OAMessageLovInputBean)webBean.findChildRecursive("Approver"); lovBean.setReadOnly(true);
就可以實(shí)現(xiàn)了,如果這樣做開(kāi)發(fā),那么就錯(cuò)了,在運(yùn)行時(shí)會(huì)拋出異常:
The OA passivation framework coding standard has been violated. Web bean properties cannot be modified in the controller processFormData or processFormRequest method. Web bean properties should be modified in the processRequest method only.
(這里有兩個(gè)方法是例外,setValue()和setText(),因?yàn)閂alue并不影響控件樹(shù))為什么把LOV設(shè)為只讀會(huì)出錯(cuò)呢?這是因?yàn)镺AF在運(yùn)行時(shí),表現(xiàn)為一棵控件樹(shù)。
當(dāng)進(jìn)入頁(yè)面時(shí),控件樹(shù)被初始化創(chuàng)建,而當(dāng)用戶(hù)事件觸發(fā)POST請(qǐng)求時(shí),控件樹(shù)并不會(huì)被重新生成(提高性能),要改變控件的屬性只有兩個(gè)辦法,一個(gè)是重新生成控件樹(shù),二是使用PPR。
方法一:重構(gòu)控件樹(shù)
重構(gòu)控件樹(shù)就意味著在processFormRequest()方法處理事件時(shí),需要Forward到本頁(yè),并通過(guò)參數(shù)控制來(lái)設(shè)置Approver LOV只讀,這樣會(huì)刷新整個(gè)頁(yè)面,而且對(duì)編碼也帶來(lái)困難。
方法二:使用PPR
實(shí)現(xiàn)方法是利用OAF數(shù)據(jù)綁定機(jī)制,將Approver LOV的ReadOnly屬性綁定到視圖對(duì)象的屬性,通過(guò)改變視圖對(duì)象屬性的值來(lái)控制Approver LOV的只讀。
這里又引出第2個(gè)技術(shù)要點(diǎn):
2,動(dòng)態(tài)創(chuàng)建視圖對(duì)象
創(chuàng)建視圖對(duì)象需要首先創(chuàng)建OAViewDef對(duì)象,然后利用OAViewDef對(duì)象來(lái)創(chuàng)建視圖對(duì)象。
這里談一下Oracle的一個(gè)開(kāi)發(fā)規(guī)范,OAViewDef接口在oracle.apps.fnd.framework.server包下,按照Oracle的規(guī)范,任何webui下的類(lèi)不允許import任何server下的類(lèi)。我是一個(gè)規(guī)范的嚴(yán)格遵守者,這樣就會(huì)使開(kāi)發(fā)變得更復(fù)雜。
要在server包下引用OAViewDef接口,就必須創(chuàng)建應(yīng)用程序模塊,將動(dòng)態(tài)創(chuàng)建視圖對(duì)象的代碼移到應(yīng)用程序模塊中實(shí)現(xiàn)。在客戶(hù)化控制器類(lèi)中,動(dòng)態(tài)創(chuàng)建應(yīng)用程序模塊,然后調(diào)用應(yīng)用程序模塊的方法。
實(shí)現(xiàn)步驟
假設(shè)開(kāi)發(fā)人員對(duì)Oracle標(biāo)準(zhǔn)的頁(yè)面結(jié)構(gòu)都已經(jīng)非常了解了,包括需要集成哪個(gè)標(biāo)準(zhǔn)的控制器,頁(yè)面上所使用的視圖對(duì)象。
1、創(chuàng)建客戶(hù)化應(yīng)用程序模塊cux.oracle.apps.ap.oie.entry.server.CuxPVOAM
2、創(chuàng)建視圖對(duì)象cux.oracle.apps.ap.oie.entry.server.CuxPVO,視圖對(duì)象中只有一個(gè)臨時(shí)屬性ReadOnlyFlag,類(lèi)型為Boolean(此步可選)
3、創(chuàng)建客戶(hù)化控制器類(lèi),繼承標(biāo)準(zhǔn)的控制器類(lèi)
4、在CuxPVOAMImpl.java中創(chuàng)建兩個(gè)方法:
import oracle.apps.fnd.framework.OAViewObject; import oracle.apps.fnd.framework.server.OAViewDefImpl; import oracle.jbo.AttributeDef; import oracle.jbo.Row; …… public void initPVO() { OAApplicationModuleImpl rootAM = (OAApplicationModuleImpl)getRootApplicationModule(); // 創(chuàng)建視圖對(duì)象 OAViewDefImpl viewDef = (OAViewDefImpl viewDef)getOADBTransaction().createViewDef(); viewDef.setFullName("CuxPVODef"); viewDef.setViewObjectClass("oracle.apps.fnd.framework.server.OAViewObjectImpl "); viewDef.addTransientAttrDef("ReadOnlyFlag", "java.lang.Boolean", null, false, AttributeDef.UPDATEABLE); OAViewObject pvo = (OAViewObject)rootAM.createViewObject("CuxViewPVO", viewDef); // 初始化PVO if (!pvo.isPreparedForExecution()) { pvo.executeQuery(); } pvo.setMaxFetchSize(1); Row row = pvo.createRow(); pvo.insertRow(row); row.setAttribute("ReadOnlyFlag", Boolean.FALSE); } public void handleTemplateChange() { OAApplicationModuleImpl rootAM = (OAApplicationModuleImpl)getRootApplicationModule(); OAViewObject vo = (OAViewObject)rootAM.findViewObject("XxxVO1"); //標(biāo)準(zhǔn)的VO OAViewObject pvo = (OAViewObject)rootAM.findViewObject("CuxViewPVO"); if () { pvo.first().setAttribute("ReadOnlyFlag", Boolean.TRUE); vo.first().setAttribute("Xxx", ); // 設(shè)置Approver LOV綁定的視圖對(duì)象屬性值 } else { pvo.first().setAttribute("ReadOnlyFlag", Boolean.FALSE); } } }
5、在客戶(hù)化控制器中添加相應(yīng)代碼
processRequest代碼:
public void processRequest(OAPageContext pageContext, OAWebBean webBean) { super.processRequest(pageContext, webBean); // 啟用Expense Template的FireAction功能 OAMessageChoiceBean choiceBean = (OAMessageChoiceBean)webBean.findChildRecursive("ExpenseTemplate"); choiceBean.setFireActionForSubmit("change", null, null, true); // 創(chuàng)建客戶(hù)化應(yīng)用程序模塊 OAApplicationModule rootAM = pageContext.getRootApplicationModule(); OAApplicationModule pvoAM = (OAApplicationModule)rootAM.findApplicationModule("CuxPVOAM"); if(pvoAM == null) { rootAM.createApplicationModule("CuxPVOAM","cux.oracle.apps.ap.oie.entry.server.CuxPVOAM"); pvoAM = HssCustomizeHelper.getNestedAMInstance(rootAM, "CuxPVOAM"); } pvoAM.invokeMethod("initPVO"); // 將ReadOnly屬性綁定到視圖對(duì)象屬性 OAMessageLovBean approverLov = (OAMessageChoiceBean)webBean.findChildRecursive("Approver"); approverLov.setAttributeValue(READ_ONLY_ATTR, new OADataBoundValueViewObject(approverLov,"ReadOnlyFlag","CuxPVO")); }
將開(kāi)發(fā)測(cè)試后的代碼發(fā)布到服務(wù)器。(測(cè)試可以在本地,將頁(yè)面上的控制器類(lèi)替換成客戶(hù)化的控制器來(lái)進(jìn)行)
processFormRequest代碼:
public void processFormRequest(OAPageContext pageContext, OAWebBean webBean) { super.processFormRequest(pageContext, webBean); OAApplicationModule rootAM = pageContext.getRootApplicationModule(); OAApplicationModule pvoAM = (OAApplicationModule)rootAM.findApplicationModule("CuxPVOAM"); if(pvoAM == null) { rootAM.createApplicationModule( "CuxPVOAM","cux.oracle.apps.ap.oie.entry.server.CuxPVOAM"); pvoAM = HssCustomizeHelper.getNestedAMInstance(rootAM, "CuxPVOAM"); } if ("change".equals(pageContext.getParameter(EVENT_PARAM))) { pvoAM.invokeMethod("handleTemplateChange"); } }
HssCustomizeHelper.getNestedAMInstance()的代碼如下:
public static OAApplicationModule getNestedAMInstance(OAApplicationModule parentAM, String nestedAMName) { OAApplicationModule am = null; String[] amNames = parentAM.getApplicationModuleNames(); for (int i=0; i< amNames.length; i++) { if (amNames[i].endsWith(nestedAMName)) { return (OAApplicationModule)parentAM.findApplicationModule(amNames[i]); } else { am = getNestedAMInstance((OAApplicationModule)parentAM.findApplicationModule(amNames[i]),nestedAMName); if (am != null) { return am; } } } return am; }
7、重啟Apache
8、進(jìn)入頁(yè)面,設(shè)置個(gè)性化,替換標(biāo)準(zhǔn)的控制器類(lèi)為客戶(hù)化控制器類(lèi)。
–
1.jpg