[Java] GWT项目实践经验

博客首页 » Java GWT项目实践经验

发布于 09 Dec 2014 05:05
标签 blog
GWT项目实践经验

http://blog.csdn.net/jinhuiyu/article/details/4808208

GWT实际项目中需要遵守的一些Patterns和Rules

新项目的UI部分用到了GWT技术,所以就花了一些时间对GWT进行了一下研究,也接受也一些培训,下面就把培训的和学习的内容进行一下总结,希望对使用GWT的朋友有所帮助。

关于GWT官网上提供的Tutorials:

官网上的教程是不适合重用和大型项目开发的,不是实际项目的best practices.

GWT开发中需要注意的问题

1. 如果不注意的话,GWT的client端会变得非常臃肿,因为cilent端的所有东西都是转化为javascript的,所以要时刻考虑如何保持瘦client端

2. Think in Javascript, 因为一切归于javascript,所以在开发时候就应该考虑到你的代码转化为javascript后会是什么样的效果,包括数据。

3. 保持客户端数据最小化,不要大量cache数据在客户端。否则开发复杂UI的话会大大增加浏览器负担。

4. 保持你的业务逻辑在服务端,这样会使你的应用易于维护也有助于trouble shooting.

5. 在服务端做数据校验, 这点在以前的blog里面已经提到过了。

http://zhidao.baidu.com/link?url=X_0Exl_zDF1OBQ2XaG-VOHaH_O2nt8O4kUa8d0csXxwmq1QZ3logi3FBK9iW_rmQ3kkGK-GGxRtqFnPQM_H_xLxtce9QhCd7J3WJAJAwwhO

GWT开发中需要follow的一些patterns 和 rules(使用于我们项目,供大家参考)

1. 每个module使用一个control panel来控制widget之间的交互。 其他所有的交互和消息都需要通过control panel和event bus进行。

2. 使用event bus来进行模块中不同对象的交互。

3. 项目按照模块分为不同的module, 每个module为一个单独的war, 模块之间的信息传递依靠session 变量来进行(我们使用WebLogic的shared session服务来支持session共享)。

4. 不使用hardcode字符串来标示label, message等内容

5. 不适用inner class, GWT的在线教程使用了inner class,为了更易于debug, source control和重用,项目不允许使用inner class.

GWT项目和开发总结

http://www.thinksaas.cn/group/topic/123162/

发表于 2014-08-25 22:33:11
从2007.08进入项目到2008.11产品正式运营,经历了两个GWT项目开发(这两个项目共享相同widget)。基本全程都很顺利。现在分享一下开发历程和注意事项。 开发环境: 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) ;

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)脚本

总结一下GWT的好处和坏处,希望对你有帮助:

好处:
对於java程序员(我自身也是学java的),我们并不擅长有关页面美化方面的技术,比如HTML、CSS和Javascript等,正因为如此,GWT是基於JAVA的,你在GWT里面所编写的全部是java的类,然後编译的时候类就会被编译成HTML、Css+Javascript。也就是说你可以用自己所擅长的java来解决自己不擅长的HTML、CSS和Javascript。换句话说,你并不需要一个一个页面地写了,不需要有login.jsp,不需要有register.jsp了,在某一个页面需要什麽内容,直接把类调用进去,就能解析出页面。
以前的页面都是通过一个一个不同的页面的跳转来运作的,使用了GWT之後,因为所有东西都模块化了(毕竟是java嘛),比如一个登陆界面,和一个登陆后的欢迎界面,假设两个界面拥有相同的界面部份,比如说背景和header,那麼我们就不需要整个页面都reload了,也就是说GWT还可以解析成Ajex,非常方便。
由於是模块化而且是熟悉的语言,你用来构建对於美工方面要求不高的网站速度非常快!

坏处:
接下来我就要谈到我之所以放弃使用GWT的原因了:
GWT是使用widget来做界面的,一个widget可以是一个按钮,也可以是一个组件,比如说登陆窗口的那几个装用户名密码的文本框以及下面的注册按钮等。这些widget一听就感觉比较模块化,可是这些东西实在是太丑了,我要做的网站是个人网站,要求页面必须很好看而且配有很多动画,就为了这个我不得不放弃了。当然,如果你要做的是商业网站等等,也可以使用bootstrap的库,它也提供不少好看的界面。(http://getbootstrap.com/getting-started/
在java里面就可以写HTML、CSS和Javascript,这是不是非常炫酷的一件事?的确,但是你想也知道不可能一个工具能轻易代替另一个工具的,每一个工具都有它自己好用的地方。我想说:“在java里面写HTML和CSS以及Javascript,绝对是非常糟糕的体验。”一个比方:我要写一句话:<p>我<b>爱</b>你</p>,这在HTML里面就这麼一句话,在GWT,你需要有三个子节点(文字,B,文字)然後放到节点P里面去。当你这样玩一下之後,你会发现非常累人,最後你就会感觉说,哈哈,我们不如就用HTML Panel来放所以的HTML吧!很好,这时候你已经把GWT的优势都扔了。


本页面的文字允许在知识共享 署名-相同方式共享 3.0协议和GNU自由文档许可证下修改和再使用,仅有一个特殊要求,请用链接方式注明文章引用出处及作者。请协助维护作者合法权益。


系列文章

文章列表

  • Java GWT项目实践经验

这篇文章对你有帮助吗,投个票吧?

rating: 0+x

留下你的评论

Add a New Comment
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License