下载地址 : 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 , 21 thanks 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 |
原文链接地址:http://www.blogjava.net/mac521/archive/2008/01/11/174653.html