IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 根据key找到JSON字符串中指定的value值 -> 正文阅读

[大数据]根据key找到JSON字符串中指定的value值





一、引言

距离上次写接口已经过去了一周,那次接口之旅让我明白打印日志的重要性,于是我自定义了一个Log注解,用于打印接受的参数和返回的参数:自定义注解+AOP,优雅的打印方法接受和返回的参数内容



上一次接口交互的数据是xml格式的数据,由于我对于dom4j不太熟悉,所以就按部就班的使用常规的形式进行解析,效果还算如人意。但是这次接口交互的数据是JSON,我依然不熟悉,但是FastJSON、Gson、Jackson它们熟悉呀,高效的API,丝滑般的体验,能够一边摸着鱼,一边完成领导的任务,舒服。


当我看到对应的业务要求时,我有一点小郁闷,具体的返回JSON数据如下图。返回了一堆的数据,然而我只需要一个id。当然用API也行,只要一层一层的往下解析就好了,可我觉得太麻烦,要写一堆无用的代码(自己太懒了,不想写代码)。



我理想的状况就是我传入一个key,调用对应的API能够直接返回我要的value值。

以下废话,可直接看第二节

最开始我想到的是树结构,把JSON字符串修改为一棵树,然后根据层级和对应的key直接获取,但是这有几个问题:

  1. 我不会写树,百度出来也没看太明白(太菜了)
  2. 相同层级的树可能存在key值一样的情况
  3. 树结构下的map值和list数组交叉在一起以后,我找起来也不方便

综上所述,我放弃了。





二、代码

上面的第二点很关键,然后想到上次解析xml格式数据的经验,我需要传入指定的路径,以此来定位对应的节点值,然后一层一层的往下找。并且我可以获取单个节点值(单个value),也有可以获取一整个大的节点(直接转化为list集合或者map),说干就干,代码从哪里开始写呢?

终于在我的辛苦百度下,找到了一个差不多的功能的代码,然后修修改改(我能说是我的了吗?哈哈),成为了下面的代码。



如果想要直接运行下面的代码,你需要引入相关的依赖:fastjson(数据转换)、commons-lang3(判空)、slf4j(日志)。主要是第一个,后面两个可以把代码相关部分注释掉即可。如果想要支持多种数据源的操作,只需要写一个简单的策略模式就能实现。

现在:传入指定的JSON字符串 + 传入想要获取的目标key + 传入目标key的value类型 = 你想要的结果

public class JsonToolsFastJson {

    private static String jsonStr = "{\"_id\":\"5973782bdb9a930533b05cb2\",\"isActive\":true,\"balance\":\"$1,446.35\",\"age\":32,\"eyeColor\":\"green\",\"name\":\"Logan Keller\",\"gender\":\"male\",\"company\":\"ARTIQ\",\"email\":\"logankeller@artiq.com\",\"phone\":\"+1 (952) 533-2258\",\"friends\":[{\"id\":0,\"name\":\"Colon Salazar\"},{\"id\":1,\"name\":\"French Mcneil\"},{\"id\":2,\"name\":\"Carol Martin\"}],\"mobian\":[{\"id\":0,\"name\":\"Colon Salazar\",\"arr\":[{\"id\":0,\"name\":\"Colon Salazar\"}]}],\"favoriteFruit\":\"banana\"}";


    private static final Logger logger = LoggerFactory.getLogger(JsonToolsFastJson.class);


    public static void main(String[] args) throws Exception {
        //测试通过json获取Object对象
        JsonToolsFastJson jsonTools = new JsonToolsFastJson();
        Object str1 = jsonTools.getObjectByJson(jsonStr, "name", TypeEnum.STRING);
        logger.info("str1:" + str1);

        Object str3 = jsonTools.getObjectByJson(jsonStr, "friends", TypeEnum.LIST);
        logger.info("str3:" + str3);

        Object str4 = jsonTools.getObjectByJson(jsonStr, "mobian.arr", TypeEnum.LIST);
        logger.info("str4:" + str4);
    }


    // 用于记录递归的次数
    private int i = 0;

    /**
     * 复杂嵌套JSON获取Object数据
     */
    public Object getObjectByJson(String jsonStr, String argsPath, TypeEnum argsType) {
        if (StringUtils.isBlank(argsPath) || argsType == null) {
            logger.info("必填参数argsPath或argsType不能为空");
            return null;
        }

        Object obj = null;
        try {
            Map maps = JSONObject.parseObject(jsonStr);
            //多层获取
            if (argsPath.contains(".")) {
                obj = getObject(maps, argsPath, argsType);
            } else {
                //直接获取
                if (argsType == TypeEnum.STRING) {
                    obj = JSONObject.parseObject(jsonStr).get(argsPath);
                } else if (argsType == TypeEnum.MAP) {
                    obj = (Map) JSONObject.parseObject(jsonStr).get(argsPath);
                } else if (argsType == TypeEnum.LIST) {
                    obj = (List) JSONObject.parseObject(jsonStr).get(argsPath);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return obj;
    }

    // 递归获取object
    private Object getObject(Object m, String key, TypeEnum type) {
        if (m == null) {
            System.out.println("over...");
            return null;
        }
        // 返回的对象
        Object o = null;

        Map mp = null;
        List ls = null;
        try {
            // 第二层只会出现{}或[]
            //{}对象层级递归遍历解析
            if (m instanceof Map) {
                mp = (Map) m;
                for (Iterator ite = mp.entrySet().iterator(); ite.hasNext(); ) {
                    Map.Entry e = (Map.Entry) ite.next();

                    //  e  : json中的key-value
                    // key : 传入的path
                    if (i < key.split("\\.").length && e.getKey().equals(key.split("\\.")[i])) {
                        i++;
                        if (e.getValue() instanceof String) {
                            //递归最后一次
                            if (i == key.split("\\.").length) {
                                o = e.getValue();
                                i = 0;
                                return o;
                            }
                        } else if (e.getValue() instanceof Map) {
                            //递归最后一次
                            if (i == key.split("\\.").length) {
                                if (type == TypeEnum.MAP) {
                                    o = (Map) e.getValue();
                                    i = 0;
                                    return o;
                                }
                            } else {
                                o = getObject((Map) e.getValue(), key, type);
                            }
                            return o;
                        } else if (e.getValue() instanceof List) {
                            //递归最后一次
                            if (i == key.split("\\.").length) {
                                if (type == TypeEnum.LIST) {
                                    o = (List) e.getValue();
                                    i = 0;
                                    return o;
                                }
                            } else {
                                o = getObject((List) e.getValue(), key, type);
                            }
                            return o;
                        }
                    }
                }
            }
            //[]数组层级递归遍历解析
            // 获取[]数据时,只能直接获取所有[]数据
            if (m instanceof List) {
                ls = (List) m;
                for (int i = 0; i < ls.size(); i++) {
                    if (ls.get(i) instanceof Map) {
                        //递归最后一次
                        if (i == key.split("\\.").length) {
                            if (type == TypeEnum.MAP) {
                                o = (Map) ls.get(i);
                                return o;
                            }
                        } else {
                            o = getObject((Map) ls.get(i), key, type);
                        }
                        return o;
                    } else if (ls.get(i) instanceof List) {
                        //递归最后一次
                        if (i == key.split("\\.").length) {
                            if (type == TypeEnum.LIST) {
                                o = (List) ls.get(i);
                                return o;
                            }

                        } else {
                            o = getObject((List) ls.get(i), key, type);
                        }
                        return o;
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return o;
    }

    /**
     * JSON数据解析返回数据类型枚举,我将value归为3类
     */
    public enum TypeEnum {
        STRING,
        MAP,
        LIST;
    }
}

补充:对于数组类型的数据,我认为在实际工作中很少会出现我只获取第一个或者某一个数组种数据的情况,所以该测试代码中如果想要获取的目标数据是一个数组,那么得到的结果就是一整个数组数据。





三、测试

测试效果图:

name对应的直接是一个string类型的value

friends对应的是list里面嵌套的map

mobian对应的是一个list,就list中的单个元素而言,它又是一个map,map里面的arr参数对应的又是一个list



JSON代码如下:

{
	"_id": "5973782bdb9a930533b05cb2",
	"isActive": true,
	"balance": "$1,446.35",
	"age": 32,
	"eyeColor": "green",
	"name": "Logan Keller",
	"gender": "male",
	"company": "ARTIQ",
	"email": "logankeller@artiq.com",
	"phone": "+1 (952) 533-2258",
	"friends": [{
		"id": 0,
		"name": "Colon Salazar"
	}, {
		"id": 1,
		"name": "French Mcneil"
	}, {
		"id": 2,
		"name": "Carol Martin"
	}],
	"mobian": [{
		"id": 0,
		"name": "Colon Salazar",
		"arr": [{
			"id": 0,
			"name": "Colon Salazar"
		}]
	}],
	"favoriteFruit": "banana"
}



我认为该方法可以当作一个工具方法来使用,现在对于层级很深的数据,我也只需要一行就能解决数据的获取问题,而不再需要一层一层的往下嵌套处理。

若干年后,你离职了,上面的方法有bug,你成功的给同事埋了一个雷,同事打开版本控制工具,看到提交人,大骂一声,xxx垃圾玩意儿。

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-11-28 11:22:04  更:2021-11-28 11:23:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:42:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码