(五) 尝试使用gwt-ext项目调用struts action
到这里到重点了,查了很多资料,关于gwt与服务器交互的讨论。Gwt的设计初衷向面向服务靠拢的,大部分交互方式也是面向服务的RPC交互方式。面向服务有面向服务的好处,但是并不是所有的程序都是webservice都是RPC服务器,传统的servlet 或者struts action仍然占据着很多的份额,这里我们主要研究如何使用gwt与传统的struts结合进而与类似的SH或者SSh框架结合。
根据笔者之前bolg资料所了解的交互方式,RPC机制是把服务层实现为具体的servlet。而我们要接触的struts又针对这个有两种交互模式,其中一种就是阿pache出的带struts gwt plugin包的交互方式。这种方式虽然apche极力推荐,但是笔者研究了源码之后仍然不是很希望使用这种方式让gwt语struts交互,因为这完全是拿struts的action当servlet用,没有摆脱RPC的交互方式。于是我选择一种使用第三方语言的方式,使得其编译后生成的js代码能够调用并操作jsp页面中的内容,使得其能够与后台进行交互得更接近传统的jsp与struts action交互的方式。
接下来我就开始讲解我是如何做的。
这里我们需要使用apache推出的一个json的处理包:
http://jsonplugin.googlecode.com/files/jsonplugin-0.32.jar
0.32是针对struts2.0.x的。这个包有一个功能负责把struts1的action序列化成json字符串,当然,这个action在struts2中是一个bean,不过都是一个回事,被几个默认的拦截器拦截后,本质仍然是action。
还有一个包:struts2-dojo-plugin-2.1.6.jar 这个我没有找到固定的地儿下,不过网上到处有。在gwt的nativ函数中,调用dojo的第三方语言,然后提交jsp中的form用到这个包。
准备动作完成了,开始代码:
1、 创建module配置文件:
虽然这里跟ext无关,但是为了显示好看些,还是选择了使用gwt-ext,所以这里继续配置相应的ext配置信息。当然,为了方便和统一化处理,可以让这个module继承test.gwt.xml的信息,免去了很多的问题,提高复用。
<module> <inherits name="com.google.gwt.user.User" /> <inherits name="com.gwtext.GwtExt" /> <inherits name="com.google.gwt.user.theme.standard.Standard" /> <inherits name="com.google.gwt.json.JSON" />
<stylesheet src="../js/ext/resources/css/ext-all.css" /> <script src="../js/ext/adapter/ext/ext-base.js" /> <script src="../js/ext/ext-all.js" /> <inherits name="com.gwtext.GwtExt" /> </module> |
2、 创建显示层java文件:
造java的过程老样子,这个重点说代码:
功能还是老样子,提交画面某个textfield的内容,然后把信息转到struts的action中,经过处理返还回来。
package com.test.ext.client;
import com.google.gwt.core.client.EntryPoint; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONParser; import com.google.gwt.json.client.JSONString; import com.google.gwt.user.client.ResponseTextHandler; import com.google.gwt.user.client.ui.RootPanel; import com.gwtext.client.core.EventObject; import com.gwtext.client.widgets.Button; import com.gwtext.client.widgets.MessageBox; import com.gwtext.client.widgets.Panel; import com.gwtext.client.widgets.Viewport; import com.gwtext.client.widgets.event.ButtonListener; import com.gwtext.client.widgets.event.ButtonListenerAdapter; import com.gwtext.client.widgets.form.TextField;
public class Testgwtstruts implements EntryPoint {
private TextField textField; public void onModuleLoad() { Panel panel = new Panel("test panel title"); panel.setFrame(true); panel.setWidth(200); panel.setHeight(300); textField = new TextField("field"); ButtonListener listener = new ButtonListenerAdapter() { @Override public void onClick(Button button, EventObject e) { callStrutsAction(); } }; Button button = new Button("test button", listener); panel.add(textField); panel.addButton(button);
new Viewport(panel); }
protected void callStrutsAction() { //目标struts action String action = "testgwtstruts.action"; //jsp画面中负责与struts交互的form名称 String form = "testform"; //要传递的action或者bean中的属性名称 String paramName = "username"; //要传递的action或者bean中的属性对应值 String paramValue = textField.getValueAsString(); //在交互的form中,临时创建的变量载体 TextField tempField = new TextField(paramName,paramName); tempField.setValue(paramValue); //把临时创建的载体添加到指定的form中 RootPanel.get(form).add(tempField);
ResponseTextHandler handler = new ResponseTextHandler() { public void onCompletion(String responseText) { JSONObject object = (JSONObject) JSONParser.parse(responseText); JSONString str = (JSONString) object.get("username"); MessageBox.alert(str.toString() + " from the struts action"); } }; asyncPost(action, form, handler);
//提交后把临时载体销毁,取消内存占用 tempField.destroy(); }
private native void asyncPost(String url, String formId, ResponseTextHandler handler) /*-{ dojo = $wnd.dojo; //don't use the dojo.io.bind({...}) shortcut, it doesn't work here var request = new dojo.io.Request(url); request.load = function(type, data, request) { handler.@com.google.gwt.user.client.ResponseTextHandler::onCompletion(Ljava/lang/String;)(data); }; request.formNode = dojo.byId(formId); request.method = "POST"; $wnd.dojo.io.bind(request); }-*/;
} |
这里只是做个实例,其实,很多地方可以做成很好的共同,还有效率的问题。
3、 创建对应的jsp文件:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <%@ page language="java" contentType="text/html; charset=UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <%@ taglib prefix="sx" uri="/struts-dojo-tags"%> <html> <head> <sx:head extraLocales="en-us,nl-nl,de-de" /> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title>Testgwtstruts</title> <script type="text/javascript" language="javascript" src="com.test.ext.testgwtstruts/com.test.ext.testgwtstruts.nocache.js"></script> </head>
<body> <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe> <form id="testform" style="visibility: hidden;" /> </body> </html> |
包的版本号对不上的话,很容易让程序跑不起来。
4、 创建struts action文件:
这里使用的是前一个例子的action,但是,在配置上却稍有变化:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts> <package name="teststruts" extends="struts-default"> <action name="teststruts" class="com.test.struts.StrutsTestAction"> <result name="success">teststrutstarget.jsp</result> </action> </package> <package name="testgwtstruts" extends="json-default"> <action name="testgwtstruts" class="com.test.struts.StrutsTestAction"> <result type="json"/> </action> </package> </struts> |
5、 编好程序开始测试了:
画面如下
到此,基本的ext+gwt+struts的整合算是介绍完毕了。相应的程序和文档已经提交到资源中。其中有很多可以优化和共通的地方,篇幅的原因,笔者没有在这里赘述。程序到了struts这里,就自由多了。可以很轻松的与spring结合,到持久层hibernate,都可以轻松整合,因为,这个方案没有破坏任何ssh框架的整合问题。只是无缝的与struts交互,模仿了jsp页面与struts进行沟通。面对gwt的oop的编程来编写表示层,这无疑是一个革命,以前只有旁客户端或者cs程序才能做到的事情,如今,gwt间接的做到了。同时,还可以美好的使用各种js框架表示显示层。我们何乐而不为呢。当然,局限也是有的,毕竟是加入了gwt,而不是直接操纵js,对于非常熟悉js的程序员,这并不是不可替代的,但是它表面上让我们看到的oop和不编写任何js就可以获得美好画面用户体验的优势,还是值得我们去跟进的。愿gwt-ext更新的速度更快些,愿google更好的作出gwt的新的体验,翘首期盼。
2009.05.31 Jimmybly Lee