锁定老帖子 主题:GWT项目和开发总结
精华帖 (0) :: 良好帖 (13) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-09-29
最后修改:2009-10-04
开发环境: ubuntu7.10 + apache php + jboss. 下面是开发总结: 1: GWT Version & Upgrade 得到一份(新)版本后,你得作如下的工作: 1)看看支持哪些功能和特性 2)看看修正了哪些bug 3)看看屏蔽了哪些function 4)更新相关的编译,运行脚本 这通常是很有用的。比如, 一开始就知道GWT支持国际化这是非常重要的。还有就是 需要知道支持哪些java package, classes, 以及jdk版本和语法特性。这比编译通不过,再来反复修改,要节省大量时间。另外,版本的升级,部分代码需要跟着同步。 比如, GWT 1.4.2 如果想让一个Popup在 browser居中,得自己另外写方法。 GWT 1.4.6就提供 popupPanel.center()直接支持。 GWT1.6.9时float类型已经不被支持,需要进行相应替换才能编译通过。 2:系统配置项: 1)XML Schema(怎么取得这些数据,参考下面的Ajax设计模式) 2)Http header. 比如: <head> <!-- HB, 2008/09/09 --> <meta id="require-logged-in" name="required" content="false"/> </head> 取得这些数据的方法: public static String getMetaContentValueById(String metaTagId,String defaultValue){ String result = null; try{ Element elem = DOM.getElementById(metaTagId); result = DOM.getElementAttribute(elem, CommonDefn.LOCALE_TOKEN); result = (result == null) ? defaultValue : result; result = (result.trim().length() < 1) ? defaultValue : result; } catch(Exception e) { result = defaultValue; } return result; } 3:完全组件化开发 自认为分模块(module)开发是不必要的,而且编译的开销特别大。 我们主要的分页面(Page)架构是基于History(Listener)的。从一个页面到另一个页面的代码页很简单: History.newItem(_link); GoBack也很简单: History.back(); 这样的架构的一个额外好处,还解决了Ajax的go back问题。 我们可以判断一个页面是通过正常的路径来的,还是通过go back来的。 这样就可以分别对待处理。 4:JSNI & JavaScript 1) 直接写javascript function,供页面或flash 调用 2)使用JSNI作多语言(英文,繁体,简体) 的选择 protected class HyperlinkCommand implements Command { protected String _url = ""; public HyperlinkCommand(String url) { _url = url; } /** * Redirects the browser to the given URL. * The following is an inline javascript: * $wnd is the handler for the browser * .location.href is the relative url */ private native void link(String url) /*-{ $wnd.location.href = url; }-*/; public void execute() { link(_url + CommonDefn.HTML_PAGE_SEPARATOR + History.getToken()); // the language link follows by the original page } } 5:架构属于你自己的RPC & Servlet. 方便及时修改,测试(在eclipse里运行测试或debug),发布(考虑css兼容问题,你得在自己的browser测试). Service部分: 采用一个Servlet来作集中控制。前端发送两个参数到Server, I.E. /proxy/proxy.php?proxyinstr=getavailmovies&jsondto={"uusystemlanguageid":"1", "uuxxx":"1"} Main.gwt.xml的 <servlet path='/proxy/proxy.php' class='xxxx.debug.proxy.HttpProxy'/> 注意上面的class部分,他不在client包中,这也是我们想要的效果。 这个只供测试RPC用. 而httpProxy,是标准的Servlet. public class HttpProxy extends HttpServlet { public void doGet(HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws ServletException, IOException { doPost(httpRequest, httpResponse); } /** * Process POST requests */ public void doPost (HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws ServletException, IOException { ... } } 之所以把这个包命名为debug,只是为了在eclipse里运行的时候debug rpc. 它是不会被编译输出到www的。 当在Browser(Firefox,以后简称FF)运行的时候,实际是访问Apache的php,而不是自己建立的Servlet(它负责把数据直接转发到8080的jboss). 而proxy.php也正是作这件事,把80端口的请求转发给8080的jboss的一个Servlet.这就是架构的巧妙之处。 技巧: 在apache下建立soft link到 开发环境下的目录(编译后生成的),就少了N次的cp to apache . 6:Server与Client的约定(term) 1)共享一份相同的常量,定义在各自的CommonDefn中。 i.e. public interface CommonDefn { public static final int PERMISSIONS_CHECKOUT = 0x02000000; }如果一方有修改,另一方需要同步。 2)由于双方都是用json交换数据,所以对于每个请求,它的json要稳定。如果Server端准备 返回的json有变化,则要同步client。一般数据库的设计发生变化,则要修改Server端。 Server的变化,则带来Client的同步变化。因此,数据库设计决定了整个project的可维护性。 3)Client 与 Server共同维护 (自定义的) Session 4)在Client的CallbackHandler中,如果收到"Session expired!"的 json message, 则需要要求用户(重)登录 5)Client做数据的sort,cache还是Server做? 最后还是Server做。唯一原因是:考虑GWT最终输出是html, js. 精简client始终是整个开发流程都要遵守的规则。 7:Ajax设计模式 1)读取本站的XML HTTPRequest.asyncGet(_xmlFile, new ResponseTextHandler() { public void onCompletion(String responseText) { // In the real world, this text would come as a RPC response. This // technique is great for testing and samples though! renderXML(responseText); } 2)一次发送多条请求(以后称指令),待所有请求完成之后,再作处理。这样能减少指令间的耦合度。 处理方式,每一条指令返回后,在callBack中把计数加1,当所有的计数达到指令的条数后,再作具体的处理。 3)go back问题。我们用public class HistoryStack extends Stack {}的一个 SingleTon的实例来记录页面的流入,流出。来达到HTML Referrer的效果。 也就是说,能够 知道当前页面是来自于哪个页面,在此基础上,再判断是否是goback到达的。然后再作处理 4)TimeOut问题。 网络的延迟,中断,甚至处理时间超过指定的等待时间,都可能引发TimeOut问题。如果你开发的是嵌入式系统。这个问题,就得慎重考虑。目前我们的处理方式:客户端触发的TimeOut处理,我们转入到一个固定页面,这个页面显示:系统正在维护中。 这个页面会定时连接server,当连接成功,重置到index page. 另外,服务端与客户端维持一个 heartbeat,如果检查到一定时间没有(heartbeat),就重新启动client. 8:GWT & 动画效果 以及 Flash 1)用GWT开发动画效果,是很容易的。记住,GWT既面向Widget,也面向DOM. 2)Flash与GWT通讯这里不多说 . 在linux下的FF, Flash可能会跳出来,挡住Popup, alert,menu 也就是说transparent特性无效。如果含有的Flash较多,这简直就是灾难。 我们采取的做法,以Flash挡住Popup为例子,我们采取FlashAnimation来显示Flash,FlashPopupManager来管理Flash与Popup的关系。以两个Popup(上面都有Flash)先后显示为例子.第2个Popup(上层的)显示的时候,把第一个Popup的Flash隐藏。第2个Popup关闭的时候,再显示第一层的flash.这是workaround.然而很有效。 算法采用Stack. 9:异常处理 1)GWT提供全局的异常处理(也就是说能够捕获未被处理的异常), I.E. // set uncaught exception handler, we should log exception for investigation GWT.setUncaughtExceptionHandler(new GWT.UncaughtExceptionHandler() { public void onUncaughtException(Throwable e) { // TODO // should call instruction for error message logging e.printStackTrace(); Window.alert("Uncaught exception:\n" + e); // String message = ""; // message += "GWT.getHostPageBaseURL(): " + GWT.getHostPageBaseURL(); // message += "GWT.getModuleBaseURL(): " + GWT.getModuleBaseURL(); // message += "GWT.getModuleName(): " + GWT.getModuleName(); // message += "GWT.isScript(): " + GWT.isScript(); // Window.alert("GWT message:\n" + message); } }); 2)局部处理,同java一样: try, catch, finally block. 10:加入第三方module(通常也是直接或间接由GWT开发) 1)注意版本的匹配和同步升级 2)在project.gwt.xml中加入模块 . I.E . <inherits name='com.allen_sauer.gwt.voices.gwt-voices' /> 3)在编译和运行的脚本中加入这些library的path 11:多个Project(在同一个目录下)共享widget(不同于上面说的引入module方式) 1)设置各自的project.gwt.xml,以及配置里面的servlet path 2)在client Package下建立各自的EntryPoint Class 3)在public Folder下建立各自的Host web File 4)建立各自的编译(project-compile),运行(project-shell)脚本 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-10-09
谢谢,很受启发
|
|
返回顶楼 | |
发表时间:2009-10-09
楼主的意思GWT只是做了M的工作,V的工作由PHP代替了,我理解的对么?
|
|
返回顶楼 | |
发表时间:2009-10-09
喜欢GWT的朋友,推荐两本好书: 《GWT in Practice》(Robert Cooper and Charles Collins), 《GWT In Action》(Robert Hanson)。
|
|
返回顶楼 | |
发表时间:2009-10-09
rockman 写道 楼主的意思GWT只是做了M的工作,V的工作由PHP代替了,我理解的对么?
GWT都作"V"的工作。V可以是一个简单index.html,也可以是index.php或index.jsp. 与一般的开发不同的是,只要这么一个 Host Web file(index.html or index.jsp)就可以了,亦即: One Page One Application. |
|
返回顶楼 | |
发表时间:2009-10-09
可是我们编译后的V非常大,一个模块需要2M左右,在广域网下有性能问题,特别是Open Page Mutiple Application
|
|
返回顶楼 | |
发表时间:2009-10-09
还有,不太清楚你们是怎么把业务对象反映在V上的,我们通常的做法是有一个M to V
的过程。从V到M又经历了从V to M的过程,这部分的代码都需要编译到client包中,所以导致V非常的大。请教你们是怎么处理,不胜感激! |
|
返回顶楼 | |
发表时间:2009-10-09
rockman 写道 可是我们编译后的V非常大,一个模块需要2M左右,在广域网下有性能问题,特别是Open Page Mutiple Application
或许,你可以尝试只编译输出给主流的browser(ie && ff). ps: 还没有做过分Module开发,也暂时没有关注性能调优. |
|
返回顶楼 | |
发表时间:2009-10-09
最后修改:2009-10-09
rockman 写道 还有,不太清楚你们是怎么把业务对象反映在V上的,我们通常的做法是有一个M to V
的过程。从V到M又经历了从V to M的过程,这部分的代码都需要编译到client包中,所以导致V非常的大。请教你们是怎么处理,不胜感激! 如果这个M用到的地方非常之多,就使用。否则,不用M. 我们大多数,直接 JSON --> V. |
|
返回顶楼 | |
发表时间:2009-10-09
已经是对各个浏览器编译了,还是大,性能调优愁死我了,想方设法缩小前台编译大小啊。
|
|
返回顶楼 | |