GWTExt 体验之旅第 4 部分 体验拖拽和通信Word文档格式.docx
《GWTExt 体验之旅第 4 部分 体验拖拽和通信Word文档格式.docx》由会员分享,可在线阅读,更多相关《GWTExt 体验之旅第 4 部分 体验拖拽和通信Word文档格式.docx(15页珍藏版)》请在冰豆网上搜索。
![GWTExt 体验之旅第 4 部分 体验拖拽和通信Word文档格式.docx](https://file1.bdocx.com/fileroot1/2022-12/7/7cf2a922-3e76-407c-8140-e7910953d7dc/7cf2a922-3e76-407c-8140-e7910953d7dc1.gif)
首先,定义一个Panel,
Paneldraggable=newPanel();
draggable.setTitle("
Draggable"
);
draggable.setBorder(true);
然后,将这个Panel作为参数来构造一个DD类,
DDdd=newDD(draggable);
这样,这个Panel就可以被拖动了。
图2.对象随鼠标移动的Panel
若将draggable这个Panel作为参数来构造DDProxy类,
DDdd=newDDProxy(draggable);
则会出现这样的效果,
图3.边框随鼠标移动的Panel
被移动的是draggablePanel的边框。
接下来,介绍一些被拖动对象可以被放置在其他对象中的功能类。
这些类主要是DDTarget和DragTarget,其中DragTarget继承自DDTarget。
DDTarget类
将元素作为参数传递到DDTarget中,那么这个元素就可以是一个DropTarget。
具体在应用中,我们一般使用DragTarget来完成这样的操作。
首先,用户需要将元素作为一个参数传递到DragTarget类的构造函数中。
除此之外,还要定义一个DropTargetConfig类来配置DragDropGroup的名字。
这里,需要注意的有两点:
第一,只有Drag元素和DropTarget元素具有同样DragDropGroup名字的,Drag元素才能够被拖放到正确的DropTarget元素中去。
方法如下:
1.构造DropTargetConfig类
DropTargetConfigcfg=newDropTargetConfig();
2.指定DragDropGroup名字
cfg.setdDdGroup(java.lang.StringddGroup);
//参数ddGroup指dragdropgroup的名字。
3.调用DropTarget的构造函数来将拖拽元素和DropTargetConfig作为参数传入进去。
DropTargettg=newDropTarget(Comopnentcomponent,DropTargetConfigcfg)
第二,在DragTarget中,还需要实现notifyDrop(DragSourcesource,EventObjecte,DragDatadata)方法以实现拖动后的效果。
其中,source是指可以被拖动到DropTarget上的元素;
e是指当前的事件;
data是指被拖动元素所包含的数据对象。
这里,我们举一个从Tree中拖动TreeNode元素到Grid中的例子来说明上述步骤。
图4.从Tree中拖动TreeNode元素到Grid中
首先,定义TreePanel和GridPanel,并定义DragDropGroup的名字。
finalTreePaneltreePanel=newTreePanel();
treePanel.setEnableDD(true);
treePanel..setEnableDrop(true);
finalGridPanelgridPanel=newGridPanel();
gridPanel.setEnableDragDrop(true);
tripTreePanel.setDdGroup("
myDDGroup"
gridPanel.setDdGroup("
然后,初始化一个DropTargetConfig,并指定同样的DragDropGroup的名字。
DropTargetConfigcfg=newDropTargetConfig();
cfg.setdDdGroup("
//指定了同样的DDGroup
最后,定义DropTarget,以gridPanel和cfg为参数,并覆写notifyDrop函数。
DropTargettg=newDropTarget(gridPanel,cfg){
publicbooleannotifyDrop(DragSourcesource,EventObjecte,DragDatadata){
//……
}
};
在notifyDrop函数中,可以实现从当前Tree中删除选中节点和在Grid中增加记录的操作。
回页首
通信
GWT-EXT是GWT在界面功能上的扩展,但在通信方面,使用的仍然是GWT所提供的通信框架。
作为AJAX的应用开发包,GWT使得实现客户端和服务器的通信变得十分简单,特别是异步通信。
在本文中,我们首先介绍GWT中用来开发异步通信应用的流程,然后介绍一个异步通信的例子。
除此之外,对于同步通信,由于GWT没有提供特别的支持,但有时我们仍需以同步的方式与Server端交互,所以,我们提供了一种变通的方法,即通过Form提交Action的方式实现此效果,并通过一个文件下载的例子来讲述。
在GWT框架下实现异步通信
在GWT中,异步通信方面的开发变得非常简单。
用户只需在服务器端定义一个Service接口及其实现,在客户端声明这样的接口,之后的事情,例如管道管理和数据的传输、转换等复杂的事情将由GWT负责。
具体的过程,有以下几个步骤。
1.在客户端定义服务接口。
服务,就像是客户端与服务器所签署的一份合约,客户端首先要定义这样的服务规则,也就是一个接口。
具体实现时,此接口要继承自RemoteService并保存在客户端。
PublicinterfaceMyServiceextendsRemoteService{
PublicListmyRequestToServer(intrequestParameters);
}
值得一提的是,GWT中的RPC机制提供了通过HTTP协议在客户端和服务器端传送java对象的方法并加以封装。
对于用户来说,只要使用GWT所能够支持的数据类型或对象作为参数和返回值就可以了。
2.在客户端定义此服务的异步接口。
为了应用AJAX(被GWT所支持)所带来的异步特性,在客户端我们还需要定义一个此接口的异步接口。
方法也很简单。
PublicinterfaceMyServiceAsyncextendsRemoteService{
PublicvoidmyRequestToServer(intrequestParameters,AsyncCallbackcallback);
可以看出,除了多了一个AsyncCallback对象作为参数,此异步接口与同步接口的方法大致相同。
此外,该方法的返回值被定义成void,原因是在GWT的异步通信机制中,客户端发送的异步请求信息和服务器端对此请求的回应信息(包括成功或失败)都会通过这个AsyncCallback对象来传递。
换句话说,这个对象将客户端与服务器端绑定了起来,返回值在这里没有什么作用。
除此之外,此异步接口的命名规则是在原接口名字的后面加上Async后缀,并放置在客户端的同一个包下面。
3.实现这个接口。
大家知道,所有的服务端接受到Service后都要执行一定的操作来响应客户端的请求。
这里,所有的RPC服务都要扩展自RemoteServiceServlet并实现相应的Service接口。
需要注意的是,它并不需要实现此Service的异步接口。
PublicMyServiceImplextendsRemoteServiceServletimplementsMyService{
PublicListmyRequestToService(intrequestParameters){
….//实现的功能代码
其中,RemoteServiceServlet类用于处理客户端请求的反序列化和相应的序列化以及调用接口中定义的方法。
GWT之所以采用这种基于Servlet的处理方式,是因为JavaServlet相对简单且广泛流行于JavaCommunity。
这样,我们所定义的服务及实现就可以轻易的重新部署到其它产品的Servlet容器中。
4.在客户端触发服务。
在GWT框架下调用Service总是经过相同的步骤:
∙使用GWT.create()初始化Service接口;
∙使用ServiceDefTarget为Service代理描述Service接入点的URL;
∙创建一个异步回调对象,用于RPC完成时调用;
∙发出RPC请求。
5.将此服务作为一个EntryPoint加入到应用程序的配置文件module.xml中,以便客户端能够找到此服务。
<
Servletpath=”/myService”class=”examples.server.MyServiceImpl”/>
以上五步是在GWT框架下开发异步通信应用的流程。
而在实际开发中,我们可以利用一些Eclipse的插件帮助我们快速地完成此过程的搭建。
接下来,将介绍一个异步通信的例子并用Eclipse下的GWT插件CypalStudio来完成创建的过程。
这是一个简单的做两位数加法的例子。
用户在输入框中输入两个整型数后,不必刷新整个页面,Server端就会返回结果。
图5.做两位数加法的例子
为了完成这个例子,首先在一个Panel中创建两个TextField和两个Label。
TextFieldtextField1=newTextField();
LabeladdLabel=newLabel(“+”);
TextFieldtextField2=newTextField();
LabelequalLabe2=newLabel(“=”);
然后,通过CypalStudio插件来创建计算两个数加法的服务。
CypalStudio是GWT在Eclipse中的一个插件,它可用于简化在GWT开发过程中执行的许多常见任务。
在安装CypalStudio插件之前,您需要配有WebToolsPlatform(WTP)插件的Eclipse版本。
WTP是支持Web应用开发的精选工具集,它包括各种标准的Web编辑器,比如HTML和层叠样式表(CascadingStyleSheet,CSS)、JavaServerPage(JSP)编辑器,支持创建和维护Web应用程序中使用的数据库,以及开发过程中在Web服务器上运行应用程序。
因此,CypalStudioForGWT插件需要WTP才能运行。
这里,对如何安装WTP和CypalStudioForGWT插件不介绍,用户可以参考以前的系列文章。
在安装CypalStudioForGWT插件后,可以在Eclipse的Window->
Preferences中找到它。
图6.CypalStudioForGWT配置选项
在CypalStudio配置窗口中,可以配置GWT的Home路径以及GWT编译后的OutPut路径。
现在,我们就应用CypalStudio插件来创建我们服务。
首先,点击Eclipse的File->
New->
Other…菜单,选择GWTRemoteService,如图7所示。
图7.选择向导的类型
然后,依次指定应用程序的配置文件路径,服务的名字,此服务的链接地址(ServiceURL)。
图8.指定配置文件路径,服务的名字和链接地址
设置好之后,点击Finish。
你会发现此插件为我们自动加入了CalcuService.java,CalcuServiceAsync.java,CalcuServiceImpl.java,
图9.CalcuService.java,CalcuServiceAsync.java,CalcuServiceImpl.java已加入工作空间
以及此服务的配置信息。
图10.服务配置信息
而我们所需要做的就是在CalcuService接口中定义方法以及在CalcuServiceImpl中实现此方法,如代码所示:
清单1.定义和实现getAddResult方法
publicinterfaceCalcuServiceextendsRemoteService{
StringgetAddResult(Stringstr1,Stringstr2);
publicclassCalcuServiceImplextendsRemoteServiceServletimplementsCalcuService{
publicStringgetAddResult(Stringstr1,Stringstr2){
//TODOAuto-generatedmethodstub
intresult=newInteger(str1).intValue()+newInteger(str2).intValue();
returnresult+"
"
;
另外,CypalStudioForGWT插件会自动监控接口中方法的变化。
比如,我们在CalcuService中添加一个getAddResult(StringStr1,StringStr2)方法后,它会自动帮助我们在CalcuServiceAsync异步接口中添加这个方法。
publicinterfaceCalcuServiceAsync{
voidgetAddResult(Stringstr1,Stringstr2,AsyncCallback<
String>
callback);
在定义好接口和实现后,接下来要做的就是定义触发此服务的方法。
示例中,一旦我们分别在两个输入框中输入整型数后,就会异步地向服务端发送请求。
因此,需要为这两个输入框定义监听事件。
这里,我们定义一个内隐类并继承自FieldListenerAdapter类,然后覆写onBlur方法使得一旦输入框失去焦点时触发此事件。
在onBlur方法中实现调用此服务的过程。
清单2.DemoFieldListenerAdapter类
classDemoFieldListenerAdapterextendsFieldListenerAdapter{
publicvoidonBlur(Fieldfield){
CalculateServiceAsyncservice=CalculateService.Util.getInstance();
service.getAddResult(textField1.getValueAsString(),
textField2.getValueAsString(),
newAsyncCallback(){//声明一个//AsyncCallBack实例
//覆写onFailure方法
publicvoidonFailure(Throwablecaught){
caught.printStackTrace();
System.out.println("
Communicationfailed"
//覆写onSuccess方法。
publicvoidonSuccess(Objectresult){
StringaddResult=(String)result;
resultLabel.setText(addResult);
);
需要说明的是,CypalStudioForGWT插件在生成CalculateService时为我们将初始化CalculateServiceAsync实例的过程封装在一个静态内隐类中。
清单3.初始化CalculateServiceAsync实例
publicstaticclassUtil{
publicstaticCalcuServiceAsyncgetInstance(){
CalcuServiceAsyncinstance=(CalcuServiceAsync)GWT.create(CalcuService.class);
ServiceDefTargettarget=(ServiceDefTarget)instance;
target.setServiceEntryPoint(GWT.getModuleBaseURL()+SERVICE_URI);
returninstance;
这样,我们每次调用时只需通过CalculateService.Util.getInstance()方法即可获得CalcuServiceAsync的实例。
获得CalcuServiceAsync实例后,即可调用服务接口。
这里的参数有三个,第一个是textField1的输入值,第二个是textField2的输入值,第三个是AsyncCallback对象。
AsyncCallback对象采用匿名内隐类来创建并覆写onFailure和onSuccess方法。
这两个方法会在服务器端执行完服务过程后在客户端执行。
如果服务器端有错误发生,则onFailure方法被执行;
如果没有错误,则onSuccess方法被执行。
例子中,在onSuccess方法里将成功返回的结果放在ResultLabel中显示。
在GWT框架下实现同步通信
在GWT框架中,其所提供的通信方式,包括HttpRequest,RequestBuilder,RPC等都是异步的,要实现同步的通信,可以利用Form中提交Action的方式。
即通过HTML中的Document所得到的FormElement来构建指向服务器端的一个链接(URL)。
然后,向Server端提交此Form。
这样,客户端会一直等待服务器端对此请求的相应。
代码如下,
清单4.Form中提交Action
Stringurl=”/”;
FormElementformElement=Document.get().createFormElement();
formElement.setAction(url);
formElement.setName("
ThisActionName"
formElement.setMethod("
post"
Document.get().appendChild(formElement);
formElement.submit();
此URL是一个指向服务器端的资源路径,我们首先在Form中设定资源路径然后提交给服务器端。
这与编写HTML很相似,只是这里我们用java代码的形式写出来。
另外,此URL也可以指定到服务器中的Servlet。
这样,可以完成更复杂的应用逻辑。
本例所讲的是一个在GWT下应用同步通信的方式完成一个文件下载的例子。
首先,要在客户端的一个触发事件中完成如上述请求服务的代码。
清单5.完成请求服务的代码
//这里指向一个专门负责下载文件的Servlet:
//DemoServiceConstants.DOWNLOAD_TASK_FILE
StringURL=GWT.getModuleBaseURL()+DemoServiceConstants.DOWNLOAD_TASK_FILE+
"
?
fileLocation="
+fileLocation;
其次,要在服务器端定义一个DownloadFileServlet用于响应客户端的请求以及完成从服务器上读取文件和发送文件的InputStream和OutputStream。
清单6.DownloadFileServlet