(这里有两个方法是例外,setValue()和setText(),因为Value并不影响控件树)为什么把LOV设为只读会出错呢?这是因为OAF在运行时,表现为一棵控件树。
当进入页面时,控件树被初始化创建,而当用户事件触发POST请求时,控件树并不会被重新生成(提高性能),要改变控件的属性只有两个办法,一个是重新生成控件树,二是使用PPR。
方法一:重构控件树
重构控件树就意味着在processFormRequest()方法处理事件时,需要Forward到本页,并通过参数控制来设置Approver LOV只读,这样会刷新整个页面,而且对编码也带来困难。
方法二:使用PPR
实现方法是利用OAF数据绑定机制,将Approver LOV的ReadOnly属性绑定到视图对象的属性,通过改变视图对象属性的值来控制Approver LOV的只读。
这里又引出第2个技术要点:
2,动态创建视图对象
创建视图对象需要首先创建OAViewDef对象,然后利用OAViewDef对象来创建视图对象。
这里谈一下Oracle的一个开发规范,OAViewDef接口在oracle.apps.fnd.framework.server包下,按照Oracle的规范,任何webui下的类不允许import任何server下的类。我是一个规范的严格遵守者,这样就会使开发变得更复杂。
要在server包下引用OAViewDef接口,就必须创建应用程序模块,将动态创建视图对象的代码移到应用程序模块中实现。在客户化控制器类中,动态创建应用程序模块,然后调用应用程序模块的方法。
实现步骤
假设开发人员对Oracle标准的页面结构都已经非常了解了,包括需要集成哪个标准的控制器,页面上所使用的视图对象。
1、创建客户化应用程序模块cux.oracle.apps.ap.oie.entry.server.CuxPVOAM
2、创建视图对象cux.oracle.apps.ap.oie.entry.server.CuxPVO,视图对象中只有一个临时属性ReadOnlyFlag,类型为Boolean(此步可选)
3、创建客户化控制器类,继承标准的控制器类
4、在CuxPVOAMImpl.java中创建两个方法:
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();
// 创建视图对象
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", .FALSE);
}
public void handleTemplateChange()
{
OAApplicationModuleImpl rootAM = (OAApplicationModuleImpl)getRootApplicationModule();
OAViewObject vo = (OAViewObject)rootAM.findViewObject("XxxVO1"); //标准的VO
OAViewObject pvo = (OAViewObject)rootAM.findViewObject("CuxViewPVO");
if ()
{
pvo.first().setAttribute("ReadOnlyFlag", .TRUE);
vo.first().setAttribute("Xxx", ); // 设置Approver LOV绑定的视图对象属性值
}
else
{
pvo.first().setAttribute("ReadOnlyFlag", .FALSE);
}
}
}
5、在客户化控制器中添加相应代码
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);
// 创建客户化应用程序模块
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属性绑定到视图对象属性
OAMessageLovBean approverLov = (OAMessageChoiceBean)webBean.findChildRecursive("Approver");
approverLov.setAttributeValue(READ_ONLY_ATTR, new OADataBoundValueViewObject(approverLov,"ReadOnlyFlag","CuxPVO"));
}
将开发测试后的代码发布到服务器。(测试可以在本地,将页面上的控制器类替换成客户化的控制器来进行)
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, nestedAMName)
{
OAApplicationModule am = null;
[] 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、进入页面,设置个性化,替换标准的控制器类为客户化控制器类。
–