对于那些宁愿使用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 —— 它非常有用!)