浙江做网站套餐,怎么做游戏推广员,抖音代运营合同模板免费下载,免费pc网站建设From: http://blog.csdn.net/struts2/article/details/1758122 GWT 入门介绍
GWT使用JSON格式的数据通讯 GWT是 Google Web Toolkit的简称。
GWT是一个以Java语言为工具#xff0c;以类似Swing的方式编写UI组件#xff0c;之后通过GWT Compiler编译
为JavaScritp和HTM…From: http://blog.csdn.net/struts2/article/details/1758122 GWT 入门介绍
GWT使用JSON格式的数据通讯 GWT是 Google Web Toolkit的简称。
GWT是一个以Java语言为工具以类似Swing的方式编写UI组件之后通过GWT Compiler编译
为JavaScritp和HTML在客户端浏览器中运行的一个开发工具和编程模型。 GWT应用程序有两种方式运行
Hosted Model 在Hosted Model方式下Java程序并不会被编译成JavaScriptGWT只是创造了一个类似 浏览器的环境直接运行使用GWT开发的程序。这种模式最具生产力这种模式下可以Debug所有的Java代码 所以开发环境通常使用Hosted Model但是真正的程序执行不使用这种模式。
Web Model 就是将使用GWT编写的Java程序整整编译成JavaScript在Web容器上运行使用浏览器 访问的模式这种方式只有在测试或者运行的时候才使用每次对Java类的修改必须重新编译 这些Java类之后重新部署应用。所以生产力比较低。 安装GWT
从如下位置下载GWT的最新版本
http://code.google.com/webtoolkit/download.html
当前最新的Release版本为1.4.60 上一个稳定的版本为1.3.3 第一步安装JDK 1.4 以上的版本都可以。
第二步下载GWT压缩文件这里使用1.4.59 RC2gwt-windows-1.4.59.zip
第三布将GWT压缩文件解压缩到制定的目录这里我使用的目录为C:/程序开发/Java/gwt-windows-1.4.59
第四步安装成功 安装之后的目录结构为
C:/程序开发/Java/gwt-windows-1.4.59 doc文档目录开发文档和Java API文档 samples示例代码目录非常有名的KitchenSink示例代码即在此目录中 about.html about.txt applicationCreator.cmd benchmarkViewer.cmd COPYING COPYING.html gwt-benchmark-viewer.jar gwt-dev-windows.jar gwt-ll.dll gwt-module.dtd gwt-servlet.jar gwt-user.jar i18nCreator.cmd index.html junitCreator.cmd projectCreator.cmd release_notes.html swt-win32-3235.dll 使用GWT建立开发
GWT的安装目录下有一个名叫Samples的目录里边有很多的例子其中KitchenSink比较全面的展现了GWT的Web组件。 applicationCreator创建一个可以以Hosted Mode形式运行的GWT应用程序
以下命令将建立一个工程 C:/程序开发/Java/gwt-windows-1.4.59applicationCreator.cmd -eclipse GWTLogon -out GWTLogon com.jpleausre.gwt.logon.client.GWTLogon Created directory GWTLogon/src Created directory GWTLogon/src/com/jpleausre/gwt/logon Created directory GWTLogon/src/com/jpleausre/gwt/logon/client Created directory GWTLogon/src/com/jpleausre/gwt/logon/public Created file GWTLogon/src/com/jpleausre/gwt/logon/GWTLogon.gwt.xml Created file GWTLogon/src/com/jpleausre/gwt/logon/public/GWTLogon.html Created file GWTLogon/src/com/jpleausre/gwt/logon/client/GWTLogon.java Created file GWTLogon/GWTLogon.launch Created file GWTLogon/GWTLogon-shell.cmd Created file GWTLogon/GWTLogon-compile.cmd 运行GWTLogon-shell.cmd可以看到GWT启动的服务端的Google Web Toolkit Development Shell如下图 和如下的Host Mode的浏览器 点击其中的 Click Me 按钮可以看到输出的Hello World。 projectCreator建立一个基于ant构建的或者基于eclipse的GWT开发工程
例如
C:/程序开发/Java/gwt-windows-1.4.59projectCreator.cmd -ant GWTLogon -eclipse GWTLogon -out GWTLogon Created directory GWTLogon/src Created directory GWTLogon/test Created file GWTLogon/GWTLogon.ant.xml Created file GWTLogon/.project Created file GWTLogon/.classpath 其中的GWTLogon.ant.xml构建文件的内容为 ?xml version1.0 encodingutf-8 ? project nameGWTLogon defaultcompile basedir. description GWTLogon build file. This is used to package up your project as a jar, if you want to distribute it. This isnt needed for normal operation. /description !-- set classpath -- path idproject.class.path pathelement path${java.class.path}// pathelement pathC:/程序开发/Java/gwt-windows-1.4.59/gwt-user.jar/ !-- Additional dependencies (such as junit) go here -- /path target namecompile descriptionCompile src to bin mkdir dirbin/ javac srcdirsrc:test destdirbin includes** debugon debuglevellines,vars,source source1.4 classpath refidproject.class.path/ /javac /target target namepackage dependscompile descriptionPackage up the project as a jar jar destfileGWTLogon.jar fileset dirbin include name**/*.class/ /fileset !-- Get everything; source, modules, html files -- fileset dirsrc include name**/ /fileset fileset dirtest include name**/ /fileset /jar /target target nameclean !-- Delete the bin directory tree -- delete fileGWTLogon.jar/ delete fileset dirbin includes**/*.class/ /delete /target target nameall dependspackage/
/project applicationCreator和projectCreator的区别是
applicationCreator创建了src目录和Demo代码projectCreator不创建Demo代码但是创建src目录和test目录。
applicationCreator创建了启动脚本GWTLogon-shell.cmd和GWT编译脚本GWTLogon-compile.cmd而projectCreator不创建。
applicationCreator创建了eclipse launch文件而projectCreator创建.classpath和.project文件。 通常情况下我们先使用projectCreator创建按projectprojectCreator创建的工程可以轻松的import到eclipse中
之后我们使用applicationCreator创建需要的Java示例代码eclipse launch文件启动脚本和编译脚本。 使用Eclipse导入的GWT工程如下 命令列表
projectCreator 生成基本项目框架可以选择使用eclipse或者使用ant构建文件 applicationCreator 生成代码示例和一个可运行的应用程序 junitCreator 生成一个JUnit测试Case i18nCreator
生成一个i18n属性文件和对应的Javascript脚本。 benchmarkViewer 显示benchmark结果 功能介绍通用
GWT体系结构 GWT Java-to-JavaScript Compiler 将Java程序翻译为JavaScript通过GWT Compiler可以让GWT程序在Web 模式下运行 GWT Hosted Web Browser GWT Hosted Web Brower让你的程序可以在Hosted模式下运行在Hosted模式下运行的是Java代码而不是编译出来的JavaScript代码在Hosted模式下可以轻松的做Debug。
JRE emulation library 可以称为JRE简化的类库。在客户端用来编译成JavaScript代码的客户端Java代码不是所有的java类库都被gwt支持只有部分被支持这些类库是几乎所有的java.lang包java.util包的一部分。 GWT Web UI class library 使用GWT Web UI类库可以创建web 浏览器的组件例如按钮文本框图片等。这是GWT的核心UI类库。 功能介绍Web控件
Web控件是GWT表示层的核心通过使用GWT提供的Web控件可以创建丰富的客户端画面。
GWT的web组件主要分为两类输入控件和Layout控件。 输入控件主要是指向服务器提交数据处理操作显示服务器数据的空间主要包括
ButtonRadionButtonPushButtonToggleButtonCheckBoxTextBoxPasswordBox
TextArea, HyperLink,ListBox,MenuBar,Tree,Table, TabBar,DialogBox, PopupPanel
RichTextArea, DisclosurePanel, SuggestBox Layout 空间主要用来有规律地放置输入控件主要包括
Stackpanel,HorizontalPanel,VerticalPanel, FlowPanel, VerticalSplitPanel, HorizontalSplitPanel,
DockPanel, TabPanel, 事件模型Event Listener 如何处理页面的事件呢例如点击按钮Textbox失去焦点等
如下的代码建立了一个按钮按钮的名字是“Click Me”当你点击这个按钮的时候处罚一个Click事件Click事件触发onClick(Widget sender)方法。
sender表示触发onClick方法的组件这里只是简单的在页面上显示Hello World信息相当于javascript的alert方法。 Button b new Button(Click Me); b.addClickListener(new ClickListener() { public void onClick(Widget sender) { Window.alert(Hello World); } });
常见的Listener如下
ChangeListener ClickListener FocusListener KeyboardListener MouseListener MouseWheelListener PopupListener ScrollListener TableListener TreeListener 功能介绍远过程调用RPC 体系结构
GWT应用中页面一旦加载就再也不会向服务器请求HTML内容所有的画面迁移转换都在客户端进行但是数据还是会向服务器提交或者从服务器获取。
服务器上负责处理数据的对象在GWT中叫做Service每个Service有三个类组成服务方法定义接口Service异步调用接口ServiceAsync和服务器方法实现类ServiceImpl。
以Login为例子说明 // 服务方法定义接口
public interface LoginService extends RemoteService { public boolean login(LoginSO login) throws ApplicationException; } // 异步调用接口
public interface LoginServiceAsync { void login(LoginSO login, AsyncCallback async); } // 服务器方法实现类 public class LoginServiceImpl extends RemoteServiceServlet implements LoginService { public boolean login(LoginSO login) throws ApplicationException { ... return true; } } 其中前两个接口在client包内部最后一个实现在server包内部。 客户端调用一个服务类的方法的代码如下 LoginServiceAsync ourInstance (LoginServiceAsync) GWT.create(LoginService.class); // Œ ((ServiceDefTarget) ourInstance).setServiceEntryPoint(GWT.getModuleBaseURL() /LoginService); // ourInstance.login(loginSO, new AsyncCallback() { //Ž public void onFailure(Throwable caught) { // if(caught instanceof InvocationException) { // system exception } else { Window.alert( GWTShowConstants.Messages.constants.maxQueryCount()); // aplication exception } } public void onSuccess(Object result) { // Window.alert(success); }
}); // ‘ 远程调用
Œ 获得服务器方法的调用接口skeleton。
设置服务位置。
Ž 远程调用服务器上的方法注意这里是异步调用在和调用之前‘代码可能先被调用了。
调用出错或者调用方法抛出异常的时候调用的方法。
调用成功返回时候调用的方法。 参数和返回值系列化类型
这里的参数指的是Service方法调用的参数和返回值。
由于GWT的客户端代码都是JavaScript而服务器代码都是使用Java编写的这就涉及到JavaScript调用Java方法的时候
如何传递参数如何取得返回值的问题。 可序列化的类型包括
1 原始类型例如char, byte, short, int, long, boolean, float, double;
2 Stringjava.util.Date或者原始类型的包装类型例如 Character, Byte, Short, Integer, Long, Boolean, Float, or Double;
3 可序列化类型数组包含4和5定义的类型
4 用户定义的可序列化类型
5 该类型至少有一个可序列化的子类型 针对上述4中说明的什么是用户自定义的可序列化类型呢必须满足以下亮点
第一必须直接或者间接例如父类型实现了这个接口的实现了IsSerializable接口
第二所有非transient类型都是可序列化的final类型的属性在GWT中被视为transient类型 是否支持容器类型呢那么又如何声明呢
支持容器类型GWT可以使用Type 参数来表示容器类型内部的元素的类型例如
注意GWT暂时不支持使用 JDK 5.0 的模板容器 //用户自定义序列化类型
public class MyClass implements IsSerializable { /** * 这个Set中的元素的类型必须都是String类型 * * gwt.typeArgs java.lang.String */ public Set setOfStrings; /** * Map中的元素的Key和Value的类型都是String类型。 * * gwt.typeArgs java.lang.String,java.lang.String */ public Map mapOfStringToString; } // 服务器方法实现类 public interface MyService extends RemoteService { /** * 第一个类型参数表示方法的参数c是一个List并且其中只能放置Integer类型。 * 第二个类型参数表示返回值为List并且其中的原书的类型为String类型。 * * gwt.typeArgs c java.lang.Integer * gwt.typeArgs java.lang.String */ List reverseListAndConvertToStrings(List c); } 异常
在调用方法的时候异常怎么处理呢
调用方法的过程中的异常可以分为两类第一类调用方法的过程中出现了异常例如网络故障服务类不存在等。
第二类服务器方法抛出了异常。 在客户端调用的过程中这两种异常都在onFailureThrowable caught方法中处理但是caught的类型有所区别
第一种情况下caught为InvocationException的子类第二种情况下caught为用户自定义的异常。 由于异常也需要在客户端JavaScript和服务器端Java传递所以Exception的定义也要满足可序列化的要求。
但是在GWT中已经定义了一个基本的异常类型来提一个Exception类的基础类这个类是SerializableException例如
public class ApplicationException extends SerializableException { public ApplicationException() { super(); } public ApplicationException(String msg) { super(msg); } public Throwable getCause() { return super.getCause(); } public String getMessage() { return super.getMessage(); } public Throwable initCause(Throwable cause) { return super.initCause(cause); } } 异常消息内容建议服务器端的错误消息内容在服务器保存客户端的错误消息内容在客户端保存参看后续的国际化部分两个地方
都需要的出于GWT技术建议使用两份分别放在客户端和服务器端。
为什么不能重用呢
客户端的消息会被编译为JavaScript所以服务器端通常无法使用。还有另外的原因参看后续的国际化部分。 功能介绍集成JUnit
TODO 功能介绍国际化 项目开发过程中经常需要一些可配置的常量例如查询最大条数目录位置等。在传统的Java应用程序中这些内容通常会放在
属性文件中Properties文件但是使用属性文件有些弊端第一不支持类型所有的内容都是String第二是只有在具体使用
的时候才能发现有些属性没有定义而不能在编译的时候发现。 那么GWT如何处理这个问题呢GWT中有一个特殊的接口com.google.gwt.i18n.client.Constants可以使用这个接口达到
定义常量的效果并且这些常量在编译的时候被绑定而且可以支持类型。 使用GWT主要有以下几步
第一步建立一个集成于Constants的接口例如
public interface NumberFormatConstants extends Constants { /** * return the localized decimal separator */ String decimalSeparator(); /** * return the localized thousands separator */ String thousandsSeparator(); } 第二步根据接口中定义的方法定义一个跟接口同名的属性文件例如
#NumberFormatConstants.properties
decimalSeparator , thousandsSeparator . 第三步获取文件中定义的内容例如
public void useNumberFormatConstants() { NumberFormatConstants constants (NumberFormatConstants) GWT.create(NumberFormatConstants.class); String decimalSep constants.decimalSeparator(); String thousandsSep constants.thousandsSeparator(); String msg Decimals are separated using decimalSep ; msg , and thousands are separated using thousandsSep ; showMessage(msg); } 上述三步中在第二步和第三步中间隐含了伊特特殊的步骤就是GWT编译器结合接口文件和属性文件编译出了一个
类这个类实现了这个接口每一个方法返回属性文件中的值。
其中GWT.create()方法可以获得生成的中间类的引用。 通常情况下接口方法明和属性文件中的名字相同例如
String decimalSeparator(); 和 thousandsSeparator .
但是也可以自定义接口方法和属性文件中内容的映射例如 public interface NumberFormatConstantsWithAltKey extends Constants { /** * gwt.key fmt.sep.decimal * return the localized decimal separator */ String decimalSeparator(); /** * gwt.key fmt.sep.decimal * return the localized thousands separator */ String thousandsSeparator(); } gwt.key fmt.sep.decimal 定义了属性文件中key的内容所以属性文件应该为
#NumberFormatConstants.properties
fmt.sep.decimal . fmt.sep.thousands , Constants子接口中定义的方法必须满足如下形式 T methodName() 这里T是一个返回值T可以使用如下表中的所有类型
T类型 属性文件定义 String 简单的字符串 String[] 使用逗号分割的字符串如果某个字符串中包含逗号需要使用//作为转移字符例如//, int int值在编译的时候做类型检查 float float值在编译的时候做类型检查 double double值在编译的时候做类型检查 boolean boolean值true 或者 false), 在编译的时候做类型检查 Map 使用逗号分隔的字符产每一个字符产在属性文件中有一条定义定义了一个Key-Value值 Map示例
a X b Y c Z someMap a, b, c Map someMap方法得到的内容为{a:X, b:Y, c:Z} ConstantsWithLookup
ConstantsWithLookup是Constants的子接口用法一样只不过ConstantsWithLookup有一组通过属性名字获取属性值的方法
getBoolean(String) 通过名字找到boolean型内容 getDouble(String) 通过名字找到double型内容 getFloat(String) 通过名字找到float型内容 getInt(String) 通过名字找到int型内容 getMap(String) 通过名字找到Map型内容 getString(String) 通过名字找到String型内容 getStringArray(String) 通过名字找到String[]型内容 效率问题Constants效率比ConstantsWithLookup高为什么呢Constants在编译的时候会生成对应的JavaScript代码
GWT Compiler会根据程序中是否使用了某些属性来决定这些内容是否会被编译为JavaScript所以及时在Constants中声明
了某些方法如果在代码中不使用的话不会被编译为JavaScript代码的。
但是ConstantsWithLookup有根据属性名字查找属性内容的方法所以GWT Compiler不能根据上述方法确定属性是否被使用
所以所有的属性内容都回被编译为JavaScript代码。
这是ConstantsWithLookup的优点也是缺点 Message类
在使用Constants或者ConstantsWithLookup的时候我们只能使用预定义的消息有些时候我们需要可变的消息。
例如 我们需要一个通用的消息再加上一个功能名字的参数怎么实现呢 Message类相当于Java中的PropertiesResourceBundle和MessageFormat的联合体例如 消息文件类 public interface GameStatusMessages extends Messages { /** * param username the name of a player * param numTurns the number of turns remaining * return a message specifying the remaining turns for a player */ String turnsLeft(String username, int numTurns); /** * param numPoints the number of points * return a message describing the current score for the current player */ String currentScore(int numPoints); } 属性文件定义 turnsLeft Turns left for player {0}: {1} currentScore Current score: {0}
使用 public void beginNewGameRound(String username) { GameStatusMessages messages (GameStatusMessages) GWT.create(GameStatusMessages.class); // Tell the new player how many turns he or she has left. int turnsLeft computeTurnsLeftForPlayer(username); showMessage(messages.turnsLeft(username, turnsLeft)); // Tell the current player his or her score. int currentScore computeScore(username); setCurrentPlayer(username); showMessage(messages.currentScore(currentScore)); } 我们可以看到在使用的时候基本一致但是可以使用参数配置原有的消息。
另外Message的方法的格式为 String methodName(optional-params)
从中我们也可以看出区别Message只能使用String类型的参数。 Constants(或者ConstantsWithLookup)和Message的区别是 Constants用来定义系统的常量支持多种类型。 Message用来定义系统的消息可以支持参数化消息但是只支持String类型的内容。 在使用Constants和Message的时候可以将属性文件的编码设置为UTF-8这样就不用 使用Native2ascii将正常的文件转移为utf-8的替换文件了。 当然如果你觉得不麻烦也可以使用传统的Java属性文件使用native2ascii处理过得文件。 功能介绍JavaScript Native Interface JavaScript Native Interface JSNI JSNI定义了在GWT环境下Java与JavaScript交互的一种方法。 虽然GWT的一些核心的方法是用JavaScript编写的但是这里还是不推荐使用JNI应为这样做与GWT的初衷相悖
并且有一定的难度开发调试也相对困难。 Java调用JavaScript方法
JSNI方法定义需要使用native关键字并且需要在参数列表之后结尾的分号之前定义。JSNI方法的开始使用/*-{
结尾使用}-*/例如 public static native void alert(String msg) /*-{ $wnd.alert(msg); }-*/; 当上述方法在Java中调用的时候实际上将会调用Window的alert方法将传入的内容打印出来。
在Hosted Mode下断点可以设置在上述方法中可以方便的查看传入的参数。 JavaScript调用Java方法
方法调用方式 [instance-expr.]class-name::method-name(param-signature)(arguments)
属性访问方式 [instance-expr.]class-name::field-name [instance-expr.] 用来区分实例方法调用还是静态方法调用。在调用实例方法的时候必须出现在调用静态方法的时候不能出现。
class-name 类的名字。
method-name 方法的名字 param-signature 方法的参数列表这里使用的是内部形式参考Java虚拟机Class格式但是不需要写返回值类型。 arguments 调用方法的实际参数。
例如
public class JSNIExample { String myInstanceField; static int myStaticField; void instanceFoo(String s) { // use s } static void staticFoo(String s) { // use s } // 该方法被调用的时候将在JavaScript中执行并且 // 可以使用JavaScript中的内容。 public native void bar(JSNIExample x, String s) /*-{ // 调用这个实例本身的instanceFoo方法 this.com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s); // 调用x实例输入参数上的instanceFoo实例方法 x.com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s); // 调用静态方法 staticFoo() com.google.gwt.examples.JSNIExample::staticFoo(Ljava/lang/String;)(s); // 读取这个实例的变量 var val this.com.google.gwt.examples.JSNIExample::myInstanceField; // 设置x上的实例变量 x.com.google.gwt.examples.JSNIExample::myInstanceField val and stuff; // Read static field (no qualifier) com.google.gwt.examples.JSNIExample::myStaticField val and stuff; }-*/;
} Java和JavaScript之间参数的传递
Java - JavaScript
Java type JavaScript Type numeric primitive a JavaScript numeric value, as in var x 42; String a JavaScript string, as in var s my string; boolean a JavaScript boolean value, as in var b true; JavaScriptObject (see notes) a JavaScriptObject that must have originated from JavaScript code, typically as the return value of some other JSNI method Java array an opaque value that can only be passed back into Java code any other Java Object an opaque value accessible through special syntax 异常 调用JSNI方法的时候会抛出一个JavaScriptException的异常但是由于JavaScript不是一个强类型的语言所以 无法想Java一样处理JavaScript异常。一个好的方式是在Java中处理Java异常在JavaScript中处理JavaScript异常。
另外在JSNI方法Java普通方法混掉的过程中异常可以从最底层移植抛到最想的调用层例如
1. Java method foo() calls JSNI method bar() 2. JavaScript method bar() calls Java method baz() 3. Java method baz() throws an exception baz()中抛出的异常可以蔓延到bar方法可以在foo方法中捕获。 从Host Model到 Web Model
在Host Model方式下GWT并不将Java代码编译为JavaScript而是在GWT环境中直接运行Java bytecode
但是项目正式部署之后使用的是Web Model那么如何从Host Model迁移到Web Model呢 首先需要将Java代码编译为JavaScript代码。
使用如下命令可以将Java代码编译为JavaScript代码
java -cp %~dp0/src;%~dp0/bin;%~dp0/../../gwt-user.jar;%~dp0/../../gwt-dev-windows.jar com.google.gwt.dev.GWTCompiler -out %~dp0/www %* com.google.gwt.sample.hello.Hello -cp 指定源代码目录Class目录和GWT的jar文件的路径
-out 指定JavaScript代码的输出路径
com.google.gwt.sample.hello.Hello 指定编译的Module一般是gwt.xml文件中entry-point类去掉client之后的内容。 当代码量比较大的时候需要指定Java使用内存的大小否则会内存溢出。
java -Xmx512m -Xms128m -cp %~dp0/src;%~dp0/bin;%~dp0/../../gwt-user.jar;%~dp0/../../gwt-dev-windows.jar com.google.gwt.dev.GWTCompiler -out %~dp0/www %* com.google.gwt.sample.hello.Hello 之后将编译成的JavaScript代码拷贝到Web项目的根目录中与WEB-INF相同层次的目录。 最后需要将gwt.xml文件中定义的service编程对应的Servlet。
servlet path/calendar classcom.google.gwt.sample.dynatable.server.SchoolCalendarServiceImpl/ servlet servlet-nameCalendar/servlet-name servlet-classcom.google.gwt.sample.dynatable.server.SchoolCalendarServiceImpl/servlet-class
/servlet servlet-mapping servlet-nameCalendar/servlet-name url-pattern/calendar/url-pattern
/servlet-mapping 使用数据源 Hosted Mode 虽然开发起来很方便但是也有缺点例如数据源的配置就有问题。
在GWT Hosted Mode下无法配置数据源一种可选的方式是使用一个假的数据库链接
管理类这个类的接口返回Connection内部以DriverManager的方式实现等待
后续部署之后再切换到数据源模式。 日志处理(Log4J)
回想GWT应用程序client包内部的代码将会被编译为客户端JavaScript代码所以这里 不需要记录日志也不可能使用Log4j。 但是Server包内的内容在服务器上运行需要合理的使用日志。 一个简单的Login示例
代码结构如下 └─src └─com └─jpleasure └─gwt └─logon │ LogonDemo.gwt.xml GWT配置模块文件 │ ├─client 客户端代码包 │ │ LogonDemo.java GWT代码的入口点 │ │ LogonDemoController.java 画面迁移控制类 │ │ │ ├─exception 异常定义包 │ │ ApplicationException.java 应用程序异常 │ │ │ ├─panel 页面Panel包 │ │ BasePanel.java 基类Panel │ │ LogonPanel.java Logon Panel │ │ WelcomePanel.java Welcome Panel │ │ │ ├─service 客户端服务定义包 │ │ LogonService.java 服务接口 │ │ LogonServiceAsync.java 服务异步调用接口 │ │ │ └─so Serializable Object 包 │ LogonSO.java Logon SO │ ├─public GWT HTML包 │ LogonDemo.css CSS定义 │ LogonDemo.html 主HTML页面 │ └─server 服务端Service包 └─service LogonServiceImpl.java Logon Service // ApplicationException
package com.jpleasure.gwt.logon.client.exception;
import com.google.gwt.user.client.rpc.SerializableException;
/** * Created by IntelliJ IDEA. * User: ma.zhaodl.cn * Date: 2007-8-27 * Time: 22:16:17 * To change this template use File | Settings | File Templates. */ public class ApplicationException extends SerializableException { public ApplicationException() { super(); } public ApplicationException(String msg) { super(msg); } } //BasePanel
package com.jpleasure.gwt.logon.client.panel;
import com.google.gwt.user.client.ui.VerticalPanel; import com.jpleasure.gwt.logon.client.LogonDemoController;
/** * Created by IntelliJ IDEA. * User: ma.zhaodl.cn * Date: 2007-8-27 * Time: 22:01:14 * To change this template use File | Settings | File Templates. */ public class BasePanel extends VerticalPanel { protected LogonDemoController ldc; public LogonDemoController getLdc() { return ldc; } public void setLdc(LogonDemoController ldc) { this.ldc ldc; } } // LogonPanel
package com.jpleasure.gwt.logon.client.panel;
import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.*; import com.jpleasure.gwt.logon.client.service.LogonService; import com.jpleasure.gwt.logon.client.service.LogonServiceAsync; import com.jpleasure.gwt.logon.client.so.LogonSO;
/** * Created by IntelliJ IDEA. * User: ma.zhaodl.cn * Date: 2007-8-27 * Time: 21:35:13 * To change this template use File | Settings | File Templates. */ public class LogonPanel extends BasePanel { private TextBox name; private PasswordTextBox password; private Button logonButton; public LogonPanel() { HorizontalPanel msgPanel new HorizontalPanel(); msgPanel.add(new Label(Please input logon information here!)); HorizontalPanel namePanel new HorizontalPanel(); Label nameLabel new Label(Name:); nameLabel.setPixelSize(100, 20); namePanel.add(nameLabel); name new TextBox(); namePanel.add(name); HorizontalPanel pwdPanel new HorizontalPanel(); Label passwordLabel new Label(Password:); passwordLabel.setPixelSize(100, 20); pwdPanel.add(passwordLabel); password new PasswordTextBox(); pwdPanel.add(password); HorizontalPanel btnPanel new HorizontalPanel(); logonButton new Button(Logon); logonButton.addClickListener(new ClickListener() { public void onClick(Widget sender) { LogonServiceAsync logonService LogonService.App.getInstance(); LogonSO logonSO new LogonSO(); logonSO.setName(getName()); logonSO.setPassword(getPassword()); logonService.logon(logonSO, new AsyncCallback() { public void onFailure(Throwable caught) { Window.alert(caught.getMessage()); } public void onSuccess(Object result) { boolean isLogon ((Boolean)result).booleanValue(); if(isLogon) { ldc.gotoWelcome(); } else { Window.alert(logon failed!); } } }) ; } }); btnPanel.add(logonButton); this.add(msgPanel); this.add(namePanel); this.add(pwdPanel); this.add(btnPanel); } public String getName() { return this.name.getText(); } public String getPassword() { return this.password.getText(); }
} // WelcomePanel
package com.jpleasure.gwt.logon.client.panel;
import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.ClickListener; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Widget;
/** * Created by IntelliJ IDEA. * User: ma.zhaodl.cn * Date: 2007-8-27 * Time: 21:49:53 * To change this template use File | Settings | File Templates. */ public class WelcomePanel extends BasePanel { public WelcomePanel() { Label welcomeLabel new Label(Welcome to LogonDemo!); this.add(welcomeLabel); Button logoutButton new Button(Logout); logoutButton.addClickListener(new ClickListener() { public void onClick(Widget sender) { ldc.gotoLogon(); } }); this.add(logoutButton); } } //LogonService
package com.jpleasure.gwt.logon.client.service;
import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.ServiceDefTarget; import com.jpleasure.gwt.logon.client.exception.ApplicationException; import com.jpleasure.gwt.logon.client.so.LogonSO;
/** * Created by IntelliJ IDEA. * User: ma.zhaodl.cn * Date: 2007-8-27 * Time: 22:13:09 * To change this template use File | Settings | File Templates. */ public interface LogonService extends RemoteService { /** * Utility/Convenience class. * Use LogonService.App.getInstance() to access static instance of LogonServiceAsync */ public static class App { private static LogonServiceAsync ourInstance null; public static synchronized LogonServiceAsync getInstance() { if (ourInstance null) { ourInstance (LogonServiceAsync) GWT.create(LogonService.class); ((ServiceDefTarget) ourInstance).setServiceEntryPoint(GWT.getModuleBaseURL() com.jpleasure.gwt.logon.LogonDemo/LogonService); } return ourInstance; } } public boolean logon(LogonSO logonSO) throws ApplicationException; } //LogonServiceAsync
package com.jpleasure.gwt.logon.client.service;
import com.google.gwt.user.client.rpc.AsyncCallback; import com.jpleasure.gwt.logon.client.so.LogonSO;
/** * Created by IntelliJ IDEA. * User: ma.zhaodl.cn * Date: 2007-8-27 * Time: 22:13:09 * To change this template use File | Settings | File Templates. */ public interface LogonServiceAsync { void logon(LogonSO logonSO, AsyncCallback async); }
// LogonSO
package com.jpleasure.gwt.logon.client.so;
import com.google.gwt.user.client.rpc.IsSerializable;
/** * Created by IntelliJ IDEA. * User: ma.zhaodl.cn * Date: 2007-8-27 * Time: 22:13:52 * To change this template use File | Settings | File Templates. */ public class LogonSO implements IsSerializable { private String name; private String password; public String getName() { return name; } public void setName(String name) { this.name name; } public String getPassword() { return password; } public void setPassword(String password) { this.password password; } }
// LogonDemo package com.jpleasure.gwt.logon.client;
import com.google.gwt.core.client.EntryPoint; import com.google.gwt.user.client.ui.DeckPanel; import com.google.gwt.user.client.ui.RootPanel; import com.jpleasure.gwt.logon.client.panel.LogonPanel; import com.jpleasure.gwt.logon.client.panel.WelcomePanel;
/** * Created by IntelliJ IDEA. * User: ma.zhaodl.cn * Date: 2007-8-27 * Time: 21:34:12 * To change this template use File | Settings | File Templates. */ public class LogonDemo implements EntryPoint { public void onModuleLoad() { DeckPanel mainPanel new DeckPanel(); LogonDemoController ldc new LogonDemoController(mainPanel); LogonPanel logonPanel new LogonPanel(); logonPanel.setLdc(ldc); mainPanel.add(logonPanel); WelcomePanel welcomePanel new WelcomePanel(); welcomePanel.setLdc(ldc); mainPanel.add( welcomePanel ); mainPanel.showWidget(0); RootPanel.get().add(mainPanel); } } // LogonDemoController
package com.jpleasure.gwt.logon.client;
import com.google.gwt.user.client.ui.DeckPanel;
/** * Created by IntelliJ IDEA. * User: ma.zhaodl.cn * Date: 2007-8-27 * Time: 21:58:02 * To change this template use File | Settings | File Templates. */ public class LogonDemoController { private DeckPanel mainPanel; public LogonDemoController(DeckPanel panel) { this.mainPanel panel; } public void gotoWelcome() { if (mainPanel ! null) { mainPanel.showWidget(1); } } public void gotoLogon() { if (mainPanel ! null) { mainPanel.showWidget(0); } } } // LogonServiceImpl
package com.jpleasure.gwt.logon.server.service;
import com.google.gwt.user.server.rpc.RemoteServiceServlet; import com.jpleasure.gwt.logon.client.exception.ApplicationException; import com.jpleasure.gwt.logon.client.service.LogonService; import com.jpleasure.gwt.logon.client.so.LogonSO;
/** * Created by IntelliJ IDEA. * User: ma.zhaodl.cn * Date: 2007-8-27 * Time: 22:13:10 * To change this template use File | Settings | File Templates. */ public class LogonServiceImpl extends RemoteServiceServlet implements LogonService { public boolean logon(LogonSO logonSO) throws ApplicationException { if (logonSO.getName() ! null logonSO.getName().length() 0 logonSO.getPassword() ! null logonSO.getPassword().length() 0 logonSO.getName().equals(logonSO.getPassword())) { return true; } else if (ex.equals(logonSO.getName())) { throw new ApplicationException(Logon Exception!); } else { return false; } } }
//LogonDemo.gwt.xml
module inherits namecom.google.gwt.user.User/ entry-point classcom.jpleasure.gwt.logon.client.LogonDemo/ servlet path/com.jpleasure.gwt.logon.LogonDemo/LogonService classcom.jpleasure.gwt.logon.server.service.LogonServiceImpl/ /module 安全相关
参看http://groups.google.com/group/Google-Web-Toolkit/web/security-for-gwt-applications
在GWT中所有的画面都是由Panel实现的而所有的Panel都会被编译为JavaScript和Html代码这些代码在程序运行的开始就会
下载到客户的浏览器中虽然这些JavaScript代码很难阅读但是毕竟以影下载到了客户的环境中所以在本质上GWT是不安全的。请大家讨论 另外由于JavaScript的灵活性可以动态的在画面上创建链接image等所以数据也有可能别提交到其他的服务器而非下载的服务器。 另外由于PanelAction等最终都编译为了JavaScript所以关于用户权限等信息最好不要放在PanelAction内部。最好能放在server包内部
在客户端对Service的每次调用的开始确认用户的权限。 GWT开发使用的工具
免费 Netbeans gwt4nb 参看http://www.javapassion.com/handsonlabs/ajaxgwtintro/ 优点直接屏蔽了GWT ShellHosted Mode开发的方式可以方便的以普通Java Web 应用程序开发的凡是进行GWT开发。 缺点不支持界面的拖拽编辑同时继承了NB 5.5 的缺点对JSPHTMLJavaScript编辑器支持不足。 Eclipse Cypal Studio for GWT 参看http://www.ibm.com/developerworks/library/os-eclipse-ajaxcypal/index.html 优点可以方便的以普通Java Web 应用程序开发的凡是进行GWT开发。支持两种运行方式GWT Shell运行和Web方式运行。 收费 Ingellij IDEA 6 参看http://www.jetbrains.com/idea/training/demos/GWT.html Eclipse GWT Builder http://www.instantiations.com/gwtdesigner/ 一些技巧/注意事项
PasswordTextBox 不像TextBox那样有长度限制所以在需要限制PasswordTextBox输入长度的时候可以有两种实现方式第一是添加一个KeyboradListener在KeyPressKeyUpKeyDown等事件的时候判断长度然后substring另一种方式是在提交的时候判断让客户自己修改。确实有些不太方便呵呵。 未完待续