<script language="JavaScript" type="text/javascript">
</script>
Benjamin Muskalla (bmuskalla@innoopract.com ), 软件工程师, Innoopract Informationssysteme GmbH
2008 年 1 月 14 日
Rich Client Platform (RCP) 是一项用于构建企业应用程序的强大平台技术。在 Rich Ajax Platform (RAP) 的帮助下,它将变得更有趣,因为可以重用 Web 应用程序的现有代码库和开发技巧,如 “
富客户端平台 ”系列的第 1 部分中所述。RAP 有一些值得注意的功能使 Web 开发更具吸引力。本文将超越 Hello World 示例,并说明一些关键概念以及如何使用 RAP 所提供的高级功能。
在开始研究新功能之前,我们希望大致介绍 RAP 的组织方法及其重要性。然后,我们将讨论一些有趣的主题,如后台作业、用户界面 (UI) 自定义,并且将介绍更加高级的主题,例如自定义小部件和主题。如果这些讨论超出了您所掌握的现有 RAP 知识,请返回到 第 1 部分 或查看 参考资料 。
请访问 Ajax 技术资源中心 ,这是有关 Ajax 编程模型信息的一站式中心,包括很多文档、教程、论坛、blog、wiki 和新闻。任何 Ajax 的新信息都能在这里找到。
RAP 的架构
要高效地开发基于 RAP 的应用程序,在某些情况下您需要知道它的工作原理 。我们不希望介绍过多内部机制让您感到厌烦,但是必须说明一些基本概念来帮助您用 RAP 进行开发。下面的示意图通过对比 RCP 的方式介绍了 RAP 组织方式。
图 1. RCP 和 RAP 的对比 正如您所看到的,RAP 分为两部分。一方面,有运行在 Equinox(OSGi 规范的 Eclipse 实现)之上的服务器端 部分。而另一方面,有客户机 部分,这部分是您在浏览器中看到的内容。两端将交换事件,各自的 UI 将相应更新。这意味着大部分代码在服务器上执行,而瘦客户 端仅在必要时更新。这样做的好处是可以运行干净的 Java™ 应用程序而无需在客户机上安装应用程序本身。
RAP 不是 RCP
构造可以在两种环境中运行的应用程序 即使 RAP 不是 RCP,也可以在 RAP 和 RCP 应用程序之间共享大量代码。为此,建议配置一个插件,将该插件用作包含可以在 RAP 和 RCP 中使用的 UI 代码的基本插件。要完成此操作,建议使用 MANIFEST.MF 中的 Import-Package 来指定依赖性。这将允许您的基本插件使用来自 RAP 或 RCP 的包。您不会将自己与某个具体实现绑定起来。设置完基本插件后,建议多配置两个插件,一个用于 RAP 专用的代码,另一个用于 RCP 专用的代码。最后,配置两个工作区,其中一个设置 RAP 的目标平台,另一个设置 RCP 的目标平台。将来,我们希望随着工具的演变,应用程序开发人员编写在 RAP 和 RCP 中运行的代码会变得更容易。
此部分的标题应该不会吓到您,但是您必须了解它。如 第 1 部分 中所示,将 RCP 应用程序迁移到启用 Web 的 RAP 副本中非常简单。开发 RCP 应用程序时,通常的情况是一次将只有一个用户使用该应用程序。相反地,运行在服务器上的 RAP 应用程序将由多个(或者上千)用户同时使用。这种情况将导致重新思考 RAP 应用程序开发中的一些概念。一个有趣的方面是实现 单例(singleton) 模式的类的单例性。在所谓的 “应用程序范围” 内,单例是惟一的。在 RAP 应用程序中存在几个范围:
应用程序范围
应用程序范围是适用于所有用户的最大范围。单例对于整个应用程序都是惟一的,并且因此存在于应用程序范围内。这意味着应用程序的所有用户都将使用单例的同一个实例。这可能非常有益,但如果实例保存一些用户特定的信息,那么也不总是一件好事。
会话范围
会话范围仅与当前用户可用的当前用户会话绑定。要实现一个仅绑定特定会话的单例,可以使用 RAP 提供的
SessionSingletonBase
类。通过扩展该类并覆盖其
getInstance
方法,该类将像单例一样运行,但是仅可用于会话范围内。
请求范围
请求范围是三个范围中最小的范围。只有在处理请求时它才可用。大多数时间里,此范围实际上与普通开发人员无关(除非需要了解 RAP 的生命周期概念)。
后台作业
RAP 最令人激动的功能之一是支持 Eclipse Jobs 框架。通过作业的帮助,可以在后台运行需要长期运行的任务,而 UI 仍然可以做出响应。为了了解其工作原理,我们将用一个安排作业的新操作来扩展第 1 部分中的邮件应用程序(参见清单 1)。
清单 1. 添加操作 (ApplicationActionBarAdvisor.java)
....
private Action progressAction;
...
protected void makeActions(final IWorkbenchWindow window) {
...
progressAction = new SampleProgressAction();
progressAction.setText("Count me!");
progressAction.setId("progress.action");
register(progressAction);
}
...
protected void fillCoolBar(ICoolBarManager coolBar) {
...
toolbar.add(progressAction);
}
除了作业 API 之外,RAP 还提供了大家熟知的用于处理作业的 UI,我们稍后就会看到它。要在工作区中激活此功能,可以指示 Eclipse 显示进度指示器(参见清单 2)。
清单 2. 启用进度指示器 (ApplicationWorkbenchWindowAdvisor.java)
...
public void preWindowOpen() {
...
configurer.setShowProgressIndicator(true);
}
...
接下来是最有趣的部分:作业 。我们的示例是一个简单实现(参见清单 3),该实现只是把变量增加到一个特定数量并在完成每个步骤之后等待,以便查看 UI 中发生的情况。
清单 3. 作业 (SampleProgressAction.java)
package rap.mail;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
public class SampleProgressAction extends Action {
private static final int TASK_AMOUNT = 100;
public void run() {
Job job = new Job("Long Running Action:") {
protected IStatus run(final IProgressMonitor monitor) {
monitor.beginTask("Number counting", TASK_AMOUNT);
for (int i = 0; i < TASK_AMOUNT; i++) {
if (monitor.isCanceled()) {
monitor.done();
return Status.CANCEL_STATUS;
}
int done = i % TASK_AMOUNT;
monitor.subTask("work done: (" + done + "%)");
monitor.worked(1);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
monitor.done();
return Status.OK_STATUS;
}
};
job.setName(job.getName() + " " + job.hashCode());
job.setUser(true);
job.schedule();
}
}
在启动应用程序并单击 antion 后,将显示一个新对话框,告诉我们当前运行的作业的进度。如果不需要等待作业完成,可以通过单击 Run in background 把它隐藏起来。此外,还可以在状态栏中单击进度图标打开进度视图。如果同时有多个作业在运行,则可以在进度视图中轻松地查看这些作业(参见图 2)。
图 2. 后台作业
标识
对于大多数基于 RCP 和基于 RAP 的应用程序,需要根据喜好标识 它们。标识是指修改应用程序的外观以满足您的目的,如符合现有企业标识。如果曾经开发过 RCP 应用程序,则有一个 .product
文件的概念可以帮助标识应用程序。由于 RAP 的目标是另一个平台 (Web),因此需要做一些额外的工作来自定义应用程序。
图 3. 带有样例标识的清单编辑器 正如您所见,自定义 RAP 应用程序的方法有很多种。
属性 描述 servletName servletName
将定义应用程序可用于外部世界的 servlet 的名称。这意味着应用程序的 URL 将显示为 http://<host><port>/<servletName>defaultEntrypointId 在没有 startup
参数的情况下访问应用程序,通常有一个应当默认装载的入口点,因此可以定义 defaultEntrypointId
。 themeId 可以在这里指定用于此标识的主题。需要为 org.eclipse.rap.ui.themes
的扩展所定义的主题提供一个 ID。如果没有 themeId
,则使用 RAP 标准主题。 title 可以用此属性自定义页面标题 —— 在大多数浏览器中显示为窗口标题或者选项卡标题。 favicon favicon
是显示在浏览器地址栏中的图标。这必须是一个有效的 .ico 文件 才能显示在浏览器中。body 如果 RAP 索引页面中需要使用一些自定义 (X)HTML 标记,则可以用生成的索引页面的 body 标记中包括的 body
属性来注册一个有效的 (X)HTML 文件。 exitConfirmation 如果非空,则 exitConfirmation
中的字符串将显示给想要离开 RAP 应用程序的用户。该属性对于避免用户意外关闭浏览器窗口/选项卡十分有用。
重新启动带有新标识的应用程序后,可以看到结果。
图 4. 带有标识的应用程序
主题
RAP 应用程序的主题将定义用户将看到的应用程序的界面外观。请不要认为它类似于 RCP 工作区中的主题支持,它更类似于常用操作系统对定义窗口、按钮等外观的支持。通常,RAP 主题允许定义:
自定义颜色 自定义字体 自定义边界 自定义尺寸和框尺寸(填充等) 自定义图片和图标 不过,实际上可以自定义哪些方面取决于要定义主题的特殊控件。一些控件允许更大的灵活性,而其他控件需要硬连接。例如,默认界面外观与自定义主题之间的差异可能如图 5 所示。
图 5. 运行的自定义主题 创建主题
在 RAP 中,主题文件是简单的 Java 属性文件。可以在 RAP org.eclipse.rap.rwt 插件的 src/ 目录中找到名为 theme-template.properties 的模板。只需要指定与自定义相关的那些属性(未定义的属性将保留为默认值)。查看下列清单以获得属性值的语法。下面是简单主题文件的示例。
清单 4. 简单主题文件
# Alternative Demo Theme
#
# Frame border for group boxes
# default: 1 solid #aca899
group.frame.border: 2 dotted #56a0ea
# Font for title bar of Shells
# default: bold 11 "Segoe UI", Corbel, Calibri, Tahoma, "Lucida Sans Unicode", sans-serif
shell.title.font: bold 15 "Trebuchet MS", Arial, Helvetica, sans-serif
# Height of the title bar of Shells
# default: 18
shell.title.height: 25
...
注册主题
要使主题可用,必须用扩展点 org.eclipse.rap.swt.themes
注册它。在应用程序项目的 plugin.xml 中,添加如清单 5 所示的扩展。
清单 5. 使主题可用
<extension
point="org.eclipse.rap.swt.themes">
<theme
id="org.eclipse.rap.dw.demotheme"
name="Alternative Demo Theme"
file="theme1/theme.properties" />
</extension>
激活主题
要激活主题,必须在标识中指定 themeId
。将其设置为新创建主题的 ID:org.eclipse.rap.demo.alttheme
。重新启动应用程序后,可以看到新样式下的应用程序。
图 6. 运行的自定义主题
自定义小部件
构造可以在两种环境中运行的应用程序 Google Web Toolkit 和 RAP 十分类似,它们都允许您使用 Java 技术编写富 Internet 应用程序。最大的差别是 GWT 运行在客户机上,而 RAP 主要运行在服务器上。由于 RAP 运行在服务器上,因此它允许您通过 OSGi 访问完整的 Java API 和使用著名的 Eclipse 插件模型。可以从 Eclipse 方面看待这种差别,GWT 类似一个独立的 SWT 应用程序(只是一个小部件工具包),而 RAP 为 Web 应用程序启用了 RCP 样式的方法。
最重要的是:RAP 中有两种自定义小部件。可以通过组合现有小部件构成一个新的小部件来开发小部件,也可以开发真正自定义小部件(也称为自制 小部件。当谈到混合小部件时,SWT (RCP) 与服务器端 (RAP) 没有差别。在大多数时间里,您都应当能够在 RAP 应用程序中重用现有混合小部件。
更复杂的情况是创建一个真正自定义的小部件。用 RAP 开发小部件时,必须注意我们有两个不同的运行时:服务器端 和客户端 实现。在服务器上,小部件带有自定义小部件用户所使用的公共 API。在客户机上,真正的实现是用 JavaScript 完成的。诀窍在于连接客户机和服务器部分。RAP 提供了一种生命周期 内部概念,其中将考虑到所有小部件。生命周期负责初始化和小部件在客户机与服务器之间的数据交换。实现自定义小部件略微超出本文的讨论范围,建议在 RAP 帮助文档中了解关于自定义小部件的更多信息(请参阅 参考资料 )。为了进行说明,图 7 显示了 SWT 小部件中封装的 Google Maps的屏幕快照,其访问方式与所有其他小部件相同。
图 7. Google Maps RAP 小部件
结束语