下载地址: 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  |