GWT开发教程.docx
《GWT开发教程.docx》由会员分享,可在线阅读,更多相关《GWT开发教程.docx(46页珍藏版)》请在冰豆网上搜索。
GWT开发教程
第一章编码基础
在eclipse中添加GWT插件。
升级安装源如下:
Eclipse3.5(Galileo)
/plugin/3.5
Eclipse3.4(Ganymede)
/plugin/3.4
Eclipse3.3(Europa)
/plugin/3.3
第一节客户端代码
1.1.1创建入口点
新建GWT工程之后将生成的类文件都删除。
并删除web.xml中如下的部分:
--Servlets-->
greetServlet
com.example.smallgwt.server.GreetingServiceImpl
greetServlet
/smallgwt/greet
然后观察生成的模块配置文件
xmlversion="1.0"encoding="UTF-8"?
>
—rename-to为模块起一个别名,使用起来简单-->
--InheritthecoreWebToolkitstuff.-->
—下面是继承其他模块,User是必须继承的一个模块。
-->
--InheritthedefaultGWTstylesheet.Youcanchange-->
--thethemeofyourGWTapplicationbyuncommenting-->
--anyoneofthefollowinglines.-->
--继承缺省的GWT样式表.你能够改变GWT程序的主题。
只需要去掉下面几行其中一个的注释-->
---->
---->
--Othermoduleinherits-->
--Specifytheappentrypointclass.-->
--指定应用的入口点类-->
--Specifythepathsfortranslatablecode-->
每一个模块都有一个入口点。
这个模块的入口点就是“Smallgwt”类。
现在使用eclipse在com.example.smallgwt.client中创建这个类Smallgwt。
同时指定接口为com.google.gwt.core.client.EntryPoint。
自动生成的代码如下:
packagecom.example.smallgwt.client;
importcom.google.gwt.core.client.EntryPoint;
publicclassSmallgwtimplementsEntryPoint{
@Override
publicvoidonModuleLoad(){
//TODOAuto-generatedmethodstub
}
}
入口点类
入口点类是整个GWT应用程序的入口,也就是说,GWT应用程序运行时会首先调用这段代码,工程的入口点类在工程模块的标签中指定。
在入口点类中必须实现入口点方法onModuleLoad(),这个入口点方法是整个GWT应用程序开始执行的地方。
这个方法中主要做的事情是:
●创建可视组件
●设置事件处理句柄
●将可视组件添加到网页上
packagecom.example.smallgwt.client;
importcom.google.gwt.core.client.EntryPoint;
importcom.google.gwt.core.client.GWT;
importcom.google.gwt.event.dom.client.ClickEvent;
importcom.google.gwt.event.dom.client.ClickHandler;
importcom.google.gwt.user.client.Window;
importcom.google.gwt.user.client.ui.Button;
importcom.google.gwt.user.client.ui.RootPanel;
publicclassSmallgwtimplementsEntryPoint{
@Override
publicvoidonModuleLoad(){
//TODOAuto-generatedmethodstub
//创建一个按钮,按钮标题是"Clickme".创建一个事件接收类,当用户点按钮的时候,这个类的方法被调用
finalButtonb=newButton("Clickme",newClickHandler(){
@Override
publicvoidonClick(ClickEventevent){
//TODOAuto-generatedmethodstub
//弹出警告窗口,显示"Hello,AJAX
Window.alert("Hello,AJAX");
}
});
//将这个按钮添加到网页上。
RootPanel.get().add(b);
GWT.log("HelloWorld!
",null);
}
}
RootPanel.get([“soltName”]).add(widget)。
如果get中为空。
则得到整个网页,将组件添加到网页上。
如果不为空。
则将组件添加到get中的名字指定的位置。
1.1.2HTML页面
HTML页面和普通的HTML页面没有什么区别,可以使用一切HTML标签。
有几个特别的地方如下:
1、这个HTML
中必须引入下面的JavaScript代码,用来加载GWT工程模块,之后GWT读入模块文件(*****.gwt.xml)来查找入口点(EntryPoint)类,整个GWT程序才得以运行。
另外,所有GWT的标签都应该出现在这段JavaScript代码之前。
下面是在模块中没有定义模块别名的时候使用完整的长名字的情形:
src="com.example.smallgwt.Smallgwt/com.example.smallgwt.Smallgwt.nocache.js">
这个nocache.js文件位于编译后的www目录下,并且其命名规则为:
模块的全路径名.nocache.js
2、在HTML的
中可以加入下面这个iframe标签,其作用是为GWT提供历史支持,但这个标签是可选的。
””id=”__gwt_historyFrame”style=”width:
0;height:
0;border:
0”>
这里的id属性值必须为“__gwt_historyFrame”。
3、如果在MyApplication.java的RootPanel中指定了使用某些id,比如这里的“solt1”和“slot2”,那么在HTML页面中也必须明确指定以这些id命名的HTML标签,否则程序将抛出NullPointerException异常。
|
1.1.3模块
前面提到那段nocache.js代码用来加载GWT工程的模块。
Smallgwt.gwt.xml中的内容:
---->--指定模块别名的方法-->
--指明此模块继承的夫模块,所有的GWT工程都继承自User-->
--指明此GWT程序的入口点类.-->
GWT模块名都是以.gwt.xml结尾的XML文件,用来配置这个工程,位于工程根目录下。
1.1.4标准GWT工程结构
使用标准的GWT工程结构可以有效的区分客户端和服务器端的代码,所以推荐使用标准的GWT工程结构。
如下表:
包名
作用
\
工程的根目录,包含模块XML文件
client\
存放客户端代码
server\
存放服务器端代码
public\
存放静态资源,如.html,.css,图片等
第二节Java语言和库的兼容性
1.2.1语言支持
GWT支持大部分的Java核心语言的语法和语义,但是还有一些小小的不同。
GWT程序的目标语言是JavsScript,所以在开发模式和发布模式运行之间还是有一些需要注意的地方。
●内置类型:
简单类型(boolean,byte,char,short,int,long,float,和double),Object,String,arrays,用户定义类等,都是被支持的。
只是有点注意。
⏹数学类型:
JavaScript中只有64位浮点型。
所有的java基本算术类型(除了长整数)在发布模式下都要转换到这个64位浮点数。
这就意味着byte、char、short和int等类型的不会象在java中一样溢出。
也就是说,这些数据类型的值可以超出合法的取值范围。
浮点数运算将作为double运算进行,并且结果的精度将更高。
整数除法的执行结果将被四舍五入到整数值。
⏹long类型:
Javascript没有64位整数类型。
GWT使用两个32位整数类型完成64为整数的模拟。
这就有两个问题:
首先是性能问题,另外就是JSNIcode代码是不支持的。
●异常:
try,catch,finally和用户定义的异常还是正常支持的,不过Throwable.getStackTrace()是不被发布模式支持的。
注意:
有几个JavaVM中最基本的异常是不会在发布模式中支持的,那就是NullPointerException、StackOverflowError和OutOfMemoryError。
取而代之的是JavaScriptException异常。
●断言:
在开发模式中断言语句总是不起作用的,因为它和在调试的时候GWT库提供的众多很有帮助的错误检测差的很远。
GWT编译器默认移除和忽略所有的断言。
但是可以通过为编译器指定-ea标志在发布模式下打开这些断言。
●多线程和同步:
Javascript解释器是单线程的,所以GWT只是单纯的接收同步的关键字,而不起任何作用。
同步相关的方法也不被接收,包括Object.wait()、Object.notify()和Object.notifyAll()。
编译器将忽略同步关键字除非对象关联一个同步方法被调用。
●反射(Reflection):
为了最大化效率,GWT编译Java源代码到一个整块的script,不支持类的连续动态调入。
对这个的优化通常使用反射机制。
不管如何,通过类的名字Object.getClass().getName()得到一个类对象是可以的。
●Java析构函数(Finalization):
JavaScript不支持对象被回收时的析构函数调用,所以GWT在发布模式中不会支持Java析构函数。
●精确浮点数:
Java语言规范定义浮点数支持,包括单精度和上精度都支持精确浮点(strictf)关键字。
GWT不支持这个关键字,不能保证任何精度的浮点运算,所以不要再客户端进行类似的精度要求较高的浮点运算。
1.2.2运行库支持
GWT只支持J2SE和J2EE类库的一个小的子集,一个大的完整的集合是不可能被浏览器支持的。
要知道那些核心Java运行包被支持,需要查询JREEmulationReference。
网址是/zh-CN/webtoolkit/doc/latest/RefJreEmulation.html
提示:
一定要搞清楚那些类是可以转换到客户端代码的。
否则会出现很多问题。
建议多看这个网页。
另外开发模式会帮助你检查那些是可以用的,那些是不可以用的。
所以要经常的,尽量早的运行程序。
1.2.3JRE和模拟类的不同
GWT模拟类和标准的Java运行时有一些差别:
●正则表达式:
Java正则表达式的语法和JavaScript正则表达式的语法基本相似。
但是还是有一点儿不同,例如:
replaceAll和split方法正则表达式。
所以使用的时候要注意你的Java正则表达式在JavaScript中要有相同的意义。
●串行化:
Java的串行化机制有一部分不支持编译到JavaScript,例如动态类的调入和反射。
结果是,GWT不支持标准的Java串行化。
代之的是GWT提供一个简单的自动对象串行化用于调用服务器端的远程方法。
1.2.4提供的相似功能的类
有一些类的功能对虚拟机来说太复杂,所以提供另一个包来提供相似的功能。
这有一些本地JRE的功能子集。
∙com.google.gwt.i18n.client.DateTimeFormat:
支持java.util.DateTimeFormat的子集。
∙com.google.gwt.i18n.client.NumberFormat:
支持java.util.NumberFormat的子集。
∙com.google.gwt.user.client.rpc:
一个标记类,提供GWTRPC中使用java.io.Serializable。
∙com.google.gwt.user.client.Timer:
一个简单的,浏览器安全的定时器类。
这个类提供与java.util.Timer相似的功能,但是更简单,因为是单线程环境的。
第三节历史
1.3.1GWT的历史机制
GWT的历史机制和其它Ajax的历史实现是基本一样的,都是RSH(ReallySimpleHistory)。
基本前提的在url标示符片段中保持跟踪程序的内部状态。
这种更新操作不会触发页面的重新调入。
这个步骤有一系列的好处:
●这种方法是仅有的一个方法可以可靠的控制浏览器的历史。
●这种方法可以给用户一个很好的反馈。
●这种方法支持收藏夹(也叫书签)机制。
也就是说可以创建当前状态的收藏夹,保存它,email它等。
1.3.2历史记号
GWT包含一个机制帮助Ajax开发者激活浏览器的历史功能。
为了是每一个页面是可以在历史中导航的,程序为每一个页面生成一个唯一的历史标记。
一个标记是一个简单的字符串,程序能够分解这个字符串返回一个详细的状态。
这个标记将以URL片段(在地址栏中,在#的后面)的形式保存在浏览器的历史中。
这个片段将在用户点击回退和前进的时候返回给程序。
例如,一个名字为"page1"的历史标记添加到了URL中,如下所示:
/HistoryExample.html#page1
当程序要将一个历史标记添加到浏览器的历史栈中的时候,只需要简单的调用History.newItem(token)。
当用户点击回退的时候,会调用任意设置了History.addValueChangeHandler()事件句柄的对象的相关方法。
1.3.3历史实例
要使用GWT的历史支持,你必须首先嵌入一个iframe到hostHTML页面中。
''"
id="__gwt_historyFrame"
style="width:
0;height:
0;border:
0">
然后,在GWT程序中完成下面的步骤:
当想要使用历史事件的时候添加历史标记的历史栈。
创建一个实现了ValueChangeHandler接口的对象,调用ValueChangeEvent.getValue()解析一个新的标记并改变程序的状态到匹配的那个位置。
下面是一个简单的例子演示一个TabPanel中如何在用户选择新的页时添加相应的历史事件。
packagecom.example.smallgwt.client;
importcom.google.gwt.core.client.EntryPoint;
importcom.google.gwt.core.client.GWT;
importcom.google.gwt.event.dom.client.ClickEvent;
importcom.google.gwt.event.dom.client.ClickHandler;
importcom.google.gwt.event.logical.shared.SelectionEvent;
importcom.google.gwt.event.logical.shared.SelectionHandler;
importcom.google.gwt.event.logical.shared.ValueChangeEvent;
importcom.google.gwt.event.logical.shared.ValueChangeHandler;
importcom.google.gwt.user.client.History;
importcom.google.gwt.user.client.Window;
importcom.google.gwt.user.client.ui.Button;
importcom.google.gwt.user.client.ui.HTML;
importcom.google.gwt.user.client.ui.RootPanel;
importcom.google.gwt.user.client.ui.TabPanel;
publicclassSmallgwtimplementsEntryPoint{
TabPaneltabPanel;
/**
*Thisistheentrypointmethod.
*/
publicvoidonModuleLoad(){
tabPanel=newTabPanel();
tabPanel.add(newHTML("
Page0Content:
Llamas"),"Page0");
tabPanel.add(newHTML("
Page1Content:
Alpacas"),"Page1");
tabPanel.add(newHTML("
Page2Content:
Camels"),"Page2");
tabPanel.addSelectionHandler(newSelectionHandler(){
publicvoidonSelection(SelectionEventevent){
//TODOAuto-generatedmethodstub
History.newItem("page"+event.getSelectedItem());
}
});
History.addValueChangeHandler(newValueChangeHandler(){
publicvoidonValueChange(ValueChangeEventevent){
StringhistoryToken=event.getValue();
//Parsethehistorytoken
try{
if(historyToken.substring(0,4).equals("page")){
StringtabIndexToken=historyToken.substring(4,5);
inttabIndex=Integer.parseInt(tabIndexToken);
//Selectthespecifiedtabpanel
tabPanel.selectTab(tabIndex);
}else{
tabPanel.selectTab(0);
}
}catch(IndexOutOfBoundsExceptione){
tabPanel.selectTab(0);
}
}
});
tabPanel.selectTab(0);
RootPanel.get().add(tabPanel);
}
}
1.3.4超链接组件(HyperlinkWidgets)
一个程序当中超链接可以很容易的整合历史支持。
GWT的超链接(Hyperlink)组件看起来就是普通的HTML锚。
可以将这个锚关联一个历史标记,当点击这个锚的时候历史标记就自动的添加到浏览器的历史栈中。
History.newItem(token)调用将是自动的。
观察上面的例子,程序添加形如“page(n)”的历史标记。
在这个程序中基本可以完成任务。
不过更复杂的情况就无法完成了。
所以推荐象下面一样使用历史标记:
page=;session=
可以告诉程序到第几页去同时