GWT开发教程.doc_第1页
GWT开发教程.doc_第2页
GWT开发教程.doc_第3页
GWT开发教程.doc_第4页
GWT开发教程.doc_第5页
已阅读5页,还剩20页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第一章 编码基础在eclipse中添加GWT插件。升级安装源如下:Eclipse 3.5 (Galileo)/eclipse/plugin/3.5Eclipse 3.4 (Ganymede)/eclipse/plugin/3.4Eclipse 3.3 (Europa)/eclipse/plugin/3.3第一节 客户端代码1.1.1 创建入口点新建GWT工程之后将生成的类文件都删除。并删除web.xml中如下的部分: greetServlet com.example.smallgwt.server.GreetingServiceImpl greetServlet /smallgwt/greet 然后观察生成的模块配置文件 !- - !- - 每一个模块都有一个入口点。这个模块的入口点就是“Smallgwt”类。现在使用eclipse在com.example.smallgwt.client中创建这个类Smallgwt。同时指定接口为com.google.gwt.core.client.EntryPoint。自动生成的代码如下:package com.example.smallgwt.client;import com.google.gwt.core.client.EntryPoint;public class Smallgwt implements EntryPoint Overridepublic void onModuleLoad() / TODO Auto-generated method stub入口点类入口点类是整个GWT应用程序的入口,也就是说,GWT应用程序运行时会首先调用这段代码,工程的入口点类在工程模块的标签中指定。在入口点类中必须实现入口点方法onModuleLoad(),这个入口点方法是整个GWT应用程序开始执行的地方。这个方法中主要做的事情是:l 创建可视组件l 设置事件处理句柄l 将可视组件添加到网页上package com.example.smallgwt.client;import com.google.gwt.core.client.EntryPoint;import com.google.gwt.core.client.GWT;import com.google.gwt.event.dom.client.ClickEvent;import com.google.gwt.event.dom.client.ClickHandler;import com.google.gwt.user.client.Window;import com.google.gwt.user.client.ui.Button;import com.google.gwt.user.client.ui.RootPanel;public class Smallgwt implements EntryPoint Overridepublic void onModuleLoad() / TODO Auto-generated method stub/创建一个按钮,按钮标题是Click me.创建一个事件接收类,当用户点按钮的时候,这个类的方法被调用final Button b = new Button(Click me, new ClickHandler() Overridepublic void onClick(ClickEvent event) / TODO Auto-generated method stub/弹出警告窗口,显示Hello, AJAXWindow.alert(Hello, AJAX); );/将这个按钮添加到网页上。 RootPanel.get().add(b);GWT.log(Hello World!, null);RootPanel.get(“soltName”).add(widget)。如果get中为空。则得到整个网页,将组件添加到网页上。如果不为空。则将组件添加到get中的名字指定的位置。1.1.2 HTML页面HTML页面和普通的HTML页面没有什么区别,可以使用一切HTML标签。有几个特别的地方如下:1、这个HTML中必须引入下面的JavaScript代码,用来加载GWT工程模块,之后GWT读入模块文件(*.gwt.xml)来查找入口点(EntryPoint)类,整个GWT程序才得以运行。另外,所有GWT的标签都应该出现在这段JavaScript代码之前。下面是在模块中没有定义模块别名的时候使用完整的长名字的情形:这个nocache.js文件位于编译后的www目录下,并且其命名规则为:模块的全路径名.nocache.js2、在HTML的中可以加入下面这个iframe标签,其作用是为GWT提供历史支持,但这个标签是可选的。这里的id属性值必须为“_gwt_historyFrame”。3、如果在MyApplication.java的RootPanel中指定了使用某些id,比如这里的“solt1”和“slot2”,那么在HTML页面中也必须明确指定以这些id命名的HTML标签,否则程序将抛出NullPointerException异常。1.1.3 模块前面提到那段nocache.js代码用来加载GWT工程的模块。Smallgwt.gwt.xml中的内容:!- - GWT模块名都是以.gwt.xml结尾的XML文件,用来配置这个工程,位于工程根目录下。1.1.4 标准GWT工程结构使用标准的GWT工程结构可以有效的区分客户端和服务器端的代码,所以推荐使用标准的GWT工程结构。如下表:包名作用工程的根目录,包含模块XML文件client存放客户端代码server存放服务器端代码public存放静态资源,如.html,.css,图片等第二节 Java语言和库的兼容性1.2.1 语言支持GWT支持大部分的Java核心语言的语法和语义,但是还有一些小小的不同。GWT程序的目标语言是JavsScript,所以在开发模式和发布模式运行之间还是有一些需要注意的地方。l 内置类型:简单类型(boolean, byte, char, short, int, long, float, 和double),Object, String, arrays,用户定义类等,都是被支持的。只是有点注意。n 数学类型:JavaScript中只有64位浮点型。所有的java基本算术类型(除了长整数)在发布模式下都要转换到这个64位浮点数。这就意味着byte、char、short和int等类型的不会象在java中一样溢出。也就是说,这些数据类型的值可以超出合法的取值范围。浮点数运算将作为double运算进行,并且结果的精度将更高。整数除法的执行结果将被四舍五入到整数值。n long类型:Javascript没有64位整数类型。GWT使用两个32位整数类型完成64为整数的模拟。这就有两个问题:首先是性能问题,另外就是JSNI code代码是不支持的。l 异常:try, catch, finally和用户定义的异常还是正常支持的,不过Throwable.getStackTrace()是不被发布模式支持的。注意:有几个Java VM中最基本的异常是不会在发布模式中支持的,那就是NullPointerException、 StackOverflowError和OutOfMemoryError。取而代之的是JavaScriptException异常。l 断言:在开发模式中断言语句总是不起作用的,因为它和在调试的时候GWT库提供的众多很有帮助的错误检测差的很远。GWT编译器默认移除和忽略所有的断言。但是可以通过为编译器指定-ea标志在发布模式下打开这些断言。l 多线程和同步:Javascript解释器是单线程的,所以GWT只是单纯的接收同步的关键字,而不起任何作用。同步相关的方法也不被接收,包括Object.wait()、Object.notify()和Object.notifyAll()。编译器将忽略同步关键字除非对象关联一个同步方法被调用。l 反射(Reflection):为了最大化效率,GWT编译Java源代码到一个整块的script,不支持类的连续动态调入。对这个的优化通常使用反射机制。不管如何,通过类的名字Object.getClass().getName()得到一个类对象是可以的。l Java析构函数(Finalization):JavaScript不支持对象被回收时的析构函数调用,所以GWT在发布模式中不会支持Java析构函数。l 精确浮点数:Java语言规范定义浮点数支持,包括单精度和上精度都支持精确浮点(strictf)关键字。GWT不支持这个关键字,不能保证任何精度的浮点运算,所以不要再客户端进行类似的精度要求较高的浮点运算。1.2.2 运行库支持GWT只支持J2SE和J2EE类库的一个小的子集,一个大的完整的集合是不可能被浏览器支持的。要知道那些核心Java运行包被支持,需要查询JRE Emulation Reference。网址是/intl/zh-CN/webtoolkit/doc/latest/RefJreEmulation.html提示:一定要搞清楚那些类是可以转换到客户端代码的。否则会出现很多问题。建议多看这个网页。另外开发模式会帮助你检查那些是可以用的,那些是不可以用的。所以要经常的,尽量早的运行程序。1.2.3 JRE和模拟类的不同GWT模拟类和标准的Java运行时有一些差别:l 正则表达式:Java正则表达式的语法和JavaScript正则表达式的语法基本相似。但是还是有一点儿不同,例如:replaceAll和split方法正则表达式。所以使用的时候要注意你的Java正则表达式在JavaScript中要有相同的意义。l 串行化: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 :一个标记类,提供GWT RPC中使用java.io.Serializable。 com.google.gwt.user.client.Timer :一个简单的,浏览器安全的定时器类。这个类提供与java.util.Timer相似的功能,但是更简单,因为是单线程环境的。第三节 历史1.3.1 GWT的历史机制GWT的历史机制和其它Ajax的历史实现是基本一样的,都是RSH (Really Simple History)。基本前提的在url标示符片段中保持跟踪程序的内部状态。这种更新操作不会触发页面的重新调入。这个步骤有一系列的好处:l 这种方法是仅有的一个方法可以可靠的控制浏览器的历史。l 这种方法可以给用户一个很好的反馈。l 这种方法支持收藏夹(也叫书签)机制。也就是说可以创建当前状态的收藏夹,保存它,email它等。1.3.2 历史记号GWT包含一个机制帮助Ajax开发者激活浏览器的历史功能。为了是每一个页面是可以在历史中导航的,程序为每一个页面生成一个唯一的历史标记。一个标记是一个简单的字符串,程序能够分解这个字符串返回一个详细的状态。这个标记将以URL片段(在地址栏中,在#的后面)的形式保存在浏览器的历史中。这个片段将在用户点击回退和前进的时候返回给程序。例如,一个名字为page1的历史标记添加到了URL中,如下所示:/com.example.gwt.HistoryExample/HistoryExample.html#page1当程序要将一个历史标记添加到浏览器的历史栈中的时候,只需要简单的调用History.newItem(token)。当用户点击回退的时候,会调用任意设置了History.addValueChangeHandler()事件句柄的对象的相关方法。1.3.3 历史实例要使用GWT的历史支持,你必须首先嵌入一个iframe到host HTML页面中。然后,在GWT程序中完成下面的步骤:当想要使用历史事件的时候添加历史标记的历史栈。创建一个实现了ValueChangeHandler接口的对象,调用ValueChangeEvent.getValue()解析一个新的标记并改变程序的状态到匹配的那个位置。下面是一个简单的例子演示一个TabPanel中如何在用户选择新的页时添加相应的历史事件。package com.example.smallgwt.client;import com.google.gwt.core.client.EntryPoint;import com.google.gwt.core.client.GWT;import com.google.gwt.event.dom.client.ClickEvent;import com.google.gwt.event.dom.client.ClickHandler;import com.google.gwt.event.logical.shared.SelectionEvent;import com.google.gwt.event.logical.shared.SelectionHandler;import com.google.gwt.event.logical.shared.ValueChangeEvent;import com.google.gwt.event.logical.shared.ValueChangeHandler;import com.google.gwt.user.client.History;import com.google.gwt.user.client.Window;import com.google.gwt.user.client.ui.Button;import com.google.gwt.user.client.ui.HTML;import com.google.gwt.user.client.ui.RootPanel;import com.google.gwt.user.client.ui.TabPanel;public class Smallgwt implements EntryPoint TabPanel tabPanel;/* * This is the entry point method. */public void onModuleLoad() tabPanel = new TabPanel();tabPanel.add(new HTML(Page 0 Content: Llamas), Page 0 );tabPanel.add(new HTML(Page 1 Content: Alpacas), Page 1 );tabPanel.add(new HTML(Page 2 Content: Camels), Page 2 );tabPanel.addSelectionHandler(new SelectionHandler() public void onSelection(SelectionEvent event) / TODO Auto-generated method stubHistory.newItem(page + event.getSelectedItem(););History.addValueChangeHandler(new ValueChangeHandler() public void onValueChange(ValueChangeEvent event) String historyToken = event.getValue();/ Parse the history tokentry if (historyToken.substring(0, 4).equals(page) String tabIndexToken = historyToken.substring(4, 5);int tabIndex = Integer.parseInt(tabIndexToken);/ Select the specified tab paneltabPanel.selectTab(tabIndex); else tabPanel.selectTab(0); catch (IndexOutOfBoundsException e) tabPanel.selectTab(0););tabPanel.selectTab(0);RootPanel.get().add(tabPanel);1.3.4 超链接组件(Hyperlink Widgets)一个程序当中超链接可以很容易的整合历史支持。GWT的超链接(Hyperlink)组件看起来就是普通的HTML锚。可以将这个锚关联一个历史标记,当点击这个锚的时候历史标记就自动的添加到浏览器的历史栈中。History.newItem(token)调用将是自动的。观察上面的例子,程序添加形如“page(n)”的历史标记。在这个程序中基本可以完成任务。不过更复杂的情况就无法完成了。所以推荐象下面一样使用历史标记:page=;session=可以告诉程序到第几页去同时可以用作为一个关键字使得可以到数据库中查找以前用户的数据。可以作更复杂的历史操作,可读性也更好。1.3.5 处理onValueChange()回调在ValueChangeHandler中处理onValueChange()回调的第一步是使用ValueChangeEvent.getValue()得到历史标记。然后需要精确(需要仔细的设计算法)的找到相关的标记。当onValueChange()方法被调用的时候,程序必须处理两种可能:1. 程序刚好启动并且已经加入了历史标记2. 程序正在运行并且已经加入了历史标记第一点说明,程序在处理状态标记之前必须正确的初始化自己。第二点说明,程序的某些部分或许需要重新初始化。第四节 数字和日期格式GWT不提供Java格式类(java.text.DateFormat、java.text.DecimalFormat、 java.text.NumberFormat和java.TimeFormat)的完整虚拟。代之的是一个功能子集com.google.gwt.i18n.client.NumberFormat和com.google.gwt.i18n.client.DateTimeFormat.要使用NumberFormat或DateTimeFormat类,需要更新模块配置,引入继承如下:1.4.1 使用NumberFormat使用NumberFormat类时不需要直接实例化该类,只需要调用它的静态方法get.Format()得到一个实例。通常使用缺省的数字格式:NumberFormat fmt = NumberFormat.getDecimalFormat();double value = 12345.6789;String formatted = fmt.format(value);/ Prints 1,2345.6789 in the default localeGWT.log(Formatted string is + formatted, null);这个类还支持将一个数字字符串转换成double浮点数:double value = NumberFormat.getDecimalFormat().parse(12345.6789);GWT.log(Parsed value is + value, null);这个类还支持科学计数法:double value = 12345.6789;String formatted = NumberFormat.getScientificFormat().format(value);/ prints 1.2345E4 in the default localeGWT.log(Formatted string is + formatted, null);还可以指定自己的数字格式:double value = 12345.6789;String formatted = NumberFormat.getFormat(000000.000000).format(value);/ prints 012345.678900 in the default localeGWT.log(Formatted string is + formatted, null);数字的格式符号如下:SymbolMeaning0Digit, zero forced#Digit, zero shows as absent.Decimal separator or monetary decimal separator-Minus sign,Grouping separator指定一个非法的模式会导致方法NumberFormat.getFormat()抛出一个异常,那就是java.lang.IllegalArgumentException。如果多次使用相同的模式,则可以使用在很多NumberFormat.getFormat(pattern)的返回值缓存格式。1.4.2 日期时间格式GWT提供DateTimeFormat类来替代标准JRE的DateFormat和TimeFormat类的功能。类DateTimeFormat有一大批的预定义格式。Date today = new Date();/ prints Tue Dec 18 12:01:26 GMT-500 2007 in the default locale. GWT.log(today.toString(), null);/ prints 12/18/07 in the default localeGWT.log(DateTimeFormat.getShortDateFormat().format(today), null);/ prints December 18, 2007 in the default localeGWT.log(DateTimeFormat.getLongDateFormat().format(today), null);/ prints 12:01 PM in the default localeGWT.log(DateTimeFormat.getShortTimeFormat().format(today), null);/ prints 12:01:26 PM GMT-05:00 in the default localeGWT.log(DateTimeFormat.getLongTimeFormat().format(today), null);/ prints Dec 18, 2007 12:01:26 PM in the default localeGWT.log(DateTimeFormat.getMediumDateTimeFormat().format(today), null);就像NumberFormat类,这个类也可以将一个日期字符串转换成一个日期。也可以自己定义格式化显示时间日期的格式。第五节 编程定时逻辑1.5.1 计划工作:Timer类创建一个定时器(timer)类实例,然后重写run()方法。Timer timer = new Timer() public void run() Window.alert (Timer expired!);/ Execute the timer to expire 2 seconds in the futuretimer.schedule(2000);Notice that the timer will not have a chance to execute the run() method until after control returns to the JavaScript event loop.1.5.2 创建超时逻辑设置一个长时间运行的命令的超时时间是一个典型的应用。记住下面四点:1. 保存一个定时器到一个实例变量中2. 开始计时之前一定检测定时器是否运行(检测实例变量是否为空)。3. 当命令成功完成后要记得取消定时器。4. 当命令完成或者定时器实效时总是设置实例变量为空下面是一个超时使用的例子,在Remote Procedure Call(RPC)的时候。import com.google.gwt.user.client.Timer;import com.google.gwt.user.client.Window;import com.google.gwt.user.client.rpc.AsyncCallback;public class Foo / A keeper of the timer instance in case we need to cancel it private Timer timeoutTimer = null; / An indicator when the computation should quit private boolean abortFlag = false; static final int TIMEOUT = 30; / 30 second timeout void startWork () / ./ Check to make sure the timer isnt already running.if (timeoutTimer != null) Window.alert(Command is already running!); return; / Create a timer to abort if the RPC takes too long timeoutTimer = new Timer() public void run() Window.alert(Timeout expired.); timeoutTimer = null; abortFlag = true; ; / (re)Initialize the abort flag and start the timer. abortFlag = false; timeoutTimer.schedule(TIMEOUT * 1000); / timeout is in milliseconds / Kick off an RPC myService.myRpcMethod(arg, new AsyncCallback() public void onFailure(Throwable caught) Window.alert(RPC Failed: + caught); cancelTimer(); public void onSuccess(Object result) cancelTimer(); if (abortFlag) / Timeout already occurred. discard result return; Window.alert (RPC returned: + (String)result); / Stop the timeout timer if it is running private void cancelTimer() if (timeoutTimer != null) timeoutTimer.cancel(); timeoutTimer = null; 1.5.3 周期性运行逻辑为了保持用户界面的更新,需要在一些时候周期性的执行更新。或许向服务器运行一个轮训检测新数据,或者需要更新屏幕动画。这个时候,就可以使用Timer类的scheduleRepeating()方法:public class Foo / A timer to update the elapsed time count private Timer elapsedTimer; private Label elapsedLabel = new Label(); private long startTime; public Foo () / . Add elapsedLabel to a Panel . / Create a new timer elapsedTimer = new Timer () public void run() showElapsed(); ; startTime = System.currentTimeMillis(); / Schedule the timer for every 1/2 second (500 milliseconds) elapsedTimer.scheduleRepeating(500); / . The elapsed timer has started . /* * Show the current elapsed time in the elapsedLabel widget. */ private void showElapsed () double elapsedTime = (System.currentTimeMillis() - startTime) / 1000.0; NumberFormat n = NumberFormat.getFormat(#,#0.000); elapsedLabel.setText(Elapsed: + n.format(elapsedTime); 1.5.4 延迟当前的一些逻辑:使用DeferredCommand类使用这个功能需要:创建Command类的子类,然后重写它的execute()方法。将这个类添加到有时候可能需要中断当前的逻辑循环以便于JavaScript时间循环得到执行另一端代码的机会。DeferredCommand.addCommand()中。例子如下: TextBox dataEntry; / Set the focus on the widget after setup completes. DeferredCommand.addCommand(new Command() public void execute () dataEntry.setFocus(); dataEntry = new TextBox();1.5.5 避免Slow Script警告:IncrementalCommand类使用AJAX开发者需要一直都让用户知道浏览器对自己的操作作出了相应。当JavaScript代码正在运行的时候,用户组件(例如按钮,文本框等)不会响应用户的任何输入。如果浏览器一直这样,用户可能会觉得浏览器挂了。不过浏览器有一个内建的机制,那就是unresponsive script warning。如下图:任何代码运行超过10秒钟,没有将控制交回给JavaScript主时间循环,浏览器都回弹出这个对话框给用户。GWT提供一个IncrementalCommand类帮助解决长时间运行计算任务问题。它会反复的执行execute()知道计算结束。下面的例子展示了如何使用IncrementalCommand类做一些计算,同时浏览器还对用户作出响应:public class IncrementalCommandTest implements EntryPoint / Number of times doWork() is called static final int MAX_LOOPS = 10000; / Tight inner loop in doWork() static final int WORK_LOOP_COUNT = 50; / Number of times doWork() is called in IncrementalCommand before / returning control to the event loop static final int WORK_CHUNK = 100; / A button to kick off the computation Button button; public void onModuleLoad() button = new Button(Start Computation); button.addClickHandler(new ClickHandler () public void onClick(ClickEvent event) doWorkIncremental(); /* * Create a IncrementalCommand instance that gets called back every so often * until all the work it has to do is complete. */ private void doWorkIncremental () / Turn off the button so it wont start processing again. button.setEnabled(false); IncrementalCommand ic = new I

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论