跳转到主要内容

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

当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

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

  • 关闭 [x]

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

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

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

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

  • 关闭 [x]

将 XForms 与 Google Web Toolkit 相结合,第 3 部分: 使用 GWT 创建 XForms

为未来的摇滚巨星创建 Web 应用程序

Michael Galpin (mike.sr@gmail.com), 开发人员, Ludi Labs
Michael Galpin 从 1998 年开始从事专业 Java 软件开发。他目前为 Mountain View, Calif. 的一家新兴企业 Ludi Labs 工作。他从 California Institute of Technology 获得了数学学位。

简介: 本系列文章 介绍如何结合使用 Google Web Toolkit (GWT) 和 XForms 创建动态 Web 应用程序,分为四部分。第 1 部分 考察了这两种技术以及它们共同的 JavaScript 基础。第 2 部分 说明了如何创建包括两个页面的小应用程序。一个页面使用 GWT 显示唱片公司旗下的歌手名单。另一个页面使用 XForms 显示某位歌手的唱片。第 3 部分在同一个页面上使用 GWT 和 XForms。通过使用 JavaScript 实现 GWT 和 XForms 之间的交换来说明如何利用这两种技术和 JavaScript 的绑定。

查看本系列更多内容

发布日期: 2007 年 11 月 09 日
级别: 中级
访问情况 : 2186 次浏览
评论: 


简介

阅读 将 XForms 与 Google Web Toolkit 相结合 系列文章:

这是第 3 部分,将进一步完善 第 2 部分 建立的摇滚巨星应用程序。通过该应用程序,唱片公司经理可以管理旗下的歌手和他们的唱片。第 2 部分已经具备的功能仍然保留。但是功能的实现将改为混合使用 GWT 和 XForms。通过这个例子将看到很容易在现有的页面中加入 GWT。我们将使用 GWT 式的 Ajax 调用动态加载数据,然后利用 GWT 的 JSNI 动态创建 XForms 模型。这样可以简化页面,如果使用 GWT JSNI 动态创建 XForms 控件甚至还能进一步简化页面。结合使用 GWT 元素不仅可以简化服务器端代码,而且创建的初始页面更小,下载和呈现的速度更快。


前提条件

本文使用了 GWT 1.4 和 Mozilla XForms 0.8 插件(下载链接参见 参考资料)。Mozilla XForms 插件可用于任何基于 Mozilla 的 Web 浏览器,如 Firefox 和 Seamonkey。使用 GWT 需要对 Java™ 语言以及 HTML 和 CSS 这样的 Web 技术有所了解。文中还用到了大量 JavaScript 代码。XForms 广泛采用模型-视图-控制器(MVC)范型,因此熟悉 MVC 将很有帮助。以前接触过 XForms 和 GWT 当然很好,但并非必须如此。


动态的 XForms?

到目前为止,看到的 XForms 呈现模型实例数据都是放在页面本身之中的。模型数据是动态的。您使用了 JSP 脚本查询和筛选数据,然后将 XML 写入页面。现在我们将进一步提高 XForms 页面的动态性。不再把实例数据写入页面,而是从服务器异步检索数据然后将其动态增加到页面模型中。我们使用 GWT 进行 Ajax 调用,使用 GWT JSNI 修改 XForms 模型。


向 XForms 页面添加 GWT

我们将在 XForms 唱片页面上使用 GWT。这就带来了一个问题,即如何向已有的网页添加 GWT?非常简单。只需要包括 GWT Java-JavaScript 编译器从代码生成的 JavaScript 库。每个模块一个文件。在 XForms 页面中就变成了清单 1 中所示的代码行。


清单 1. 向唱片页面引入 GWT
                
<xhtml:script language="text/javascript" 
src="org.developerworks.rockstar.RockStarMain.nocache.js"></xhtml:script>

在页面中加入 GWT 如此简单,开发人员常常惊讶不已。毫无疑问这正是设计时的初衷。大部分关于 GWT 的例子都是 “green field” 应用程序,换句话说,就是都是使用 GWT 从头开始创建的。但实际上遗留应用程序至少一样常见,这两种情形 GWT 都适用。要记住,所有的 GWT 都只不过是 JavaScript。所以这么简单也就情有可原了。现在在页面中加入了 GWT,可以开始编写 GWT 代码(或者说将被编译成 JavaScript 的 Java 代码)了。


使用 Ajax 载入唱片数据:用 JSNI 操作 XForms 数据

本系列文章的 第 2 部分 中使用 GWT 向页面加载歌手的名单。该操作是异步完成的。换句话说,创建了页面然后发出 Ajax 请求来获取歌手名单。现在我们要对唱片采用同样的技术。因此需要一种服务来使用 GWT Ajax 加载唱片。


建立远程服务

首先要声明服务接口,如清单 2 所示。


清单 2. Album Service 接口
                
package org.developerworks.rockstar.client;

import com.google.gwt.user.client.rpc.RemoteService;

public interface AlbumService extends RemoteService{
 public Album[] getAlbumsForArtist(int artistId);
 public void addAlbum(Album newAlbum);
}

和第 2 部分中创建的服务差不多。类似的,还需要服务的异步版本,如清单 3 所示。


清单 3. 异步服务接口声明
                
package org.developerworks.rockstar.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface AlbumServiceAsync {
 public void getAlbumsForArtist(int artistId, AsyncCallback callback);
 public void addAlbum(Album newAlbum, AsyncCallback callback);
}

最后还需要服务的服务器端实现,该实现必须扩展 GWT 的 RemoteServiceServlet,以便客户机能够使用 HTTP 调用它。如清单 4 所示。


清单 4. Album 服务实现
                
package org.developerworks.rockstar.server;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.developerworks.rockstar.client.Album;
import org.developerworks.rockstar.client.AlbumService;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class AlbumServiceImpl extends RemoteServiceServlet implements AlbumService {

 private static final long serialVersionUID = -2706402745094297460L;
 private Map<Integer,List<Album>> albumCache;
 private AlbumDao dao;
 
 public AlbumServiceImpl(){
 this.dao = new AlbumFileDao();
 List<Album> allAlbums = this.dao.getAllAlbums();
 // initialize cache
 int size = allAlbums.size();
 this.albumCache = new HashMap<Integer, List<Album>>(size);
 for (Album album : allAlbums){
 int artistId = album.getArtistId();
 List<Album> albums = this.albumCache.get(artistId);
 if (albums == null){
 albums = new ArrayList<Album>();
 this.albumCache.put(artistId, albums);
 }
 albums.add(album);
 }
 }

 public void addAlbum(Album newAlbum) {
 int artistId = newAlbum.getArtistId();
 List<Album> albums = this.albumCache.get(artistId);
 if (albums == null){
 albums = new ArrayList<Album>();
 this.albumCache.put(artistId, albums);
 }
 albums.add(newAlbum);
 List<Album> all = this.getAllAlbums();
 this.dao.saveAlbums(all);
 }

 public Album[] getAlbumsForArtist(int artistId) {
 List<Album> albums = this.albumCache.get(artistId);
 if (albums == null){
 return null;
 }
 Album[] array = new Album[albums.size()];
 array = albums.toArray(array);
 return array;
 }
 
 private List<Album> getAllAlbums(){
 List<Album> allAlbums = new ArrayList<Album>();
 for (int artistId : this.albumCache.keySet()){
 List<Album> albums = this.albumCache.get(artistId);
 allAlbums.addAll(albums);
 }
 return allAlbums;
 }

}

另外,我们已经使用了 Data Access Object (DAO) 模式来抽象物理数据的管理(从文件系统检索数据、解析 XML 等)。这样很容易就能把过于简单化的基于 XML 文件的实现改成更加标准的数据库驱动实现。现在 GWT 代码可以使用新建立的服务了。


使用 GWT 调用远程服务

org.developerworks.rockstar.client 包中的所有代码都将被编译成 JavaScript,可以从包含该 JavaScript 库的任何页面中调用,如清单 1 所示。因此我们将创建一个新的 Java 类来处理唱片页面。源代码如清单 5 所示。


清单 5. AlbumLib
                
package org.developerworks.rockstar.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;

public class AlbumLib {
 public void loadAlbums(int artistId){
 AlbumServiceAsync albumService = this.getAlbumService();
 AsyncCallback callback = new AsyncCallback(){

 public void onFailure(Throwable caught) {
 // TODO Auto-generated method stub
 
 }

 public void onSuccess(Object result) {
 Album[] albums = (Album[]) result;
 for (int i=0;i<albums.length;i++){
 addAlbumToModel(albums[i]);
 }
 refreshXformsModel();
 }
 
 };
 albumService.getAlbumsForArtist(artistId, callback);
 }
 
 private AlbumServiceAsync getAlbumService(){
 AlbumServiceAsync albumService = (AlbumServiceAsync) 
 GWT.create(AlbumService.class);
 ServiceDefTarget endpoint = (ServiceDefTarget) albumService;
 String moduleRelativeUrl = GWT.getModuleBaseURL() + "albumService";
 endpoint.setServiceEntryPoint(moduleRelativeUrl);
 return albumService;
 }
 
 private native void addAlbumToModel(Album album)/*-{
 var model = $doc.getElementById("albums");
 var instance = model.getInstanceDocument("albumData");
 var dataElement = instance.getElementsByTagName("Data")[0];
 // create the new album node
 var newAlbumElement = instance.createElement("Album");
 var titleElement = instance.createElment("Title");
 titleElement.appendChild(instance.createTextNode(album.getTitle()));
 newAlbumElement.appendChild(titleElement);
 var yearElement = instance.createElement("Year");
 yearElement.appendChild(instance.createTextNode(album.getYear()));
 newAlbumElement.appendChild(yearElement);
 dataElement.appendChild(newAlbumElement);
 }-*/;
 
 private native void refreshXformsModel()/*-{
 var model = $doc.getElementById("albums");
 model.rebuild();
 model.recalculate();
 model.refresh();
 }-*/;
}

这个 Java 类做了很多工作。首先,它提供了两个 Java 方法远程调用前面建立的 AlbumService。这和 第 2 部分 中调用 ArtistService 很相似。代码中包含服务成功响应异步请求时调用的回调函数。这里,回调函数用到了另外两个方法,addAlbumToModel()refreshXformsModel()

这两个方法都是 JavaScript 原生方法,和第 1 部分中看到的例子类似。

addAlbumToModel() 方法访问表示 XForms 模型的 JavaScript 对象。从而能够访问 XML 实例数据。您已经看到,第 1 部分 是使用常见的 JavaScript 格式 document.getElementById(...) 实现的。要注意的是,由于是 GWT,必须使用 $doc 来代替 JavaScript 隐含的 document 对象。得到文档引用之后,就可以用熟悉的 DOM 方法向 XML 对象中添加新的唱片了。要反复调用 addAlbumToModel 方法,把服务器返回的唱片全部加进去。遍历服务器响应之后,就用到 refreshXformsModel() 方法了。这也是一个原生方法。它再一次获得 XForms 模型的句柄,然后利用该对象的 API 刷新绑定到模型的控件。

最好,还需要保证在页面加载的时候调用 GWT 方法。为此需要修改原来的 Albums.jsp,如清单 6 所示。


清单 6. 从 JSP 调用 GWT JavaScript
                
<?xml version="1.0" encoding="UTF-8"?>
<xhtml:html xmlns:ev="http://www.w3.org/2001/xml-events" 
xmlns:xforms="http://www.w3.org/2002/xforms" 
 xmlns:xhtml="http://www.w3.org/1999/xhtml" 
 xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <xhtml:head>
 <xhtml:title>Albums</xhtml:title>
 <xhtml:script language="text/javascript"
 src="org.developerworks.rockstar.RockStarMain.nocache.js">
 </xhtml:script>
 <xforms:model id="albums" xmlns="http://www.w3.org/1999/xhtml" 
 xmlns:xforms="http://www.w3.org/2002/xforms">
 <xforms:instance id="albumData" xmlns=""/>
 </xforms:model>
 </xhtml:head>
 <xhtml:body onload="loadAlbums(<%=request.getParameter("artistid") %>)">
 <xhtml:div id="albumList">
 <xforms:repeat id="repeatItem" 
 nodeset="instance('albumData')/Data/Album"
 xmlns="http://www.w3.org/1999/xhtml" 
 xmlns:xforms="http://www.w3.org/2002/xforms">
 <xhtml:div>
 <xforms:output ref="Title" xmlns="http://ww.w3.org/1999/xhtml" 
xmlns:xforms="http://www.w3.org/2002/xforms">
 <xforms:label 
 xmlns:xforms="http://www.w3.org/2002/
 xforms">Title:</xforms:label>
 </xforms:output>
 <xforms:output ref="Year" xmlns="http://www.w3.org/1999/xhtml"
xmlns:xforms="http://www.w3.org/2002/xforms">
 <xforms:label 
 xmlns:xforms="http://www.w3.org/2002/
 xforms">Year:</xforms:label>
 </xforms:output>
 </xhtml:div>
 </xforms:repeat>
 </xhtml:div>
 </xhtml:body>
</xhtml:html>

可以看到,仅仅在页面体加载完成之后才调用 GWT 方法。此外,原来的脚本就不再需要了。但页面体声明中仍然有一个非常小的脚本。它仅仅用来传入 artistId 请求参数。现在的大部分代码用于创建 UI 控件。我们看看如何也用 GWT 通过编程来创建控件。


用 GWT JSNI 创建 XForms 控件

前面介绍了如何使用 GWT 和 JSNI 访问 XForms 模型和实例数据。我们再前进一步,看看如何使用 GWT 和 JSNI 动态创建 XForms 控件。首先用 JavaScript 代码替换重复出现的控件,如清单 7 所示。


清单 7. 用 GWT JSNI 动态创建 XForms 控件
                
private native void createControls()/*-{
 var xfNs = "http://www.w3.org/2002/xforms";
 // get the container div
 var container = $doc.getElementById("albumList");
 
 var repeater = $doc.createElementNS(xfNs,"xforms:repeat");
 repeater.setAttribute("id", "repeatItem");
 repeater.setAttribute("nodeset", "instance('albumData')/Data/Album");
 
 var titleOut = $doc.createElementNS(xfNs, "xforms:output");
 titleOut.setAttribute("ref", "Title");
 var titleLabel = $doc.createElementNS(xfNs, "xforms:label");
 titleLabel.appendChild($doc.createTextNode("Title:"));
 titleOut.appendChild(titleLabel);
 repeater.appendChild(titleOut);
 
 var yearOut = $doc.createElementNS(xfNs, "xforms:output");
 yearOut.setAttribute("ref", "Year");
 var yearLabel = $doc.createElementNS(xfNs, "xforms:label");
 yearLabel.appendChild($doc.createTextNode("Year:"));
 yearOut.appendChild(yearLabel);
 repeater.appendChild(yearOut);
 
 container.appendChild(repeater);
}-*/;

同样也是使用原生的 JavaScript 通过简单的 DOM 编程来创建 XForms 控件。完成上述代码后,剩下的就是将其添加到 loadAlbums() 方法中,加载页面的时候调用该方法。JSNI 代码将创建控件,然后调用远程服务检索唱片信息了。然后使用唱片数据动态创建 XForms 模型实例数据。再刷新 XForms 模型以便绑定的控件显示新的数据。JSP 非常简单,如清单 8 所示。


清单 8. 简化后的 JSP —— 没有了 XForms 控件
                
    <xhtml:body onload="loadAlbums(<%=request.getParameter("artistid") %>)">
 <xhtml:div id="albumList">
 </xhtml:div>
 </xhtml:body>
 

转瞬之间,XForms JSP 看起来就像是显示歌手名单的 GWT HTML 页面了。所有的 UI 都使用 Java 类编译成的 JavaScript 动态创建。数据使用 GWT Ajax 检索。

结束语

本文中,我们把一个大量使用 JSP 脚本装载数据的 XForms 页面变成了主要依靠 GWT 的小页面。利用 GWT 的 Ajax 机制从服务器异步加载数据。然后使用 GWT 的 JSNI 工具动态创建 XForms 模型中的实例数据。最后,沿着 JSNI 的路线更进一步,利用它动态创建显示唱片数据所需要的全部 XForms 控件。第 4 部分将介绍如何使用 XForms 控件按需调用 GWT Ajax。



下载

描述名字大小下载方法
第 3 部分样例代码rockstar3_src.zip14KBHTTP

关于下载方法的信息


参考资料

学习

获得产品和技术

讨论

关于作者

Michael Galpin 从 1998 年开始从事专业 Java 软件开发。他目前为 Mountain View, Calif. 的一家新兴企业 Ludi Labs 工作。他从 California Institute of Technology 获得了数学学位。

关于报告滥用的帮助

报告滥用

谢谢! 此内容已经标识给管理员注意。


关于报告滥用的帮助

报告滥用

报告滥用提交失败。 请稍后重试。


developerWorks:登录


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


忘记密码?
更改您的密码

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

 


当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

请选择您的昵称:

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

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

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


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

 


为本文评分

评论

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML, Java technology, Open source
ArticleID=268259
ArticleTitle=将 XForms 与 Google Web Toolkit 相结合,第 3 部分: 使用 GWT 创建 XForms
publish-date=11092007
author1-email=mike.sr@gmail.com
author1-email-cc=ruterbo@us.ibm.com

标签

Help
使用 搜索 文本框在 My developerWorks 中查找包含该标签的所有内容。

使用 滑动条 调节标签的数量。

热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。

我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。

使用搜索文本框在 My developerWorks 中查找包含该标签的所有内容。热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。