`

重新整理后的Oracle OAF学习笔记——5.应用构建基础之实现控制器

阅读更多

设计一个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 orderNumber = 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的属性。

public void processFormRequest(OAPageContext pageContext, OAWebBean webBean)
{
   // Always call this before adding your code
   super.processFormRequest(pageContext, webBean);

   // Pressing the Go button causes the search to be executed.
   If (pageContext.getParameter("Go") != null)
   {
     String orderNumber = 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);

     // Now forward back to this page so we can implement UI changes as a
     // consequence of the query in processRequest(). NEVER make UI changes in
     // processFormRequest().

     pageContext.setForwardURLToCurrentPage(null, // no parameters to pass
                                            true, // retain the AM
                                            OAWebBeanConstants.ADD_BREAD_CRUMB_NO,
                                            OAWebBeanConstants.IGNORE_MESSAGES);
  }
} // end processFormRequest();
这个例子展示了如何使用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 orderNumber = 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学习笔记——离线版本

    这个“重新整理后的Oracle OAF学习笔记——离线版本”提供了一套详细的学习资源,帮助用户深入理解并掌握OAF的相关技术。 在这些压缩包文件中,我们可以看到一些关键的文档和样式表,它们可能是笔记的各个章节或...

    oracle OAF 开发笔记 .part2

    oracle OAF 开发笔记 .part2,王重东大侠所写,内含高级案例,值得推荐

    深入浅出Oracle之OAF开发参考

    3) OAF使用Oracle Business Components for JAVA(BC4J)框架作为其模型部分,来实现业务逻辑和数据操作。 4) OAF使用元数据库支持的(整个页面由XML来定义,定义存储于Oracle数据库中)UIX框架作为其视图部分,将BC...

    ORACLE OAF入门学习教程

    ORACLE OAF入门学习教程主要涉及Oracle公司提供的Oracle Application Framework(OAF)的入门级知识和操作指南。OAF是基于Java语言开发的Web应用框架,它是用于构建企业级应用的一种集成工具,符合J2EE的MVC(Model-...

    oracle OAF R12开发笔记.part1

    王重东大侠写的,R12版的,包含进阶案例,可与R11的基础案例结合使用

    ORACLE EBS OAF开发笔记

    ### ORACLE EBS OAF开发...通过这些步骤,读者可以逐步学习如何使用OAF的各种组件和技术来构建功能丰富的企业级应用。此外,本篇文档还提供了关于OAF框架的一些基础概念,帮助开发者更好地理解和应用这一强大的工具。

    OracleEBS11i-OAF开发笔记

    ### Oracle EBS 11i – OAF 开发笔记 #### 概述 ...通过以上步骤的学习和实践,开发人员可以逐步掌握 OAF 开发的核心概念和技术要点,从而构建出高效、稳定且功能丰富的 Oracle EBS 11i 应用程序。

    Oracle_OAF_开发笔记

    Oracle Application Framework (OAF)是Oracle E-Business Suite (EBS)中的一个关键组件,用于构建用户界面。本文档是基于Oracle EBS 11i的更新版本R12的OAF开发笔记,由Jarwang(王重东)编写,并由Cao Liankai(曹...

    oaf学习笔记 转的别人的 免费给大家

    Oracle Application Framework (OAF) 是Oracle公司开发的一种企业级应用框架,主要用于构建和定制Oracle E-Business Suite(EBS)的应用程序。OAF提供了一种可视化、组件化的开发环境,使得开发者可以快速创建用户...

    R12-OAF开发笔记

    《R12-OAF开发笔记》是一份由IT专家JarWang(王重东)编写的详尽文档,专门针对Oracle E-Business Suite (EBS) R12中Oracle Application Framework (OAF)的开发过程进行了深入解析。这份笔记不仅包含了OAF的基本概念...

    OAF开发学习总结教程.doc

    文档标题和描述中的“OAF开发学习总结教程”指的是Oracle Application Framework(OAF)的学习教程,这是一套用于构建和定制Oracle应用的开发框架。在本文档中,作者南生分享了其对OAF开发的理解和实践经验,主要...

    OracleEBS R12-OAF开发笔记

    Oracle E-Business Suite (EBS) R12 的 OAF (Oracle Applications Framework) 是一个强大的开发框架,用于构建高度可定制的企业应用程序。本笔记由 JarWang(王重东)编写,主要涵盖了从环境搭建到实际应用开发的一...

    OAF开发笔记.pdf

    OAF开发笔记

    oracle oaf教程

    Oracle OAF(Oracle Application Framework)教程是学习如何扩展Oracle应用的一种技术指南,特别是针对那些希望构建自定义企业级应用程序的开发者。本教程的第一课主要涵盖了基础的技术设计和实践操作,帮助初学者...

    OAF入门学习教程.pdf

    Oracle Application Framework (OAF) 是Oracle公司推出的一种用于构建企业级应用的开发框架。它基于Java EE技术,为开发者提供了一种高效、可扩展且易于维护的平台来开发Oracle E-Business Suite (EBS) 应用。本教程...

    OAF 开发笔记

    ### OAF 开发笔记知识点详解 #### 一、AM设置与命名规范 ##### AM设置 在Oracle Application Framework (OAF)开发中,AM(Application Module)是管理业务逻辑的关键组件。为了防止对象钝化(即对象状态丢失),需...

    OAF开发手册Release 12

    6. **安全性与权限控制**:学习如何配置OAF应用的安全性,包括用户角色、权限和访问控制。 7. **性能优化**:探讨OAF应用的性能监控和优化技巧,以提升用户体验。 8. **调试与测试**:学习有效的调试工具和方法,...

Global site tag (gtag.js) - Google Analytics