论坛首页 Java企业应用论坛

实战Ext -> Struts2 -> Spring数据传递与解析

浏览 8281 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (11)
作者 正文
   发表时间:2011-01-07   最后修改:2011-01-07

在以Spring为核心的Web应用中,使用Ext作为Web前台,通过Struts2作为数据交换的“跳板”。

 

原本Struts2自身具备的ModelDriven接口,在使用Ext前台后变得已经没有什么大用了。

 

由于有struts2-json-plugin的支持,可以很方便的获取前台的数据。

 

有点像Ext将数据序列化后,再由后台的Java进行反序列化。但是,Ext毕竟只能提供JSON数据,它的本质还只是POST过来的字符串而已。

 

然而借助struts2-json-plugin提供的 Object JSONUtil.deserialize(String) 方法,可以很简单的将 request 中的字符串“反序列化”为Java对象。

 

但是,在实战中发现,由于“反序列化”的时候并没有一个Java类作为“模板”,所以到底“反序列化”出来的对象是什么类型的,完全由JSONUtil.deserialize方法自己决定。而它只能参考唯一的参数——那个大大的JSON字符串来决定。于是 见到形如数字的就生成 Long,有小数点的就是 Double,其他统统 String,见到[ ]就是List,见到{ }就是Map。

 

然而我们Java端的JavaBean中真的是这些类型吗?

 

那个Long可能仅仅是int,或者根本就是个String;

那个List或许是个数组;

那个Map其实是另一个JavaBean。。。

 

但是,JSONUtil真的猜不到呀。

多么希望JSONUtil能够提供一个这样的重载方法:deserialize(String, Class)

但是,它真的没有。

 

于是我在我的框架中,从Struts2的Action入手。给所有的Action类编制一个抽象父类,并在其中实现这样的“智能反序列化”功能。

 

写这段代码时,发现最为麻烦的就是,如果JSONUtil反序列化后得到的对象中的某个属性是集合类型,而我们的JavaBean中,它其实应该是数组或JavaBean时,如何得到集合类型泛型中的类型。

 

举个例子,JSON字符串经JSONUtil处理后,有个属性 stuffs 的类型是List<E>,而按照JavaBean中的定义,这个 stuffs 的类型是个数组 Human[] stuffs ,这个相对简单一些,假设从JavaBean中反射得到各个属性并遍历时,得到的属性类型为propType:

 

beanInfo = Introspector.getBeanInfo(type);

for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {

    Class propType = descriptor.getPropertyType();



}

 

 

那么 Class innerCls = propertyType.getComponentType(); 就能得到数组的元素类型,如上例中的 Human。

 

更为复杂的是,当JSON中的 List<E> 对应于 JavaBean 中的 List<?> 时,如果上例中,JavaBean中 stuffs 属性的类型改为 List<Human> :

 

那么很遗憾,我没有找到方法可以从 propTpye (List<Human>的Class)中找到并提取 Human 这个类。

只能通过 stuffs 这个属性在其JavaBean中的setter方法,取得其参数里面的泛型,来发现这个Human。

// get the inner Type
ParameterizedType rType = (ParameterizedType) wm.getGenericParameterTypes()[0];
Type fType = rType.getActualTypeArguments()[0];
// Type to Class
Field field = fType.getClass().getDeclaredField("name");
field.setAccessible(true);
String name = (String) field.get(fType);
Class innerCls = Class.forName(name);

 

 

Map中泛型也与此类型,唯一的区别是,Map中有key和value,需要取两个泛型的类型。

 

剩下的工作就是递归了,这样才能无线层次的构筑复杂的JavaBean对象。

 

详细代码如下:

 

 

AbstractAction.java

 

/**
 * Action的抽象骨架类
 * 
 */
public abstract class AbstractAction extends ActionSupport {

     /** Logger available to subclasses */
     protected final Log logger = LogFactory.getLog(getClass());
 
     // 此处省略一些与本功能无关的代码
     
     /**
     * 预处理。确认request有效,并强制编码格式为UTF-8
     */
    private boolean proParseRequestData() {
        ServletRequest request = ServletActionContext.getRequest();
        try {
            request.setCharacterEncoding("UTF-8");
        } catch (UnsupportedEncodingException e) {
            logger.warn("Can't encoding to UTF-8. use the default encode.");
        }
        if (request == null) {
            logger.error("Can't get http servlet request.");
            return false;
        } else {
            return true;
        }
    }

    /**
     * 获取数组型JSON字符串
     * 因数组型数据,前台可能有两种提交方式。一种是提交多个同名的项目,一种是提交单个以[]包裹、逗号分割的JSON格式的字符串。本方法将这两种提交方式统一化处理为JSON字符串格式
     */
    private String parseParametersJSONString(ServletRequest request, String propertyName) {
        String[] stringArray = request.getParameterValues(propertyName);
        if(stringArray == null){
            return null;
        }
        if (stringArray.length == 1 && stringArray[0].startsWith("[")) {
            return stringArray[0];
        } else {
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < stringArray.length; i++) {
                sb.append("[");
                sb.append(stringArray[i]);
                sb.append("]");
                if (i < stringArray.length - 1) {
                    sb.append(",");
                }
            }
            return sb.toString();
        }
    }

    /**
     * 解析页面提交的所有数据 从request中提取JSON序列化字符串,并据此解析出复杂的JavaBean数据(VOBean)
     * 
     * @param type
     *            装填JavaBean的类型
     * @return 装填好的JavaBean
     */
    protected <T> T parseRequestData(Class<T> type) {
        // 检查并预置HttpRequest
        if (!proParseRequestData()) {
            return null;
        }
        T result = null;
        try {
            result = (T) type.newInstance();
        } catch (Exception e) {
            logger.warn("Can't parse JOSN object.");
            logger.warn(e.getMessage());
        }
        BeanInfo beanInfo = null;
        try {
            beanInfo = Introspector.getBeanInfo(type); // 获取类属性
        } catch (Exception e) {
            logger.warn("Can't parse JOSN object.");
            logger.warn(e.getMessage());
        }
        ServletRequest request = ServletActionContext.getRequest();
        // 给 JavaBean 对象的属性赋值
        for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {
            Method wm = descriptor.getWriteMethod();
            if (wm != null) {
                String propertyName = descriptor.getName();
                Class propType = descriptor.getPropertyType();
                if (propType.isArray()) {
                    // 数组型属性
                    try {
                        String jsonString = parseParametersJSONString(request, propertyName);
                        Object jsonObj = JSONUtil.deserialize(jsonString);
                        Object value = parseProperties(jsonObj, propType);
                        wm.invoke(result, value);
                    } catch (Exception e) {
                        logger.warn("Can't set property " + propertyName);
                        logger.warn(e.toString());
                    }
                } else if (List.class.isAssignableFrom(propType)) {
                    Class innerCls = null;
                    try {
                        String propertyString = parseParametersJSONString(request, propertyName);
                        if (propertyString != null) {
                            // get the inner Type
                            ParameterizedType rType = (ParameterizedType) wm.getGenericParameterTypes()[0];
                            Type fType = rType.getActualTypeArguments()[0];
                            // Type to Class
                            Field field = fType.getClass().getDeclaredField("name");
                            field.setAccessible(true);
                            String name = (String) field.get(fType);
                            innerCls = Class.forName(name);

                            Object jsonObj = JSONUtil.deserialize(propertyString);
                            Object value = parseProperties(jsonObj, propType, innerCls);

                            wm.invoke(result, value);
                        }
                    } catch (Exception e) {
                        logger.warn("Can't get inner generic class.");
                        logger.warn(e.getMessage());
                    }
                } else if (Map.class.isAssignableFrom(propType)) {
                    try {
                        String propertyString = parseParametersJSONString(request, propertyName);
                        if (propertyString != null) {
                            // get the inner Type([0] is the Key type of the Map)
                            ParameterizedType rType1 = (ParameterizedType) wm.getGenericParameterTypes()[0];
                            Type fType1 = rType1.getActualTypeArguments()[0];
                            // Type to Class
                            Field field1 = fType1.getClass().getDeclaredField("name");
                            field1.setAccessible(true);
                            String name1 = (String) field1.get(fType1);
                            Class innerCls1 = Class.forName(name1);
                            // get the inner Type([1] is the Value type of the Map)
                            ParameterizedType rType2 = (ParameterizedType) wm.getGenericParameterTypes()[1];
                            Type fType2 = rType2.getActualTypeArguments()[0];
                            // Type to Class
                            Field field2 = fType2.getClass().getDeclaredField("name");
                            field2.setAccessible(true);
                            String name2 = (String) field2.get(fType2);
                            Class innerCls2 = Class.forName(name2);

                            Object jsonObj = JSONUtil.deserialize(propertyString);
                            Object value = parseProperties(jsonObj, propType, innerCls1, innerCls2);

                            wm.invoke(result, value);
                        }
                    } catch (Exception e) {
                        logger.warn("Can't get inner generic class.");
                        logger.warn(e.getMessage());
                    }
                } else if (ClassUtil.isValueType(propType)) {
                    Object value = null;
                    try {
                        String propertyString = request.getParameter(propertyName);
                        if (propertyString != null) {
                            value = stringToObject(propertyString, propType);
                            wm.invoke(result, value);
                        }
                    } catch (Exception e) {
                        logger.warn("Can't set property " + propertyName);
                        logger.warn(e.getMessage());
                    }
                } else {
                    Object value = null;
                    try {
                        String propertyString = request.getParameter(propertyName);
                        if (propertyString != null) {
                            Object jsonObj = JSONUtil.deserialize(propertyString);
                            value = parseProperties(jsonObj, propType);
                            wm.invoke(result, value);
                        }
                    } catch (Exception e) {
                        logger.warn("Can't set property " + propertyName);
                        logger.warn(e.getMessage());
                    }
                }
            }
        }
        // 返回结果
        return result;
    }

    /**
     * 解析页面提交的某个数据 从request中提取JSON序列化字符串,并据此解析出某个复杂的JavaBean数据(VOBean)
     * 
     * @param type
     *            装填JavaBean的类型
     * @param propertyName
     *            预解析的属性名(在request信息中的名)
     * @return 装填好的JavaBean
     */
    protected <T> T parseRequestData(Class<T> type, String propertyName) {
        // 检查并预置HttpRequest
        if (!proParseRequestData()) {
            return null;
        }

        ServletRequest request = ServletActionContext.getRequest();

        if (type.isArray()) {
            try {
                String jsonString = parseParametersJSONString(request, propertyName);
                if (jsonString != null) {
                    Object jsonObj = JSONUtil.deserialize(jsonString);
                    return parseProperties(jsonObj, type);
                }
            } catch (Exception e) {
                logger.warn("Can't set property " + propertyName);
                logger.warn(e.getMessage());
            }
        } else if (List.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type)) {
            try {
                String propertyString = parseParametersJSONString(request, propertyName);
                if (propertyString != null) {
                    // can't get the inner Type, use Object
                    Object jsonObj = JSONUtil.deserialize(propertyString);
                    return parseProperties(jsonObj, type, Object.class);
                }
            } catch (Exception e) {
                logger.warn("Can't get inner generic class.");
                logger.warn(e.getMessage());
            }
        } else if (ClassUtil.isValueType(type)) {
            try {
                String propertyString = request.getParameter(propertyName);
                if (propertyString != null) {
                    return (T) stringToObject(propertyString, type);
                }
            } catch (Exception e) {
                logger.warn("Can't get inner generic class.");
                logger.warn(e.getMessage());
            }
        } else {
            try {
                String propertyString = request.getParameter(propertyName);
                if (propertyString != null) {
                    Object jsonObj = JSONUtil.deserialize(propertyString);
                    return parseProperties(jsonObj, type);
                }
            } catch (Exception e) {
                logger.warn("Can't get inner generic class.");
                logger.warn(e.getMessage());
            }
        }
        return null;
    }

    /**
     * 解析属性
     * @param <T> 返回值类型
     * @param source JSON字符串反序列得到的源数据
     * @param type 返回值的类型
     * @return 解析得到的Java对象
     */
    private <T> T parseProperties(Object source, Class<T> type) {
        return parseProperties(source, type, null);
    }

    /**
     * 解析属性
     * @param <T> 返回值类型
     * @param source JSON字符串反序列得到的源数据
     * @param type 返回值的类型
     * @param innerType 内部(泛型)类型,对应List<E>的E
     * @return 解析得到的Java对象
     */
    private <T> T parseProperties(Object source, Class<T> type, Class innerType) {
        return parseProperties(source, type, innerType, null);
    }
    
    /**
     * 解析属性
     * @param <T> 返回值类型
     * @param source JSON字符串反序列得到的源数据
     * @param type 返回值的类型
     * @param innerType1 内部(泛型)类型1,对应Map<K, V>的K
     * @param innerType2 内部(泛型)类型2,对应Map<K, V>的V
     * @return 解析得到的Java对象
     */
    private <T> T parseProperties(Object source, Class<T> type, Class innerType1, Class innerType2) {
        // JavaBean or Map
        if (source instanceof Map) {
            Map<Object, Object> jsonMap = (Map<Object, Object>) source;
            if (Map.class.isAssignableFrom(type)) {
                // type is Map
                Map<Object, Object> rtnMap = new HashMap<Object, Object>();
                for (Map.Entry<Object, Object> entry : jsonMap.entrySet()) {
                    rtnMap.put(parseProperties(entry.getKey(), innerType1), parseProperties(entry.getValue(), innerType2));
                }
                return (T) rtnMap;
            } else {
                // JavaBean
                T obj = null;
                try {
                    obj = type.newInstance();
                } catch (Exception e) {
                    logger.warn("Can't parse JOSN object.");
                    logger.warn(e.getMessage());
                }
                BeanInfo beanInfo = null;
                try {
                    beanInfo = Introspector.getBeanInfo(type); // 获取类属性
                } catch (Exception e) {
                    logger.warn("Can't parse JOSN object.");
                    logger.warn(e.getMessage());
                }
                // 给 JavaBean 对象的属性赋值
                for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {
                    Method wm = descriptor.getWriteMethod();
                    if (wm != null) {
                        String propertyName = descriptor.getName();
                        Class propertyType = descriptor.getPropertyType();
                        try {
                            if (jsonMap.containsKey(propertyName)) {
                                Object value = jsonMap.get(propertyName);
                                if (value != null) {
                                    if (propertyType.isArray()) {
                                        // get the inner Type
                                        Class innerCls = propertyType.getComponentType();

                                        wm.invoke(obj, parseProperties(value, propertyType, innerCls));
                                    } else if (List.class.isAssignableFrom(propertyType)) {
                                        // get the inner Type
                                        ParameterizedType rType = (ParameterizedType) wm.getGenericParameterTypes()[0];
                                        Type fType = rType.getActualTypeArguments()[0];
                                        // Type to Class
                                        Field field = fType.getClass().getDeclaredField("name");
                                        field.setAccessible(true);
                                        String name = (String) field.get(fType);
                                        Class innerCls = Class.forName(name);

                                        wm.invoke(obj, parseProperties(value, propertyType, innerCls));
                                    } else if (Map.class.isAssignableFrom(propertyType)) {
                                        // get the inner Type([0] is the Key type of the Map)
                                        ParameterizedType rType1 = (ParameterizedType) wm.getGenericParameterTypes()[0];
                                        Type fType1 = rType1.getActualTypeArguments()[0];
                                        // Type to Class
                                        Field field1 = fType1.getClass().getDeclaredField("name");
                                        field1.setAccessible(true);
                                        String name1 = (String) field1.get(fType1);
                                        Class innerCls1 = Class.forName(name1);
                                        // get the inner Type([1] is the Value type of the Map)
                                        ParameterizedType rType2 = (ParameterizedType) wm.getGenericParameterTypes()[1];
                                        Type fType2 = rType2.getActualTypeArguments()[0];
                                        // Type to Class
                                        Field field2 = fType2.getClass().getDeclaredField("name");
                                        field2.setAccessible(true);
                                        String name2 = (String) field2.get(fType2);
                                        Class innerCls2 = Class.forName(name2);

                                        wm.invoke(obj, parseProperties(value, propertyType, innerCls1, innerCls2));
                                    } else if (propertyType.isAssignableFrom(value.getClass())) {
                                        wm.invoke(obj, value);
                                    } else if(ClassUtil.isValueType(propertyType)){
                                        wm.invoke(obj, stringToObject(value.toString(), propertyType));
                                    } else {
                                        wm.invoke(obj, parseProperties(value, propertyType));
                                    }
                                }
                            }
                        } catch (Exception e) {
                            logger.warn("Can't set property " + propertyName);
                            logger.warn(e.getMessage());
                        }
                    }
                }
                return obj;
            }
        } else if (source instanceof List) {
            // List from JSON
            if (List.class.isAssignableFrom(type)) {
                // Data into a List
                if (ClassUtil.isValueType(type)) {
                    return (T) source;
                } else {
                    List rtn = new ArrayList();
                    for (Object obj : (List) source) {
                        rtn.add(parseProperties(obj, innerType1));
                    }
                    return (T) rtn;
                }
            } else {
                // Data into a Array
                List<Object> innerList = (List<Object>) source;
                Class arrayType = type.getComponentType();
                Object[] array = (Object[]) Array.newInstance(arrayType, innerList.size());
                for (int i = 0; i < innerList.size(); i++) {
                    Object src = innerList.get(i);
                    Object item = parseProperties(src, arrayType);
                    array[i] = item;
                }
                return (T) array;
            }
        } else {
            return (T) source;
        }
    }

    /**
     * 将String转换为type所指定的类型
     * 
     * @param str
     *            String型元数据
     * @param type
     *            转换后的数据类型的class
     * @return 转换后的结果
     * @throws NumberFormatException
     *             当参数不能转换为数值型时
     */
    private Object stringToObject(String str, Class type) {
        try {
            if (String.class.isAssignableFrom(type)) {
                return str;
            }
            if (char.class.isAssignableFrom(type)) {
                return str.charAt(0);
            }
            if (Character.class.isAssignableFrom(type)) {
                return Character.valueOf(str.charAt(0));
            }
            if (int.class.isAssignableFrom(type)) {
                return Integer.valueOf(str);
            }
            if (Integer.class.isAssignableFrom(type)) {
                return Integer.valueOf(str);
            }
            if (boolean.class.isAssignableFrom(type)) {
                return Boolean.valueOf(str);
            }
            if (Boolean.class.isAssignableFrom(type)) {
                return Boolean.valueOf(str);
            }
            if (short.class.isAssignableFrom(type)) {
                return Short.valueOf(str);
            }
            if (Short.class.isAssignableFrom(type)) {
                return Short.valueOf(str);
            }
            if (long.class.isAssignableFrom(type)) {
                return Long.valueOf(str);
            }
            if (Long.class.isAssignableFrom(type)) {
                return Long.valueOf(str);
            }
            if (float.class.isAssignableFrom(type)) {
                return Float.valueOf(str);
            }
            if (Float.class.isAssignableFrom(type)) {
                return Float.valueOf(str);
            }
            if (double.class.isAssignableFrom(type)) {
                return Double.valueOf(str);
            }
            if (Double.class.isAssignableFrom(type)) {
                return Double.valueOf(str);
            }
            if (byte.class.isAssignableFrom(type)) {
                return Byte.valueOf(str);
            }
            if (Byte.class.isAssignableFrom(type)) {
                return Byte.valueOf(str);
            }
            if (Date.class.isAssignableFrom(type)) {
                return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").parse(str);
            }
            if (Calendar.class.isAssignableFrom(type)) {
                Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").parse(str);
                Calendar result = Calendar.getInstance();
                result.setTime(date);
                return result;
            }
            if (BigInteger.class.isAssignableFrom(type)) {
                return new BigInteger(str);
            }
            if (BigDecimal.class.isAssignableFrom(type)) {
                return new BigDecimal(str);
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }
}

 

这里边用到了一个 ClassUtil.isValueType(Class) 方法用来判定给定的类型是为Java的值类型和基本型:

 

ClassUtil.java

 

public class ClassUtil {
    /**
     * 判定指定的 Class 对象是否表示一个值类型。 八个基本类型及它们的包装类、五个 Class 和 void。 即
     * boolean、Boolean、byte、Byte、char、Character、short、Short、int、Integer、long、Long、float、Float、double、Double、String、BigInteger、BigDecimal、Date、Calendar、void。
     * 
     * @param clazz
     * @return 当且仅当指定类表示一个值类型时,才返回 true
     */
    public static boolean isValueType(Class clazz) {
        if (clazz.isPrimitive()) {
            return true;
        }
        if (String.class.isAssignableFrom(clazz)) {
            return true;
        }
        if (Byte.class.isAssignableFrom(clazz)) {
            return true;
        }
        if (Character.class.isAssignableFrom(clazz)) {
            return true;
        }
        if (Short.class.isAssignableFrom(clazz)) {
            return true;
        }
        if (Integer.class.isAssignableFrom(clazz)) {
            return true;
        }
        if (Long.class.isAssignableFrom(clazz)) {
            return true;
        }
        if (Float.class.isAssignableFrom(clazz)) {
            return true;
        }
        if (Double.class.isAssignableFrom(clazz)) {
            return true;
        }
        if (Date.class.isAssignableFrom(clazz)) {
            return true;
        }
        if (Calendar.class.isAssignableFrom(clazz)) {
            return true;
        }
        if (BigInteger.class.isAssignableFrom(clazz)) {
            return true;
        }
        if (BigDecimal.class.isAssignableFrom(clazz)) {
            return true;
        }
        return false;
    }
}

 

 

最后,在各个Action中的使用方法是:

 

XxxxxAction.java

 

// 前台提交的request就是stuffs这个对象在前台的JSON对象
Human stuffs = parseRequestData(Human.class);

// 前台提交的request中的项目并非某个JavaBean的众属性,而是单独接收它们
String listType = this.parseRequestData(String.class, "listType");
boolean hasBlankItem = this.parseRequestData(Boolean.class, "hasBlankItem");
Object[] params = this.parseRequestData(Object[].class, "params");

 

 

就此我们的反序列化工具完成了,复杂的JavaBean可以成功反序列化了。

 

但是,期间的代码(主要是提取泛型中的类型),看上去有些丑陋,如果你知道更好的方法,请一定跟帖!

 

   发表时间:2011-01-10  
EXT非得要以JSON形式提交数据?一个对象只有某个属性改变,用得着整个提交?带宽问题不是问题?
费那么大劲反序列化,json-lib不是提供了类似的功能?真正难搞的是日期类型而已。
0 请登录后投票
   发表时间:2011-01-10  
llade 写道
EXT非得要以JSON形式提交数据?一个对象只有某个属性改变,用得着整个提交?带宽问题不是问题?
费那么大劲反序列化,json-lib不是提供了类似的功能?真正难搞的是日期类型而已。


Ext已JSON形式提交的数据,不一定非是大数据。简单的一个id和一个数量,就可以组成一个简单的JSON:
{id:'0501',count:12}

这与 ?id='0501'&count=12 的数据量没有什么差异。

对于后台,可以“特意”用两个 String和int型变量去接收它们(setter注入、ModelDriven都可以,甚至getParameter),
但是,现在我想要的是一个通用的方法,把它们放入一个JavaBean中。
pulic Class MyPOJO{
  private String id;
  private int count;
  // getter/setter ....
}

而使用struts-json-plugin的功能,只能得到一个 Map
0 请登录后投票
   发表时间:2011-01-10   最后修改:2011-01-10
精神可嘉。

其实可以考虑在json中带上元数据,然后自己实现一套serialize/deserialize就简单多了。
0 请登录后投票
   发表时间:2011-01-10  
我感觉用Json-lib就挺好,能解决楼主的难处。

关于数据传输,我感觉只提交修改的数据就可以,应该数据量不大
0 请登录后投票
   发表时间:2011-01-10  
有人能估测下EXT的发展前景吗?

我觉得这个比这篇文章重要



0 请登录后投票
   发表时间:2011-01-11  
Ext.decode() or encode

后台拿JsonUtil
0 请登录后投票
   发表时间:2011-01-12  
zhaoxy_sunrain 写道
我感觉用Json-lib就挺好,能解决楼主的难处。

关于数据传输,我感觉只提交修改的数据就可以,应该数据量不大


当前台是个收集数据的表格的时候,数据量就大了。

比如,修改了4行数据,添加了8行数据。
0 请登录后投票
   发表时间:2011-01-13  
TonyLian 写道
llade 写道
EXT非得要以JSON形式提交数据?一个对象只有某个属性改变,用得着整个提交?带宽问题不是问题?
费那么大劲反序列化,json-lib不是提供了类似的功能?真正难搞的是日期类型而已。


Ext已JSON形式提交的数据,不一定非是大数据。简单的一个id和一个数量,就可以组成一个简单的JSON:
{id:'0501',count:12}

这与 ?id='0501'&count=12 的数据量没有什么差异。

对于后台,可以“特意”用两个 String和int型变量去接收它们(setter注入、ModelDriven都可以,甚至getParameter),
但是,现在我想要的是一个通用的方法,把它们放入一个JavaBean中。
pulic Class MyPOJO{
  private String id;
  private int count;
  // getter/setter ....
}

而使用struts-json-plugin的功能,只能得到一个 Map


不知道是不是误解,我说的是json-lib。

http://json-lib.sourceforge.net/usage.html

引用
From JSON to Beans
0 请登录后投票
   发表时间:2011-01-13  

多谢LS,看来我有些重复造轮子了。

根据LS的提示,搜索了一下,看来这样的lib还真多。我大概总结了一下,我的需求,和这些lib的特征,
希望大家都能来做补充。

我的需求是:
1. JSON字符串 -> Java对象 的反序列化
2. Java对象要求支持从基本类、集合、到JavaBean
   所以需要lib提供有2个参数的反序列化方法,一个是JSONString,一个是希望反序列化后的类型

   MyBean myBean = (MyBean)Xxxxx.deserialize(jsonString, MyBean.class)

3. 要求支持泛型,就是说MyBean的某个属性可能是

public class MyBean{

    public Map<MyBean2, List<MyBean3>> getXxxx(){
        ...
    }

}

4. 要支持数组,不能和List弄混

public class MyBean{
    public MyBean4[] getXxxxx(){
        ...
    }
}

 

 

我所搜集的信息如下:希望大家补充

 

各种JSON2JAVA反序列工具比较
名称 反序列 Class参数 集合类型 泛型 JavaBean 性能 作者 备注 网址
Struts2-json-plugin        
json-lib ○麻烦?   X半自动   比Struts插件慢30% 国外组织 还有xml--json转换功能 http://json-lib.sourceforge.net/ 
jackson         国外组织 线程安全  
Nutz.Json   国人个人   http://code.google.com/p/nutz/
jroi.json   国人个人   http://www.iteye.com/topic/587170
JSONEX   国人个人   http://johnson-lee.iteye.com/blog/586686
JsonTools        
gson 比jackson慢一个数量级 Google 对field序列化,而非getter  
xstream        
stringtree         
JSEL JSON   国人个人   http://code.google.com/p/lite/wiki/JSON
                   
                   
                   
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics