是不是有经验的JavaEE开发者,看你json玩的6不6(下)

下面逐一解答上面文章提出的问题。我们使用struts2官网给的demo工程struts2-blank struts-2.3.16.1-all.zip解压后,进入struts-2.3.16.1-all\struts-2.3.16.1\apps\文件夹,将struts2-blank.war解压。eclipse里新建一个Dynamic Web Project工程,工程名叫struts2-blank。然后将相应的文件拷贝到新建的工程的相应路径下。源码见文章最后。


如何把form表单序列化成一个json对象? 序列化表单时,会遇到哪些问题?

先来看看jquery的serialize和serializeArray两个方法。


<form id="form1" action="" method="post">
    <label>姓名:</label><input type="text" name="name" /><br/>
    <label>年龄:</label><input type="text" name="age" /><br/>
    <label>男</label><input type="radio" name="gender" />
    <label>女</label><input type="radio" name="gender" /><br/>
    <label>是否有经验:</label><input type="checkbox" name="experienceFlag" /><br/>
    <input id="sbmt" type="button" value="提交" />
</form>


$(function(){
        $("#sbmt").click(function(){
            var serializeData = $("#form1").serialize();
            var serializeArrayData = $("#form1").serializeArray();
            console.log(serializeData);
            console.log(serializeArrayData);
        });
    });


是不是有经验的JavaEE开发者,看你json玩的6不6(下)
I.可以看到radio和checkbox的值都是“on",checkbox是on还可以区分开来,但是radio怎么办?



如果我们把form改成这样会序列化成什么样子?



<form id="form1" action="" method="post">
    <label>姓名:</label><input type="text" name="name" /><br/>
    <label>年龄:</label><input type="text" name="age" value="23" disabled="disabled"/><br/>
    <label>男</label><input type="radio" name="gender" value="0" />
    <label>女</label><input type="radio" name="gender" value="1" /><br/>
    <label>是否有经验:</label><input type="checkbox" name="experienceFlag" /><br/>
    <input id="sbmt" type="button" value="提交" />
</form>


是不是有经验的JavaEE开发者,看你json玩的6不6(下)

II.可以看到disabled的input框和没有选中的checkbox不会被序列化。这里还有一个问题,checkbox的value不是0和1。这个要么在提交表单前将所有选中的checkbox值设置为1,要么在后台进行处理,将experienceFlag的值为"on"变为1。为null就置为0。


可以看到serialize和serializeArray都没有达到我们的要求。serialize的结果是一个字符串,我们不能以"&"和"="进行切割,假如值里就有"&"和"="怎么办? 我们要将整个表单的值都放在一个js对象里。 这里啰嗦一下,js对象就是json对象。json的全称是JavaScript Object Notation。



III.将表单序列化成一个js对象还有一个问题,假如form里有多个text框的name是一样的怎么办?这里介绍一个网友的给出的方法,我仔细的看过,写的非常好。

表单序列化为Json对象

这里做成了插件的形式,非常好用。 

如果对jquery.fn.extend和jquery.extend两种写法不熟悉的同学可以看看这篇文章: jquery.fn.extend与jquery.extend





var formData = $("#form1").serializeJson();
console.log(formData);


是不是有经验的JavaEE开发者,看你json玩的6不6(下)

以上就是form表单序列化经常遇到的问题,就说到这儿。解决了第一个问题,就算是入门了。



如何传一个对象数组到后台? 有几种实现方式?

据我所知有两种方式:

I.用struts2自带的json拦截器,自动将json填充到List<Bean>里。

这个方法亲测好用 可以看看这篇文章,文章的最后有源码可以下载: Send JSON to Struts2 action

demo也可以从这里下载: jquery的ajax传json对象数组到struts2的action

文章里已经说的很详细了,这里不再赘述。注意这种方式除了 II里提到的jar包,还需要  struts2-json-plugin-2.3.16.1.jar 这个Jar包。

II.将json转成json字符串,在后台用jar包里的方法手动解析。

使用json-lib-2.3-jdk15.jar这个jar包。这个jar包需要依赖其他几个jar包。官网这里有介绍:json-lib

需要用到下面几个Jar包。

json-lib-2.3-jdk15.jar

commons-lang-2.4.jar

commons-beanutils-1.8.0.jar

commons-collections-3.1.jar

commons-logging-1.1.3.jar

ezmorph-1.0.6.jar

import java.util.List;


import net.sf.json.JSONObject;


public class JsonMapObject {
    public static void main(String[] args) {
        String jsonStr = "{\"users\":[{\"name\":\"aaa\",\"age\":23,\"gender\":\"0\",\"experienceFlag\":\"0\"},{\"name\":\"bbb\",\"age\":25,\"gender\":\"1\",\"experienceFlag\":\"1\"},{\"name\":\"ccc\",\"age\":26,\"gender\":\"1\",\"experienceFlag\":\"1\"}]}";
        JSONObject json = JSONObject.fromObject(jsonStr);
        List<User> users = (List<User>) json.get("users");
        System.out.println(users.size());
    }
}


假设jsonStr是前台传过来的字符串。我们可以手动解析,手动解析比较灵活。解析完了还可以做些处理,比如用element()方法给json添加元素,或者remove()方法删除某个元素等。   输出结果: 3


后台如何传json到前台


jquery用ajax请求后台。

$.ajax({
    url: "aaa/getSomething.action",
    type: "post",
    dataType: "json", // 服务端返回的数据类型
    data: {"id":123},
    success:function(data){
        console.log(data.msg);
    }
});



后台定义一个map,注意map不能为Null,要有setter和getter。


private Map<String, Object> resultData = new HashMap<String, Object>();
public Map<String, Object> getResultData() {
    return resultData;
}
public void setResultData(Map<String, Object> resultData) {
    this.resultData = resultData;
}
public String getSomething(){
    resultData.put("msg", "success");
    return SUCCESS;
}



<action name="getSomething" class="someAction" method="getSomething">
    <result type="json">
        <param name="root">resultData</param>
    </result>
</action>




前端如何将json字符串转成js对象? 如何将js对象转成json字符串?

var str = '{"name":"张三", "age":22}';
var obj = JSON.parse(str); // 转成js对象
console.log(obj);
var str2 = JSON.stringify(obj); // 转成json字符串
console.log(str2);


是不是有经验的JavaEE开发者,看你json玩的6不6(下)

注意json的key必须是双引号。


可以用input框存储json字符串吗? 如果不能可以用5的方式解决问题吗?

有些时候我们从一个action跳转到一个页面的时候希望将json数据保存下来供插件使用。我们首先想到的就是用隐藏的input框保存。

但是input框不能存储json字符串,因为json字符串里有冒号!



可以在js中取出EL表达式的值吗

不能。这个问题搞不清基本上可以肯定你不合格。JavaScript王者归来那本书里已经提到,js是运行在客户端的,EL表达式是运行在服务端的。怎么可能取到!

那为什么我确实取到了呢?我这样写不就取到了吗?<script>var aa = "${aa}"</scirpt>。这是一个投机的办法。有一个弊端就是你的js代码不能放在一个单独的js文件里,切记!这样写之所以可以取到,是因为 服务端的jsp编译成servlet之后,通过out.print()将所有html标签以字符串的形式发给浏览器,浏览器会把<script>标签里所有的东西都当作js代码来解析。<script>var aa = "${aa}"</scirpt>在servlet里就是

out.print("<script>var aa = {name:ccc,age:23}</scirpt>");

所以这个时候我们应该怎么做?  用ajax。 我们在使用各种插件的时候基本上都是这种方式。先到达页面,等页面加载完了之后再发一个ajax请求然后拿到数据。虽然有两次请求感觉上很慢,但是真正运行的时候基本上是感觉不到的。所以别犹豫,就用ajax吧。


如何将Java对象转成json?

User user = new User("李四", 26, "1", "1");
JSONObject jsonUser = JSONObject.fromObject(user);
System.out.println(jsonUser);



如何将json字符串转成Java对象?

String strUser = "{\"name\":\"aaa\",\"age\":23,\"gender\":\"0\",\"experienceFlag\":\"0\"}";
JSONObject jsonUser2 = JSONObject.fromObject(strUser);
System.out.println(jsonUser2);




json对象,map,Java对象三者之间如何互相转换?

Java对象----->  map 

try {
        User user = new User("李四", 26, "1", "1");
        Map<String, Object> map = BeanUtils.describe(user);
        System.out.println(map);
    } catch (Exception e) {
        e.printStackTrace();
    }


Java对象-----> json对象 

JSONObject jsonUser = JSONObject.fromObject(user);


json对象------>  map  

User user = new User("李四", 26, "1", "1");
Map userMap = JSONObject.fromObject(user); // net.sf.json.JSONObject实现了Map接口,可以直接用map接收Json对象


json对象------> Java对象 

JSONObject jsonObj = new JSONObject();
jsonObj.element("name", "王五");
jsonObj.element("age", 23);
User user2 = (User) JSONObject.toBean(jsonObj, User.class);


map      ------>  Java对象

Map<String, Object> map = new HashMap<String, Object>();
 map.put("name", "王五");
map.put("age", 23);
User user3 = new User();
try {
        BeanUtils.populate(user3, map);
    } catch (Exception e) {
        e.printStackTrace();
    }


map      ------>  json对象 

JSONObject mapToJson = JSONObject.fromObject(map); // map也是一个Java对象


json中如何处理Null值? *重要*

先举几个小例子

JSONObject valueNullJson = new JSONObject();
valueNullJson.element("aa", (Object)null); // 注意element有许多重载的方法,直接传null会报错,element方法不知道具体的类型
System.out.println(valueNullJson); // {}

JSONNull jsonNull = JSONNull.getInstance(); // JSONNull 没有构造函数,只能通过getInstance实例化。这是json里正宗的null
valueNullJson.element("bb", jsonNull);
System.out.println(valueNullJson);  // {"bb":null}

Map<String, Object> valueNullMap = new HashMap<String, Object>();
valueNullMap.put("cc", null);
valueNullMap.put("dd", JSONNull.getInstance());
JSONObject jobj = JSONObject.fromObject(valueNullMap);
System.out.println(jobj); // {"cc":null,"dd":null}

String valueNullStr = "{\"ee\":\"null\"}";
JSONObject strJson = JSONObject.fromObject(valueNullStr);
System.out.println(strJson); // {"ee":null}

String valueNullStr2 = "{\"ff\":null}";
JSONObject strJson2 = JSONObject.fromObject(valueNullStr2);
System.out.println(strJson2); // {"ff":null}


如果通过struts2将一个map转成json返回给前台,(<resut type="json"></result>)

那么你的map里的value不能为null,否则会报错。

如果你在struts.xml里配置了全局的异常处理,像这样

<global-results>
    <result type="redirect" name="error">/error.jsp</result>
    <result name="exp">/exp.jsp</result>
</global-results>

因为这里有一个重定向的处理。所以struts2在转json的时候出现异常就会返回一个302的错误。 debug调试代码的时候没有任何问题,return SUCCESS;后就会报错,切记。
一般struts2报重定向错误就是因为你的代码里某个地方有重定向行为,比如上面说的全局异常处理,或者是自定义的拦截器里的重定向行为。
 
再说一遍,struts2将一个map转成json返回给前台,那么你的map里的value不能为null,否则会报错。

有什么工具可以格式化和测试json字符串?

使用在线工具,比如: json.cn 。可以格式化json字符串,也可以压缩json字符串,将json转成xml等。



json是有序的吗?

json对象由许多个element构成。element就是一个key-value的键值对。 就键值对来说它是无序的。

对于一个json对象,我们几乎完全可以把它当作一个map来用。说它是无序的,原则上是没错的。但是有人可能会因此而忽悠你说因为json是无序的,所以我从db里查出东西后不能排序,这个你得自己重新排个序。

想想如果value是一个List<Object>。因为list里的元素是有序的。所以json里的数据可以是“已排好序的”。不要被忽悠了。



// todo

源码链接

上一篇:我的博客即将入驻“云栖社区”,诚邀技术同仁一同入驻。


下一篇:GO从入门到进阶教程系列 - 研发高性能ORM框架入门