根据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垃圾玩意儿。

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
好的,以下是 Java 代码示例来获取 JSON 字符串的所有 keyvalue: ```java import org.json.simple.JSONObject; import org.json.simple.JSONArray; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; public class JsonUtil { public static void main(String[] args) throws ParseException { String jsonStr = "{\"name\":\"John\", \"age\":30, \"car\":null, \"hobbies\":[\"reading\",\"music\"]}"; JSONObject jsonObj = (JSONObject) new JSONParser().parse(jsonStr); JSONObject result = new JSONObject(); getKeysAndValues(jsonObj, result); System.out.println(result.toJSONString()); } private static void getKeysAndValues(JSONObject jsonObj, JSONObject result) { for (Object key : jsonObj.keySet()) { Object value = jsonObj.get(key); result.put(key, value); if (value instanceof JSONObject) { getKeysAndValues((JSONObject) value, result); } else if (value instanceof JSONArray) { getKeysAndValuesFromJsonArray((JSONArray) value, result); } } } private static void getKeysAndValuesFromJsonArray(JSONArray jsonArray, JSONObject result) { for (Object obj : jsonArray) { if (obj instanceof JSONObject) { getKeysAndValues((JSONObject) obj, result); } else if (obj instanceof JSONArray) { getKeysAndValuesFromJsonArray((JSONArray) obj, result); } } } } ``` 这个示例使用了 JSON.simple 库来解析 JSON 字符串。它递归遍历 JSON 对象和数组,并将所有 keyvalue 存储在一个新的 JSONObject 。你可以根据你的需要修改这个示例,比如将 JSONObject 替换成 Map,等等。注意,这个示例假设 JSON 没有循环引用,否则会进入死循环。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

默辨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值