利用FastJson,拼接复杂嵌套json数据&&直接从json字符串中(不依赖实体类)解析出键值对

 

1.拼接复杂嵌套json

FastJson工具包中有两主要的类: JSONObject和JSONArray ,前者表示json对象,后者表示json数组。他们两者都能添加Object类型的对象,但是JSONArray没有put()方法,只有add()方法。这与json数组的定义有关,json数组只能添加元素,而不能添加键值对。而JSONObject因为是一个对象,不能容纳其他对象,不能添加对象,没有add() 方法,它就只有put()方法来添加键值对。JSONObject和JSONArray 似乎只能两选一,要么用JSONObject的put()方法添加一个键值对,或使用JSONArray的add()方法添加一个元素。实际上是可以两者兼顾的,JSONObect的put(String key,Object value)方法中值参数value是Object类型,那么这个数据类型也就可以是JSONArray类型。这样的话,就可以在json对象中添加json数组中,从而轻松地拼接复杂的嵌套型的son数据。

如果要返回如下格式的json数据,常规的手工拼接将非常难以实现,且容易出错。

 

 1).首先从最内层开始分析,最内层是两个json对象,{item": "目录管理","url": "/system/menu/toMain"},这个json对象有相应的实体类AdminMenu,而外层是一个json数组将这两个对象包含进去。

        AdminMenu menu1 = new AdminMenu();
        menu1.setUrl("/system/menu/toMain");
        menu1.setName("目录管理");//通过"getItem(){ return name}",所以只设置setName即可
        
        AdminMenu menu2 = new AdminMenu();
        menu2.setUrl("/system/user/toMain");
        menu2.setName("用户管理");
        
        JSONArray level2Array = new JSONArray();
        //将两个实体类添加一json数据中,FastJson会将实体类自动转为json对象
        level2Array.add(menu1); 
        level2Array.add(menu2);

 

2).然后分析Level2(json数据)和Level1(键值对)又是一个匿名json对象的两个属性,把这两个属性添加到json对象中。

        JSONObject menuInfoElement = new JSONObject();
        menuInfoElement.put("Level2", level2Array);
        menuInfoElement.put("Level1", "系统管理");

 

3)再然后分析那个匿名json对象menuInfoElement是json数组menuInfo的唯一的一个元素,那么将匿名json对象menuInfoElement添加到menuInfo数组中。

        JSONArray menuInfoArray = new JSONArray();
        menuInfoArray.add(menuInfoElement);

 

4)再分析,menuInfo是json对象content的一个属性

        JSONObject contentObj = new JSONObject();
        contentObj.put("menuInfo", menuInfoArray);

 

5)最终,将'status' 'content' 'message'作为最终返回的json对象的属性

        JSONObject jsonMainObj = new JSONObject();
        jsonMainObj.put("status", "success");
        jsonMainObj.put("message", "查询成功");
        jsonMainObj.put("content", contentObj);

 

测试代码

  @Test
    public void testJson1()
    {
        AdminMenu menu1 = new AdminMenu();
        menu1.setUrl("/system/menu/toMain");
        menu1.setName("目录管理");//通过"getItem(){ return name}",所以只设置setName即可
        
        AdminMenu menu2 = new AdminMenu();
        menu2.setUrl("/system/user/toMain");
        menu2.setName("用户管理");
        
        JSONArray level2Array = new JSONArray();
        //将两个实体类添加一json数据中,FastJson会将实体类自动转为json对象
        level2Array.add(menu1); 
        level2Array.add(menu2);
        
        JSONObject menuInfoElement = new JSONObject();
        menuInfoElement.put("Level2", level2Array);
        menuInfoElement.put("Level1", "系统管理");
        
        JSONArray menuInfoArray = new JSONArray();
        menuInfoArray.add(menuInfoElement);
      
        
        JSONObject contentObj = new JSONObject();
        contentObj.put("menuInfo", menuInfoArray);
        
        JSONObject jsonMainObj = new JSONObject();
        jsonMainObj.put("status", "success");
        jsonMainObj.put("message", "查询成功");
        jsonMainObj.put("content", contentObj);
        
        System.out.println(jsonMainObj.toJSONString());
    }

 

输出的字符串

{"message":"查询成功",
"content":{"menuInfo":[{"Level2":[{"item":"目录管理","name":"目录管理","url":"/system/menu/toMain"},
{"item":"用户管理","name":"用户管理","url":"/system/user/toMain"}],
"Level1":"系统管理"}]},
"status":"success"}

 

2.不依赖实体类,直接从json格式字符串中解析出键值对

JSONObject 有 parseObject(String text, Class<T> clazz) 静态方法,将json字符串解析成T类型的java对象;而 JSONArray也有parseArray(String text, Class<T> clazz) 将json字符串解析成List<T>的集合对象。

但它们都需要传入一个Class对象作为参数,换句话说,必须先有一个Class对应的实体类,而很多时候我们只会将其中的键值对解析出来用一次,只临时使用它一次就去创建一个新的实体类,将会导致类爆炸。

 换种思路,JSONArray.parseArray(String text)将返回一个JSONArray对象。根据其add(Object obj)的方法入参类型是Object,那么其元素类型可能是一个实体类也可能是一个普通的json对象JSONObject,。但当前我们调用parseArray(String text)静态方法传入了的一个json字符串,以此构建出一个json数组,那么可以肯定其内部的元素类型一定是JSONObject,因此将其中的每个元素从Object强制转换为JSONObject类型,然后再从每个JSONObject取出键值对。

 @Test
    public void parseJsonText()
    {
        String menuList = "[{'id':1,'locked':false,'loginedTime':'2014-01-21'},"
            + "{'id':2,'locked':true,'loginedTime':'2015-03-22'},]";
        /*
         * 有属性名与之对应的User类,则可以写成这种形式,但目前并不存在User类,
         * 所以无法实现 List<User> uList=JSONArray.parseArray(menuList, User.class);
         */
        JSONArray jUsers = JSONArray.parseArray(menuList);
        /**
         * 这个for循环也可以
         * for(int i=0;i<jUsers.size();i++){
            JSONObject user=jUsers.getJSONObject(i);
             }
         */
        for (Object userObj : jUsers)
        {
            JSONObject jUser = (JSONObject)userObj; // 强制类型转换,因为知道其元素的具体类型是JSONObject,那么就不会出错
            /**
             * {'id':1}键值对的值1没加引号,FastJson认为它是数字,
             *  如果是{'id':'1'}格式,FastJson认为它是字符串,转换为Integer将出错
             */
            Integer id = (Integer)jUser.get("id");
            /*
             * {'locked':false}键值对的值没加引号,FastJson视作boolean类型,
             * 如果是{'locked':'false'}格式,FastJson视作String类型,强制转换为boolean将运行时出错
             * 
             */
            boolean locked = (boolean)jUser.get("locked");
            String loginTime = (String)jUser.get("loginedTime");
            System.out.println("用户id:" + id + " ,锁定了吗? " + locked + "  登录时间:" + loginTime);
        }
    }

 

 

结果输出

 

     另外需要注意,前端语言JavaScript是弱类型语言,它可以根据变量具体的值去推断其类型,而JAVA是强类型语言,对字符串和数字有着明确的区分。

前端的{'id',23}和{'id','23'}没有区别,但FastJson解析对这两种格式有明显的不同,前者键值对没有引号的值(23)视为数字,后者键值对有引号的值('23')视作字符串。

    @Test
    public void parseJsonError()
    {
        String menuList = "[{'id':1,'locked':false,'loginedTime':'2014-01-21'},"
            + "{'id':2,'locked':true,'loginedTime':'2015-03-22'},]";
    
        JSONArray jUsers = JSONArray.parseArray(menuList);
        try{
            for (Object userObj : jUsers)
            {
                JSONObject jUser = (JSONObject)userObj; // 强制类型转换,因为知道其元素的具体类型是JSONObject,那么就不会出错
              
                String id = (String)jUser.get("id");//将出错
              
                String locked = (String)jUser.get("locked");//将出错
                String loginTime = (String)jUser.get("loginedTime");
                System.out.println("用户id:" + id + " ,锁定了吗? " + locked + "  登录时间:" + loginTime);
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }

 

控制台提示类型转换异常

 

posted @ 2019-09-01 18:59  蜀中孤鹰  阅读(15375)  评论(3编辑  收藏  举报