对于那些宁愿使用Google Web Toolkit(以下简称:GWT)去开发动态的AJAX的应用程序的人们来说,Seam提供了一个允许GWT widget直接与Seam组件交互的整合层。
为了使用GWT,我们假设你已经很熟悉GWT工具 - 更多信息可以在 http://code.google.com/webtoolkit/ 中找到。 本章就不去解释GWT如何工作以及如何使用了。
在Seam应用程序中使用GWT并不需要特别的配置,但是Seam资源的servlet是必须安装的。更多详情请看 Chapter 25, Seam配置和Seam应用程序打包 。
准备一个要通过GWT进行调用的Seam组件的第一步,是给你想要调用的方法创建同步和异步的服务接口。这两个接口都应该扩展GWT接口 com.google.gwt.user.client.rpc.RemoteService :
public interface MyService extends RemoteService
{
public String askIt(String question);
}异步接口应该完全相同,除此之外,它还要给它声明的每一个方法包含一个额外的 AsyncCallback 参数:
public interface MyServiceAsync extends RemoteService
{
public void askIt(String question, AsyncCallback callback);
}在这个范例 MyServiceAsync 中,异步接口将通过GWT实现,并且永远不应该直接实现。
下一步,是创建一个实现同步接口的Seam组件:
@Name("org.jboss.seam.example.remoting.gwt.client.MyService")
public class ServiceImpl implements MyService
{
@WebRemote
public String askIt(String question)
{
if (!validate(question))
{
throw new IllegalStateException("Hey, this shouldn't happen, I checked on the client, " +
"but its always good to double check.");
}
return "42. Its the real question that you seek now.";
}
public boolean validate(String q)
{
ValidationUtility util = new ValidationUtility();
return util.isValid(q);
}
}应该做成能通过GWT访问的那些方法,需要通过标识 @WebRemote 进行注解,这是所有能够进行Web远程访问的方法都要求的。
下一步,是编写一个将异步接口返回给组件的方法。这个方法可以放在小组件类里面,将被小组件用来获得一个对异步客户端存根(stub)的引用:
private MyServiceAsync getService()
{
String endpointURL = GWT.getModuleBaseURL() + "seam/resource/gwt";
MyServiceAsync svc = (MyServiceAsync) GWT.create(MyService.class);
((ServiceDefTarget) svc).setServiceEntryPoint(endpointURL);
return svc;
}最后一步就是编写小组件代码,它在客户端存根上调用方法。以下代码创建一个简单的用户接口,包含label(标签)、text input(文本输入框)和一个button(按钮):
public class AskQuestionWidget extends Composite
{
private AbsolutePanel panel = new AbsolutePanel();
public AskQuestionWidget()
{
Label lbl = new Label("OK, what do you want to know?");
panel.add(lbl);
final TextBox box = new TextBox();
box.setText("What is the meaning of life?");
panel.add(box);
Button ok = new Button("Ask");
ok.addClickListener(new ClickListener()
{
public void onClick(Widget w)
{
ValidationUtility valid = new ValidationUtility();
if (!valid.isValid(box.getText()))
{
Window.alert("A question has to end with a '?'");
}
else
{
askServer(box.getText());
}
}
});
panel.add(ok);
initWidget(panel);
}
private void askServer(String text)
{
getService().askIt(text, new AsyncCallback()
{
public void onFailure(Throwable t)
{
Window.alert(t.getMessage());
}
public void onSuccess(Object data)
{
Window.alert((String) data);
}
});
}
...
当点击按钮时,它就调用 askServer() 方法来传递输入框的内容(在这个例子中,还执行了验证,以确保输入的是有效的问题)。这个 askServer() 方法获得一个对异步客户端存根的引用(由 getService() 方法返回),并调用 askIt() 方法。这个结果(或者调用失败时的错误信息)显示在以一个警告窗口中。

这个例子的完整代码可以在Seam发行包的 examples/remoting/gwt 中找到。
对于GWT应用程序的发布(部署)来说,有一个编译成JavaScript的步骤(它压缩和混淆了代码)。 有一个Ant实用程序可以用来取代GWT提供的命令行或者GUI实用程序。 为了使用这个功能,你不仅在Ant classpath中要有Ant的任务jar包,还要下载GWT(无论怎样,你在本机模式下时也会需要它)。
接下来在你的Ant文件中(在你的Ant文件顶头附近)
<taskdef uri="antlib:de.samaflost.gwttasks"
resource="de/samaflost/gwttasks/antlib.xml"
classpath="./lib/gwttasks.jar"/>
<property file="build.properties"/>创建一个 build.properties 文件,它包括以下内容:
gwt.home=/gwt_home_dir
这当然应该指向GWT的安装路径。然后用它创建一个Target:
<!-- the following are are handy utilities for doing GWT development.
To use GWT, you will of course need to download GWT seperately -->
<target name="gwt-compile">
<!-- in this case, we are "re homing" the gwt generated stuff, so in this case
we can only have one GWT module - we are doing this deliberately to keep the URL short -->
<delete>
<fileset dir="view"/>
</delete>
<gwt:compile outDir="build/gwt"
gwtHome="${gwt.home}"
classBase="${gwt.module.name}"
sourceclasspath="src"/>
<copy todir="view">
<fileset dir="build/gwt/${gwt.module.name}"/>
</copy>
</target>This target when called will compile the GWT application, and copy it to the specified directory (which would be in the webapp part of your war - remember GWT generates HTML and Javascript artifacts). You never edit the resulting code that gwt-compile generates - you always edit in the GWT source directory. 当这个Target被调用时,将编译GWT应用程序,并将它复制到指定的目录中(它会在你war的 webapp 部分中 —— 记住GWT生成HTML和Javascript工件)。 你永远不用编辑 gwt-compile 生成的结果代码 —— 你始终在GWT源路径中进行编辑。
记住GWT有一个本机模式浏览器 —— 你在用GWT开发时使用的应该就是它。 如果你没有使用该浏览器,而只是每次对它进行编译,那你就没有充分利用这个工具包(事实上,如果你无法或者没有使用本机模式浏览器,我只能说你根本不应该使用GWT —— 它非常有用!)