下載地址: http://code.google.com/p/jsonplugin/downloads/list
Apache提供的一個插件包,可以把Action中的數據以JSON做個封裝然后返回。
它會將整個action中的變量轉化為JSON數據(根對象在JSON中數據添加一個”root”標識)。如果要使用它,Action必須遵循以下幾點:
1. 返回的頁面類型中”content-type”必須是”application/json”.(這個已經Internet Community采用).
2. JSON內容必須是符合格式要求的.
3. Action中field必須有public的set方法.(是不是沒有set方法就不會將field添加到JSON數據中,有待驗證).
4. 它支持的類型有: 基本類型(int,long...String), Date, List, Map, Primitive Arrays, 其它class, 對象數組.
5. 在JSON中任何的Object會被封裝在list或map中,數據會被封裝程Long,如果是含有的數據則會被封裝程Double,數組會被封裝程List.
下面給出JSON的數據格式:
{
"doubleValue": 10.10,
"nestedBean": {
"name": "Mr Bean"
},
"list": ["A", 10, 20.20, {
"firstName": "El Zorro"
}],
"array": [10, 20]
}
說明:
a. 這個插件支持以下幾個注釋:
注釋名
|
簡介
|
默認值
|
序列化
|
反序列化
|
name
|
配置JSON中name
|
empty
|
yes
|
no
|
serialize
|
在serialization中
|
true
|
yes
|
no
|
deserialize
|
在deserialization中
|
true
|
no
|
yes
|
format
|
格式化Date字段
|
"yyyy-MM-dd'T'HH:mm:ss"
|
yes
|
yes
|
可以通過配置來顯示指出要放在JSON中field,其中有個自己的驗證規則需要研究.
<!-- Result fragment -->
<result type="json">
<param name="excludeProperties">
login.password,
studentList.*".sin
</param>
</result>
<!-- Interceptor fragment -->
<interceptor-ref name="json">
<param name="enableSMD">true</param>
<param name="excludeProperties">
login.password,
studentList.*".sin
</param>
</interceptor-ref>
b. 根對象
<result type="json">
<param name="root">
person.job
</param>
</result>
也可以使用攔截器配置操作父對象
<interceptor-ref name="json">
<param name="root">bean1.bean2</param>
</interceptor-ref>
c. 將JSON數據用注釋封裝
如果wrapWithComments設置為true(默認值為false),則生成的JSON數據會變成這樣:
/* {
"doubleVal": 10.10,
"nestedBean": {
"name": "Mr Bean"
},
"list": ["A", 10, 20.20, {
"firstName": "El Zorro"
}],
"array": [10, 20]
} */
這樣做可以避免js中一些潛在的風險,使用時需要:
Var responseObject = eval("("+data.substring(data.indexOf(""/"*")+2, data.lastIndexOf(""*"/"))+")");
d. 父類
“root”對象中父類的field不會默認存放到JSON數據中,如果不想這樣做,需要在配置時指定ignoreHierarchy為false:
<result type="json">
<param name="ignoreHierarchy">false</param>
</result>
e. 枚舉類型
默認處理枚舉類型時,會被處理成JSON數據中name等于枚舉中value而value等于枚舉中name.
public enum AnEnum {
ValueA,
ValueB
}
JSON: "myEnum":"ValueA"
如果在處理枚舉類型時,在xml中配置了enumAsBean,則會被當作一個Bean處理,在JSON數據中會有一個特別的屬性”_name”值為name().這個枚舉中的所有屬性都會被處理.
public enum AnEnum {
ValueA("A"),
ValueB("B");
private String val;
public AnEnum(val) {
this.val = val;
}
public getVal() {
return val;
}
}
JSON: myEnum: { "_name": "ValueA", "val": "A" }
Xml中配置:
<result type="json">
<param name="enumAsBean">true</param>
</result>
f. 例子
a) Action
import java.util.HashMap;
import java.util.Map;
import com.opensymphony.xwork2.Action;
public class JSONExample {
private String field1 = "str";
private int[] ints = {10, 20};
private Map map = new HashMap();
private String customName = "custom";
//'transient' fields are not serialized
private transient String field2;
//fields without getter method are not serialized
private String field3;
public String execute() {
map.put("John", "Galt");
return Action.SUCCESS;
}
public String getField1() {
return field1;
}
public void setField1(String field1) {
this.field1 = field1;
}
public int[] getInts() {
return ints;
}
public void setInts(int[] ints) {
this.ints = ints;
}
public Map getMap() {
return map;
}
public void setMap(Map map) {
this.map = map;
}
@JSON(name="newName")
public String getCustomName() {
return this.customName;
}
}
b) 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="JSONExample" class="example.JSONExample">
<result type="json"/>
</action>
</package>
</struts>
這里有兩個地方需要注意:
1) 需要繼承json-default包
2) <result>簽的定義
c) JSON數據
{
"field1" : "str",
"ints": [10, 20],
"map": {
"John":"Galt"
},
"newName": "custom"
}
d) JSON RPC
JSON插件可以在js中調用action方法,返回執行結果。這個已經在dojo中有了實現,可以用Simple Method Definition調用遠程服務。來一起看看下面的例子:
首先寫一個Action:
package smd;
import com.googlecode.jsonplugin.annotations.SMDMethod;
import com.opensymphony.xwork2.Action;
public class SMDAction {
public String smd() {
return Action.SUCCESS;
}
@SMDMethod
public Bean doSomething(Bean bean, int quantity) {
bean.setPrice(quantity * 10);
return bean;
}
}
e) 方法必須用SMDMethod加上注解,這樣才能被遠程調用,為了安全因素。這個方法會產生一個bean對象,實現修改價格的功能。Action被添加上SMD注解會生成一個SMD,同時參數也會被加上SMDMethodParameter注解。像你所看到的,Action中定義了一個空方法:smd。這個方法是作為Simple Method Definition (定義class中提供的服務),在struts.xml配置<result>時使用type屬性值為”json”。
下面是bean的定義:
package smd;
public class Bean {
private String type;
private int price;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
Xml文件:
<package name="RPC" namespace="/nodecorate" extends="json-default">
<action name="SMDAction" class="smd.SMDAction" method="smd">
<interceptor-ref name="json">
<param name="enableSMD">true</param>
</interceptor-ref>
<result type="json">
<param name="enableSMD">true</param>
</result>
</action>
</package>
這里需要注意一點:” enableSMD”這個必須在interceptor和result都要配置.
Js代碼:
<s:url id="smdUrl" namespace="/nodecorate" action="SMDAction" />
<script type="text/javascript">
//load dojo RPC
dojo.require("dojo.rpc.*");
//create service object(proxy) using SMD (generated by the json result)
var service = new dojo.rpc.JsonService("${smdUrl}");
//function called when remote method returns
var callback = function(bean) {
alert("Price for " + bean.name + " is " + bean.price);
};
//parameter
var bean = {name: "Mocca"};
//execute remote method
var defered = service.doSomething(bean, 5);
//attach callback to defered object
defered.addCallback(callback);
</script>
JsonService會發出一個請求到action加載SMD,同時遠程方法會返回一個JSON對象,這個過程是Dojo給action中的方法創建了一個Proxy。因為這是異步調用過程,當遠程方法執行的時候,它會返回一個對象到callback方法中。
f) 代理的對象
當使用的注解不是繼承自Java,可能你使用代理會出現一些問題。比如:當你使用aop攔截你的action的時候。在這種情況下,這個插件不會自動發現注解的方法。為了避免這種情況發生,你需要在xml中配置ignoreInterfaces為false,這樣插件會自己查找注解的所有接口和父類。
注意:這個參數只有在Action執行的過程是通過注解來運行的時候才應該設為false。
<action name="contact" class="package.ContactAction" method="smd">
<interceptor-ref name="json">
<param name="enableSMD">true</param>
<param name="ignoreInterfaces">false</param>
</interceptor-ref>
<result type="json">
<param name="enableSMD">true</param>
<param name="ignoreInterfaces">false</param>
</result>
<interceptor-ref name="default"/>
</action>
g) 使用方法
把插件的jar包copy到” /WEB-INF/lib”就可以了。
h) 版本歷史
Version
|
Date
|
Author
|
Notes
|
0.19
|
Nov 02, 200t
|
musachy
|
Return a JSON error instead of execeptions. Some bug fixes and refactoring. Thanks Joe Germuka and the other anonymous guys
|
0.18
|
Aug 10, 2007
|
musachy
|
Add SMDMethodsHack, fix 16,18,21thanks for the patches guys!
|
0.17
|
Aug 10, 2007
|
Oleg Mikheev
|
Ignore properties matching 'excludedProperties' when generating SMD
|
0.16
|
Jul 27, 2007
|
musachy
|
Resolve issue where method is evaluated even if its result is ignored (#14)
|
0.15
|
Jul 18, 2007
|
musachy
|
Add excludedProperties attribute to interceptor
|
0.14
|
Jun 27, 2007
|
musachy
|
Add root (OGNL expression) attribute to interceptor
|
0.13
|
Jun 14, 2007
|
musachy
|
Add 'ignoreHierarchy' property to JSON result to allow serialization of properties on base classes
|