🎉🎉《Spring Boot实战案例合集》目前已更新186个案例,我们将持续不断的更新。文末有电子书目录。
💪💪永久更新承诺
我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务。
💌💌如何获取
订阅我们的合集《点我订阅》,并通过私信联系我们,我们将第一时间将电子书发送给您。
环境:SpringBoot3.4.2
1. 简介
本篇文章将介绍使用Jackson库处理JSON数据的多种高级技术,涵盖了JSON解析、查询、序列化/反序列化控制等核心功能。主要实现了以下能力:
JSON路径查询:通过findValue()和at()方法实现嵌套JSON结构的深度查询
多值提取:支持批量获取相同名称的多个值
视图控制:使用@JsonView实现字段级序列化控制,区分公开和内部视图
动态属性处理:通过@JsonAnySetter/Getter处理未知字段,实现灵活的动态对象
对象展开:使用@JsonUnwrapped将嵌套对象属性扁平化到父级
原始JSON保留:通过@JsonRawValue保持字符串字段的原始JSON格式
这些功能组合构成了强大的JSON数据处理能力,适用于API开发、配置解析、数据转换等场景,特别适合需要灵活处理复杂JSON结构的Java应用程序。
2.1 findValue查找值
Jackson中的findValue()方法允许我们在JSON树中搜索特定键值并获取其关联的值。首先,我们将使用ObjectMapper将JSON字符串转换为JsonNode,从而创建JSON数据的树形表示:
@Testpublic void test1() throws Exception {String json = """{"user": {"id": 1,"name": "Pack_xg","details": {"email": "pack@gmail.com","phone": "18999999999"}}}""" ;ObjectMapper mapper = new ObjectMapper();JsonNode rootNode = mapper.readTree(json) ;String email = rootNode.findValue("email").asText();System.err.println(email) ;}
输出结果
pack@gmail.com
2.2 优雅处理缺失的键
在处理 JSON 时,我们可能会遇到键值缺失的情况。当 JSON 结构中找不到指定键时,findValue() 方法将返回 null。如下示例:
@Testpublic void test2() throws Exception {String json = """{"user": {"id": 1,"name": "Pack_xg","details": {"phone": "18999999999"}}}""" ;ObjectMapper mapper = new ObjectMapper();JsonNode rootNode = mapper.readTree(json);JsonNode emailNode = rootNode.findValue("email");System.err.println(emailNode) ;}
输出结果
null
在此示例中,findValue("email") 返回 null,因为 JSON 中不存在 email 键。
2.3 使用 findValues() 方法处理数组
findValues方法查找指定名称的JSON对象字段的方法——包括直接子值和后代值——并将找到的字段作为List返回。
@Testpublic void test3() throws Exception {String json = """{"users": [{ "id": 1, "name": "pack", "details": { "email": "pack@gmail.com" } },{ "id": 2, "name": "xg", "details": { "email": "xg@qq.com" } }]}""";ObjectMapper mapper = new ObjectMapper();JsonNode rootNode = mapper.readTree(json);List<String> emails = rootNode.findValues("email").stream().map(JsonNode::asText).toList() ;System.err.println(emails) ;}
输出结果
[pack@gmail.com, xg@qq.com]
2.4 处理深度嵌套的key
与其在JSON结构中通过名称查找键值,我们可使用at()方法定位深层嵌套JSON结构中特定路径下的字段。如下示例:
@Testpublic void test4() throws Exception {String json = """{"company": {"dept": {"team": {"lead": {"name": "Pack_xg","details": {"email": "pack@gmail.com"}}}}}}""" ;ObjectMapper mapper = new ObjectMapper();JsonNode rootNode = mapper.readTree(json);String email = rootNode.at("/company/dept/team/lead/details/email").asText() ;System.err.println(email) ;}
输出结果
pack@gmail.com
此处传递给 at() 方法的路径是一个 JSON 指针,它是一种使用字符串语法遍历 JSON 文档的标准化方式。
2.5 使用@JsonView视图控制字段输出
用于指示由被注解的方法或字段所定义的属性所属视图(一个或多个)的注解。示例注解如下:
该注解指定,被注解的属性在处理(序列化、反序列化)由BasicView.class(或其子类)标识的视图时将被包含。如果包含多个视图类标识符,则该属性将属于所有这些视图。
public class User {public interface PublicView {}public interface InternalView extends PublicView {}private String name;private String email;private String password;}
测试用例
public void test5() throws Exception {User user = new User("Pack_xg", "pack@gmail.com", "123456") ;// 使用ObjectMapper mapper = new ObjectMapper();// 只输出 public 字段String publicJson = mapper.writerWithView(User.PublicView.class).writeValueAsString(user);System.err.println(publicJson) ;// 输出所有字段String internalJson = mapper.writerWithView(User.InternalView.class).writeValueAsString(user);System.err.println(internalJson) ;}
输出结果
{"name":"Pack_xg"}{"name":"Pack_xg","email":"pack@gmail.com","password":"123456"}
关于@JsonView更多用法,请查看下面链接:
绝了!Spring Boot凭@JsonView注解,强大到逆天
2.6 处理未知属性
@JsonAnySetter / @JsonAnyGetter 用于处理 JSON 中可能存在的额外字段,避免反序列化失败。如下示例:
public class DynamicObject {private Long id ;private String name ;private Map<String, Object> properties = new HashMap<>();// ...public void set(String name, Object value) {properties.put(name, value);}public Map<String, Object> getProperties() {return properties;}}
测试用例
@Testpublic void test6() throws Exception {String json = """{"id": 666,"name": "Pack_xg","age": 33,"details": {"phone": "18999999999","addr": "中国"}}""";ObjectMapper objectMapper = new ObjectMapper() ;// 反序列化:未知字段会被 @JsonAnySetter 捕获DynamicObject user = objectMapper.readValue(json, DynamicObject.class);System.out.println(user);// 序列化:properties 中的内容会被 @JsonAnyGetter 写回 JSONString serializedJson = objectMapper.writeValueAsString(user);System.out.println("\n重新序列化后的 JSON:");System.out.println(serializedJson);}
输出结果
2.7 扁平化嵌套对象
将嵌套对象的字段“展开”到外层。
public class Order {private Long id ;private String orderNo ;private Address address ;}public class Address {private String provice;private String city ;private String county ;}
测试用例
public void test7() throws Exception {Order order = new Order(1L, "XP-00001", new Address("新疆", "乌鲁木齐", "天山区")) ;ObjectMapper objectMapper = new ObjectMapper() ;System.err.println(objectMapper.writeValueAsString(order)) ;}
输出结果
{"id" : 1,"orderNo" : "XP-00001","provice" : "新疆","city" : "乌鲁木齐","county" : "天山区"}
2.8 插入原始JSON
@JsonRawValue将一个字符串字段的内容直接作为原始 JSON 片段写入最终的 JSON 输出中,而不是将其转义为字符串。这在你需要嵌入已生成的 JSON 或动态 JSON 结构时非常有用。如下示例:
public class Product {private String name ;private BigDecimal price ;/**json字符串内容*/private String details ;}
测试用例
public void test7() throws Exception {Order order = new Order(1L, "XP-00001", new Address("新疆", "乌鲁木齐", "天山区")) ;ObjectMapper objectMapper = new ObjectMapper() ;objectMapper.enable(SerializationFeature.INDENT_OUTPUT) ;System.err.println(objectMapper.writeValueAsString(order)) ;}
输出结果
{"name" : "Spring Boot3实战案例200讲","price" : 70,"details" : {"author": "pack_xg", "page_count": 1000}}
如果没有@JsonRawValue注解,输出结果如下:
{"name" : "Spring Boot3实战案例200讲","price" : 70,"details" : "{\"author\": \"pack_xg\", \"page_count\": 1000}"}
字符串被转义了。
性能相差60倍!Spring Boot 批量插入你做对了吗?5种方式对比
高级开发!手撕Controller底层调用链,深度功能扩展、性能优化
Spring Boot 请求处理超大JSON数据 3种 方式性能对比
知道太晚了!实时通信新选择fetch-event-source,真香
Spring AI + LangGraph4j 多智能体开发,太强大了!
告别OOM!Spring Boot 流式导出百万数据:支持MyBatis/JPA/Jdbc


