GWT+EXT探索五之交互模式——Struts2(gwt调用dojo native函数提交form)
2009-06-04 10:34
447 查看
虽然,apache极力推荐使用它所带的一个插件,然后使用之前介绍过的那种方式来使用gwt与struts的交互。然而,我更推崇眼前这个方式,因为它可以无缝与struts结合,是现有struts项目重构表示层的最佳选择。而且,从原理上,它更接近于传统的struts提交反馈方式。接下来一篇文章,我将集中介绍,如何使用这个技术,结合现有ssh框架与gwt和ext框架
Struts without gwt plugin
Write your action.
Example action:
"Hello.java"
package example;
import com.opensymphony.xwork2.Action;
public class Hello {
private String firstName;
private String lastName;
public String execute() {
return Action.SUCCESS;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Write the mapping for your action.
In this example the mapping is in struts.xml:
struts.xml
<?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="example" extends="json-default">
<action name="Hello" class="example.Hello">
<result type="json" />
</action>
<action name="Main" class="com.opensymphony.xwork2.ActionSupport">
<result>org.apache.struts.gwt.Main/Main.jsp</result>
</action>
</package>
</struts>
The "Hello" action has a result of type "json", which will serialize the action object into a JSON string. If "firstName" is set to "John" and "lastName" is set to "Galt", the output of the "Hello" action will be:
{
"firstName" : "John",
"lastName" : "Galt"
}
The "Main" action points to the "Main.jsp" page which is the page that uses GWT. The path of the result is "org.apache.struts.gwt.Main/Main.jsp". That means that the files generated by GWT must go under a folder named "org.apache.struts.gwt.Main" under the root of your application. See "Deployment structure" for more details.
Write "Main.jsp" page.
This is the page that is generated by GWT's "applicationCreator". It has been renamed to .jsp because we have modified it to be a jsp page, instead of a plain html page.
Main.jsp
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<s:head theme="ajax" debug="true"/>
<meta name='gwt:module' content='org.apache.struts.gwt.Main/org.apache.struts.gwt.Main'>
</head>
<body>
<script language="javascript" src="${pageContext.request.contextPath}/org.apache.struts.gwt.Main/gwt.js"/>
<form id="form1">
<input type="text" name="firstName">
<br/>
<input type="text" name="lastName">
<span id="slot1"></span>
</form>
<br/>
<span id="slot2"></span>
</body>
</html>
We set head's tag attribute "theme" to ajax to use Dojo, don't panic, you won't have to use it directly. Note that we have changed a few things from the original html page generated by GWT, we set "content" to "org.apache.struts.gwt.Main/org.apache.struts.gwt.Main" because the GWT generated files will be under "AppRoot/org.apache.struts.gwt.Main" instead of beneath root, and we set "src" to "${pageContext.request.contextPath}/org.apache.struts.gwt.Main/gwt.js" for the same reason. Without these two changes the GWT files wouldn't be loaded.
Struts2GWTHelper
This class will take care of making the request. Why? Why do I need this class? Couple of reasons, first, there is a bug on HTTPRequest.asyncPost which doesn't encode the payload properly, second, if you want to submit a form, you have to encode it yourself, and this class will help you do that. Optionally you can download a jar containing this class (with more methods) from here , and add this to your GWT application file (i.e Main.gwt.xml):
<inherits name='struts2gwt.Struts2GWT'/>
and add the jar to the classpath in your compile script (i.e Main-compile.cmd) and the compile script (i.e Main-shell.cmd).
Struts2GWTHelper .java
package org.apache.struts.gwt.client;
import com.google.gwt.user.client.ResponseTextHandler;
public class Struts2GWTHelper {
/**
* Make asynchronous post
* @param url Action url
* @param formId id of form that will be posted
* @param handler callback function
*/
public static 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);
}-*/;
/**
* Make asynchronous post
* @param url Action url
* @param handler callback function
*/
public static void asyncPost(String url, ResponseTextHandler handler) {
Struts2GWTHelper.asyncPost(url, handler);
}
}
See? It wasn't that bad.
Write your GWT entry point
Main.java
package org.apache.struts.gwt.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.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class Main implements EntryPoint {
final Label label = new Label();
/**
* This is the entry point method.
*/
public void onModuleLoad() {
final Button button = new Button("Click me");
button.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
makeRequest();
}
});
RootPanel.get("slot1").add(button);
RootPanel.get("slot2").add(label);
}
private void makeRequest() {
Struts2GWTHelper.asyncPost("Hello.action", "form1", new ResponseTextHandler() {
public void onCompletion(String responseText) {
JSONObject obj = (JSONObject)JSONParser.parse(responseText);
JSONString firstName = (JSONString)obj.get("firstName");
JSONString lastName = (JSONString)obj.get("lastName");
label.setText("Welcome " + firstName.stringValue() + " " + lastName.stringValue());
}
});
}
}
The makeRequest() method will make a request to the "Hello" action that we created before, and will pass the fields of the form "form1" as parameters. Which will be populated on the action, and serialized back as JSON. Using JSONParser the JSON string is parsed into a JSON object. It is definitely not type safe as GWT Remoting, but it works.
Create Main.gwt.xml
Nothing new on this file, just as reference:
Main.gwt.xml
<module>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User'/>
<inherits name='com.google.gwt.json.JSON'/>
<!-- Specify the app entry point class. -->
<entry-point class='org.apache.struts.gwt.client.Main'/>
</module>
Struts without gwt plugin
Write your action.
Example action:
"Hello.java"
package example;
import com.opensymphony.xwork2.Action;
public class Hello {
private String firstName;
private String lastName;
public String execute() {
return Action.SUCCESS;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Write the mapping for your action.
In this example the mapping is in struts.xml:
struts.xml
<?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="example" extends="json-default">
<action name="Hello" class="example.Hello">
<result type="json" />
</action>
<action name="Main" class="com.opensymphony.xwork2.ActionSupport">
<result>org.apache.struts.gwt.Main/Main.jsp</result>
</action>
</package>
</struts>
The "Hello" action has a result of type "json", which will serialize the action object into a JSON string. If "firstName" is set to "John" and "lastName" is set to "Galt", the output of the "Hello" action will be:
{
"firstName" : "John",
"lastName" : "Galt"
}
The "Main" action points to the "Main.jsp" page which is the page that uses GWT. The path of the result is "org.apache.struts.gwt.Main/Main.jsp". That means that the files generated by GWT must go under a folder named "org.apache.struts.gwt.Main" under the root of your application. See "Deployment structure" for more details.
Write "Main.jsp" page.
This is the page that is generated by GWT's "applicationCreator". It has been renamed to .jsp because we have modified it to be a jsp page, instead of a plain html page.
Main.jsp
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<s:head theme="ajax" debug="true"/>
<meta name='gwt:module' content='org.apache.struts.gwt.Main/org.apache.struts.gwt.Main'>
</head>
<body>
<script language="javascript" src="${pageContext.request.contextPath}/org.apache.struts.gwt.Main/gwt.js"/>
<form id="form1">
<input type="text" name="firstName">
<br/>
<input type="text" name="lastName">
<span id="slot1"></span>
</form>
<br/>
<span id="slot2"></span>
</body>
</html>
We set head's tag attribute "theme" to ajax to use Dojo, don't panic, you won't have to use it directly. Note that we have changed a few things from the original html page generated by GWT, we set "content" to "org.apache.struts.gwt.Main/org.apache.struts.gwt.Main" because the GWT generated files will be under "AppRoot/org.apache.struts.gwt.Main" instead of beneath root, and we set "src" to "${pageContext.request.contextPath}/org.apache.struts.gwt.Main/gwt.js" for the same reason. Without these two changes the GWT files wouldn't be loaded.
Struts2GWTHelper
This class will take care of making the request. Why? Why do I need this class? Couple of reasons, first, there is a bug on HTTPRequest.asyncPost which doesn't encode the payload properly, second, if you want to submit a form, you have to encode it yourself, and this class will help you do that. Optionally you can download a jar containing this class (with more methods) from here , and add this to your GWT application file (i.e Main.gwt.xml):
<inherits name='struts2gwt.Struts2GWT'/>
and add the jar to the classpath in your compile script (i.e Main-compile.cmd) and the compile script (i.e Main-shell.cmd).
Struts2GWTHelper .java
package org.apache.struts.gwt.client;
import com.google.gwt.user.client.ResponseTextHandler;
public class Struts2GWTHelper {
/**
* Make asynchronous post
* @param url Action url
* @param formId id of form that will be posted
* @param handler callback function
*/
public static 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);
}-*/;
/**
* Make asynchronous post
* @param url Action url
* @param handler callback function
*/
public static void asyncPost(String url, ResponseTextHandler handler) {
Struts2GWTHelper.asyncPost(url, handler);
}
}
See? It wasn't that bad.
Write your GWT entry point
Main.java
package org.apache.struts.gwt.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.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class Main implements EntryPoint {
final Label label = new Label();
/**
* This is the entry point method.
*/
public void onModuleLoad() {
final Button button = new Button("Click me");
button.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
makeRequest();
}
});
RootPanel.get("slot1").add(button);
RootPanel.get("slot2").add(label);
}
private void makeRequest() {
Struts2GWTHelper.asyncPost("Hello.action", "form1", new ResponseTextHandler() {
public void onCompletion(String responseText) {
JSONObject obj = (JSONObject)JSONParser.parse(responseText);
JSONString firstName = (JSONString)obj.get("firstName");
JSONString lastName = (JSONString)obj.get("lastName");
label.setText("Welcome " + firstName.stringValue() + " " + lastName.stringValue());
}
});
}
}
The makeRequest() method will make a request to the "Hello" action that we created before, and will pass the fields of the form "form1" as parameters. Which will be populated on the action, and serialized back as JSON. Using JSONParser the JSON string is parsed into a JSON object. It is definitely not type safe as GWT Remoting, but it works.
Create Main.gwt.xml
Nothing new on this file, just as reference:
Main.gwt.xml
<module>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User'/>
<inherits name='com.google.gwt.json.JSON'/>
<!-- Specify the app entry point class. -->
<entry-point class='org.apache.struts.gwt.client.Main'/>
</module>
相关文章推荐
- GWT+EXT探索三之交互模式——RPC
- GWT+EXT探索四之交互模式——Struts(仿servlet RPC)
- struts2 + ajax(由前台的form提交数据到后台,再根据form所调用返回获取的后台json格式的数据返回到前端,然后前端用jquery对json数据进行解析)==》》涉及非文件上传的部分
- struts2 + ajax(由前台的form提交数据到后台,再根据form所调用返回获取的后台json格式的数据返回到前端,然后前端用jquery对json数据进行解析)==》》涉及文件上传的部分
- cos与EXT调用AJAX提交上传文件
- GWT+EXT探索六之项目实践2——GWTEXT+Struts2.0工程
- Extjs Ajax 提交方式 Form.doAction('submit',...)和 Ext.Ajax.request的返回值
- Ext调用Struts2执行某个Action时,Action对异常未进行捕获,Ext再请求这个Action的其他方法时也报同样的异常
- struts2总结四:Action与Form表单的交互
- 【转】解决Ext.form.ComboBox提交始终获得displayField的值
- struts2——学习笔记2 通过form表单方式或者js的方式提交请求,封装boolean值的问题
- Extjs form.submit()提交与Ext.Ajax.request的区别
- jQuery纯手写前台,动态分页,调用ajax,与后台struts2动态交互!
- struts2中form提交到action中的中文参数乱码问题解决办法(包括取中文路径)
- GWT+EXT探索六之项目实践3——GWTEXT+Struts2.0工程
- ExtJS的Ajax提交(Ext.Ajax.request或form1.getForm().submit)超时设置timeout
- Ext.form.ComboBox提交始终获得displayField的值-解决
- ext的form提交
- Jquery调用Asp.Net WebService和form 提交到Handler方式
- ExtJS的Ajax提交(Ext.Ajax.request或form1.getForm().submit)超时设置timeo...