使用GWT简化AJAX开发 | |
(2007-02-01 10:22:59) | |
Google Web工具包(GWT)是一种Java开发框架,它力求简化AJAX应用程序的开发。GWT让开发人员可以使用常用的Java开发工具,开发及调试用Java开发的AJAX应用程序,并且把同一应用程序作为客户端HTML和JavaScript以及服务器端Java来部署。 Google Web工具包是一种应用开发平台,它包括Java类库、名为窗口组件(widget)的AJAX风格的用户界面组件、基于RPC的请求/响应通信框架以及集成调试环境。GWT提供了java.lang和java.util程序包的子集,还提供了方便基于组件的GUI开发的Java API。开发后的程序经编译成HTML和JavaScript,可部署到浏览器上。 GWT应用程序有两种执行模式。一是宿主模式,这种模式把GWT应用程序作为普通的Java应用程序来执行,允许进行标准的Java调试。为了支持宿主模式,GWT提供了专有的Web浏览器,可与Java虚拟机(JVM)进行交互。还有一种是Web模式,这种模式让GWT应用程序可以作为原生JavaScript和HTML来部署及执行,由GWT Java到JavaScript编译器利用Java源代码生成。 GWT有四大组件/库,分别如下。 GWT Java到JavaScript编译器:该组件可把Java源代码转换成原生JavaScript和HTML;GWT宿主Web浏览器: 该组件让GWT应用程序可以作为Java代码在支持JVM的Web浏览器里面执行;JRE仿真库:该库提供了java.lang和java.util程序包的子集;GWT Web UI类库:该库是一组专有的接口和类,名为窗口组件,可用于构建基于浏览器的GUI组件。 GWT应用程序需要提供一个“入口点”类以及独立的配置数据单元,它们捆绑起来即可形成一个应用“模块”。每个模块包括:根据模式module-name.gwt.xml命名的一个配置文件以及实现com.google.gwt.core.client.EntryPoint接口的一个类——该接口充当了应用程序的主入口点。GWT的JavaScript运行库依赖这种基于模块的结构。以下代码显示了一个典型的模块配置文件。 < module> < !-- Inherit the core Web Toolkit stuff. --> < inherits name='com.google.gwt.user.User'/> < !-- Specify the app entry point class. --> < entry-point class='com.example.client.MyApp'/> < /module> 模块的入口点类必须实现com.google.gwt.core.client.EntryPoint接口,并且提供no-arg构造函数。模块装入后,为其入口点类创建实例,GWT框架调用其onModuleLoad()方法。 GWT入门 为了开始使用GWT,先要从Google(http://code.google.com/webtoolkit/download.html)下载及提取针对你所用特定操作系统的GWT SDK。GWT的库包括类和接口,即窗口组件,可用来为AJAX应用程序构建用户界面组件。窗口组件的布局由名为窗格的容器窗口组件来管理,容器窗口组件可以嵌套在其他窗格组件里面。 下列代码显示了如何为一个按钮窗口组件创建实例,并且嵌入在名为MyContanerPanel的容器窗格里面: Final com.google.gwt.user.client.ui.Button button=new com.google.gwt.user.client.ui.Button("Click me"); button.addClickListener(new com.google.gwt.user.client.ui.ClickListener() { public void onClick(com.google.gwt.user.client.ui.Widget sender) { System.out.println("The 'Click me' button was clicked"); } } com.google.gwt.user.client.ui.RootPanel.get("MyContainerPanel").add(button); GWT应用程序的GUI由类似前一个例子的Java代码组成,代码可以用标准的Java调试工具在宿主模式下进行调试。宿主模式下执行的应用程序在由com.google.gwt.dev.GWTShell类所体现的一个专有外壳里面运行。这个类可以独立执行,也可以在IDE里面执行。在宿主模式下运行时,GWT在专有浏览器的窗口里面执行Java字节码。 一旦应用程序准备好了,GWT编译器就可以用来把Java源代码转换成JavaScript,因而可以把Java应用程序转换成类似的JavaScript应用程序。com.google.gwt.dev.GWTCompiler类用于从命令行把GWT应用程序编译成JavaScript。 就GWT而言,通常在Web浏览器里面进行的所有活动都被称为客户端处理。如果客户端代码准备在Web浏览器里面运行,那么它最终会成为JavaScript。因而,只使用那些由上述GWT编译器来转换的库和Java语言构件很重要。 同样,通常在服务器主机上进行的所有活动都被称为服务器端处理。应用程序与服务器进行交互时,它会使用GWT的远程过程调用(RPC)框架,通过浏览器(客户端)对服务器端代码提出请求。 构建GWT应用程序 GWT随带一个命令行实用程序applicationCreator,它可以自动生成运行最基本的GWT应用程序所需的所有文件。这些文件构成一个项目的基本框架,可以在此基础上构建应用程序。本文演示的这个应用程序可从远程站点检索图书,并将结果显示在Web浏览器中基于AJAX的GUI。为了给这个名为BookSearch的应用程序构建一个框架,用下列命令启动applicationCreator实用程序: applicationCreator -out ./BookSearch com.example.client.BookSearch 一定要用安装的GWT的目录名取代。applicationCreator实用程序可在BookSearch目录下生成众多文件,包括类com/example/client/BookSearch.java中的一些基本的客户端功能。该实用程序还能生成名为BookSearch-shell的宿机模式启动脚本和名为BookSearch-compile的编译脚本。要在宿主模式下运行BookSearch框架应用程序,应执行BookSearch-shell脚本。 创建主页 最终的BookSearch应用程序使用有两个td元素的一个表。一个含有处理搜索词语的窗口组件,另一个含有显示图书相关数据列表的窗口组件。该表添加到com/example/public目录中的BookSearch.html,如下所示: < table width="100%" border="0" summary="Book Search"> < tr valign="top"> < td id="searchterm" align="center" width="100%"> < /td> < /tr> < tr valign="top"> < td id="booklist" align="center" width="100%"> < /td> < /tr> < /table> 现在,UI布局可进行初始化,以便可以添加UI窗口组件。以下代码显示了对BookSearch应用程序的UI布局进行初始化所需的代码: public void onModuleLoad() { private static final int VISIBLE_ROWS = 5; public void onModuleLoad() { RootPanel booklistPanel = RootPanel.get("booklist"); if (booklistPanel != null) {BookListWidget booklistWidget = new BookListWidget(VISIBLE_ROWS); booklistPanel.add(booklistWidget); RootPanel searchtermPanel = RootPanel.get("searchterm"); if (searchtermPanel != null) { SearchTermWidget searchTermWidget =new SearchTermWidget(booklistWidget); searchtermPanel.add(searchTermWidget); }}}} 所有初始化代码都在BookSearch类的onModuleLoad()方法里面。onModuleLoad()方法是由com.google.gwt.core.client.EntryPoint接口定义的惟一一个方法。模块装入后,该方法被调用。请注意com.google.gwt.user.client.ui.RootPanel类是如何用来通过ID来检索BookSearch.html元素引用的。GWT依靠命名约定来查找映射到HTML元素ID的窗口组件类。 创建客户端行为 我们这个应用程序的客户端行为封装在三个主要的UI窗口组件实例里面:负责搜索词语处理的窗口组件实例、拥有搜索服务提供程序和分页列表的容器窗口组件实例、将集成一组窗口组件实例形成导航条和图书分页列表的分页列表窗口组件实例。以下代码显示了处理图书列表检索、含有分页列表的窗口组件: public class BookListWidget extends com.google.gwt.user.client.ui.Composite { private final PageableListWidget pageableListWidget; private String searchTerm = ""; public BookListWidget(int visibleRows) { String[] columns = new String[]{"Title","ISBN","Edition","MSRP"}; String[] styles = new String[]{"title","isbn","edition","msrp"}; pageableListWidget = new PageableListWidget(bookSearchProvider, columns, styles, visibleRows); initWidget(pageableListWidget); } protected void onLoad() {pageableListWidget.refresh(); } protected void setSearchTerm(String searchTerm) { if (this.searchTerm.equals(searchTerm)) { return; } this.searchTerm = searchTerm; pageableListWidget.refresh(); }} BookListWidget类扩展了com.google.gwt.user.client.ui.Composite类,可为集成了一个或若干个相关窗口组件的组合UI组件提供方便。这里只用了一个组合式的嵌套窗口组件: PageableListWidget。PageableListWidget类也扩展了com.google.gwt.user.client.ui.Composite类,并含有多个子窗口组件,包括一个定制的导航条窗口组件和一个处理图书相关数据列表的com.google.gwt.user.client.ui.Grid窗口组件。导航条窗口组件包括com.google.gwt.user.client.ui.DockPanel窗口组件的实例以及com.google.gwt.user.client.ui.Button类的几个实例 SearchTermWidget扩展了com.google.gwt.user.client.ui.Composite类,总共含有一个标签、一个文本框和一个按钮。文本框含有搜索词语,按钮启动每次搜索。 创建服务器端行为 现在可以为应用程序添加服务器端功能了。对BookSearch应用程序而言,需要调用远程API,才能检索与给定的搜索词语相匹配的图书列表。GWT提供了RPC框架,可用于把服务提供给客户端,还可以调用它进行实际搜索。 图中显示了BookSearch应用程序的通信机制。 实现服务器端代码的第一步就是为搜索服务定义接口。该接口必须扩展com.google.gwt.user.client.rpc.RemoteService接口,并含有将提供给GWT客户端代码的方法。下列代码显示了搜索服务接口。其惟一的一个方法将搜索词语作为输入,并返回一组含有表示匹配列表的数据的Book对象: public interface SearchService extends com.google.gwt.user.client.rpc.RemoteService { Book[] getBooks(String searchTerm, int startIndex, int maxCount); } 来自JavaScript的AJAX调用是异步的,因此,必须定义与RemoteService接口相对应的异步接口。该异步接口的方法签名与远程接口的方法签名相匹配,不过多了类型com.google.gwt.user.client.rpc.AsyncCallback这个参数。异步服务完成后,就会调用该参数。返回类型也被清除,因为回调对象将用于传送响应。下列代码显示了SearchService的异步接口: public interface SearchServiceAsync { void getBooks(String searchTerm, int startIndex, int maxCount, com.google.gwt.user.client.rpc.AsyncCallback callback); } AsyncCallback类有两个方法:onSuccess()和onFailure(),远程服务成功或失败后,就会调用这两个方法。 现在可以为SearchService类创建异步实现类。只要使用Apache HTTPClient框架,通过与搜索相关的远程API,调用HTTP GET方法,就可以为实际搜索操作的逻辑提供便利。这里,搜索API由Safari Books Online提供,并由URL:http://my.safaribooksonline.com/xmlapi/search=来调用。从Safari Books Online搜索API返回的结果是一个XML文档。该文档作为文档对象模型(DOM)文档,使用Java API for XML Processing(JAXP)框架来处理。 下列代码显示了使用Apache Commons HttpClient类调用搜索API,并使用JAXP API将结果作为DOM文档来处理: HttpClient client = new HttpClient(); GetMethod get = new GetMethod(url); org.w3c.dom.Document xmlDoc = null; try { // 调用远程搜索API int resultCode = client.executeMethod(get); if (resultCode == 200) { InputStream in = get.getResponseBodyAsStream(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); xmlDoc = builder.parse(in); } else { throw new IOException("HTTP error with response code: "+ resultCode); }} finally { // 释放连接 get.releaseConnection(); } 一旦该DOM文档创建完毕,就可以遍历其中的每个元素,找到匹配项目、添加到图书列表,如下列代码所示: org.w3c.dom.NodeList nodeList = xmlDoc.getElementsByTagName("book"); if (nodeList != null) { int len = nodeList.getLength(); for (int i = 0; i < len; i++) { org.w3c.dom.Element bookElement = (org.w3c.dom.Element)nodeList.item(i); org.w3c.dom.Element title = (org.w3c.dom.Element) bookElement.getElementsByTagName("title").item(0); String titleStr = (title != null ? title.getTextContent() : ""); org.w3c.dom.Element isbn = (org.w3c.dom.Element)bookElement.getElementsByTagName("isbn").item(0); String isbnStr = (isbn != null ? isbn.getTextContent() : ""); org.w3c.dom.Element edition = (org.w3c.dom.Element) bookElement.getElementsByTagName("edition").item(0); String editionStr = (edition != null ? edition.getTextContent() : ""); org.w3c.dom.Element msrp = (org.w3c.dom.Element) bookElement.getElementsByTagName("msrp").item(0); String msrpStr = (msrp != null ? msrp.getTextContent() : ""); books.add(new Book(titleStr, isbnStr, editionStr, msrpStr)); } 从客户端代码调用搜索服务 由于搜索服务类和接口已实现,就可以增强客户端类,以便调用服务,处理响应。步骤如下:首先创建SearchServiceAsync类的实例,如下所示: searchService = (SearchServiceAsync)GWT.create(SearchService.class); 然后,根据SearchServiceAsync实例设定入口点的URL,如下所示: ServiceDefTarget target = (ServiceDefTarget)searchService; String moduleRelativeURL = GWT.getModuleBaseURL() + "booksearch"; target.setServiceEntryPoint(moduleRelativeURL); 第三步,为搜索按钮SearchTermWidget类的onClick方法添加逻辑,并且用SearchTermWidget类的文本框里面的搜索词语来更新相关的BookListWidget类,如下所示: Button searchBtn = new Button("Search", new ClickListener() { public void onClick(Widget sender) { booklistWidget.setSearchTerm(searchTermTxtBox.getText()); } } 接着,通过调用更新方法,更新PageableListWidget实例的UI。通过调用updateRow Data方法——它会调用搜索服务的getBooks方法,用新的搜索词语更新BookSearchProvider。 最后,搜索服务执行及调用通过getBooks方法传送给它的AsyncCallback实例的onFailure或者onSuccess方法: searchService.getBooks(searchTerm, startRow, maxRows, new AsyncCallback() { public void onFailure(Throwable caught) { // 处理失败 } public void onSuccess(Object result) {// 用结果更新com.google.gwt.user.client.ui.Grid窗口组件} } onSuccess方法被调用后,com.google.gwt.user.client.ui.Grid窗口组件的实例可以用新的图书列表来更新。 链接:GWT消除Web应用难题 Google Web工具包是面向AJAX应用开发的一种Java开发框架。GWT消除了基于AJAX的RPC通信机制的许多技术细节,并提供了窗口组件库,可用于构建丰富的UI。GWT让开发人员可以使用常用的Java开发工具,实现及调试用Java开发的基于AJAX的应用程序,然后把应用程序作为客户端的HTML和JavaScript以及服务器端的Java来编译及部署。 GWT利用Java作为通用语言,把客户端代码和服务器代码融合在一起。这种通用环境以及增强的调试功能等特性确实也存在几个缺点。譬如说,GWT完全依赖JavaScript的可用性。要是没有JavaScript,UI根本无法正常工作。而且,只要是传统Web客户端开发技术力图找出有安全漏洞的地方,都会因为GWT使用Java开发客户端和服务器端代码而将漏洞隐藏起来,因而给人以安全运行的虚假感。 GWT的抽象构成了一种黑盒框架,消除了Web应用开发面临的许多难题,因为它让开发人员转向AJAX风格的开发模型。不过,这种黑盒环境给集成其他非AJAX技术的工作增添了复杂性。因而,GWT最适用于围绕丰富GUI、单一页面模式开发的应用程序。 (沈建苗 编译 计算机世界报) |
Oops... the system was unable to perform your operation(error code 008).Please try again in a few seconds.
My search engines(Get information from Microsoft,Wiki and other technical site)
2007年3月1日星期四
订阅:
博文评论 (Atom)
没有评论:
发表评论