原文地址: Oracle OAF 应用构建基础之实现控制器

设计一个OA Controller

如OA Framework Page解析中所描述的,OA Controller定义了web beans的行为。具体来说,编写控制器代码的目的是:
•在运行时处理/初始化UI(包含那些通过编程方式添加的layout)
•拦截或响应按钮按下之类的用户事件

控制器不应该包含任何业务逻辑;这应该属于模型类。

必备知识

通常来说,在提出如何设计控制器之前,应该思考一下是否需要创建控制器。

作为一条规则,应该只在绝对必要的情况下才编写控制器。如果可以通过设计的方式创建页面,就不要通过编程的方式实现region和item。编程方式创建的web beans不能被个性化,重用或继承。而且,一些硬编码的layouts可能会丢失BLAF UI样式。

实现视图中说过,所有位于共同组件中的顶级regions必须与一个控制器关联。

粒度

OA Controllers可以与任何region关联(任何实现oracle.apps.fnd.framework.webui.beans.OAWebBeanContainer接口的web beans);不能将控制器与items关联。

许多OA Framework新手都想知道控制器应该是”多大“。应该一个页面一个,或一个功能region一个(比如“Search” region),或一个复合web bean(比如一个table)一个,或者?答案是要看情况。

最初,在一个非常简单的页面,你可能不需要任何控制器(如果没有工作要作就不需要创建控制器)。如果需要编写代码,你需要根据下面的条件决定创建什么样的控制器:
•利于封装,一个web bean实现了它自己的行为
•组件重用,如果组件被设置为重用,它必须是自包含,自已自足。
•代码实用性,尽管页面包含了8个regions时可以很容易的添加8个控制器(每个包含少量的代码),这种“纯”OO的观念可以导致代码维护困难,可能导致产品代码文件膨胀。

有一些方法可以帮助决定如何处理:
•永远不要从child bean中设置parent/grandparent web bean的属性。
•为相关联的region定义控制器来设置region和它的子孙region的属性。如果需要主控制器管理多个子/孙web bean,控制器应该与适当的父/祖父bean相关联。
•对于复杂的beans(比如OATableBean)应该将控制器关联到bean自身,或关联到一个简单的容器bean中(如果它实现功能逻辑单元)。

通常,应该为页面创建少于满足上面规则和考虑数量的控制器。对于非常简单的页面,通常是为pageLayout区域关联单个的控制器。对于更复杂的 页面,应该为各个功能组件(比如,查询页面中典型的“Search”区域控制器和“Results”区域控制器)创建少量不同的控制器。共享区域应该拥有 自己的适当的控制器。

模型性/重用

在同一组相关联的页面中,你有时将找到可以重用代码的机会。下面是创建模块性更强的控制器代码的方法:
•在控制器中添加私自己的私有方法。
•创建一个公用的控制器类(它是oracle.apps.fnd.framework.webui.OAControllerImpl),然后为有需要的页面/区域继承这个类。
•创建辅助的实用工具类,控制器中可以根据需要代理。这些类不需要实现任何OA Framework类或接口,应该被包含在与它们所辅助的控制器类所在的包中。注意,静态方法适合于在这些类中使用,当使用静态方法时,应该考虑下面的问题: ◦不能影响子类中的静态方法。
◦封装相关常量和静态方法。(There are packaging implications related to the use of constants and static methods )

线程安全

OA Framework被设计为支持多线程web bean访问(尽管还没有实现)。大部分对于你的代码来说是透明的,只有少量规则必须在控制器代码中遵守:
•如果在控制器或辅助类中使用静态方法,则永远不要包含状态。
•总是将页面的OAPageContext传递给任何web bean存储器(如果需要可以带OAPageContext)。比如,使用setText(OAPageContext pageContext, String text)代替setText(String text)。

状态管理

不要在控制器中或你实例化的辅助类中添加非易失性成员变量。OA Framework不会钝化成员变量,因此一旦虚拟机失效被支持后将不能恢复这些值。可以添加static final成员变量。

编码规则

创建一个控制器

为一个区域创建控制器:
1.在JDEveloper Structure页面中选择区域
2.右键选择Set New Controller...
3.在New Controller对话框中,输入包和类名。选择OK创建与选择区域关联的控制器。注意Inspector中的Controller Class属性值是类的全名,如: oracle.apps.fnd.framework.toolbox.tutorial.webui.HoMESearchCO。

JDeveloper将创建控制器模板。

/*===========================================================================+
| Copyright (c) 2001, 2003 Oracle Corporation, Redwood Shores, CA, USA |
| All rights reserved. |
+===========================================================================+
| HISTORY |
+===========================================================================*/
package oracle.apps.fnd.framework.toolbox.tutorial.webui; import oracle.apps.fnd.common.VersionInfo;
import oracle.apps.fnd.framework.webui.OAControllerImpl;
import oracle.apps.fnd.framework.webui.OAPageContext;
import oracle.apps.fnd.framework.webui.beans.OAWebBean; /**
* Controller for ...
*/
public class OrderSummaryCO extends OAControllerImpl
{
public static final String RCS_ID="$Header$";
public static final boolean RCS_ID_RECORDED =
VersionInfo.recordClassVersion(RCS_ID, "%packagename%"); /**
* Layout and page setup logic for a region.
* @param pageContext the current OA page context
* @param webBean the web bean corresponding to the region
*/
public void processRequest(OAPageContext pageContext, OAWebBean webBean)
{
super.processRequest(pageContext, webBean);
} /**
* Procedure to handle form. submissions for form. elements in
* a region.
* @param pageContext the current OA page context
* @param webBean the web bean corresponding to the region
*/
public void processFormRequest(OAPageContext pageContext, OAWebBean webBean)
{
super.processFormRequest(pageContext, webBean);
} }

注意: 缺省的模板内容不包含processFormData(OAPageContext pageContext, OAWebBean webBean)方法,这个方法在POST处理的第一个阶段被调用。如果需要(非常少见),可以将它加到控制器中。

注意: 也可以通过编程的方式将控制器与区域关联。查看OAWebBeanContainer中的setControllerClass(String javaClass)方法。

处理HTTP GET

在GET处理过程中,每个控制器的processRequest(OAPageContext pageContext, OAWebBean webBean)方法被按照它们被实例化时的层级结构而依次被调用。处理从pageLayout bean开始,然后递归处理整个层级结构。初始化页面——或影响层级结构中的web bean(通过设置属性,创建web bean等等)——属于processRequest()方法。

注意: 传递到processRequest()方法中的oracle.apps.fnd.framework.webui.OAWebBean参数是与当前控制器关联的区域。

下面是一个典型的processRequet的代码。它描绘的是根据从“search”页面传递过来的参数,初始化用于查看的“detail”页面。

/**
* Layout and page setup logic for region.
* @param pageContext the current OA page context
* @param webBean the web bean corresponding to the region
*/
public void processRequest(OAPageContext pageContext, OAWebBean webBean)
{
// Always call this before adding your own code.
super.processRequest(pageContext, webBean); // Get the purchase order number from the request.
String rderNumber = pageContext.getParameter("headerId"); // We need to set the page header text to include the PO order number for reference.
MesSageToken[] tokens = { new MessageToken("PO_NUMBER", orderNumber) }; // Always use a translated value from Message Dictionary when setting strings in
// your controllers.
String pageHeaderText = pageContext.getMessage("ICX", "FWK_TBX_T_PO_HEADER_TEXT", tokens); // Set the po-specific page title (which also appears in the breadcruMBS. Since this
// controller is associated with the page layout region, simply cast the webBean
// parameter to the right type and set the title. ((OAPageLayoutBean)webBean).setTitle(pageHeaderText); // Now we want to initialize the query for our single purchase order with all of its
// details.
OAApplicationModule am = pageContext.getApplicationModule(webBean);
Serializable[] parameters = { orderNumber };
am.invokeMethod("initDetails", parameters); } // end processRequest()

在调用super.processRequest(pageContxt, webBean)后,范例中的代码从request参数中获取名为“headerId(从Search页面传递过来的参数)”。这个值被显示在页面标题和 breadcrumbs上,并且它被传递给模型以便查询。
使用页面的title值定义页面标题和breadcrumbs:

由于显示于页面中的值必须被翻译,我们在Oracle应用消息字典(Oracle Application Message Dictionary)中创建了一个名为FWK_TBX_T_PO_HEADER_TEXT的消息,消息内容为“Purchase Order: &PO_NUMBER”。这个代码定义了以令牌PO_NUMBER作为Purchase Order Number的占位符,然后从oracle.apps.fnd.framework.webui.OAPageContext(它将操作委派给 AOL/J)中提取翻译后的版本。然后将翻译后的字符串作为页面标题。

警告: 不要在用户界面中使用硬编码的文本值。所有以编程方式显示的文本值必须来源于消息字典(Message Dictionary)。也可以在设计时在web bean中使用这种方式(所有显示的bean属性都是被翻译的),或者也可以从多国语言表中查询出值来显示。

最后,这个只读的”details“页面自动按给定的编号进行查询而不管它是否会被渲染。它通过将编号传递给页面根应用模块的initDetails()方法。然后应用模块将参数传递给适当的视图对象,在那里将参数与WHERE子句绑定并执行查询。

修改Bean属性

注意: 作为规则来说,更好的修改web bean属性的方法是使用局部页面渲染(partial page rendering (PPR))和SPEL,在Dynamic User Interface中有描述。在不能通过PPR和SPEL的环境下,也必须在processRequest()方法中修改web bean层级结构(这节被包含在GET处理一章中,也是由于只能在processRequest()方法中才允许修改web bean层级结构)。

如果需要以编程方式在响应表单提交的事件中修改层级结构,必须forward到同一个页面的processRequest()方法(见下面POST事件处理)。作出这个限制的原因有:
•确保web bean层级结构能在需要的时候被正确的重建。
•Beans被适当的初始化。主要是Rendered属性,或影响复杂组件渲染的prepareForRendering()方法。
•Bean层级结构被放在同一个方法中维护。

修改web bean的属性时,只需要简单的根据它的名称(在JDeveloper中赋给它的ID)查找到正确的bean,然后按下面的方法调用适当的方法。

警告: 当获得web bean时,在调用它的任何方法前都需要检查对象是否为空。即使你认为bean被包含于web bean层级结构中,但也有可能在用户使用个性化定制时半它隐藏了。

processRequest(OAPageContext pageContext, OAWebBean webBean)
{
// Always call this before adding your own code.
super.processRequest(pageContext, webBean); OATableBean table = (OATableBean)webBean.findIndexedChildRecursive("OrdersTable"); if (table == null)
{
MessageToken[] tokens = { new MessageToken("OBJECT_NAME", "OrdersTable")};
throw new OAException("ICX", "FWK_TBX_OBJECT_NOT_FOUND", tokens);
} // Set the purchase-order specific "control bar" select text:
// "Select Purchase Order(s) and..." String selectPOText = pageContext.getMessage("ICX", "FWK_TBX_T_SELECT_PO", null);
table.setTableSelectionText(selectPOText); }

使用findIndexedChildRecursive(String name)方法可以在整个web bean层级结构中查找到第一个与名称匹配的被索引的子对象。如果如果要修改的web bean是一个被命名的UIX子对象(或,如果你不确定它是否“被命名(named)“或”被索引(indexed)“),则使用 findChildRecursive(String name)方法。
如果需要修改控制器区域的属性,只需要将processRequest()的OAWebBean参数转换为正确的类型并调用需要的方法。

编程的方式创建Bean

注意: 本节包含于GET处理部分,因为只允许在processRequest()方法中修改web bean层级结构。

如果需要在响应表单提交事件中添加web bean到层级结构中,必须forward到同一个页面的processRequest()代码中执行。

作为规则,如果你可以通过设计的方式产生web bean就不应该通过编程的方式产生web beans。另外,如果你的页面与局部页面渲染相关,则也不能在运行时修改web bean层级结构。

对于那些极少见的必须手工实例化web bean的情况,则使用OAControllerImpl类中的createWebBean()工厂方法。不要直接使用web bean的构造器,不必担心要直接创建oracle.apps.fnd.framework.webui.OAWebBeanFactory,因为控制器 的createWebBean()方法代理了OAWebBeanFactory。

注意: 对于这些手工创建的beans,使用工厂方法时可以指定bean的“name”(JDeveloper中的ID属性)。避免使用deprecated的方 法,它允许你在创建web bean时不指定name。web bean的名称(name)在同一个页面中必须是一个唯一标识。另外,bean的名称可能被OA Framework用于BC4J对象实例名(比如应用模块实例),因此不应该包含Java命名中规定的无效字符。

比如,下面的代码描述了如何创建两个web bean并将它们添加到父区域中。

OATableLayoutBean tableLayout = (OATableLayoutBean)findIndexedChildRecursive("tableLayout");

// Create a row layout and give it the unique ID "topRow"
OARowLayoutBean row = (OARowLayoutBean)createWebBean(pageContext,
OAWebBeanConstants.ROW_LAYOUT_BEAN,
null, // no need to specify a data type
"topRow"); // Create a row layout and give it the unique ID "bottomRow"
OARowLayoutBean anotherRow = (OARowLayoutBean)createWebBean(pageContext,
OAWebBeanConstants.ROW_LAYOUT_BEAN,
null, // no need to specify a data type
"bottomRow"); // Always check to see if a web bean exists.
if (tableLayout != null)
{ // Add the two row layout beans to the table so the "topRow" renders above
// the "bottomRow"
tableLayout.addIndexedChild(row);
tableLayout.addIndexedChild(anotherRow);
}

也可以通过编程的方式将设计时定制的web bean关联到父区域中。比如,在下面的代码中,名为“HomeSearchRN”的stackLayout区域是在JDeveloper中定义的,但它 必须通过编程的方式创建side navigation component。

OASideNavBean sideNav = (OASideNavBean)createWebBean(pageContext,
OAWebBeanConstants.SIDE_NAV_BEAN,
null, // no need to specify a data type
"sideNav" // always specify name); OAStackLayoutBean search =
(OAStackLayoutBean)createWebBean(pageContext,
"/oracle/apps/fnd/framework/toolbox/tutorial/webui/HomeSearchRN",
"HomeSearchRN", // always specify name
true); // region created in Oracle JDeveloper OA Extension sideNav.addIndexedChild(search);

约束

OA Framework并不能很容易的支持通过编程的方式添加、删除、替换任何“默认(default)”区域中的子对象(比如OA Extension中的defaultSingleColumn区域是 oracle.apps.fnd.framework.webui.beans.layout.OADefaultSingleColumnBean的实 例)。这些区域应该通过设计的方式定义。如果绝对必须替换或删除“默认(default)”区域(不能添加item),则要遵循下面的步骤:
1.调用webBean.findIndexedChildRecursive()获得要被移除或替换的子web bean。
2.通过调用子web bean的childWebBean.getAttribute(OAWebBeanConstants.PARENT)方法获取子web bean的父对象。

注意: OAWebBeanConstants.PARENT属性被用作OA Framework内部开发使用(如果查看OAWebBeanConstants的Javadoc将看到警告信息)。只可以对缺省区域使用这个入口。另 外,缺省区域已经不被推荐使用(deprecated),因此不应该在新的开发中使用这这些。
1.执行从父bean中替换或移除自己的操作。

处理HTTP POST(表单提交)

在HTTP POST处理过程中,OA Framework首先检查页面的web bean层级结构是否位于它的缓存中。如果没有(资源被限制或者用户使用了浏览器的后退按钮),则OA Framework必须在处理前重新创建web bean层级结构。这意味着processRequest()中的代码被重新执行,就好像浏览器发出了一个HTTP GET请求。

注意: 可能发生的重建web bean层级结构将导致产生了大量编码上的考虑,这些在Chapter 6: Supporting the Brower Back Button和OA Framework View和Controller编码规范中有完整的描述。

POST的主要处理过程发生在整个web bean层级结构中的两个分开的途径中:
•首先,OA Framework将在整个web bean层级结构中递归调用web bean的processFormData()方法将form的数据写入模型。任何需要在这个处理阶段执行的代码应该添加到控制器的 processFormData(OAPageContext pageContext, OAWebBean webBean)方法。
•假设第一阶段的处理过程中没有发生异常,OA Framework处理第二阶段,在每个web bean上调用processFormRequest(OAPageContext pageContext, OAWebBean webBean)。

processFormData()

多数情况(并非所有情况)下没有理由要覆盖这个方法。实际上,使用这种方法只会在极端的情况下,而不像是在OA Framework应用中:如果区域的数据源不是一个视图对象,因此没有为各个web bean定义视图实例和属性,这时你可以在区域的processFormData()方法中编码将子web bean的数据写入适当的数据源。

注意: OA Framework在item级实现了processFormData(),但你只能在region级别覆盖它,因此如果你实现了这个方法则必须处理 region中的所有item。如果是有选择性的修改,则要记得先要调用super.processFormData(OAPageContext pageContext, OAWebBean webBean)。

processFormRequest()

任何处理用户表单提交的动作属于processFormRequest()方法。

下面是一个典型的processFormRequest()的代码。它描述了好何决定是哪个组件的区域表单提交(在这里是“Go“按钮),如果开始 在模型中查询,如何执行一个JSP Forward回到同一个页面以便在processRequest()方法中修改web bean的属性。

OASideNavBean sideNav = (OASideNavBean)createWebBean(pageContext,
OAWebBeanConstants.SIDE_NAV_BEAN,
null, // no need to specify a data type
"sideNav" // always specify name); OAStackLayoutBean search =
(OAStackLayoutBean)createWebBean(pageContext,
"/oracle/apps/fnd/framework/toolbox/tutorial/webui/HomeSearchRN",
"HomeSearchRN", // always specify name
true); // region created in Oracle JDeveloper OA Extension sideNav.addIndexedChild(search);

这个例子展示了如何使用setForwardUrl()方法传递请求参数,包括了如休替换一个已经存在的参数值(在这里,“X”将成为目标页面被“忽略(ignore)“的值)。 import

com.sun.java.util.collections.HashMap;
import oracle.bali.share.util.IntegerUtils; ... processFormRequest(OAPageContext pageContext, OAWebBean webBean)
{
// Always call this before adding your code
super.processFormRequest(pageContext, webBean); String poEvent = pageContext.getParameter("poEvent"); HashMap params = new HashMap(2); // Replace the current poEvent request parameter value with "X"
params.put("poEvent", "X"); // IntegerUtils is a handy utility
params.put("poStep", IntegerUtils.getInteger(5)); pageContext.setForwardURL("OA.jsp?page=/oracle/apps/dem/employee/webui/EmpDetailsPG", // target page
null, // not necessary with KEEP_MENU_CONTEXT
OAWebBeanConstants.KEEP_MENU_CONTEXT, // no change to menu context
null, // No need to specify since we're keeping menu context
params, // request parameters
true, // retain the root application module
OAWebBeanConstants.ADD_BREAD_CRUMB_YES, // display breadcrumbs
OAException.ERROR); // do not forward w/ errors
}

注意: 如果视图对象被作为被显示的web bean的数据源,则不要移除视图对象和它的行,以及嵌套包含的应用模块。如果你需要在定向到页面之前移除这些对象,则将不会显示视图对象中数据(出于性 能优化的原因),在作出移除的调用后,确保使用 oracle.apps.fnd.framework.webui.OAPageContext.forwardImmediatelyOAPageContext.setforwardURL 方法定向到新页面。这保证了forward动作将立即发生,当前页面中forward调用后其它的web bean将不会处理;否则,移除视图对象或行实例将导致后续处理产生不良影响。

使用不同的技术POST到OA Framework页面

如果你使用不同的技术(比如JTT页面)POST到OA Framework页面,OA Framework只会执行目录页面的processRequest段。它不执行processFormData和processFormRequest段。

与模型交互

简单来说,应该只从OA Controller中直接访问应用模块。换言之,在控制器中唯一有效的模型导入代码如下:
import oracle.apps.fnd.framework.OAApplicationModule;
不应该访问视图对象直接执行查询、迭代行集或与下层的实体交互。比如,下面的代码(尽管技术上是可行的)是不符合OA Framework Controller Coding Starndards的。

import oracle.apps.fnd.framework.OAViewObject;
... // Get the root application module
OAApplicationModule am = pageContext.getRootApplicationModule(); // Find the view object you want to query
OAViewObject vo = (OAViewObject)am.findViewObject("<instanceName>"); ...

如果需要执行视图对象查询,应该按下面在“Search”区域中按下“Go”按钮的事件处理的例子的方式。 
首先,添加方法到应用模块中(这个例子中,它是页面的根应用模块)它接收查询,然后将它委派给视图对象执行查询(查看

实现模型获取关于查询的信息)。

public void search(String orderNumber, String created, String showMyOrders)
{
PoSummarySimpleExpVOImpl vo = getPoSummarySimpleExpVO(); // Always check for the null condition if the VO cannot be found/created
if (vo == null)
{
MessageToken[] tokens = { new MessageToken("OBJECT_NAME", "PoSummarySimpleExpVO")};
throw new OAException("ICX", "FWK_TBX_OBJECT_NOT_FOUND", tokens);
} vo.initQuery(orderNumber, created, showMyOrders); } // end search()

然后,添加如下的按钮处理代码到控制器中,它调用应用模块中对应的方法。 
注意,总是应该在processFormRequest()的代码中检查事件源;不要假设浏览器发送的POST请求是由于你的item被选中了(即使是一个只有一个按钮的简单页面)。在后台,OA Framework经常提交页面的表单,而这可能是不是你所期望的。

processFormRequest(OAPageContext pageContext, OAWebBean webBean)
{ // Check to see if the "Go" button was pressed...
if (pageContext.getParameter("gButton") != null)
{
// Get the search criteria
String rderNumber = pageContext.getParameter("SearchOrder");
String created = pageContext.getParameter("Created");
String showMyOrders = pageContext.getParameter("MyOrders"); OAApplicationModule am = pageContext.getApplicationModule(webBean); // All parameters passed using invokeMethod() must be serializable.
Serializable[] parameters = { orderNumber, created, showMyOrders };
am.invokeMethod("search", parameters);
}
}

技巧: 不要在服务端BC4J组件中调用invokeMethod(),任何你传递的参数必须是Serializable类型的。上例中展示的的 invokeMethod()方法需要的参数都是字符串。如果需要传递其它对象类型,可以使用带一个类型数组参数版本的invokeMethod()。比 如:
Class[] parameterTypes = { String.class, Hashtable.class, Number.class ...};
am.invokeMethod("search", parameters, parameterTypes);
类似地,由于视图对象是实体对象的导管——不应该在控制器中直接与视图对象交互——也应该通过应用模块来处理实体操作。 
注意: 如实现模型中描述的,添加到应用模块中的方法命名应该与UI“事件(events)“对应。比如,如果用户按了“Create”按钮,应用模块方法应该命名为“create”等等。

创建的实例

processFormRequest(OAPageContext pageContext, OAWebBean webBean)
{
OAApplicationModule am = pageContext.getApplicationModule(webBean);
am.invokeMethod("create", null);
}

删除的实例

这个例子展示了调用共享区域中的嵌套应用模块中的delete方法而不是调用页面根应用模块中的方法。

processFormRequest(OAPageContext pageContext, OAWebBean webBean)
{ if (pageContext.getParameter("DeleteYesButton") != null)
{
// User has confirmed that she wants to delete this purchase order.
// Invoke a method on the AM to set the current row in the VO and
// call remove() on this row. String poHeaderId = pageContext.getParameter("poHeaderId");
Serializable[] parameters = { poHeaderId }; OAApplicationModule am = pageContext.getApplicationModule(webBean);
am.invokeMethod("delete", parameters);
} ...

自定义动作实例(“Approve”)

processFormRequest(OAPageContext pageContext, OAWebBean webBean)
{
if (pageContext.getParameter("Approve") != null)
{
OAApplicationModule am = pageContext.getApplicationModule(webBean);
am.invokeMethod("approve");
}
}

提交操作实例

processFormRequest(OAPageContext pageContext, OAWebBean webBean)
{
// Simply telling the transaction to commit will cause all the Entity Object validation
// to fire.
//
// Note: there's no reason for a developer to perform. a rollback. This is handled by
// the OA Framework if errors are encountered during the processFormData phase. OAApplicationModule am = pageContext.getApplicationModule(webBean);
am.invokeMethod("apply");
}

禁用校验

有多个机会可以屏蔽在处理OA Framework HTTP POST过程中的校验。比如,实现表格中的”Add Another Row“中,在用户添加新行的操作时,可能不需要因为未填写完整的行数据而显示错误信息。同样,你可能在一个多步骤的页面流中想要将校验延时到最后一个预 览提交页面,或者通过tabs导航到同一个下层对象的不同视图上时。

禁用服务端校验

为了阻止从模型校验逻辑中抛出异常,在页面中与下面列表对应的bean上调用setServerUnvalidated(true)方法(记住在processRequest()方法中添加修改web bean的代码):
•OASubmitButtonBean
•OATableBean
•OAAdvancedTableBean
•OASubTabLayoutBean
•OANavigationBarBean
•OADefaultHideShowBean
•OAHideShowHeaderBean

注意: 也可以在设计时设置组件的Disable Server Side Validation属性为True,也可以为那些配置为提交表单的链接或图标设置禁用校验。查看下面的Javascript. URL一节获得更多信息。

当用户执行一个由这些bean导致的表单提交时,OA Framework按上面描述的方式执行所有的HTTP POST处理——包括执行属性级别的校验逻辑(实体级别的校验没有被执行)。如果在处理processFormData()过程中抛出了 oracle.apps.fnd.framework.OARowValException或 oracle.apps.fnd.framework.OAAttrValException异常(功它们被deprecated的子类),OA Framework只是简单的忽略这些异常,并继续执行就像没有遇到异常一样。

注意: OA Framework不会忽略processFormData()中的严重异常(比如NullPointerException)。这些会按正常的方式显示 出来,并且不会继续处理processFormRequest()。而且processFormRequest()中由你或者由BC4J抛出的异常都会被 正常的显示出来。

禁用客户端校验

当一个带的客户输入的数据的表单提交时,UIX执行一些基础的onSubmit JavaScript校验(它校验必填字段,数据类型和格式),如果校验通过就提交表单。为了屏蔽校验,也需要在上节“禁用服务端校验”中的bean列表 中的bean上调用setUnvalidated(true)方法。

注意: 也可以在设计时设置组件的Disable Server Side Validation属性为True,也可以为那些配置为提交表单的链接或图标设置禁用校验。查看下面的Javascript. URL一节获得更多信息。

技巧: 对于tables和HGrid组件,必须通过设置table和HGrid区域自己的属性启用/禁用客户端校验,因为你不能直接访问OANavigationBarBean的用作数据集导航的子web bean。注意,现在不能禁用这些组件的服务端校验。

错误处理

OA Framework自动显示模型层抛出的任何错误信息;不需要在控制器中做什么就能处理。
•查看Error Handling获取更多关于在控制器中抛出异常和在页面顶端显示错误、警告、确认信息。
•查看Chapter 4: Dialog Pages获取关于显示模型错误、警告、确认和信息的对话框页面。

JavaScript

UIX和OA Framework正在快速的添加新的功能以提供更好的用户体验(区域页面渲染、自动的表格统计等等)。当这些功能发布后,你将受益于这些功能,但是,在这之前你不应该自己实现这些功能。

简单来说,Javascript在OA Framework开发团队外是被禁止的。

JavaScript. URL

以前,如果需要配置链接或图像来提交页面表单(由于你需要在导航到新页面前处理事件),可以将它设置在UIX submitForm. Javascript函数中。

现在,应该配置fireAction事件来代替使用Javascript. URL。查看Declarative Submit Form文档获取其它信息。

Oracle OAF 应用构建基础之实现控制器 (转)的更多相关文章

  1. Gradle笔记——构建基础

    本篇文章主要介绍一下Gradle的构建基础. 它看起来似乎和android项目没多大关系.不能让人一下子理解android项目中的Gradle配置文件,可是这篇基础真的非常重要. 学习Gradle前, ...

  2. asp.net core系列 59 Ocelot 构建基础项目示例

    一.入门概述 从这篇开始探讨Ocelot,Ocelot是一个.NET API网关,仅适用于.NET Core,用于.NET面向微服务/服务的架构中.当客户端(web站点.ios. app 等)访问we ...

  3. 从头开始学gradle【Gradle 构建基础】

    构建基础 Project 和 task:projects 和 tasks是 Gradle 中最重要的两个概念. 任何一个 Gradle 构建都是由一个或多个 projects 组成.每个 projec ...

  4. 响应式流API的构建基础

    下面三个重要的概念是响应式流API的构建基础: 发布者是事件的发送方,可以向它订阅. 订阅者是事件订阅方. 订阅将发布者和订阅者联系起来,使订阅者可以向发布者发送信号. http://www.info ...

  5. .Net Core 商城微服务项目系列(一):使用IdentityServer4构建基础登录验证

    这里第一次搭建,所以IdentityServer端比较简单,后期再进行完善. 1.新建API项目MI.Service.Identity,NuGet引用IdentityServer4,添加类InMemo ...

  6. oracle(sql)基础篇系列(五)——PLSQL、游标、存储过程、触发器

      PL/SQL PL/SQL 简介 每一种数据库都有这样的一种语言,PL/SQL 是在Oracle里面的一种编程语言,在Oracle内部使用的编程语言.我们知道SQL语言是没有分支和循环的,而PL语 ...

  7. oracle(sql)基础篇系列(一)——基础select语句、常用sql函数、组函数、分组函数

        花点时间整理下sql基础,温故而知新.文章的demo来自oracle自带的dept,emp,salgrade三张表.解锁scott用户,使用scott用户登录就可以看到自带的表. #使用ora ...

  8. 使用OpenLDAP构建基础账号系统

    LDAP - Lightweight Directory Access Protocol,对该协议的具体应用,常见的是微软的Active Directory服务和Linux上的OpenLDAP组件. ...

  9. oracle PL/SQL语法基础

    目录 数据类型 定义变量 PL/SQL控制结构 参考资料 Oracle10g数据类型总结 PL/SQL之基础篇 数据类型 学习总结 字符类型 char.nchar.varchar.nvarchar:有 ...

随机推荐

  1. 20145104张家明 《Java程序设计》第9周学习总结

    20145104张家明 <Java程序设计>第9周学习总结 教材学习内容总结 第16章 -撰写应用程序是利用通信协议对数据库进行指令交换,以进行数据的增删查找. -JDBC目的:让Java ...

  2. Code First技术介绍

    地址:https://wenku.baidu.com/view/5620b862eefdc8d376ee3258.html 仅供参考

  3. grep如何结尾匹配

    答:grep "jello$" 如:git branch输出以下内容: yes-jello-good yes-jellos yes-jello 那么使用以下命令只能过滤出一行: $ ...

  4. centos7下yum升级被PackageKit锁定

    新安装centos7后,第一次升级出现下面的错误: Another app is currently holding the yum lock; waiting for it to exit... 另 ...

  5. C#学习笔记(二十):C#总结和月考讲解

    m1w1d2_console_variable_constant 输入Console.WriteLine(); 输出Console.ReadLine(); 快捷键 折叠代码:快捷键“Ctrl+ K + ...

  6. LA 3135 阿格斯(优先队列)

    https://vjudge.net/problem/UVALive-3135 题意: 你的任务是编写一个称为Argus的系统.该系统支持一个Register的命令 Register Q_num Pe ...

  7. python 递增递减数列

    def is_arithmetic(l): delta = l[] - l[] ): ] - l[index] == delta): return False return True print(is ...

  8. bash 判断两个文件相等的代码

    #!/bin/bash #定义参数 username="xxx" passwd="xxxxxxxx" dbname="xxx" #判断入参为 ...

  9. Qt_QString.indesOf和mid测试

    1.indexOf #define GID_PREFIX "dr_" QString str = "dr__awedr4"; int iIdx = str.in ...

  10. ListView事件的研究

    1. ListView的OnItemClickListener不被触发的另外一种情况 如上图,在一个ItemView中,只有一个TextView位于最左侧,他的右侧是空白区域,没有任何控件,当点击右侧 ...