级别: 中级 Qian Jie (Jove) Zhong, 软件开发人员, Systems Documentation, Inc. (SDI) Wei (Marshall) Shi, 软件开发人员, Systems Documentation, Inc. (SDI) Zheng (Erik) Bi, 软件开发人员, Systems Documentation, Inc. (SDI) Peng Yu (Joard) Zhang, 软件开发人员, Systems Documentation, Inc. (SDI)
2009 年 7 月 23 日 本文介绍了 IBM® Mashup Center 中的小部件编程模型:IBM iWidget 规范、小部件基础以及事件服务。为了帮助您更好地理解如何从头构建小部件,本文将指导您开发一个小部件,它可以监视后端服务器的内存使用。
作为行业中首个集成式企业 Web 2.0 mashup 软件平台,IBM Mashup Center 提供了完整的端到端 mashup 平台,支持对简单、灵活和动态的 Web 应用程序进行业务线集成,并提供了 IT 所需的管理、安全性和治理功能。IBM 创建了一个轻量级部件模型,并为小部件定义了一个标准。作为这项工作的一部分,IBM 在 OpenAJAX 中领导了一个新的小部件规范工作组。
首先,本文给出了一个包含静态文本的样例 Hello World 小部件。随后,我们展示了如何在 IBM InfoSphere™ MashupHub 中上传小部件并将其添加到用户面板。接着演示如何将后端 Java™ 代码添加到小部件应用程序,并利用 AJAX 技术在避免页面刷新的情况下与服务器进行通信。最后本文介绍了有关小部件开发的一些更加高级的主题,比如小部件通信和全球化支持等等。
小部件编程模型
要为 IBM Mashup Center 开发新的小部件,首先需要了解 IBM iWidget 规范的基本知识和一些关键概念。
IBM iWidget 规范 V1.0
IBM Mashup Center 中的小部件开发采用了不断发展的 IBM iWidget 规范,并且建立在该规范的 V1.0 的基础之上。该规范定义了一个简单的、可扩展的、基于浏览器的组件模型。不同软件供应商会为这些组件提供不同的名称。由于缺乏开放的标准,这些共享概念全部以不同的方式执行,因此造成不同框架之间的组件无法进行互操作。该规范尝试解决这一问题,定义了一个开放的标准来实现这些共享的概念,并定义一个扩展模型来提供更多高级概念。
小部件基础
让我们首先明确几个概念,其中一些概念来自 IBM iWidget 规范。
-
iWidget。面向浏览器的组件,可以扩展一个服务器端组件,为页面提供了逻辑服务,或是为用户提供了虚拟化(通常与服务器端组件或已配置的数据源有关)。
-
页面。经过组合后呈现给用户的更大的实体。该实体可以包含显示或非显示 iWidgets,每个 iWidgets 可以来自不同的源。在呈现页面时可以修改页面组合(例如,可以将新的 iWidgets 添加到组合中),这样,精确定义何时迁移到新页面将作为一项策略决策,交由管理页面组合的实现负责。
-
iContext。iWidgets 运行时上下文,它提供对 iWidgets 的总体管理。该上下文包括任何用户界面(UI)控件、iWidgets 之间的协调以及与后端服务的交互。
-
标记片段。iWidget 为用户生成的视图。iWidget 可以同时为客户展示多个片段。
-
ItemSet。iWidget 的属性,通常用于控制 iWidget 的外观及其数据源。ItemSet 的一个数据示例就是名为 bgColor 的属性,该属性控制 iWidget 的背景色。另一个例子是名为 feedURL 的属性,该属性控制 iWidget 所连接的或呈现的 Atom 提要。
-
模式。由 iContext 管理的状态的 iWidget 内容,告诉 iWidget 要为用户生成哪种类型的标记。标记类型包括 view 类型(用于普通用户标记)和 edit 类型(用于 iWidget 属性编辑标记)。
-
事件。一种机制,提供可以临时共享信息的方式。iWidgets 可以通过发布事件共享数据,发布事件中包含事件数据。有两种类型的事件:已发布事件(表示 iWidget 通过这一事件发布某些数据)和已处理事件(表示 iWidget 从其他 iWidget 接收数据)。
逐步创建一个真实的小部件
我们在此引入了一些新的术语和概念。使用以下说明开发小部件后,这些新概念将变得更加清晰。
HelloWorld,您的第一个 iWidget
要创建 HelloWorld iWidget,请执行以下步骤:
- 打开您最喜欢的文本编辑器并使用清单 1 所示的代码片段创建一个 widget.xml 文件。
清单 1. 一个简单的 widget.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<iw:iwidget name="myWidget" xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget"
supportedModes="view edit" mode="view">
<iw:content mode="view">Hello World!</iw:content>
<iw:content mode="edit">Configure me.</iw:content>
</iw:iwidget>
|
从这个 XML 文件中可以看到,该小部件有两个模式。它在默认的 view 模式下显示 “Hello World!” 文本,而在小部件的 edit 模式下显示 “Configure me.”。
- 要测试您的第一个小部件,在任何公共 Web 站点输入这个 XML 文件。获得一个公共 URL,比如 http://www.mycompany.com/widgets/widget.xml,然后在 InfoSphere MashupHub 中注册它。
要完成此步骤,登录到 https://<host>:9443/mashuphub/,然后单击 Upload Widget,如图 1 所示。
图 1. 单击 InfoSphere MashupHub 中的 Upload Widget 链接
- 选择 widget- iWidget,然后单击 Next。
- 在显示的窗口中选择 Register a Widget URL 选项,如图 2 所示。输入小部件的 URL。
图 2. 在 InfoSphere MashupHub 中注册一个 Widget URL
- 单击 Next,然后指定所有必需的信息,比如小部件名称、描述和版本。
- 单击 Finish 以在 InfoSphere MashupHub 中注册小部件。
- 要将此小部件添加到 Lotus® Mashups 工具框,返回到 InfoSphere Mashup Hub 的主 UI,单击 List Widgets,将鼠标移动到新注册的小部件之上,然后单击 Add to Lotus Mashups,如图 3 所示。
图 3. 将小部件添加到 Lotus Mashups
- 指定所有必需的信息,比如 Lotus Mashups 用户名、密码、小部件类别。然后返回到 Lotus Mashups,这个新的小部件将显示在您所选的工具框 drawer 中。将其拖拽到页面后,可以在 view 和 edit 模式下查看小部件 UI,如图 4 所示。
图 4. 在 view 和 edit 模式下的小部件用户界面
将小部件打包为 WAR 文件并上传到 Mashup Catalog
如果您不能在一个公共 Web 站点上托管您的小部件文件,那么可以将小部件打包为 Java Platform, Enterprise Edition WAR 文件。InfoSphere MashupHub 还支持上传一个小部件 WAR 文件并将 WAR 文件中的所有小部件添加到 Lotus Mashups 工具框。将小部件打包为 WAR 文件的另一个好处就是可以利用 JavaServer™ Pages (JSP) 和 servlet 技术来作为小部件的后端,比如数据库操作或事务管理。
可以使用 IBM Rational® Application Developer 或 Eclipse IDE for Java EE Developers (Ganymede Package) 创建一个动态 Web 项目。然后,将 widget.xml 添加到 WebContent 文件夹。还需要将两个特殊文件添加到 WebContent/WEB-INF 文件夹,即 catalog.xml 和 mashup.properties,如图 5 所示。
图 5. Eclipse 项目中的小部件工件
让我们首先查看一下 mashup.properties,如清单 2 所示。
清单 2. mashup.properties 的内容
contextRoot=MonitorWidget
componentName=dw.widget.monitor
|
需要使用 lib 文件夹中的 mashup.properties 文件告诉 IBM Mashup Center 服务器如何部署 WAR 文件。如果参数 contentRoot 没有在该文件中指定,那么 deployer 服务将自动为 Web 应用程序生成一个唯一的上下文根。显式地为这个参数指定一个唯一的名称,这样就可以在小部件内部使用 /%contentRoot%/abc 引用小部件可能会使用的任何 servlet 或资源。参数 componentName 是 mashup.properties 文件的另一个必需属性。IBM Mashup Center deployer 服务使用这个名称确定是否需要进行一次完整的部署或更新。为了避免出现任何冲突,使用一个 Java 风格的包命名约定来命名该属性的值,比如 componentName=com.foo.MyWidget
然后,检查 catalog.xml 的内容,如清单 3 所示。
清单 3. catalog.xml 的内容
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<category name="Test">
<entry id="myWidget" unique-name="myWidget">
<title>
<nls-string lang="en">Memory Monitor</nls-string>
</title>
<description>
<nls-string lang="en">Track the J2EE server memory status</nls-string>
</description>
<definition>widget.xml</definition>
<icon>widget_icon.png</icon>
</entry>
</category>
</catalog>
|
这个样例 catalog.xml 清单包含小部件的元数据(ID、标题、描述、定义和图标)。在这个 catalog.xml 文件中,可以声明多个小部件。换句话说,在 <catalog> 下可以有多个 <entry> 标记。
由于这是一个 Java Platform, Enterprise Edition Web 项目,您可以添加任何数量的 servlet。让我们创建一个 servlet 来获得服务器端 Java Virtual Machine (JVM) 内存使用信息并将其传递给小部件。参见图 6。
图 6. 在 Eclipse IDE 中创建一个 Java servlet
如图 6 所示,在 Create Servlet 窗口中输入以下信息:
- 在 Java package 字段中,输入 dw.widget.monitor。
- 在 Class name 字段中,输入 WidgetServlet。
- 在 Superclass 字段中,输入 javax.servlet.http.HttpServlet。
字段 Web project 和 Source folder 将由 Eclipse IDE 自动填充。
servlet Java 代码非常简单。它调用 Runtime.totalMemory() 和 freeMemory() 方法来获得数据,随后返回一个 JSON-style 响应。参见清单 4。
清单 4. dw.widget.monitor.WidgetServlet 的 Java 源代码
package dw.widget.monitor;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class WidgetServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public WidgetServlet() {
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long total=Runtime.getRuntime().totalMemory();
long current=total-Runtime.getRuntime().freeMemory();
response.getWriter().print("["+total+","+current+"]");
}
}
|
接下来,需要修改小部件定义 XML,删除硬编码的 “HelloWorld!” 文本并添加真正的用户界面。参见清单 5。
清单 5. 更新后的小部件定义 XML (widget.xml) 的内容
<?xml version="1.0" encoding="UTF-8"?>
<iw:iwidget name="myWidget" xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget"
supportedModes="view edit" mode="view" iScope="dw.MonitorWidget">
<iw:resource uri="widget.js" />
<iw:content mode="view">
<![CDATA[
<div style="margin:5px">
<h3>Memory usage:</h3>
<p>Total:<span id="totalMemory">loading..</span> MB ,
Current: <span id="currentMemory">loading..</span> MB </p>
<span id="percentage" style="float:right">loading..</span>
<div style="width:300px;background-color:#f1f1f1;">
<span id="bar" style="height:10px;background-color:#E7AB6D;
border-style:solid;border-width:1px;display:block;width:19%;">
</span>
</div>
</div>
]]>
</iw:content>
<iw:content mode="edit">Configure me.</iw:content>
</iw:iwidget>
|
注意,在 <iw:content mode="view"> 中添加了更多 HTML 元素。其中一些元素提供了一个静态的视图,比如 <h3>Memory usage:</h3>。其他元素则根据来自服务器端的数据动态更新。需要为这些元素指定 ID,这样就可以使用 JavaScript™ 操作它们。
您可能还会注意到,您添加了一个 <iw:resource> 元素并指定了一个 iScope 属性。通过这样做,您可以使用 JavaScript 来控制小部件。JavaScript 文件的路径在 <iw:resource> 标记中指定。参见清单 6 中显示的内容。该文件中定义的类名与 <iw:widget> 标记中 iScope 属性的值相同。
清单 6 展示了 widget.js 的源代码。
清单 6. 小部件 JavaScript 类(widget.js)的内容
dojo.declare("dw.MonitorWidget",null,{
spanTotalMemory:null,
spanCurrentMemory:null,
spanBar:null,
spanPercentage:null,
onLoad:function(){
this.spanTotalMemory=this.iContext.getElementById("totalMemory")
this.spanCurrentMemory=this.iContext.getElementById("currentMemory")
this.spanBar=this.iContext.getElementById("bar")
this.spanPercentage=this.iContext.getElementById("percentage")
this.getDataAndUpdateUI()
var _this=this
setInterval(function(){
_this.getDataAndUpdateUI()
},20*1000)
},
getDataAndUpdateUI:function(){
var _this=this
dojo.xhrGet({
url:"/MonitorWidget/WidgetServlet",
handle:function(data,ioArgs){
var numbers=eval(data)
_this.updateUI(numbers[0],numbers[1])
}
})
},
updateUI:function(total,current){
this.spanTotalMemory.innerHTML=parseInt(total/1024/1024)
this.spanCurrentMemory.innerHTML=parseInt(current/1024/1024)
var percentage=""+parseInt(current/total*100)+"%"
this.spanBar.style.width=percentage
this.spanPercentage.innerHTML=percentage
}
})
|
首先,您利用 dojo.declare() 方法创建了一个新的 JavaScript 类 dw.MonitorWidget。Lotus Mashups 在加载小部件时自动调用 onLoad 方法。在这个方法中,创建一个 JavaScript 计时器来每隔 20 秒钟查询一次服务器端内存使用信息并更新 UI。
要测试 IBM Mashup Center 中的新的小部件,首先在 Eclipse 中右键单击 Web Project,选择 Export - WAR 文件,然后生成一个 WAR 文件。登录到 IBM InfoSphere MashupHub,然后上传这个小部件 WAR 文件。用户界面非常类似于图 2,唯一的不同是您需要选择 Upload a Widget Package 选项。最后,需要将这个小部件添加到 Lotus Mashup 工具框,如图 3 所示。
图 7 展示了在向 mashup 页面添加小部件时显示的窗口。小部件将一个 AJAX 请求发送到服务器来获得最新的内存信息并更新 UI,并且无需刷新整个页面。
图 7. 更新后的样例小部件的用户界面
高级主题
前面的例子已经解释了 iWidget 开发的大部分基本主题。但是,在结束本文之前,让我们快速浏览一些更加高级的主题。
使用 ItemSet
ItemSet API 用于存储和检索 iWidget 属性,该属性通常用于自定义 iWidget 的外观或对 iWidget 进行配置。iWidget 属性可以在 iWidget 定义 XML 中定义并可以通过 ItemSet API 更新。
让我们以 XML 语法为例。参见清单 7。
清单 7. 属性可以定义为项集合 “attributes” 中的项
<iw:itemSet name="attributes" >
<iw:item name="username" value="IBM" readOnly="false"/>
</iw:itemSet>
|
要获得 ItemSet 值,可以调用 iContext.getiWidgetAttributes().getItemValue(“username”)。它返回字符串值 IBM。
要保存 ItemSet 值,需要调用 setItemValue() 方法。参见清单 8。
清单 8. 保存小部件偏好设置的样例代码
this.iContext.getiWidgetAttributes().setItemValue(attributeName,attributeValue,
isReadOnly);
this.iContext.getiWidgetAttributes().save();
|
向 iWidget 添加事件
小部件使用事件来进行部件之间的通信。有两种类型的事件:发布(publish)事件和处理(handle)事件。
让我们使用来自 Feed Reader iWidget 的事件定义为例,Feed Reader iWidget 是 IBM Mashup Center V1 附带的一个生产小部件。参见清单 9。
清单 9. 一个发布事件的样例代码
<iw:event id="feedURLChanged" published="true" eventDescName=
"desc_feedURLChanged" onNewWire="publishURLOnNewWire"/>
<iw:eventDescription id="desc_feedURLChanged" payloadType="string"
description="Publish URL when feed URL setting is changed" lang="en">
<iw:alt discription="" lang="de"/>
<iw:alt discription="" lang="cn"/>
</iw:eventDescription>
|
这个可发布的事件称为 feedURLChanged。它发送字符串负载,如清单 10 所示。
清单 10. 一个处理事件的样例代码
<iw:event id="getFeedFromURL" handled="true"
onEvent="handleGetFeedFromURL" eventDescName="desc_getFeedFromURL"/>
<iw:eventDescription id="desc_getFeedFromURL"
payloadType="string" description="get feed content from the url" lang="en">
<iw:alt discription="" lang="de"/>
<iw:alt discription="get feed content from the url" lang="cn"/>
</iw:eventDescription>
|
该样例是一个称为 getFeedFromURL 的处理事件,该事件可以接受一个字符串作为负载并在被触发时调用函数 handleGetFeedFromURL。
源 iWidget 可以发布源事件,后者使用 iEvents API 触发目标 iWidget 中的目标事件。参见清单 11。
清单 11. 触发事件的样例代码
this.iContext.iEvents.publishEvent("feedURLChanged", newFeedURL);
|
这里提供了一个方便的连接 UI,可以在编辑页面时将两个 iWidgets 连接在一起。图 8 展示了这个连接 UI。
图 8. 使用连接界面的 Lotus Mashups 小部件
连接以清单 12 所示的 span 格式保存在目标 iWidget 实例中。通过以目标小部件的微格式显式定义一个 ReceivedEvent,可以在一个静态页面中连接两个事件。
清单 12. 小部件连接定义的样例微格式代码
<span class="mm_ReceivedEvent" >
<a class="mm_SourceEvent"href="#1"
style="visibility:hidden" > nameOfPublishEvent</a>
<span class="mm_TargetEvent"
style="visibility:hidden" > displayEventData </span>
</span>
|
注意:在锚 <a class=""mm_SourceEvent"> 内部,href 属性指向源部件的 ID。其内容为发布事件的名称。<span class="mm_TargetEvent"></span> 标记的内容为处理事件的名称。
本国语言支持
如果希望向小部件添加本国语言支持(NLS),可以遵循以下步骤:
- 向脚本添加 dojo.require("dojo.i18n");。
- 按照以下方式组织所有依赖于语言的字符串。<lang> 应当使用语言代码替代:
js\nls\<lang>\helloWorldStrings.js
- 随后,在小部件 onLoad method() 中,注册清单 13 中显示的资源,这样小部件 JavaScript 就可以引用它们。
清单 13. 注册 NLS 资源
dojo.registerModulePath("helloWorldWidgetModule",this.iContext.io.rewriteURI("js"));
dojo.requireLocalization("helloWorldWidgetModule","hwStrings");
this.resourceBundle =
dojo.i18n.getLocalization("helloWorldWidgetModule","hwStrings");
|
- 现在可以根据需要引用 helloWorldStrings.js 文件中定义的任何字符串。如果您具有如下所示的字符串:
helloWidgetStr_AskName = What is your name?
那么可以像下面这样引用它:
this.resourceBundle.helloWidgetStr_AskName
结束语
在本文中,我们演示了如何创建一个可以在 IBM Mashup Center 中注册的简单小部件。随后向这个小部件添加了更多特性,比如 Java servlet 后端和 Dojo XmlHttpRequest。在本文的最后部分,我们介绍了一些有关小部件编程的高级主题。
下载 | 名字 | 大小 | 下载方法 |
|---|
| widget.monitor.zip | 11KB | HTTP | | widget.monitor.war | 6KB | HTTP |
参考资料 学习
获得产品和技术
作者简介  | |  | Jove Zhong 是位于上海的 IBM Lotus Mashups UI 开发团队的团队主管。他在 IBM 已经工作了四年,主要从事基于 Flash 或 AJAX 的富 Internet 应用程序开发。 |
 | |  | Wei Shi (Marshall) 是 IBM 中国实验室 IBM Lotus Mashups UI 开发团队的软件工程师。他主要研究 Web 2.0 技术,并且具有超过两年的相关项目经验。 |
 | |  | Zheng Bi (Erik) 是位于中国上海的 IBM Lotus Mashups UI 开发团队的软件工程师,擅长于 Java 和 Web 技术。他在 Web 应用程序开发方面具有超过 2 年的经验。 |
 | |  | Peng Yu (Joard) Zhang 是 IBM 中国实验室的 IBM Lotus Mashups UI 开发团队的软件工程师。 |
对本文的评价
|