posts - 41,  comments - 8,  trackbacks - 0
 Apache提供的一个插件包,可以把Action中的数据以JSON做个封装然后返回。

它会将整个action中的变量转化为JSON数据(根对象在JSON中数据添加一个”root”标识)。如果要使用它,Action必须遵循以下几点:

1.       返回的页面类型中”content-type”必须是”application/json”.(这个已经Internet Community采用).

2.       JSON内容必须是符合格式要求的.

3.       Actionfield必须有publicset方法.(是不是没有set方法就不会将field添加到JSON数据中,有待验证).

4.       它支持的类型有: 基本类型(int,long...String), Date, List, Map, Primitive Arrays, 其它class, 对象数组.

5.       JSON中任何的Object会被封装在listmap中,数据会被封装程Long,如果是含有的数据则会被封装程Double,数组会被封装程List.

下面给出JSON的数据格式:

{

   "doubleValue": 10.10,

   "nestedBean": {

      "name": "Mr Bean"

   },

   "list": ["A", 10, 20.20, {

      "firstName": "El Zorro"

   }],

   "array": [10, 20]

}

说明:

a.       这个插件支持以下几个注释:

注释名

简介

默认值

序列化

反序列化

name

配置JSONname

empty

yes

no

serialize

serialization

true

yes

no

deserialize

deserialization

true

no

yes

format

格式化Date字段

"yyyy-MM-dd'T'HH:mm:ss"

yes

yes

可以通过配置来显示指出要放在JSONfield,其中有个自己的验证规则需要研究.

<!-- 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数据中,如果不想这样做,需要在配置时指定ignoreHierarchyfalse:

<result type="json">

 <param name="ignoreHierarchy">false</param>

</result>

e.       枚举类型

默认处理枚举类型时,会被处理成JSON数据中name等于枚举中valuevalue等于枚举中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”这个必须在interceptorresult都要配置.

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对象,这个过程是Dojoaction中的方法创建了一个Proxy。因为这是异步调用过程,当远程方法执行的时候,它会返回一个对象到callback方法中。

f)         代理的对象

当使用的注解不是继承自Java,可能你使用代理会出现一些问题。比如:当你使用aop拦截你的action的时候。在这种情况下,这个插件不会自动发现注解的方法。为了避免这种情况发生,你需要在xml中配置ignoreInterfacesfalse,这样插件会自己查找注解的所有接口和父类。

注意:这个参数只有在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>

posted on 2008-10-04 14:45 Loy Fu 阅读(7717) 评论(2)  编辑  收藏 所属分类: struts

只有注册用户登录后才能发表评论。


网站导航: