一 GWT是什么?
1 简介
“The heart of GWT is a compiler that converts Java source into JavaScript, transforming your working Java application into an equivalent JavaScript application.”
GWT是一个javascript或者说ajax的开发工具。但使用java作为开发语言。用户编写的java code由GWT Compiler编译成js脚本。
这里的java code是受限的java语言。它与java语言标准基本一致(稍许区别),但支持的java类库仅有java.lang, java.util。具体的区别参见文档:GWT文档的Develop Guide>Fundamentals >GWT Compiler。
2 开发流程
Code In java, test , debug (hosted mode)
Compile into javascript
Run (web mode)
3 开发工具
GWT(projectCreator.cmd, applicationCreator.cmd, junitCreator.cmd, lib)
ant
eclipse
4 开发流程
使用projectCreator.cmd, applicationCreator.cmd创建一个工程,程序
project-Creator
Src
.project
.classpath
projectName.ant.xml
applicationCreator.cmd(新建客户端类):
appName-compile.cmd
appName-shell.cmd
appName.launch
src/com/comName/projectName/client/app.java
src/com/comName/projectName/public/app.html
src/com/comName/projectName/app.gwt.xml
二 专题
1 构造复杂页面(参见:Develop Guide>Buiding User Interface)
由GWT生成的工程,是为了开发采用了AJAX技术的web应用程序。他工作起来更像一个运行在浏览器中的应用程序。网页的界面一部份是html文档中的静态页面,另一部份是由js脚本生成的。生成界面的脚本由GWT编译器编译java程序得到。
在开发时,对于界面,我们要做的工作就是:编辑静态页面(位于src/com/comName/projectName/public中),以及开发java源程序以生成js脚本(位于src/com/comName/projectName/client中)。
在GWT中,仅支持java.lang, java.util类库, 不支持java.awt, javax.swing这些java界面类库。在GWT工程的java程序中,界面的实现是通过使用GWT提供的界面类库,(主要的类有:com.google.gwt.user.client.ui.Widget,com.google.gwt.user.client.ui.Panel)来实现的。
下面我们通过一个例子来看看脚本生成的界面。
在GWT开发过程中,一个application最基本的构成由一个静态网页和一个java源程序。Java源程序必须包含一个public void onModuleLoad()函数,这个函数是继承自com.google.gwt.core.client.EntryPoint一个函数(但在给出的sample中有一个类没有实现该接口);在这个函数中通过操纵com.google.gwt.user.client.ui.RootPanel来向网页中增加界面内容。以下是一个最简单的java源程序的构成:
package com.google.gwt.sample.hello.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
public class Hello implements EntryPoint {
public void onModuleLoad() {
Button b = new Button("Click me", new ClickListener() {
public void onClick(Widget sender) {
Window.alert("Hello, AJAX ");
}
});
RootPanel.get().add(b);
}
}
RootPanle.get()函数仍然返回一个RootPanle对象,参数是一个字符串或者为空。这个参数的意义是:它对应于该application中静态页面中一个元素的id属性。返回的是给id对应元素关联的RootPanle对象,也就是该元素对应的显示区域。
Panel的概念和javax.swing中Panel的概念类似,Widget和javax.swing中的控件的概念类似。
一些基本的控件在GWT文档的Develop Guide>Buiding User Interface>Widgets Gallery中有一个展示。
由js脚本生成并添加到页面中的控件在静态页面的源文件中没有任何html代码信息。
2 事务处理及Layout
与java.awt, javax.swing中事件处理机制类似,只是现在要使用的是com.google.gwt.user.client.ui中的类库。
3 和Servlet的数据交互(参见:Developer Guide>Remote Procedure Calls)
运行在浏览器中的应用程序通过Remote Service的概念和服务器交互。
首先在客户端的java代码中,先定义自己的服务接口,这个接口要继承com.google.gwt.user.client.rpc.RemoteService接口。
这个自动义的接口提供了可远程调用的函数。以下是个例子:
public interface MyService extends RemoteService {
public String myMethod(String s);
}
函数的参数时要传给远程服务器的参数,返回值是远程服务器返回的结果。
然后,要实现提供这个服务的Servlet。
这个Servlet要实现先前定义的服务接口。
而且要继承自com.google.gwt.user.server.rpc.RemoteServiceServlet。当然RemoteServiceServlet继承自HttpServlet。这个Servlet运行在web server上,例如tomcat。
public class MyServiceImpl extends RemoteServiceServlet implements
MyService {
public String myMethod(String s) {
// Do something interesting with 's' here on the server.
return s;
}
}
第三,定义异步接口。
“Ajax的核心是JavaScript对象XmlHttpRequest。该对象在Internet Explorer 5中首次引入,它是一种支持异步请求的技术。简而言之,XmlHttpRequest使您可以使用JavaScript向服务器提出请求并处理响应,而不 阻塞用户。”
GWT支持的是这种异步请求机制。要实现这种异步请求机制,就要实现异步接口。
异步接口定义在客户端。
异步接口的定义规则是:不需要继承任何接口,名字是在自定义服务接口的名字后面添加Async后缀;接口中的方法与自定义服务接口方法同名,返回值为void,参数在自定义服务接口方法参数的基础上增加一个com.google.gwt.user.client.rpc.AsyncCallback类型的参数。
interface MyServiceAsync {
public void myMethod(String s, AsyncCallback callback);
}
第四,调用过程。
参考如下示例:
public void 调用函数() {
// (1) Create the client proxy. Note that although you are creating the
// service interface proper, you cast the result to the async version // of the interface. The cast is always safe because the generated proxy
// implements the async interface automatically.
//
MyServiceAsync myService = (MyServiceAsync) GWT
.create(MyService.class);
// (2) Specify the URL at which our service implementation is running.
// Note that the target URL must reside on the same domain and port from
// which the host page was served.
//
ServiceDefTarget endpoint = (ServiceDefTarget) myService;
endpoint.setServiceEntryPoint("/requestPath");
// (3) Create an async callback to handle the result.
//
AsyncCallback callback = new AsyncCallback() {
public void onSuccess(Object result) {
// do some UI stuff to show success
}
public void onFailure(Throwable caught) {
// do some UI stuff to show failure
}
};
// (4) Make the call. Control flow will continue immediately and later
// 'callback' will be invoked when the RPC completes.
//
myService.myMethod (“argument”, callback);
}
可以看到,远程服务调用的过程是这样的:
1 生成异步接口的对象。
2 定义远程访问点。
3 建立AsyncCallback对象。
4 远程调用。
实现异步接口的调用过程,不会阻塞用户进程,会从函数中直接返回;当用户结果返回时会由AsyncCallback对象对返回结果做处理。
4 和Structs的整合
现在关于AJAX和Structs整合的文章在google, baidu上基本上搜索不到。
如果Ajax客户端向服务器发请求和通过浏览器向某Servlet发请求的机制一样,可以用一个Action来实现3中提到的Servlet。
但服务器结果返回Ajax客户端的的过程和普通Servlet响应返回浏览器的过程明显不同,所以Structs的整合问题还有待进一步研究。