如何优雅解析多层嵌套的复杂JSON数据

我们在平时开发中经常会涉及调用某个REST接口从而获取对应数据的情况,在这个过程中,返回的数据往往都是JSON数据,一般情况下,我们都会针对这些JSON数据定义对应实体类,从而获取我们需要的数据。这种方式对于结构简单的JSON数据是OK的,但是如果遇到下面这种多级嵌套的数据就比较蛋疼了:

json 复制代码
{  
    "a1": {    
        "b1": {      
            "c1": {        
                "d1": "d1"      
            }    
        }  
    },  
    "a2": {    
        "b2": {      
            "c2": {        
                "d2": ["i1","i2","i3"]      
            }    
        }  
    }
}

那么对于这种情况,有没有比较优雅的处理方式呢?

什么是OGNL表达式

OGNL全称 "对象图导航语言",我们可以使用其提供的表达式语言获取JAVA对象树中的任意属性或调用其方法。不仅如此,它还能自动实现必要的类型转换,废话不多说,我们来看看如何使用吧。

如何使用

首先引入所需的maven依赖,主要包括jackson和ognl

xml 复制代码
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>  
    <artifactId>jackson-core</artifactId>  
    <version>2.11.4</version>
</dependency>
<dependency>  
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>  
    <version>2.11.4</version>
</dependency>
<dependency>  
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.11.4</version>
</dependency>        
<dependency>  
    <groupId>ognl</groupId>  
    <artifactId>ognl</artifactId>  
    <version>3.1.26</version>
</dependency>

封装JSON反序列化与数据提取的方法

我们封装两个方法:

  • parse:将JSON数据反序列化为Map对象;
  • getValue:使用OGNL表达式从Map中提取数据;
java 复制代码
public class JsonUtils {    
    private static Logger logger = Logger.getLogger("JsonUtils");
    private final static ObjectMapper objectMapper = new ObjectMapper();    
    
    public static ObjectMapper getInstance() {        
        return objectMapper;    
    }
    
    public static <T> T parse(String jsonStr, Class<T> clazz) throws Exception {        
        return getInstance().readValue(jsonStr, clazz);    
    }
    
    public static <T> T getValue(Map map, String path, Class<T> klass) throws Exception {        
        OgnlContext ctx = new OgnlContext();        
        ctx.setRoot(map);        
        T value = (T) Ognl.getValue(path, ctx, ctx.getRoot());  
        return value;    
    }
}

测试

java 复制代码
public class Demo {
    public static void main(String[] args) throws Exception{        
        String jsonData = "{"a1":{"b1":{"c1":{"d1":"d1"}}},"a2":{"b2":{"c2":{"d2":["i1","i2","i3"]}}}}";

        Map<String, Object> map = JsonUtils.parse(jsonData, Map.class);
        String s = JsonUtils.getValue(map, "a1.b1.c1.d1", String.class);     
        System.out.println(s);
        List<String> list = JsonUtils.getValue(map, "a2.b2.c2.d2", List.class);        
        System.out.println(list);    
    }
}

我们就以开篇展示的多层JSON数据为例进行演示,其中"a1.b1.c1.d1"将取到值为"d1"的字符串数据,"a2.b2.c2.d2"将取到一个列表,运行代码,我们可得到如下结果:

csharp 复制代码
d1
[i1, i2, i3]

小结

我们通过Demo可以看到,使用Ognl表达式可以使我们代码变得更加精炼,避免构造各种复杂实体类的尴尬,关于OGNL的更多用法,小伙伴们可以自行学习。

相关推荐
独泪了无痕9 小时前
探索Pinyin4j-Java中的拼音转换利器
java·后端
道尔柯南11 小时前
C++ string 类详解:从常用接口到深拷贝,彻底掌握字符串处理
android·java·c++
kingx312 小时前
Bugku 3122 谷歌小恐龙题解:纯离线逆向 Vault 的 AES-GCM 加密资源(附 Python 解密器)
java·逆向·ctf·bugku·aes-gcm
DevOpenClub14 小时前
职教高考控制线 API:招生类别枚举、筛选与空分数含义
java·数据库·高考
露天赏雪15 小时前
第3篇:Sentinel熔断降级实战:大模型接口抖动时的服务兜底方案
java·开发语言·人工智能·spring boot·spring·servlet·sentinel
天天被压力15 小时前
【A股分钟级高频数据完全手册 #06】北交所分钟级数据接口:京市股票Pro版最新分时
java·人工智能·python
天天被压力15 小时前
【A股分钟级高频数据完全手册 #05】指数历史分钟数据接口:Pro版沪深指数分时回放
java·人工智能·python
captain37615 小时前
▲统一功能——DispatcherServlet源码分析
java·spring·java-ee·log4j·maven
金銀銅鐵15 小时前
JDK 21 中 List.of 的实现细节:从 List12 到 ListN
java·后端·ai编程
yeccheng17 小时前
MySQL 索引超详解:从底层 B+ 树到面试高频考点
java·开发语言·jvm·mysql·面试