Struts2中使用JSON做數據的get/post,方法有很多種,這里有一篇文章比較詳細的列舉出了JSON在Struts和Servlet中如何GET:
http://yshjava.iteye.com/blog/1333104
Servlet的不寫了,也就是how to use HttpRequest和HttpResponse。主要是在Struts2身上。
以文章所描述的方法似乎總是差了那么點東西:可以不使用那么多配置嗎?
於是研究了些時間,可以這么玩:
1)Eclipse引用Struts2的JSON plug-in和Convertion plug-in。
2)struts.xml這么寫:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <!-- 把它設置為開發模式,發布時要設置為false --> <constant name="struts.devMode" value="true" /> <!-- 設置在class被修改時是否熱加載,發布時要設置為false --> <constant name="struts.convention.classes.reload" value="true"/> <!-- 自動動態方法的調用,使用這個設置后可以這樣調用:action!method --> <constant name="struts.enable.DynamicMethodInvocation" value="true" /> <!-- 指定jsp文件所在的目錄地址 --> <constant name="struts.convention.result.path" value="/WEB-INF/content/" /> <!-- 用於配置包名后綴。默認為action、actions、struts--> <!-- <constant name="struts.convention.package.locators" value="controller" /> --> <constant name="struts.convention.action.packages" value="com.my.controller"></constant> <!-- 用於配置類名后綴,默認為Action,設置后,Struts2只會去找這種后綴名的類做映射 --> <constant name="struts.convention.action.suffix" value="Controller"/> <!-- 設置即使沒有@Action注釋,依然創建Action映射。默認值是false。因為Convention-Plugin是約定優於配置的風格, 可以不通過注解根據預先的定義就能訪問相應Action中的方法 --> <constant name="struts.convention.action.mapAllMatches" value="true"/> <!-- 自定義jsp文件命名的分隔符 --> <constant name="struts.convention.action.name.separator" value="-" /> <!-- 國際化資源文件名稱 --> <constant name="struts.custom.i18n.resources" value="i18n" /> <!-- 是否自動加載國際化資源文件 --> <constant name="struts.i18n.reload" value="true" /> <!-- 瀏覽器是否緩存靜態內容 --> <constant name="struts.serve.static.browserCache" value="false" /> <!-- 上傳文件大小限制設置 --> <constant name="struts.multipart.maxSize" value="-1" /> <!-- 主題,將值設置為simple,即不使用UI模板。這將不會生成額外的html標簽 --> <constant name="struts.ui.theme" value="simple" /> <!-- 編碼格式 --> <constant name="struts.i18n.encoding" value="UTF-8" /> <!-- 設置默認package --> <constant name="struts.convention.default.parent.package" value="default"></constant> <package name="default" namespace="/" extends="json-default"> <interceptors> <interceptor name="cacheInterceptor" class="com.my.interceptor.CacheInterceptor" /> <interceptor-stack name="cacheStack"> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="paramsPrepareParamsStack"></interceptor-ref> <interceptor-ref name="cacheInterceptor"></interceptor-ref> </interceptor-stack> </interceptors> <default-interceptor-ref name="cacheStack"></default-interceptor-ref> <default-action-ref name="index" /> <global-results> <!-- <result name="error">/error.jsp</result> --> <result name="json" type="json"> <!-- 是否包括父類的屬性輸出,默認true. --> <!-- <param name="ignoreHierarchy">false</param> --> <!-- 是否輸出null值的屬性,默認false --> <!-- <param name="excludeNullProperties">true</param> --> </result> </global-results> <global-exception-mappings> <exception-mapping exception="java.lang.Exception" result="error"/> </global-exception-mappings> </package> </struts>
上面有兩個<param/>注釋了,使用方法已經有寫在里頭,如果需要,可以加上或在類中加入@Results。
關鍵點在於把<package />中的 extends設置為json-default,以及在global-results中的這個json result。
3)加入一個UserControl.java
package com.my.controller; import java.io.IOException; import java.util.ArrayList; import java.util.List; import net.sf.json.JSONObject; import com.my.beans.User; import com.opensymphony.xwork2.ActionSupport; @SuppressWarnings("serial") public class UserController extends ActionSupport { private User user = new User(); public User getUser() { return user; } public void setUser(User user) { this.user = user; } private String json; public String getJson() { return json; } public void setJson(String json) { this.json = json; } private List<User> users = new ArrayList<User>(); public List<User> getUsers() { return users; } public void setUsers(List<User> users) { this.users = users; } @Override public String execute() throws Exception { return SUCCESS; } public String loadModel() throws IOException { System.out.println("json=" + getJson()); System.out.println("user=" + getUser().getUsername()); System.out.println("users=" + getUsers().size()); User userBean = new User(); userBean.setUsername("robin"); users.add(userBean); this.setJson(JSONObject.fromObject(userBean).toString()); return "json"; } }
這里沒有什么特別的東西,就是一些getter/setter,以及一個loadModel() action
4)JS對JSON的提交:
var url = "user!loadModel"; var params = { "json": "json string", "user.username" : "zhang", "users[0].username" : "zhang1", "users[0].password" : "1", "users[1].username" : "zhang2", "users[1].password" : "2", }; $.post(url, params, function callback(data) { console.log(data) });
這里是重點。
可以看到這段JS里的params有:json/user.username/users[X].username
其中:
a) json
對應的就是上頁java中的getJson/setJson,這個東東列出來是可以用於在頁面與服務器之間傳遞JSON字符串用的。如果你需要在action中輸出或提交json的字符串,它有很大作用,直接到位。但是缺點是要自己去將對象轉化為json string以及json string轉化為對象。
b) user.username
這樣的寫法可以在后台java中直接轉化成了對象。user.username中的user就是java中的user object。
c) users[0].username
這可以直接轉化成后台java中的List<user>對象users。
可以看出,Struts2是可以完成將json直接轉化成java object的。不過這樣的寫法,不是好的。因為這個JS的JSON只能稱作是一個字符串拼接,不是一個JSON object
還有一種方法,使用ModelDriven:
package com.my.controller; import com.my.beans.User; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; @SuppressWarnings("serial") public class UserModelController extends ActionSupport implements ModelDriven<Object> { private User user = new User(); @Override public Object getModel() { return user; } @Override public String execute() throws Exception { return SUCCESS; } public String load() { return "json"; } }
使用ModelDriven,可以JS直接提交JSON了:
var url = "user-model!load"; var params = { "username": "zhang1", "password": "123456" }; $.post(url, params, function callback(data) { console.log(data) });
這個params才是真正的JSON object,它會被ModelDriven直接轉成user model。
但是:它似乎不能提交List object。至今寫文時也沒有找到在ModelDriven中可以提交JSON array to List的方法。
如果需要提交復雜的JSON到服務器,如果你用的是Struts,使用第一種方法的json的getter/setter吧。
個人Struts2研究了些日子對它的總結:
1)如果是使用MVC開發的,它是個非常好的選擇。因為它提供了非常豐富的可配置的功能及標簽。但是也正是因為這些復雜的配置,會使用得開發及維護上帶來很多詬病,比如速度上、發布上、后期清理上的問題。既然MVC的理想是約定優於配置,那為什么還需要這么復雜的配置呢?
2)它的Action在URL上的表現上讓人看着不舒服,因為太不restful了,同時它的restful plug-in似乎沒太多的可擴展性。說白了,如果要做rest,理應不選擇它。
3)struts它合適於使用普通的form提交開發當中(即MVC)。不合適於MVVM模式的開發。如果想使用MVVM,那么建議使用SpringMVC,而不是Struts。
沉思:
如果MVVM是未來的主流設計,那么struts將會有天淡去在這個舞台。