SpringBoot使用JSONPath实现高效处理JSON数据

 更新时间:2026年01月15日 11:51:52   作者:风象南  
在日常开发中,我们经常需要处理 JSON 数据,特别是从复杂的 JSON 结构中提取特定字段,下面我们就来看看如何使用SpringBoot和JSONPath实现处理JSON数据吧

前言

在日常开发中,我们经常需要处理 JSON 数据,特别是从复杂的 JSON 结构中提取特定字段。传统的处理方式如 Gson、Jackson 的 API 虽然功能强大,但在处理复杂路径提取时代码往往显得冗长且不易维护。

今天给大家介绍一个更优雅的解决方案 —— JSONPath,它就像 JSON 界的 XPath,让我们可以用简洁的路径表达式来定位和提取 JSON 数据。

什么是 JSONPath

JSONPath 是一种用于从 JSON 文档中提取特定数据的查询语言。它的语法简洁直观,类似于 JavaScript 对象属性的访问方式。

常用 JSONPath 语法

表达式说明
$根节点
@当前节点
. 或 []子节点操作符
..递归下降(任意深度)
*通配符,匹配所有成员/元素
[]下标运算符
[start:end]数组切片
[?()]过滤表达式

Spring Boot 集成 JSONPath

1. 添加依赖

pom.xml 中添加 JSONPath 依赖:

<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <version>2.9.0</version>
</dependency>

2. 基础使用示例

首先准备一个 JSON 示例:

{
  "store": {
    "book": [
      {
        "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      {
        "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      },
      {
        "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  }
}

读取数据

import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.PathNotFoundException;

public class JsonPathExample {

    private String json = "..."; // 上述 JSON 字符串

    @Test
    public void testReadJson() {
        // 获取所有书籍的作者
        List<String> authors = JsonPath.parse(json)
            .read("$.store.book[*].author");

        // 获取第一本书的价格
        Double price = JsonPath.parse(json)
            .read("$.store.book[0].price");

        // 获取所有价格低于10元的书籍
        List<Map> cheapBooks = JsonPath.parse(json)
            .read("$.store.book[?(@.price < 10)]");

        // 获取最后一本书
        Map lastBook = JsonPath.parse(json)
            .read("$.store.book[-1]");
    }
}

在 Spring Boot 中的实际应用

import org.springframework.web.bind.annotation.*;
import com.jayway.jsonpath.JsonPath;

@RestController
@RequestMapping("/api")
public class BookController {

    @PostMapping("/extract")
    public ResponseEntity<?> extractData(@RequestBody String jsonString) {
        try {
            // 提取所有书籍标题
            List<String> titles = JsonPath.parse(jsonString)
                .read("$.store.book[*].title");

            // 提取价格区间内的书籍
            List<Map> books = JsonPath.parse(jsonString)
                .read("$.store.book[?(@.price >= 8 && @.price <= 12)]");

            return ResponseEntity.ok(Map.of(
                "titles", titles,
                "filteredBooks", books
            ));
        } catch (PathNotFoundException e) {
            return ResponseEntity.badRequest()
                .body("JSON路径不存在: " + e.getMessage());
        }
    }

    @GetMapping("/authors")
    public ResponseEntity<?> getAuthors(@RequestParam String jsonData) {
        List<String> authors = JsonPath.parse(jsonData)
            .read("$.store.book[*].author");
        return ResponseEntity.ok(authors);
    }
}

3. 高级用法

自定义配置

import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.Option;

@Configuration
public class JsonPathConfig {

    public Configuration jsonPathConfiguration() {
        return Configuration.builder()
            // 抑制异常,返回 null
            .options(Option.SUPPRESS_EXCEPTIONS)
            // 默认值为空集合
            .options(Option.DEFAULT_PATH_LEAF_TO_NULL)
            // 总是返回列表
            .options(Option.ALWAYS_RETURN_LIST)
            // 缓存
            .options(Option.CACHE)
            .build();
    }
}

缓存解析结果

@Service
public class JsonPathCacheService {

    private final Map<String, Object> cache = new ConcurrentHashMap<>();

    public Object readWithCache(String json, String path) {
        return JsonPath.using(Configuration.defaultConfiguration())
            .parse(json)
            .read(path);
    }

    // 预编译路径,提升性能
    private final JsonPath compiledPath = JsonPath.compile("$.store.book[*]");

    public List<Map> readOptimized(String json) {
        return compiledPath.read(json);
    }
}

与 REST 调用结合

@Service
public class ExternalApiService {

    private final RestTemplate restTemplate;

    public List<String> extractFromExternalApi(String url, String jsonPath) {
        String response = restTemplate.getForObject(url, String.class);
        return JsonPath.parse(response).read(jsonPath);
    }
}

过滤表达式详解

// 价格大于10的书籍
$.store.book[?(@.price > 10)]

// category 为 fiction 的书籍
$.store.book[?(@.category == 'fiction')]

// 包含 isbn 字段的书籍
$.store.book[?(@.isbn)]

// 正则匹配
$.store.book[?(@.author =~ /.*Melville.*/)]

// 多条件组合
$.store.book[?(@.price < 10 && @.category == 'fiction')]

除了 Jayway JsonPath,常见的 JSON 处理库也有各自的 JSONPath 或类似功能实现。

FastJSON - 内置 JSONPath

FastJSON内置了 JSONPath 支持,使用起来非常简洁。

添加依赖

<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.53</version>
</dependency>

使用示例

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONPath;
import com.alibaba.fastjson2.JSONObject;

public class FastJsonPathExample {

    private String json = "..."; // 同上 JSON 示例

    @Test
    public void testFastJsonPath() {
        JSONObject object = JSON.parseObject(json);

        // 获取所有书籍作者
        List<String> authors = (List<String>) JSONPath.eval(object, "$.store.book[*].author");

        // 获取第一本书价格
        Double price = (Double) JSONPath.eval(object, "$.store.book[0].price");

        // 过滤价格小于10的书籍
        List books = (List) JSONPath.eval(object, "$.store.book[?(@.price < 10)]");

        // size 方法
        Integer size = (Integer) JSONPath.eval(object, "$.store.book.size()");

        // 获取所有包含 isbn 的书籍
        List booksWithIsbn = (List) JSONPath.eval(object, "$.store.book[?(@.isbn)]");
    }
}

FastJSON JSONPath 多种查询方式

FastJSON 提供了多种查询方式,适应不同场景:

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONPath;
import com.alibaba.fastjson2.JSONObject;

public class FastJsonPathQueryExample {

    private JSONObject object = JSON.parseObject(json);

    @Test
    public void testDifferentQueryMethods() {

        // ========== 方式一:JSONPath.eval(静态方法,最常用)==========
        List authors1 = (List) JSONPath.eval(object, "$.store.book[*].author");


        // ========== 方式二:JSONPath.of + extract(推荐,性能更好)==========
        // 预编译路径表达式,性能更优(适合重复使用)
        JSONPath path = JSONPath.of("$.store.book[*].author");
        List authors2 = (List) path.extract(object);


        // ========== 方式三:compile + eval(另一种编译方式)==========
        JSONPath compiledPath = JSONPath.compile("$.store.book[*].author");
        List authors3 = (List) compiledPath.eval(object);


        // ========== 方式四:路径对象直接调用 set(修改操作)==========
        JSONPath pricePath = JSONPath.of("$.store.book[0].price");
        pricePath.set(object, 88.88);


        // ========== 方式五:contains(判断是否包含路径)==========
        boolean hasBook = JSONPath.contains(object, "$.store.book");
        boolean hasIsbn = JSONPath.contains(object, "$.store.book[2].isbn");


        // ========== 方式六:size(获取数组大小)==========
        Integer arraySize = (Integer) JSONPath.eval(object, "$.store.book.size()");
        // 或者使用编译后的路径
        JSONPath sizePath = JSONPath.of("$.store.book.size()");
        Integer size = (Integer) sizePath.eval(object);
    }
}

FastJSON JSONPath 修改操作

FastJSON 的 JSONPath 不仅可以读取数据,还支持修改数据,这是它的一个强大特性。

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONPath;
import com.alibaba.fastjson2.JSONObject;

public class FastJsonPathModifyExample {

    @Test
    public void testJsonPathSet() {
        JSONObject object = JSON.parseObject(json);

        // 修改第一本书的价格
        JSONPath.set(object, "$.store.book[0].price", 99.99);

        // 修改自行车的颜色
        JSONPath.set(object, "$.store.bicycle.color", "blue");

        // 批量修改所有书籍价格
        JSONPath.set(object, "$.store.book[*].price", 15.88);

        // 修改包含 isbn 的书籍的 category
        JSONPath.set(object, "$.store.book[?(@.isbn)].category", "classic");

        // 添加新字段
        JSONPath.set(object, "$.store.book[0].publisher", "Tech Press");

        // 数组末尾添加元素(通过路径获取数组后操作)
        JSONArray bookArray = (JSONArray) JSONPath.eval(object, "$.store.book");
        bookArray.add(JSON.parseObject("{\"title\":\"New Book\",\"price\":9.99}"));

        // 删除字段
        JSONPath.remove(object, "$.store.bicycle");

        System.out.println(JSON.toJSONString(object));
    }
}

FastJSON JSONPath 其他操作

// 获取集合大小
Integer size = (Integer) JSONPath.eval(object, "$.store.book.size()");

// 获取集合第一个
Object first = JSONPath.eval(object, "$.store.book.first()");

// 获取集合最后一个
Object last = JSONPath.eval(object, "$.store.book.last()");

// 获取属性所有值
Collection values = (Collection) JSONPath.eval(object, "$.store.book.values()");

Jackson - JsonPointer / Jackson JsonPath

Jackson 原生支持 JsonPointer (RFC 6901),但不是完整的 JSONPath 实现。若要使用 JSONPath 功能,可以通过以下两种方式:

方式一:使用 JsonPointer(原生支持)

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.18.2</version>
</dependency>
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonPointer;

public class JacksonJsonPointerExample {

    private String json = "...";
    private ObjectMapper mapper = new ObjectMapper();

    @Test
    public void testJsonPointer() throws Exception {
        JsonNode root = mapper.readTree(json);

        // 使用 JsonPointer 定位节点
        JsonPointer ptr = JsonPointer.compile("/store/book/0/author");
        JsonNode authorNode = root.at(ptr);
        String author = authorNode.asText();

        // 链式写法
        String title = root.at("/store/book/1/title").asText();
        Double price = root.at("/store/bicycle/price").asDouble();
    }
}

JsonPointer 限制

  • 语法较简单,不支持通配符、过滤表达式
  • 无法一次获取多个值
  • 不支持数组切片

方式二:使用 Jackson-JsonPath(第三方扩展)

<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <version>2.9.0</version>
</dependency>
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;

public class JacksonJsonPathExample {

    // 配置使用 Jackson
    private Configuration configuration = Configuration.builder()
        .jsonProvider(new JacksonJsonNodeJsonProvider())
        .mappingProvider(new JacksonMappingProvider())
        .build();

    @Test
    public void testJacksonJsonPath() {
        List<String> authors = JsonPath.using(configuration)
            .parse(json)
            .read("$.store.book[*].author");
    }
}

Gson - 无原生 JSONPath

Gson 本身不提供 JSONPath 支持,这是 Gson 的一个局限。建议搭配 Jayway JsonPath 使用。

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.11.0</version>
</dependency>

<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <version>2.9.0</version>
</dependency>
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.jayway.jsonpath.JsonPath;

public class GsonJsonPathExample {

    private Gson gson = new Gson();
    private String json = "...";

    @Test
    public void testGsonWithJsonPath() {
        // 使用 JsonPath 提取数据
        List<String> authors = JsonPath.parse(json)
            .read("$.store.book[*].author");

        // 将结果转回 Gson 对象
        JsonElement element = gson.toJsonTree(authors);
    }
}

三种方案对比

特性FastJSONJackson + JsonPointerJayway JsonPath
JSONPath 支持原生支持仅 JsonPointer完整支持
过滤表达式支持不支持支持
通配符支持不支持支持
性能优秀优秀良好
生态稳定性曾有安全漏洞最稳定社区活跃
Spring Boot 集成需手动配置默认集成需添加依赖

选型建议

  • 已有 FastJSON 项目:直接使用 FastJSON 的 JSONPath
  • 使用 Jackson 的项目:简单场景用 JsonPointer,复杂场景引入 Jayway JsonPath
  • 使用 Gson 的项目:建议搭配 Jayway JsonPath 使用
  • 新项目:推荐 Jackson + Jayway JsonPath 组合

总结

JSONPath 是处理 JSON 数据的利器,通过简洁的路径表达式实现复杂字段提取、条件过滤和动态查询。在 Spring Boot 中集成 JSONPath 可大幅简化代码、提升可读性,是处理复杂 JSON 结构和第三方 API 数据的一种可选技术方案。

以上就是SpringBoot使用JSONPath实现高效处理JSON数据的详细内容,更多关于SpringBoot处理JSON数据的资料请关注脚本之家其它相关文章!

相关文章

  • Java中LocalDate的详细方法举例总结

    Java中LocalDate的详细方法举例总结

    这篇文章主要给大家介绍了关于Java中LocalDate详细方法举例的相关资料,LocalDate主要是用来处理日期的类,文中通过代码示例介绍的非常详细,需要的朋友可以参考下
    2023-09-09
  • 基于Mybatis-plus实现多租户架构的全过程

    基于Mybatis-plus实现多租户架构的全过程

    多租户是一种软件架构技术,在多用户的环境下,共有同一套系统,并且要注意数据之间的隔离性,下面这篇文章主要给大家介绍了关于基于Mybatis-plus实现多租户架构的相关资料,需要的朋友可以参考下
    2022-02-02
  • Servlet简单实现登录功能

    Servlet简单实现登录功能

    这篇文章主要为大家详细介绍了Servlet简单实现登录功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-03-03
  • Spring Boot设置并使用缓存的步骤

    Spring Boot设置并使用缓存的步骤

    今天小编就为大家分享一篇关于Spring Boot设置并使用缓存的步骤,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • java web实现简单登录注册功能全过程(eclipse,mysql)

    java web实现简单登录注册功能全过程(eclipse,mysql)

    前期我们学习了javaweb项目用JDBC连接数据库,还有数据库的建表功能,下面这篇文章主要给大家介绍了关于java web实现简单登录注册功能的相关资料,需要的朋友可以参考下
    2022-07-07
  • Java中使用数组实现栈数据结构实例

    Java中使用数组实现栈数据结构实例

    这篇文章主要介绍了Java中使用数组实现栈数据结构实例,本文先是讲解了实现栈至少应该包括以下几个方法等知识,然后给出代码实例,需要的朋友可以参考下
    2015-01-01
  • CyclicBarrier之多线程中的循环栅栏详解

    CyclicBarrier之多线程中的循环栅栏详解

    这篇文章主要介绍了CyclicBarrier之多线程中的循环栅栏的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-05-05
  • 浅谈Java8对字符串连接的改进正确姿势

    浅谈Java8对字符串连接的改进正确姿势

    这篇文章主要介绍了Java8:对字符串连接的改进,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • mybatisPlus中批量删除的示例代码

    mybatisPlus中批量删除的示例代码

    本文主要介绍了mybatisPlus中批量删除的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • Java语言的11大特点(Java初学者必知)

    Java语言的11大特点(Java初学者必知)

    Java是一种简单的,面向对象的,分布式的,解释型的,健壮安全的,结构中立的,可移植的,性能优异、多线程的静态语言。这篇文章主要介绍了Java语言的11大特点,需要的朋友可以参考下
    2020-07-07

最新评论