0

0

如何在 Java 中动态生成 JsonPath 表达式(无需硬编码)

聖光之護

聖光之護

发布时间:2026-01-07 14:53:29

|

620人浏览过

|

来源于php中文网

原创

如何在 Java 中动态生成 JsonPath 表达式(无需硬编码)

本文介绍如何根据运行时用户筛选条件(如国家代码、房间数等)动态构建合法、安全的 jsonpath 表达式,避免字符串拼接风险,提升可维护性与灵活性。

在实际企业级 JSON 数据处理场景中,前端常需向后端传递动态筛选条件(例如:国家代码为 "IN" 或 "ENG",且公寓房间数为 1 或 2),而后端需据此生成对应的 JsonPath 表达式对原始 JSON 进行过滤。若直接使用字符串拼接(如 "$.countries[?(@.country.countryCode=='IN')].building[?(@.floor[?(@.apartment[?(@.rooms==1)])])]")不仅易出错、难维护,还存在注入与语法错误风险。

推荐采用 语义化构建 + 第三方库辅助 的方式实现动态 JsonPath 生成。以下以主流库 Jayway JsonPath 为例(Maven 依赖:com.jayway.jsonpath:json-path:2.9.0),展示专业、可扩展的实现方案:

✅ 正确做法:基于 Criteria 构建可组合过滤器

Jayway JsonPath 提供了 Filter 和 Criteria API,支持链式构建逻辑表达式,避免手写复杂字符串:

SekoTalk
SekoTalk

商汤科技推出的AI对口型视频创作工具

下载
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.Filter;
import com.jayway.jsonpath.Criteria;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;

import java.util.Arrays;
import java.util.List;

public class DynamicJsonPathGenerator {

    /**
     * 动态生成 JsonPath 过滤表达式
     * @param countryCodes 允许的国家代码列表(如 ["IN", "ENG"])
     * @param roomNumbers  允许的房间数列表(如 [1, 2])
     * @return 完整的 JsonPath 字符串(兼容 $.countries[*].country.* 结构)
     */
    public static String generateJsonPath(List<String> countryCodes, List<Integer> roomNumbers) {
        // Step 1: 构建国家码匹配条件(嵌套在 countries[*].country 下)
        Criteria countryCriteria = Criteria.where("country.countryCode").in(countryCodes.toArray());

        // Step 2: 构建房间数匹配条件(深层嵌套:building[*].floor[*].apartment[*].rooms)
        // 注意:JsonPath 中需用 '..' 或显式路径;此处按原始结构展开
        String roomCondition = String.format(
            "building[*].floor[*].apartment[*].rooms in %s",
            roomNumbers.toString().replace("[", "[").replace("]", "]")
        );

        // Step 3: 组合为完整 Filter(注意:Jayway 的 Filter 不直接支持多层嵌套 in,建议分步或改用 Predicate)
        // 更健壮方式:使用 DocumentContext 配合自定义 Predicate(见下方进阶示例)
        return "$.countries[?(@." + countryCriteria.toString() + ")]"
                + ".[" + roomCondition + "]";
    }

    // ✅ 推荐进阶方案:使用 Predicate 实现类型安全、可调试的动态过滤
    public static <T> List<T> filterJsonByDynamicCriteria(String json, List<String> countryCodes, List<Integer> roomNumbers) {
        Configuration config = Configuration.defaultConfiguration();
        DocumentContext ctx = JsonPath.parse(json, config);

        // 自定义 Predicate —— 完全可控、可单元测试、无字符串注入风险
        Predicate<Object> predicate = item -> {
            if (!(item instanceof Map)) return false;
            Map<?, ?> countryMap = (Map<?, ?>) item;
            Object countryCodeObj = getNestedValue(countryMap, "country", "countryCode");
            if (countryCodeObj == null || !countryCodes.contains(countryCodeObj.toString())) {
                return false;
            }

            Object buildingsObj = getNestedValue(countryMap, "country", "building");
            if (!(buildingsObj instanceof List)) return false;

            for (Object building : (List<?>) buildingsObj) {
                if (!(building instanceof Map)) continue;
                Object floorsObj = getNestedValue((Map<?, ?>) building, "floor");
                if (!(floorsObj instanceof List)) continue;

                for (Object floor : (List<?>) floorsObj) {
                    if (!(floor instanceof Map)) continue;
                    Object apartmentsObj = getNestedValue((Map<?, ?>) floor, "apartment");
                    if (!(apartmentsObj instanceof List)) continue;

                    for (Object apt : (List<?>) apartmentsObj) {
                        if (!(apt instanceof Map)) continue;
                        Object roomsObj = getNestedValue((Map<?, ?>) apt, "rooms");
                        if (roomsObj instanceof Number && roomNumbers.contains(((Number) roomsObj).intValue())) {
                            return true; // 找到匹配项
                        }
                    }
                }
            }
            return false;
        };

        return ctx.parseJson()
                .read("$.countries[?]", List.class)
                .stream()
                .filter(predicate)
                .map(Object::toString)
                .map(s -> (T) s)
                .toList();
    }

    // 辅助方法:安全获取嵌套 Map 值
    private static Object getNestedValue(Map<?, ?> map, String... keys) {
        Object result = map;
        for (String key : keys) {
            if (result instanceof Map && ((Map<?, ?>) result).containsKey(key)) {
                result = ((Map<?, ?>) result).get(key);
            } else {
                return null;
            }
        }
        return result;
    }
}

⚠️ 注意事项与最佳实践

  • 避免纯字符串拼接:"$.countries[" + index + "]" 类方式极易引发越界或语法错误,且无法校验 JSON 结构合法性;
  • 优先使用 Predicate + DocumentContext.read():比生成 JsonPath 字符串更灵活、更易调试,尤其适合复杂嵌套与运行时逻辑;
  • 输入校验不可少:对 countryCodes、roomNumbers 等参数做空值、非法字符(如 ', ], *)过滤,防止恶意构造;
  • 性能考量:若数据量极大,建议预编译 JsonPath(JsonPath.compile(path))并复用;
  • 替代方案参考:对简单场景,也可结合 Jackson 的 JsonNode 遍历 + 条件判断,语义更清晰。

✅ 总结

动态生成 JsonPath 的本质不是“拼字符串”,而是将业务筛选逻辑映射为可执行的、类型安全的过滤策略。借助 Jayway JsonPath 的 Predicate 或 Jackson 的树模型遍历,不仅能彻底规避硬编码,还能保障健壮性、可测性与长期可维护性。在微服务与低代码平台中,此类能力是构建动态 API 查询能力的关键基础设施。

立即学习Java免费学习笔记(深入)”;

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

452

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

546

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

326

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

81

2025.09.10

Java Maven专题
Java Maven专题

本专题聚焦 Java 主流构建工具 Maven 的学习与应用,系统讲解项目结构、依赖管理、插件使用、生命周期与多模块项目配置。通过企业管理系统、Web 应用与微服务项目实战,帮助学员全面掌握 Maven 在 Java 项目构建与团队协作中的核心技能。

0

2025.09.15

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

678

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

219

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1561

2023.10.24

Golang 测试体系与代码质量保障:工程级可靠性建设
Golang 测试体系与代码质量保障:工程级可靠性建设

Go语言测试体系与代码质量保障聚焦于构建工程级可靠性系统。本专题深入解析Go的测试工具链(如go test)、单元测试、集成测试及端到端测试实践,结合代码覆盖率分析、静态代码扫描(如go vet)和动态分析工具,建立全链路质量监控机制。通过自动化测试框架、持续集成(CI)流水线配置及代码审查规范,实现测试用例管理、缺陷追踪与质量门禁控制,确保代码健壮性与可维护性,为高可靠性工程系统提供质量保障。

48

2026.02.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.1万人学习

C# 教程
C# 教程

共94课时 | 10.6万人学习

Java 教程
Java 教程

共578课时 | 75.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号