GWT 入门介绍
GWT是 Google Web Toolkit的简称。
GWT是一个以Java语言为工具,以类似Swing的方式编写UI组件,之后通过GWT Compiler编译
为JavaScritp和HTML在客户端浏览器中运行的一个开发工具和编程模型。
GWT应用程序有两种方式运行:
Hosted Model
在Hosted Model方式下,Java程序并不会被编译成JavaScript,GWT只是创造了一个类似
浏览器的环境,直接运行使用GWT开发的程序。这种模式最具生产力(这种模式下可以Debug所有的Java代码),
所以开发环境通常使用Hosted Model,但是真正的程序执行不使用这种模式。
Web Model
就是将使用GWT编写的Java程序整整编译成JavaScript,在Web容器上运行,使用浏览器
访问的模式,这种方式只有在测试或者运行的时候才使用,每次对Java类的修改必须重新编译
这些Java类,之后重新部署应用。所以生产力比较低。
安装GWT
从如下位置下载GWT的最新版本:
http://code.google.com/webtoolkit/download.html
当前最新的Release版本为1.4.60, 上一个稳定的版本为1.3.3
第一步,安装JDK, 1.4 以上的版本都可以。
第二步,下载GWT压缩文件,这里使用1.4.59 RC2(gwt-windows-1.4.59.zip)
第三布,将GWT压缩文件解压缩到制定的目录,这里我使用的目录为,C:\程序开发\Java\gwt-windows-1.4.59
第四步,安装成功
安装之后的目录结构为:
C:\程序开发\Java\gwt-windows-1.4.59
doc(文档目录,开发文档和Java API文档)
samples(示例代码目录,非常有名的KitchenSink示例代码即在此目录中)
about.html
about.txt
applicationCreator.cmd
benchmarkViewer.cmd
COPYING
COPYING.html
gwt-benchmark-viewer.jar
gwt-dev-windows.jar
gwt-ll.dll
gwt-module.dtd
gwt-servlet.jar
gwt-user.jar
i18nCreator.cmd
index.html
junitCreator.cmd
projectCreator.cmd
release_notes.html
swt-win32-3235.dll
使用GWT建立开发
GWT的安装目录下有一个名叫Samples的目录,里边有很多的例子,其中KitchenSink比较全面的展现了GWT的Web组件。
applicationCreator创建一个可以以Hosted Mode形式运行的GWT应用程序,
以下命令将建立一个工程
C:\程序开发\Java\gwt-windows-1.4.59>applicationCreator.cmd -eclipse GWTLogon -out GWTLogon com.jpleausre.gwt.logon.client.GWTLogon
Created directory GWTLogon \src
Created directory GWTLogon \src\com\jpleausre\gwt\logon
Created directory GWTLogon \src\com\jpleausre\gwt\logon\client
Created directory GWTLogon \src\com\jpleausre\gwt\logon\public
Created file GWTLogon \src\com\jpleausre\gwt\logon\GWTLogon .gwt.xml
Created file GWTLogon \src\com\jpleausre\gwt\logon\public\GWTLogon .html
Created file GWTLogon \src\com\jpleausre\gwt\logon\client\GWTLogon .java
Created file GWTLogon \GWTLogon .launch
Created file GWTLogon \GWTLogon -shell.cmd
Created file GWTLogon \GWTLogon -compile.cmd
运行GWTLogon -shell.cmd可以看到GWT启动的服务端的Google Web Toolkit Development Shell,如下图:
projectCreator建立一个基于ant构建的,或者基于eclipse的GWT开发工程,
例如:
C:\程序开发\Java\gwt-windows-1.4.59>projectCreator.cmd -ant GWTLogon -eclipse GWTLogon -out GWTLogon
Created directory GWTLogon \src
Created directory GWTLogon \test
Created file GWTLogon \GWTLogon .ant.xml
Created file GWTLogon \.project
Created file GWTLogon \.classpath
其中的GWTLogon .ant.xml构建文件的内容为:
GWTLogon build file. This is used to package up your project as a jar,
if you want to distribute it. This isn't needed for normal operation.
applicationCreator和projectCreator的区别是
applicationCreator创建了src目录和Demo代码,projectCreator不创建Demo代码,但是创建src目录和 test目录。
applicationCreator创建了启动脚本GWTLogon -shell.cmd 和GWT编译脚本GWTLogon -compile.cmd,而 projectCreator不创建。
applicationCreator创建了eclipse launch文件,而projectCreator创建.classpath和.project文件。
通常情况下,我们先使用projectCreator创建按project,projectCreator创建的工程可以轻松的 import到eclipse中,
之后我们使用applicationCreator创建需要的Java示例代码,eclipse launch文件,启动脚本和编译脚本。
使用Eclipse导入的GWT工程如下:
命令列表
projectCreator
生成基本项目框架,可以选择使用eclipse或者使用ant构建文件
applicationCreator
生成代码示例和一个可运行的应用程序
junitCreator
生成一个JUnit测试Case
i18nCreator
生成一个i18n属性文件和对应的Javascript脚本。
benchmarkViewer
显示benchmark结果
功能介绍(通用)
GWT体系结构
功能介绍(Web控件)
Web控件是GWT表示层的核心,通过使用GWT提供的Web控件可以创建丰富的客户端画面。
GWT的web组件主要分为两类:输入控件和Layout控件。
输入控件主要是指向服务器提交数据,处理操作,显示服务器数据的空间,主要包括:
Button,RadionButton,PushButton,ToggleButton,CheckBox,TextBox,PasswordBox
TextArea, HyperLink,ListBox,MenuBar,Tree,Table, TabBar,DialogBox, PopupPanel
RichTextArea, DisclosurePanel, SuggestBox
Layout 空间主要用来有规律地放置输入控件,主要包括:
Stackpanel,HorizontalPanel,VerticalPanel, FlowPanel, VerticalSplitPanel, HorizontalSplitPanel,
DockPanel, TabPanel,
事件模型(Event & Listener)
如何处理页面的事件呢,例如点击按 钮,Textbox失去焦点等?
如下的代码建立了一个按钮,按钮的名字是“Click Me”,当你点击这个按钮的时候处罚一个Click事件,Click事件触发onClick(Widget sender)方法。
sender表示触发onClick方法的组件,这里只是简单的在页面上显示Hello World信息(相当于javascript的alert方法)。
Button b = new Button("Click Me");
b.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
Window.alert("Hello World");
}
});
常见的Listener如下:
ChangeListener
ClickListener
FocusListener
KeyboardListener
MouseListener
MouseWheelListener
PopupListener
ScrollListener
TableListener
TreeListener
功能介绍(远过程调用RPC)
体系结构
GWT应用中页面一旦加载,就再也不会向服务器请求HTML内容,所有的画面迁移,转换都在客户端进行,但是数据还是会向服务器提交,或者从服务器 获取。
服务器上负责处理数据的对象在GWT中叫做Service,每个Service有三个类组成:服务方法定义接口(Service),异步调用接口 (ServiceAsync)和服务器方法实现类ServiceImpl。
以Login为例子说明:
// 服务方法定义接口
public interface LoginService extends RemoteService {
public boolean login(LoginSO login) throws ApplicationException;
}
// 异步调用接口
public interface LoginServiceAsync {
void login(LoginSO login, AsyncCallback async);
}
// 服务器方法实现类
public class LoginServiceImpl extends RemoteServiceServlet implements LoginService {
public boolean login(LoginSO login) throws ApplicationException {
...
return true;
}
}
其中前两个接口在client包内部,最后一个实现在server包内部。
客户端调用一个服务类的方法的代码如下:
LoginServiceAsync ourInstance = (LoginServiceAsync) GWT.create(LoginService.class); // Œ
((ServiceDefTarget) ourInstance).setServiceEntryPoint(GWT.getModuleBaseURL() + "/LoginService"); //
ourInstance.login(loginSO, new AsyncCallback() { //Ž
public void onFailure(Throwable caught) { //
if(caught instanceof InvocationException) {
// system exception
} else {
Window.alert(" " + GWTShowConstants.Messages.constants.maxQueryCount());
// aplication exception
}
}
public void onSuccess(Object result) { //
Window.alert("success");
}
});
// ‘
远程调用
Œ 获得服务器方法的调用接口(skeleton)。
设置服务位置。
Ž 远程调用服务器上的方法,注意这里是异步调用,在 和 调用之前‘ 代码 可能先被调用了。
调用出错,或者调用方法抛出异常的时候调用的方法。
调用成功返回时候调用的方法。
参数和返回值系列化类型
这里的参数指的是Service方法调用的参数和返回值。
由于GWT的客户端代码都是JavaScript,而服务器代码都是使用Java编写的,这就涉及到JavaScript调用Java方法的时候
如何传递参数,如何取得返回值的问题。
可序列化的类型包括:
(1) 原始类型,例如:char, byte, short, int, long, boolean, float, double;
(2) String,java.util.Date,或者原始类型的包装类型,例如: Character, Byte, Short, Integer, Long, Boolean, Float, or Double;
(3) 可序列化类型数组(包含(4)和(5)定义的类型)
(4) 用户定义的可序列化类型
(5) 该类型至少有一个可序列化的子类型
针对上述(4)中说明的,什么是用户自定义的可序列化类型呢?必须满足以下亮点:
第一,必须直接或者间接(例如,父类型实现了这个接口)的实现了IsSerializable接口
第二,所有非transient类型都是可序列化的(final类型的属性在GWT中被视为transient类型)
是否支持容器类型呢?那么又如何声明呢?
支持容器类型,GWT可以使用Type 参数来表示容器类型内部的元素的类型,例如:
注意GWT暂时不支持使用 JDK 5.0 的模板容器
//用户自定义序列化类型
public class MyClass implements IsSerializable {
/**
* 这个Set中的元素的类型必须都是String类型
*
* @gwt.typeArgs
*/
public Set setOfStrings;
/**
* Map中的元素的Key和Value的类型都是String类型。
*
* @gwt.typeArgs
*/
public Map mapOfStringToString;
}
// 服务器方法实现类
public interface MyService extends RemoteService {
/**
* 第一个类型参数表示方法的参数c是一个List,并且其中只能放置Integer类型。
* 第二个类型参数表示返回值为List,并且其中的原书的类型为String类型。
*
* @gwt.typeArgs c
* @gwt.typeArgs
*/
List reverseListAndConvertToStrings(List c);
}
异常
在调用方法的时候异常怎么处理呢?
调用方法的过程中的异常可以分为两类:第一类,调用方法的过程中出现了异常,例如网络故障,服务类不存在等。
第二类,服务器方法抛出了异常。
在客户端调用的过程中这两种异常都在onFailure(Throwable caught)方法中处理,但是caught的类型有所区别,
第一种情况下,caught为InvocationException的子类,第二种情况下caught为用户自定义的异常。
由于异常也需要在客户端(JavaScript)和服务器端(Java)传递,所以Exception的定义也要满足可序列化的要求。
但是在GWT中已经定义了一个基本的异常类型来提一个Exception类的基础类,这个类是SerializableException,例如:
public class ApplicationException extends SerializableException {
public ApplicationException() {
super();
}
public ApplicationException(String msg) {
super(msg);
}
public Throwable getCause() {
return super.getCause();
}
public String getMessage() {
return super.getMessage();
}
public Throwable initCause(Throwable cause) {
return super.initCause(cause);
}
}
异常消息内容建议,服务器端的错误消息内容在服务器保存,客户端的错误消息内容在客户端保存(参看后续的国际化部分),两个地方
都需要的,出于GWT技术建议使用两份,分别放在客户端和服务器端。
为什么不能重用呢?
客户端的消息会被编译为JavaScript,所以服务器端通常无法使用。(还有另外的原因,参看后续的国际化部分)。