• 周一. 5月 27th, 2024

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

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

admin

11月 28, 2021

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();
        }
    }

控制台提示类型转换异常

《利用FastJson,拼接复杂嵌套json数据&&直接从json字符串中(不依赖实体类)解析出键值对》有2个想法
  1. Wow, awesome blog layout! How long have you ever been blogging for?
    you made blogging glance easy. The overall look of your web site is fantastic, let alone the
    content material! You can see similar here dobry sklep

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注