混搭,不止是报告

使用 IBM Mashup Center 关系型更新数据源构建表单小部件

所有开发人员都会遇到这样的需求,构建一个应用程序,对数据库表做简单的更新。本文讲解构建一个 IBM® Mashup Center 小部件,它能显示一个 HTML 表单让用户更新关系数据库表。您可以通过使用 可下载的小部件示例 或自己的 HTML 表单快速创建混搭应用页面。

Louis Mau, 解决方案架构师, IBM

Louis Mau 是 InfoSphere MashupHub 开发团队的成员。他目前的工作重点是帮助客户使用 IBM Mashup Center 构建环境应用程序。在此之前,Louis 曾经担任过 DB2 Everyplace SyncServer 的架构师。



Klaus Roder, 解决方案架构师, IBM

Klaus Roder 是 IBM Silicon Valley Lab 的 IBM Mashup Center 的解决方案架构师。他目前关注的重点是使用 IBM Mashup Center 帮助客户开发和部署混搭应用程序。在此之前,Klaus 从事 IBM Web Interface for Content Management (WEBI) 项目,在 WebSphere Information Integrator Content Edition (IICE) 开发团队工作。Klaus 拥有维尔茨堡应用科学大学的计算机科学硕士学位,还是旧金山湾区 ACM 分会的会员。



2010 年 12 月 10 日

概览

很多开发人员会需要构建一个应用程序对数据库表进行简单更新。借助 IBM Mashup Center 第 2 版,您可以轻松创建一个关系型(JDBC)数据源,它可执行单个的 INSERTUPDATEDELETE SQL 语句。本文讲解如何开发一个小部件,帮助您在混搭应用程序中利用这些数据源。

本文假设您已熟悉构建混搭和数据源,以及编写小部件的基础。特别是,您应该知道如何进行 JavaScript 编程,并使用过 IBM Mashup Center。参考资料 一节包含一些很好的介绍资料的链接,能帮助您补上构建混搭应用的基本知识:“Creating a feed from an enterprise database (JDBC)” 和 “Developing widgets for IBM Mashup Center”。

IBM Mashup Center 数据库支持

IBM Mashup Center 包括 InfoSphere MashupHub 和 Lotus Mashups。它提供一个即装即用的关系型数据源生成器,能生成来源于很多常用数据库服务器的可用的数据源,包括:DB2®、Informix® 和 IMS™。

关系型更新数据源

可以通过 IBM Mashup Center 创建一个来自数据的数据源,该数据是从关系型查询返回的。数据源是通过选择感兴趣的表和列、或者使用 SQL 语句查询数据库生成。数据源是由查询结果集返回的数据创建。

通过 IBM Mashup Center 第 2 版,以及使用 SELECT SQL 语句,也可以用关系型数据源生成器执行 INSERTUPDATEDELETE SQL 语句。也可以只执行单个 SQL 语句,所以此特性不适合用于复杂的事务处理。尽管如此,也可以使用更新功能支持很多相对简单的场景,如以下示例:

  • 拍摄快照,进行趋势分析。例如,假设您有一个数据源,它返回每天的新订单总数。通过运行和保存数据库表中的数据源内容,可以生成一个数据源来显示订单到达趋势。使用数据混搭编辑器,就可以创建一个混搭应用,用 FOREACH 操作符将内容从每个报表条目 INSERT 到各自的行中。
  • 保存评论或说明。例如,有一个简单的投票应用程序来收集用户的喜好或观点。
  • 开发一个表单,保存待办事项清单,它保存在数据库中。
  • 开发一个表单,提交服务请求。例如,这些服务请求可能是一个构建模型、打印机或 IT 系统。

有时候,构建一个关系型更新数据源的简单应用的混搭页面并不简单。例如,可以用IBM Mashup Center 附带的 User Input 小部件来生成诸如文本框这类控件来收集用户输入。尽管如此,User Input 小部件不能直接执行关系型更新数据源,没有一个小部件能以一种良好的方式显示执行结果。

本文将介绍如何构建一个自定义小部件,可在上述第二种场景中轻松使用这些更新数据源。自定义小部件采用 HTML 表单作为配置参数。它呈现一个表单,将表单数据提交给关系型更新数据源,并显示更新状态。由于此自定义小部件接受任意的 HTML 表单片段,因此可以更自由地控制表单布局。HTML 表单片段的使用也使得在多个页面中创建相同表单变得容易。下一节将通过场景示例来演示 HTML 表单小部件的特性。


场景示例

为了简化安装过程,易于学习,场景示例将使用安装在 IBM Mashup Center 中的 Apache Derby 示例数据库的策略表。图 1 是介绍如何构建混搭应用程序的样例混搭应用程序屏幕截图。该应用程序相当简单,包含两个小部件。

图 1. 混搭页面示例
左边有个表格,其中有 policyid、 customername 和 coverage 列;右边是 Policy Address Update 和 Delete 表单

如图 1 所示,左边的 DataViewer 小部件用于显示感兴趣的策略列表,它们取自数据库。如果有一行(策略)被选中,此策略的详细信息将在右边的 HTML 表单小部件中显示。用户可以改变地址,点击 HTML 表单小部件上的提交按钮。此按钮配置为执行关系型更新数据源。执行的结果是产生一个 XML 文档。此 XML 文档将被解析,并显示一个简单的成功或失败消息。图 2 显示了一个成功消息。

如果您想能立刻将这个示例小部件用于您自己的表单中,从 下载 部分获取,并添加到自己的 IBM Mashup Center 中。然后可以跳过如何构建的讲解部分,直接跳到 全部组装起来 小节。

图 2. 成功执行的消息
成功执行的消息

在构建可以支持上述功能的小部件之前,还需要关注其他事情:定义关系型数据源。下一节讲述如何定义。


创建 JDBC 数据源

如前所述,为了便于学习,本文中的场景示例使用的是 IBM Mashup Center 示例数据库附带的策略表。

按以下步骤创建策略表的关系型数据源:

  1. 跳到 Catalog Home Page 点击 Create
  2. 选择 New Feed
  3. 选择 Enterprise Database (JDBC) 作为数据源数据源。
  4. 为了获得包含策略表的数据库,在 Connection Profile 字段选择 Mashup Hub Sample Database

    如果配置文件不存在,通过提供以下信息创建:

    • Connection Profile Name: MashupHub Sample Database
    • Database Type: Derby Embedded
    • Connection Type: Driver Manager (Non-managed Connection)
    • Database Name: <installDir>/Hub/installedApps/MashupHub.ear/mashuphub-enterprise.war/hubsample
  5. 使用以下的 SQL 语句创建两个对应图 1 中两个小部件的数据源:
    • 第一个数据源用于显示策略列表的 DataViewer 小部件。请注意,添加 state 参数后能够过滤给定状态。
      select * from samples.policyholders where state = ':state'
    • 第二个数据源用于 HTML 表单小部件使用的关系型更新数据源。
      update samples.policyholders set address = ':address', city = ':city', 
      state = ':state' where policyid = ':policyid'

    本文假设您已熟悉使用 IBM Mashup Center 创建关系型数据源。由于这两个查询都用参数,因此需要通过将 SQL 语句粘贴到 JDBC 数据源编辑器的 Advanced 方框中来创建。参考资料 中包含创建关系型数据源的详细信息的链接。

在继续以下内容之前,最好先检查一下在使用关系型更新数据源时需要额外注意的几个地方:

  • 使用 HTTP GET

    参考资料 中的 W3C 文章所述,当 “交互行为以一种用户能看到的方式改变资源状态(例如,订阅服务)” 时应当使用 HTTP POST。原因之一是 HTTP GET URL 易于标记和缓存,这可能导致意外和不想要的调用。在本文中开发的 HTML 表单小部件使用 HTTP POST 作为访问方法。默认情况下,IBM Mashup Center 提供 GETPOST 支持。可以通过展开数据源明细页面上的 Access Method 按钮和取消选择 GET 复选框来禁用 HTTP GET 访问。

  • 避免重复行。

    关系型更新数据源包含单个 SQL 语句。因为没有错误处理逻辑,必须依靠数据库的限制,以确保数据的语义完整性。例如,为了保证没有重复行,必须有一列声明为 KEY 列,以确保使用已插入键值插入新行时失败。

  • 缓存。

    大多数情况下,执行更新的数据源不应该被缓存。一个例外就是更新数据源用于数据混搭中。编辑过程中,如果没有缓存,则只要输出被预览,更新数据源就会执行。默认情况下,source 操作符缓存其输入数据源一个小时。这正是您在混搭构建中所需要的。在保存完成的混搭之前,应在所有使用关系型更新数据源的 source 操作符中关闭缓存。

有了这些额外的准备工作,现在可以开始构建自定义 HTML 表单小部件。


小部件开发

Mashup Center 小部件遵循 iWidget 规范。有两种小部件。其中主要区别是部署方法。

  • 基于 WAR 文件小部件 — 这些小部件包含基于服务器的组件,必须部署在应用程序服务器上。
  • 轻量级小部件 — 这些小部件完全在客户端运行, 需要部署在应用程序服务器上。本文中描述的 HTML 表单小部件示例就是一个轻量级小部件。

按以下步骤开始使用 IBM Mashup Center Version 2 进行 HTML 表单小部件开发:

  1. 如图 3 所示,单击 Mashup Builder 页面右上角的 Go to View 并选择 Create a New Widget...
    图 3. 创建 Widget 菜单
    Mashup Builder 页面中 Create a New Widget 选择项高亮显示的屏幕截图
  2. 如图 4 所示,在 Widget Builder 对话框,选择 Work with the widget editor
    图 4. Widget Builder 对话框
    屏幕截图显示从向导或用小部件编辑器创建小部件的选项
  3. 到下一个对话框,选择 Create a new project
  4. 在 New Widget Project 对话框中,选择 Create a project from starter files。这将创建一个新项目,其中包含小部件框架定义和目录文件。所有文件由服务器保存。如图 5 所示,Customized Widget Project 对话框显示了 “Select a file” 标题下的文件名称。可以使用列表下的按钮选择任何已有的文件进行编辑或将其他文件上传到项目中。
    图 5. Customized Widget Project 对话框
    屏幕截图显示可选择文件列表
  5. 准备好测试后,点击 Export 并选择 Add to palette

本文的项目示例相当简单,仅包含两个文件。


小部件定义文件

不需要更改已生成的 catalog.xml 文件。它只是提供在工具箱菜单中显示的名称和小部件定义文件(iWidget.xml)的位置。iWidget.xml 文件指定实现逻辑、小部件发送或接收的静态事件、视图模式布局、编辑模式布局的 JavaScript 文件。这一小节将向您介绍需要对 iWidget.xml 所做的所有更改。

清单 1 显示了 iWidget.xml 文件的根元素。iwidget 根元素的 iScope 属性最重要。它指定了实现 iWidget 回调函数的 JavaScript 对象。包含 JavaScript 的文件使用根元素加载。关于这部分内容和其他属性的细节,请查阅 参考资料 一节中小部件编程和 API 文档链接。

清单 1. iWidget.xml 头部
<iw:iwidget name="htmlForm"
            xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget"
            iScope="sample.mashupcenter.htmlForm"
	    allowInstanceContent="true" supportedModes="view edit"
            mode="view" lang="en">

<iw:resource uri="htmlForm.js"/>

清单 2 显示小部件的一个预定义接收事件和两个发送事件的定义。接收事件是由 handledonEvent 属性指定的。onEvent 属性的值是接收事件时调用的函数名称。published 属性的值定义了发布事件的名称。本文后面的 事件处理和生成 一节将描述事件如何处理。

清单 2. iWidget.xml 事件格式
<iw:event id="ResetForm" handled="true" onEvent="handleReset"
          eventDescName="desc_handleReset"/>
<iw:eventDescription id="desc_handleReset" payloadType="any" title="Clear all Fields"
                        description="Clear all the fields in the form" lang="en">
</iw:eventDescription>

<iw:event id="actionSuccessful" eventDescName="desc_actionSuccessful" published="true"/>
<iw:eventDescription id="desc_actionSuccessful" payloadType="text"
                        description="Number of records updated by WebService" lang="en">
</iw:eventDescription>

<iw:event id="actionFailed" eventDescName="desc_actionFailed" published="true" />
<iw:eventDescription id="desc_actionFailed" payloadType="text"
                        description="Failure to assign" lang="en">
</iw:eventDescription>

最后,小部件的定义文件还指定了小部件视图和编辑模式的布局。布局是由 iw:content 元素中名为 CDATA 的 HTML 标记指定的。清单 3 显示了视图模式的 HTML 标记。请注意所有 div 元素都有 id,因此可以用 JavaScript 来操作。还有,请注意每个 id 都使用 _IWID_ 作为前缀。在运行时,IBM Mashup Center 用小部件生成时的实际的惟一的实例 id 取代所有 _IWID_ 前缀。这确保了即使同一个 HTML 页面有多个小部件实例,所有的 id 也是惟一的。在视图模式定义中有两个 div 元素。id_IWID_formdivdiv 将包含一个 HTML 表单片段,初始为空。另一个 divstyle 格式是 display:none,这表示它不可见。它包含一个显示表单提交结果的模板,而且在执行更新程序后,可由 JavaScript 变为可见。

清单 3. iWidget.xml 视图模式布局
<iw:content mode="view">
  <![CDATA[
  <div id='_IWID_formdiv'></div>

  <div id='_IWID_resultdiv' style='display:none; font-size:1.3em;'>
      <div id="_IWID_ResultXML" ></div>
      <br />
      <a href=""
         onclick="javascript:iContext.iScope().showFormAndHideResult();return false;">
         Back</a>
  </div>

  ]]>
</iw:content>

编辑模式一节包含一个文本区和三个文本框的表单的代码。它会在用户点击 Edit Settings 时显示。文本区用于输入 HTML 表单片段。三个文本框最多输入三个 URL。后面的章节中将讲述如何将这些 URL 与表单中按钮关联。URL 值将会与输入到表单 method 属性的一样。即去掉 ? 字符后的名称值对的 URL。

htmlForm Edit 对话框 显示了所呈现的表单。简单起见,本文不重新生成整个编辑模式 HTML 布局。它作为完整的小部件包的一部分,可以从 参考资料 一节中相应的链接下载。


JavaScript 实现

JavaScript 实现文件名为 htmlForm.js。它是 Dojo 类,可处理标准事件,如 loadunloadviewedit 及其他任何自定义事件和服务器通信。以下是文件中所包含函数的快速概览:

  • onLoad— 在此函数中放置初始化代码。这通常包括检索保存在前一次 Edit Settings 对话框调用中的配置信息。

    回想一下,视图和编辑模式的 HTML 标记中所有 id 属性都包含 _IWID_ 前缀,这些前缀在小部件创建时会被实际的小部件实例 id 替代。这意味着在 JavaScript 代码能通过 id 检索 HTML 元素之前,iContext 对象的实例小部件 id 必须用来构建实际的 id。请注意,在清单 4 中,小部件配置数据从与 iContext 关联的小部件 attributes 对象中检索出来。

    清单 4. ononload 函数
    onLoad: function() {
    
            this.uid = "_" + this.iContext.widgetId + "_";
    
            this.formDivNode   = dojo.byId(this.uid + 'formdiv');
            this.resultNode = dojo.byId(this.uid + 'resultdiv');
    
            // load attributes
            var attributes = this.iContext.getiWidgetAttributes();
            this.formHtml  = attributes.getItemValue( "formHtml" );
            
    },
  • onUnload— 此函数只在页面被关闭前调用。通常不需要清理,这意味着不需要实现该函数。尽管如此,由于 Dojo V1.3 Dijit 的 id 必须惟一而且在页面转换清理时不会自动移除,因此需要手工完成。

    清单 5. onUnload 函数
    onUnload: function()
    {
        // need to clear all existing dijits (to free up id's)
        if ( this.formDijit != null )
            this.formDijit.destroyRecursive( false );
    },
  • onview— 此函数在小部件显示时就会调用。小部件示例在没有配置时(例如,第一次拖到页面上)就显示一个默认消息。其他函数将在以后章节中详细解释。
    清单 6. onview 函数
    onview: function()
    {
        if ( this.formHtml == null  ||  this.formHtml.length <= 0 ) {
            this.formDivNode.innerHTML = "Switch To Edit to specify HTML form";
        } else if ( this.viewContent.length <= 0 ) {
            this.displayForm();
            this.reCreateEvents( );
        }  // else form already there, no need to do anything
    },
  • onedit— 当调用 Edit Settings 时会调用此函数。清单 7 中的代码只是用户在以前调用时提供的值预先填充 Edit Settings 对话框。

    清单 7. onedit 函数
    onedit: function()
    {
        dojo.byId( this.uid + "formHtml" ).value = this.formHtml;   
    },
  • saveConfigData— 此函数不对应任何事件构建。这是编辑模式 HTML 标记中 Save 按钮 onclick 方法中小部件特定的函数。清单 8 中的代码只是检索和保存 Edit Settings 对话框中用户最近输入的值。onModeChanged 事件用来通知小部件运行时关闭 Edit Settings 对话框。

    清单 8. saveConfigData 函数
    saveConfigData: function()
    {
        this.formHtml = dojo.byId( this.uid + "formHtml" ).value;
        this.iContext.iEvents.fireEvent("onModeChanged", null, "{newMode:'view'}");
    
        var attributes = this.iContext.getiWidgetAttributes();
        attributes.setItemValue("formHtml"  ,  this.formHtml );
    
        attributes.save();
    },

参考资料 一节包含可以下载整个小部件包的链接。现在您已熟悉了所有小部件通用的函数,下一节将介绍小部件示例特定的函数。


显示 HTML 表单

要使用小部件,需要提供一个 HTML 表单。可以根据喜好用编辑器或代码生成工具创建表单。创建 HTML 表单后,确保对每个表单输入字段都有合适的 dojotype 属性。(例如,可以参考 全部组装起来 一节中的 HTML 清单示例。)表单中可有多个按钮。要激活按钮,必须提供带有如下值的 onclick 属性:

            onclick="_${widgetId}_iContext.iScope().submit('formUrl1');"

以上是小部件的 JavaScript 文件中定义的调用 submit 函数的语法。处理表单提交 一节中讲述了 submit 函数如何处理的细节。现在,只要将以上示例中的 ${widgetId} 字符串替换为小部件实际的 id,让其成为有效的 JavaScript。下一步将讲解工作原理。

为了显示粘贴到 Edit Settings 对话框的 HTML 表单片段,只要将 HTML 字符串设置为 iWidget.xml 视图模式布局 占位符 divinnerHTML,如清单 9 所示。但在此之前,需要将 ${widgetId} 字符串替换为小部件实际 id。这通过调用 Dojo 字符串工具函数 substitute 来完成。这些也显示在清单 9 中。关于清单 9 中的代码,最后要注意的一点是由于表单包含 Dojo Dijits,需要调用 Dojo 行为的 Dojo parse 方法使其起作用。

清单 9. displayForm 函数
displayForm: function()
{
    // fix up button onclick action to point to submit method of this widget.
    this.viewContent = dojo.string.substitute( this.formHtml
                                             , { widgetId: this.iContext.widgetId });
"
    // Add form content to the view content root node.
    if ( this.formDijit != null )  // need to clear all existing dijits (to free up id's)
        this.formDijit.destroyRecursive( false );
    this.formDivNode.innerHTML = this.viewContent;

    // Parse dojo components to display Dojo widgets
    dojo.parser.parse( this.formDivNode );
    this.formDijit = this.getFormDijit(  this.formDivNode );
},

事件处理和生成

HTML 表单小部件示例的一个关键特性是可以将数据捆绑到小部件中。如 场景示例 一节所描述,单击 DataViewer 小部件的一行会使此行所有列传到小部件的表单输入字段。由于各表单的输入字段不同,不可能像之前在 iWidget.xml 事件规范 事先定义一个接收事件和两个发送事件那样,在 iWidget.xml 文件中静态定义输入字段的接收事件。

为了对每个表单输入字段动态创建事件,首先需要对所有表单输入字段的 HTML 解析,如清单 10 所示。

清单 10. createEventsForFields 函数
createEventsForFields : function(  )
{   
    this.eventNames = [];
    this.dijitMap   = {};

    var children = this.formDijit.getChildren();
    for (var i = 0  ;  i < children.length  ;  i++ ) {
        var widget = children[i];
        var name  = widget.attr( 'name' );
        if ( name == null ||  name.length == 0 )
            continue;  // skip over unnamed form input fields
        if ( widget.type == 'radio'  &&  widget.checked == false )
            continue;   // for radio button, pick the one that is true

确定表单输入字段之后,创建同名的事件,如清单 11 所示。

清单 11. 动态创建事件
this.eventNames.push( name );
this._createEvent({
    name : name,
    type: "any",
    isHandled : true,
    handlingFn : dojo.hitch(this, this.handleEvent )
});

for 循环最后,将所有事件添加到 dijitMap,如清单 12 所示。后面将使用此映射,在调用事件时激发响应事件。

清单 12. dijitMap 保存事件名
// will also create dijit mapping to process event
this.dijitMap[ name ] = widget;

下一步,在正确的位置加入代码,以便在激发事件时进行处理。当如上显示的某一事件捆绑到小部件,将用其名称来查找(在 dijitMap 代码的协助下)相应的表单输入字段。如果表单输入字段不为空,将小部件的值设为接收到的负载,如清单 14 所示。

清单 14. handleEvent 函数
handleEvent: function(iEvent){
    ::::::::::::::::::::::::::::::::::::::::::::::::::
    var  evtname    = iEvent.name;
    var  widget     = this.dijitMap[ evtname ];
    if ( widget != null )
        widget.setValue( iEvent.payload ); 
}

处理表单提交

正如 显示 HTML 表单 一节中所提到的,HTML 表单片段中的按钮必须包含对 submit 函数的显示调用。submit 函数的参数定义了在 htmlForm Edit 对话框 中定义的、会在按钮按下时执行的数据源 URL。如清单 15 所示,参数必须为以下字符串:

  • formUrl1— 执行第一个表单方法的数据源 URL。
  • formUrl2— 执行第二个表单方法的数据源 URL。
  • formUrl3— 执行第三个表单方法的数据源 URL。
清单 15. submit 函数
submit: function( action ) {
    ::::::::::::::::::::::::::::::::::::::::::::::::::
    var actionURL = "";
    //Specify the root URL of the feed that you want to trigger:
    if ( action == 'formUrl1' ) {
        if (  this.formUrl1  &&  this.formUrl1.length > 0 )
            actionURL = this.formUrl1;
    } else if ( action == 'formUrl2' ) {
        if (  this.formUrl2  &&  this.formUrl2.length > 0 )
            actionURL = this.formUrl2;
    } else if ( action == 'formUrl3' ) {
        if (  this.formUrl3  &&  this.formUrl3.length > 0 )
            actionURL = this.formUrl3; 
    ::::::::::::::::::::::::::::::::::::::::::::::::::

现在对选择的动作有了正确的基础 URL,需要收集用户输入的表单值。这是用 collectNVP 函数完成的。如清单 16 所示,从各种不同输入表单字段检索值的单调工作由 Dojo 库表单 Dijit getValues 函数完成。代码只要顺着字段循环并对值编码,确保没有无效字符。

清单 16. collectNVP 函数
collectNVP: function(  ) {
    this.debugTrace( "collectNVP entered" );

    var formData = "";
    var temp = this.formDijit.getValues();
    for ( var  name in temp ) {
        if ( formData.length > 1 )  formData += '&';
        //Encode the key and value, to make sure there are no invalid characters.
        formData +=  encodeURI( name );
        formData +=  "=";
        // encodeURI( value );   doesn't escape &, ...
        var value =  temp[ name ];
        formData +=  escape( value );
    }
    return formData;
}

收集表单数据和基础 URL 之后,使用 Dojo 库 xhrPost 方法提交 AJAX 调用。按照 创建 JDBC 数据源 一节中的建议,使用 HTTP Post 而不是 HTTP GET 作为访问方法来执行关系行更新数据源。

如清单 17 所示,xhrPost 方法的参数包含 load(成功)和 error 情况的回调函数。这些回调函数的细节将在下面两个小节中讲解。urlToLoad 参数包含基础 URL 或表单方法,不直接使用。这是由于浏览器沙箱规则要求用户提供的基础 URL 要重定向,遵循 Mashup Server AJAX 协议。这是由调用通过 iContext 访问的 reWriteURI 函数实现的。

清单 17. 表单提交
// Using POST for update type URL
submitUrl: function(urlToLoad, formdata )
    var location = this.iContext.io.rewriteURI( urlToLoad );
    dojo.xhrPost({
        url     : location,
        postData: formdata,
        load    :  dojo.hitch( this, this.handleFeedContent ),
        error   :  dojo.hitch( this, this.handleErrorResponse ),
        handleAs: "xml",
        sync    : true
    });
}

处理成功的表单数据提交

根据 xhrPost AJAX 调用中所指定的,当表单成功提交后调用 handleFeedConent 函数。这个小部件只能用于 MashupCenter 关系型(JDBC)更新数据源。数据源返回 XML 响应,如图 6 所示。如果检索到不同的响应,程序会显示一个消息,指示返回了一个 “Unsupported result format”。

图 6. 成功更新数据源响应
xml 片段,有执行结果 executionreslut 顶部元素, rowcount 元素,值为 1,以及空的 systemmsg 元素

如清单 18 所示, 如果返回格式正确,handleFeedConent 函数显示 “Operation successful” 消息,并且成功插入行数。此函数还激发 actionSuccessful 事件,这是在前面 小部件定义文件 一节中描述的在 iWidget.xml 中静态定义的。

清单 18. 成功的表单提交
handleFeedContent: function(data){
    ::::::::::::::::::::::::::::::::::::::::::::::::::
    resultHTML += "Operation successful.";
    resultHTML += rowCount;
    resultHTML += " record(s) changed.";

    this.iContext.iEvents.fireEvent("actionSuccessful", null, "" );
    ::::::::::::::::::::::::::::::::::::::::::::::::::

如清单 19 中所示,如果 MashupCenter Relational (JDBC)插件调用返回错误(-1),handleFeedConent 函数生成一个结果字符串,附有 systemmsg 元素中返回的消息。它还激发 iWidget.xml 事件格式 中定义的 actionFailed 事件。

清单 19. 成功的表单提交后的错误消息
handleFeedContent: function(data){
    ::::::::::::::::::::::::::::::::::::::::::::::::::
    if (  rowCount ==  "-1" ) {

       var  msg     = "Unknown error. <br><br>";
       var  msgList = dojo.query( "systemmsg" , data );
       if ( msgList  &&  msgList[0] )
            msg = dojox.xml.parser.textContent( msgList[0] );
       resultHTML += msg;

       this.iContext.iEvents.fireEvent("actionFailed", null, rowCount );

在数据提交过程中处理错误

如清单 20 所示,如果表单数据提交失败,handleErrorResponse 函数通过调用 displayResult 显示通信失败结果。

清单 20. handleErrorResponse 函数
handleErrorResponse: function(data)
{
    this.debugTrace( "handleErrorResponse entered data="  + data );
    this.displayResult( data );
}

显示表单提交结果

两种情况下,无论表单提交成功还是有错误,都用 displayResult 函数来记住表单大小、隐藏当前输入表单并显示表单提交结果。

resultNodestyleiWidget.xml 视图模式布局 初始定义为 display:none,这使得它被隐藏。如清单 21 所示,displayResult 函数通过将 style.display 定义改变为 block 使得 resultNode 可见。

清单 21. displayResult 函数
displayResult: function(data)
{
    // save the current size
    var  formSize = dojo.contentBox( this.formDivNode );
    // hide the form
    this.formDivNode.style.display = "none";

    // show the result
    this.resultNode.style.display = "block";
    dojo.contentBox( this.resultNode, formSize );
    var resultXmlNode = dojo.byId(this.uid + 'ResultXML');
    resultXmlNode.innerHTML = data;
},

resultdiv 包含一个 Back 链接,它调用 showFromAndHideResult 函数。如清单 22 所示,该函数隐藏 resultdiv 并再次显示表单。

清单 22. showFormAndHideResult 函数
//Clear data, hide the result node, and show the form again.
showFormAndHideResult: function()
{
    this.debugTrace( "handleFeedContent entered" );

    this.formDivNode.style.display = "block";

    // clear any message text
    var resultXmlNode = dojo.byId(this.uid + 'ResultXML');
    resultXmlNode.innerHTML = "";
    this.resultNode.style.display = "none";
},

全部组装起来

现在已经可以将 HTML 表单小部件加入 场景示例 一节中描述的混搭应用程序示例中了。从策略记录的 HTML 表单片段开始。如清单 23 所示,使用 HTML 表格来组织文本框。如前所述,表单必须使用 Dojo Dijits。和在普通 HTML 页面上一样,输入表单字段的名称必须与关系型更新数据源中使用的参数名称匹配。 此前已在 创建 JDBC 数据源 一节中创建了数据源。表单可有多个按钮对应 INSERTUPDATEDELETE 动作。为了展现进一步扩展的可能,表单包含一个额外的非功能性按钮,标记为 Delete Policy,它没有对应的数据源。

清单 23. 策略 HTML 表单
<form dojotype="dijit.form.Form" style="font-size:1.3em;">

  <div style='background-color:#D1EACC; height:4em; padding-top:5px; padding-bottom:5px'>
      <center><h3>Policy Address Update and Delete Form</h3></center>
  </div>

  <br>
  <table>

  <tr><td>Policy Id:</td>
      <td><input type="text"  name="policyid"  dojotype="dijit.form.TextBox"
                 style="width: 6em;" readonly /></td>
      <td></td>
      <td></td>
  </tr>

           :::::::::::::::::::::::::::::::::::::::::

  <tr>
  <td></td>
  <td colspan='4' align='right'>
      <button dojotype="dijit.form.Button" value="formUrl1">Update Address
              onclick="_${widgetId}_iContext.iScope().submit('formUrl1');"
      </button>
      <button dojotype="dijit.form.Button" value="formUrl2">Delete policy</button>
  </td>
  </tr>
  </table>
</form>

现在如图 7 所示,转到 htmlForm Edit 对话框,edititML 表单片段粘贴到 Form Html 字段,并将在 创建JDBC 数据源 一节中创建的关系型数据源粘贴到对应的表单方法字段。单击 Save 完成小部件配置。

图 7. htmlForm Edit 对话框
htmlForm Edit 对话框及 HTML 片段文本框和关系型数据源文本框的屏幕截图

当选中 DataViewer 小部件一行后弹出所有输入字段。如 事件处理和生成 一节中所述,HTML 表单小部件为每个输入字段动态创建接收事件。需要做的就是将他们写入 DataViewer 发送事件。图 8 显示将一个生成的接收事件捆绑到对应的 DataViewer 小部件上。

图 8. 接收事件捆绑
将 htmlForm 连接到 ResetForm 的 Wiring 对话框截图

最后,如果需要将 HTML 表单小部件的 actionSuccessful 事件捆绑到一个 URL Customizer 小部件。后者捆绑到 DataViewer 小部件,并配置为使用与 DataViewer 一样的 URL。图 9 显示了 URL 定制器和捆绑图片。

Figure 9. URL Customizer 和 Wiring Graph
屏幕截图显示 Wiring Graph 接口, with htmlForm 捆绑到 URL Customizer 捆绑到 Data Viewer

更新操作成功后,事件被激发,DataViewer is 自动刷新。这只是为了演示,因为示例的更新操作不改变 DataViewer 中的显示内容。

图 10. 发送事件捆绑
屏幕截图显示, Wiring 对话框中显示发送事件捆绑到小部件,接收内容

结束语

本文讲解了构建小部件的基本步骤,包括动态事件注册和服务器通信。如果要扩展从本文学到的内容,可以通过加入对关系型更新数据源更详细的错误处理来增强小部件。

混搭应用程序通常用作显示不同数据源的仪表板。通过使用关系型更新数据源和小部件,可以快速构建混搭应用程序,它不仅提供报告,还提供了进行简单更新操作的方法。


下载

描述名字大小
本文代码示例HTMLformWidget.zip8KB

参考资料

学习

获得产品和技术

  • 要获取 IBM Mashup Center 的实际经验,访问 Lotus greenhouse
  • 从 developerWorks 下载 IBM Mashup Center 免费试用版。
  • 使用可直接从 developerWorks 下载的 IBM 产品评估试用软件 构建您的下一个开发项目。
  • 现在可以免费使用 DB2。下载 DB2 Express-C,这是为社区提供的 DB2 Express Edition 的免费版本,它提供了与 DB2 Express Edition 相同的核心数据特性,为构建和部署应用程序奠定了坚实的基础。

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Information Management, Lotus
ArticleID=600050
ArticleTitle=混搭,不止是报告
publish-date=12102010