JSON路径工具类`JsonPathUtil`的实现与应用
JSON路径工具类JsonPathUtil的实现与应用
作者:zibo
日期:2024/11/25
口号:慢慢学,不要停。
文章目录
- JSON路径工具类`JsonPathUtil`的实现与应用
- 〇、完整代码
- 一、引言
- 二、功能概述
- 三、代码实现详解
- 1. 工具类基础结构
- 2. 核心方法`getValue`
- 3. 处理表达式片段`processPart`
- 4. 处理数组类型的表达式片段`processArrayPart`
- 5. 获取对象的字段值`getFieldValue`
- 6. 测试主方法`main`
- 四、应用示例
- 五、总结
- 六、后记
〇、完整代码
package com.kumy.requrchase.treasure.service.letusign.impl;import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.Objects;/*** JSON路径工具类* 用于根据表达式获取JSON字符串中的值* 支持以下功能:* 1. 获取普通属性值,如: user.name* 2. 获取数组元素,如: users[0].name* 3. 支持多层嵌套,如: company.department.employees[0].name* * @author zibo* @date 2024/11/25* @slogan 慢慢学,不要停。*/
public class JsonPathUtil {// 定义常量,提高代码可维护性private static final String DOT_SEPARATOR = "\\.";private static final String LEFT_BRACKET = "[";private static final String RIGHT_BRACKET = "]";private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();private JsonPathUtil() {throw new IllegalStateException("工具类不允许实例化");}/*** 根据表达式获取对象的值** @param jsonString JSON字符串,不能为空* @param expression 表达式,不能为空* @return 表达式对应的值* @throws IllegalArgumentException 参数校验异常* @throws Exception 解析异常*/public static Object getValue(String jsonString, String expression) throws Exception {// 参数校验if (Objects.isNull(jsonString) || Objects.isNull(expression)) {throw new IllegalArgumentException("参数不能为空");}// 将 JSON 字符串转换为 Map 对象Map<String, Object> rootObject = OBJECT_MAPPER.readValue(jsonString, new TypeReference<Map<String, Object>>() {});// 分割表达式并处理String[] parts = expression.split(DOT_SEPARATOR);Object currentObject = rootObject;for (String part : parts) {currentObject = processPart(currentObject, part);if (Objects.isNull(currentObject)) {return null;}}return currentObject;}/*** 处理表达式片段* * @param currentObject 当前对象* @param part 表达式片段* @return 处理后的对象* @throws Exception 处理异常*/private static Object processPart(Object currentObject, String part) throws Exception {if (part.contains(LEFT_BRACKET)) {return processArrayPart(currentObject, part);}return getFieldValue(currentObject, part);}/*** 处理数组类型的表达式片段* * @param currentObject 当前对象* @param part 表达式片段* @return 处理后的对象* @throws Exception 处理异常*/private static Object processArrayPart(Object currentObject, String part) throws Exception {String fieldName = part.substring(0, part.indexOf(LEFT_BRACKET));int index = Integer.parseInt(part.substring(part.indexOf(LEFT_BRACKET) + 1, part.indexOf(RIGHT_BRACKET)));Object arrayObject = getFieldValue(currentObject, fieldName);return arrayObject instanceof List ? ((List<?>) arrayObject).get(index) : null;}/*** 获取对象的字段值** @param object 对象,不能为空* @param fieldName 字段名,不能为空* @return 字段值* @throws Exception 反射异常*/@SuppressWarnings("all")private static Object getFieldValue(Object object, String fieldName) throws Exception {if (Objects.isNull(object) || Objects.isNull(fieldName)) {return null;}if (object instanceof Map) {return ((Map<?, ?>) object).get(fieldName);}Field field = object.getClass().getDeclaredField(fieldName);field.setAccessible(true);return field.get(object);}public static void main(String[] args) {try {// 测试JSON字符串String jsonString = "{"+ "\"userInfo\": {"+ "\"id\": 1,"+ "\"photoPath\": \"yx.mm.com\","+ "\"realName\": \"张三\","+ "\"examInfoDict\": ["+ "{\"id\": 1, \"examType\": 0, \"answerIs\": 1},"+ "{\"id\": 2, \"examType\": 0, \"answerIs\": 0}"+ "]"+ "},"+ "\"flag\": 1"+ "}";// 测试不同场景System.out.println("测试普通属性: " + getValue(jsonString, "userInfo.realName")); // 输出张三System.out.println("测试数组访问: " + getValue(jsonString, "userInfo.examInfoDict[0].id")); // 输出1System.out.println("测试空值处理: " + getValue(jsonString, "userInfo.notExist")); // 输出null} catch (Exception e) {System.err.println("处理异常: " + e.getMessage());e.printStackTrace();}}
}
一、引言
在日常的Java开发中,经常需要根据特定的路径或表达式,从JSON字符串中提取所需的数据。虽然市场上有诸如JsonPath等强大的工具可以实现这一需求,但有时候我们需要一个轻量级、可自定义的解决方案。本文将介绍一个自定义实现的JSON路径工具类JsonPathUtil,它可以根据表达式从JSON字符串中获取对应的值,支持获取普通属性、数组元素以及多层嵌套的属性值。
二、功能概述
JsonPathUtil工具类的主要功能包括:
- 获取普通属性值:如
user.name,获取user对象的name属性值。 - 获取数组元素:如
users[0].name,获取users数组中第一个元素的name属性值。 - 支持多层嵌套:如
company.department.employees[0].name,获取嵌套结构中指定员工的姓名。
三、代码实现详解
1. 工具类基础结构
首先,定义了JsonPathUtil工具类,并声明了一些常量:
package com.kumy.requrchase.treasure.service.letusign.impl;import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.Objects;public class JsonPathUtil {private static final String DOT_SEPARATOR = "\\.";private static final String LEFT_BRACKET = "[";private static final String RIGHT_BRACKET = "]";private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();private JsonPathUtil() {throw new IllegalStateException("工具类不允许实例化");}// 其他方法...
}
解析:
- 使用了
ObjectMapper来处理JSON字符串的解析。 - 工具类的构造方法被私有化,防止实例化。
2. 核心方法getValue
getValue方法是工具类的核心,用于根据表达式从JSON字符串中获取对应的值。
public static Object getValue(String jsonString, String expression) throws Exception {// 参数校验if (Objects.isNull(jsonString) || Objects.isNull(expression)) {throw new IllegalArgumentException("参数不能为空");}// 将 JSON 字符串转换为 Map 对象Map<String, Object> rootObject = OBJECT_MAPPER.readValue(jsonString, new TypeReference<Map<String, Object>>() {});// 分割表达式并处理String[] parts = expression.split(DOT_SEPARATOR);Object currentObject = rootObject;for (String part : parts) {currentObject = processPart(currentObject, part);if (Objects.isNull(currentObject)) {return null;}}return currentObject;
}
解析:
- 参数校验:确保
jsonString和expression不为空,否则抛出IllegalArgumentException。 - JSON解析:使用
ObjectMapper将JSON字符串解析为Map<String, Object>类型的rootObject。 - 表达式解析:根据
.分隔符,将表达式拆分为多个部分parts,然后逐一处理每个部分。 - 逐层解析:通过循环,每次处理表达式的一部分,并不断更新
currentObject,直到获取最终的值。
3. 处理表达式片段processPart
该方法用于处理表达式中的每一部分,判断是普通属性还是数组访问。
private static Object processPart(Object currentObject, String part) throws Exception {if (part.contains(LEFT_BRACKET)) {return processArrayPart(currentObject, part);}return getFieldValue(currentObject, part);
}
解析:
- 如果表达式部分包含
[,说明需要处理数组,调用processArrayPart方法。 - 否则,直接调用
getFieldValue获取属性值。
4. 处理数组类型的表达式片段processArrayPart
该方法用于解析数组元素的访问。
private static Object processArrayPart(Object currentObject, String part) throws Exception {String fieldName = part.substring(0, part.indexOf(LEFT_BRACKET));int index = Integer.parseInt(part.substring(part.indexOf(LEFT_BRACKET) + 1, part.indexOf(RIGHT_BRACKET)));Object arrayObject = getFieldValue(currentObject, fieldName);return arrayObject instanceof List ? ((List<?>) arrayObject).get(index) : null;
}
解析:
- 获取字段名和索引:通过字符串操作,提取数组字段名
fieldName和索引index。 - 获取数组对象:使用
getFieldValue方法获取对应的数组对象arrayObject。 - 获取数组元素:检查
arrayObject是否为List的实例,如果是,则返回对应索引的元素。
5. 获取对象的字段值getFieldValue
该方法用于获取当前对象中指定字段的值。
@SuppressWarnings("all")
private static Object getFieldValue(Object object, String fieldName) throws Exception {if (Objects.isNull(object) || Objects.isNull(fieldName)) {return null;}if (object instanceof Map) {return ((Map<?, ?>) object).get(fieldName);}Field field = object.getClass().getDeclaredField(fieldName);field.setAccessible(true);return field.get(object);
}
解析:
- 空值检查:如果
object或fieldName为null,直接返回null。 - 处理Map类型:如果当前对象是
Map,直接获取对应键的值。 - 处理普通对象:使用反射获取对象的字段值,即使字段是私有的(通过
setAccessible(true))。
6. 测试主方法main
编写了一个main方法用于测试工具类的功能。
public static void main(String[] args) {try {// 测试JSON字符串String jsonString = "{"+ "\"userInfo\": {"+ "\"id\": 1,"+ "\"photoPath\": \"yx.mm.com\","+ "\"realName\": \"张三\","+ "\"examInfoDict\": ["+ "{\"id\": 1, \"examType\": 0, \"answerIs\": 1},"+ "{\"id\": 2, \"examType\": 0, \"answerIs\": 0}"+ "]"+ "},"+ "\"flag\": 1"+ "}";// 测试不同场景System.out.println("测试普通属性: " + getValue(jsonString, "userInfo.realName")); // 输出张三System.out.println("测试数组访问: " + getValue(jsonString, "userInfo.examInfoDict[0].id")); // 输出1System.out.println("测试空值处理: " + getValue(jsonString, "userInfo.notExist")); // 输出null} catch (Exception e) {System.err.println("处理异常: " + e.getMessage());e.printStackTrace();}
}
解析:
- 构造了一个包含嵌套对象和数组的JSON字符串。
- 测试了获取普通属性、数组元素以及处理不存在的属性的情况。
- 输出结果验证了工具类的功能。
四、应用示例
为了更清晰地展示JsonPathUtil的应用,下面提供一个实际例子。
示例JSON字符串:
{"employee": {"name": "李华","age": 30,"department": {"name": "研发部","location": "北京"},"skills": [{"name": "Java", "level": "高级"},{"name": "Python", "level": "中级"}]}
}
示例代码:
String jsonString = "{...}"; // 如上所示的JSON字符串// 获取员工姓名
String name = (String) JsonPathUtil.getValue(jsonString, "employee.name");
System.out.println("员工姓名:" + name); // 输出:员工姓名:李华// 获取部门名称
String departmentName = (String) JsonPathUtil.getValue(jsonString, "employee.department.name");
System.out.println("部门名称:" + departmentName); // 输出:部门名称:研发部// 获取第一项技能的名称
String firstSkill = (String) JsonPathUtil.getValue(jsonString, "employee.skills[0].name");
System.out.println("第一项技能:" + firstSkill); // 输出:第一项技能:Java// 尝试获取不存在的属性
Object nonExistent = JsonPathUtil.getValue(jsonString, "employee.address");
System.out.println("不存在的属性:" + nonExistent); // 输出:不存在的属性:null
解析:
- 使用
JsonPathUtil.getValue方法,根据不同的表达式,成功获取了嵌套对象和数组中的值。 - 当尝试获取不存在的属性时,方法返回
null,程序没有抛出异常,这体现了对异常情况的良好处理。
五、总结
本文详细介绍了JsonPathUtil工具类的实现原理和应用。通过逐步解析代码,我们了解到:
- 如何解析复杂的JSON路径表达式,包括嵌套属性和数组元素。
- 使用
ObjectMapper将JSON字符串转换为可操作的Java对象。 - 通过反射和类型检查,实现了对
Map和普通Java对象的字段访问。
优点:
- 轻量级:不依赖于第三方库,适合对JSON路径解析需求不复杂的场景。
- 易于理解和扩展:代码简洁明了,方便根据需求进行定制。
不足:
- 功能有限:不支持复杂的表达式,如过滤条件、通配符等。
- 性能考虑:对于大规模的JSON数据和高并发场景,可能需要优化或选择性能更优的方案。
建议:
- 对于简单的JSON解析需求,可以直接使用
JsonPathUtil工具类。 - 如果需要更高级的JSON路径功能,建议使用专业的JSON路径解析库,如Jayway的JsonPath。
- JsonPath 开源地址:https://github.com/json-path/JsonPath
- 在线语法检查:https://jsonpath.com/
六、后记
“慢慢学,不要停。”在编程的道路上,理解每一段代码背后的原理,都能让我们走得更远。希望通过本文的讲解,能帮助到有需要的读者,加深对JSON解析和Java反射的理解。
感谢阅读!
相关文章:
JSON路径工具类`JsonPathUtil`的实现与应用
JSON路径工具类JsonPathUtil的实现与应用 作者:zibo 日期:2024/11/25 口号:慢慢学,不要停。 文章目录 JSON路径工具类JsonPathUtil的实现与应用〇、完整代码一、引言二、功能概述三、代码实现详解1. 工具类基础结构2. 核心方法get…...
人名分类器(nlp)
# coding: utf-8 import osos.environ[KMP_DUPLICATE_LIB_OK] True# 导入torch工具 import jsonimport torch # 导入nn准备构建模型 import torch.nn as nn import torch.nn.functional as F import torch.optim as optim # 导入torch的数据源 数据迭代器工具包 from torch.ut…...
斐波那契数列 相关问题 详解
斐波那契数列相关问题详解 斐波那契数列及其相关问题是算法学习中的经典主题,变形与应用非常广泛,涵盖了递推关系、动态规划、组合数学、数论等多个领域。以下是斐波那契数列的相关问题及其解法的详解。 1. 经典斐波那契数列 定义 初始条件࿱…...
Pytorch微调深度学习模型
在公开数据训练了模型,有时候需要拿到自己的数据上微调。今天正好做了一下微调,在此记录一下微调的方法。用Pytorch还是比较容易实现的。 网上找了很多方法,以及Chatgpt也给了很多方法,但是不够简洁和容易理解。 大体步骤是&…...
springboot 使用笔记
1.springboot 快速启动项目 注意:该启动只是临时启动,不能关闭终端面板 cd /www/wwwroot java -jar admin.jar2.脚本启动 linux shell脚本启动springboot服务 3.java一键部署springboot 第5条 https://blog.csdn.net/qq_30272167/article/details/1…...
网络安全基础——网络安全法
填空题 1.根据**《中华人民共和国网络安全法》**第二十条(第二款),任何组织和个人试用网路应当遵守宪法法律,遵守公共秩序,遵守社会公德,不危害网络安全,不得利用网络从事危害国家安全、荣誉和利益,煽动颠…...
SCAU软件体系结构实验四 组合模式
目录 一、题目 二、源码 一、题目 个人(Person)与团队(Team)可以形成一个组织(Organization):组织有两种:个人组织和团队组织,多个个人可以组合成一个团队,不同的个人与团队可以组合成一个更大的团队。 使用控制台或者JavaFx界面…...
Amazon商品详情API接口:电商创新与用户体验的驱动力
在电子商务蓬勃发展的今天,作为全球最大的电商平台之一,亚马逊(Amazon)凭借其强大的技术实力和丰富的商品资源,为全球用户提供了优质的购物体验。其中,Amazon商品详情API接口在电商创新与用户体验提升方面扮…...
手机无法连接服务器1302什么意思?
你有没有遇到过手机无法连接服务器,屏幕上显示“1302”这样的错误代码?尤其是在急需使用手机进行工作或联系朋友时,突然出现的连接问题无疑会带来不少麻烦。那么,什么是1302错误,它又意味着什么呢? 1302错…...
Android adb shell dumpsys audio 信息查看分析详解
Android adb shell dumpsys audio 信息查看分析详解 一、前言 Android 如果要分析当前设备的声音通道相关日志, 仅仅看AudioService的日志是看不到啥日志的,但是看整个audio关键字的日志又太多太乱了, 所以可以看一下系统提供的一个调试指令…...
Python 网络爬虫操作指南
网络爬虫是自动化获取互联网上信息的一种工具。它广泛应用于数据采集、分析以及实现信息聚合等众多领域。本文将为你提供一个完整的Python网络爬虫操作指南,帮助你从零开始学习并实现简单的网络爬虫。我们将涵盖基本的爬虫概念、Python环境配置、常用库介绍。 上传…...
基于FPGA的2FSK调制-串口收发-带tb仿真文件-实际上板验证成功
基于FPGA的2FSK调制 前言一、2FSK储备知识二、代码分析1.模块分析2.波形分析 总结 前言 设计实现连续相位 2FSK 调制器,2FSK 的两个频率为:fI15KHz,f23KHz,波特率为 1500 bps,比特0映射为f 载波,比特1映射为 载波。 1)…...
JavaScript的基础数据类型
一、JavaScript中的数组 定义 数组是一种特殊的对象,用于存储多个值。在JavaScript中,数组可以包含不同的数据类型,如数字、字符串、对象、甚至其他数组。数组的创建有两种常见方式: 字面量表示法:let fruits [apple…...
第三讲 架构详解:“隐语”可信隐私计算开源框架
目录 隐语架构 隐语架构拆解 产品层 算法层 计算层 资源层 互联互通 跨域管控 本文主要是记录参加隐语开源社区推出的第四期隐私计算实训营学习到的相关内容。 隐语架构 隐语架构拆解 产品层 产品定位: 通过可视化产品,降低终端用户的体验和演…...
JDBC编程---Java
目录 一、数据库编程的前置 二、Java的数据库编程----JDBC 1.概念 2.JDBC编程的优点 三.导入MySQL驱动包 四、JDBC编程的实战 1.创造数据源,并设置数据库所在的位置,三条固定写法 2.建立和数据库服务器之间的连接,连接好了后ÿ…...
Python绘制太极八卦
文章目录 系列目录写在前面技术需求1. 图形绘制库的支持2. 图形绘制功能3. 参数化设计4. 绘制控制5. 数据处理6. 用户界面 完整代码代码分析1. rset() 函数2. offset() 函数3. taiji() 函数4. bagua() 函数5. 绘制过程6. 技术亮点 写在后面 系列目录 序号直达链接爱心系列1Pyth…...
Spring框架特性及包下载(Java EE 学习笔记04)
1 Spring 5的新特性 Spring 5是Spring当前最新的版本,与历史版本对比,Spring 5对Spring核心框架进行了修订和更新,增加了很多新特性,如支持响应式编程等。 更新JDK基线 因为Spring 5代码库运行于JDK 8之上,所以Spri…...
Linux关于vim的笔记
Linux关于vim的笔记:(vimtutor打开vim 教程) --------------------------------------------------------------------------------------------------------------------------------- 1. 光标在屏幕文本中的移动既可以用箭头键,也可以使用 hjkl 字母键…...
linux mount nfs开机自动挂载远程目录
要在Linux系统中实现开机自动挂载NFS共享目录,你需要编辑/etc/fstab文件。以下是具体步骤和示例: 确保你的系统已经安装了NFS客户端。如果没有安装,可以使用以下命令安装: sudo apt-install nfs-common 编辑/etc/fstab文件&#…...
【vue】导航守卫
什么是导航守卫 在vue路由切换过程中对行为做个限制 全局前置守卫 route.beforeEach((to, from, next)) > {// to是切换到的路由// from是正要离开的路由// next控制是否允许进入目标路由next(false); //不允许 }路由级别的导航守卫 const routes [{path: /User,name: U…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态
前言 在人工智能技术飞速发展的今天,深度学习与大模型技术已成为推动行业变革的核心驱动力,而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心,系统性地呈现了两部深度技术著作的精华:…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
