根据key找到JSON字符串中指定的value值(Java实现)

Posted 默辨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了根据key找到JSON字符串中指定的value值(Java实现)相关的知识,希望对你有一定的参考价值。





一、引言

距离上次写接口已经过去了一周,那次接口之旅让我明白打印日志的重要性,于是我自定义了一个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垃圾玩意儿。

以上是关于根据key找到JSON字符串中指定的value值(Java实现)的主要内容,如果未能解决你的问题,请参考以下文章

返回数组中指定的一列

如何根据它在 Java 中指定的版本规范验证 json 模式

react找到对象数组中指定的值

Jmeter中处理json

接口测试学习——Jmeter中处理json

Azure 应用服务:未找到应用程序依赖项清单 (Microsoft.AspNetCore.AzureAppServices.HostingStartup.deps.json) 中指定的程序集