Spring Boot 处理JSON的方法
简述
从基础的File/InputStream/byte[]数据转换,到URL资源直接解析;从动态Map集合的安全处理,到树模型JsonNode的灵活应用;再到ObjectNode动态构建JSON和JsonParser流式处理超大文件
1. 解析File & InputStream & byte转对象
在日常开发中,我们通常会将 JSON 字符串转换为对象。实际上,Jackson 库的功能十分强大,它支持将多种格式的数据转换为对象。接下来,本文将详细介绍如何使用 Jackson 把 File、InputStream 以及 byte[] 这几种格式的数据转换为对象。
private final ObjectMapper objectMapper;
public ApiController(ObjectMapper objectMapper) {this.objectMapper = objectMapper;
}
@GetMapping("/file")
public ResponseEntity<?> file() throws Exception {ClassPathResource resource = new ClassPathResource("book.json") ;// 1.通过JSON文件对象转换到对象// return ResponseEntity.ok(this.objectMapper.readValue(resource.getFile(), Book.class)) ;// 2.通过InputStream转换到对象// return ResponseEntity.ok(this.objectMapper.readValue(resource.getInputStream(), Book.class)) ;// 3.通过byte[]转换到对象return ResponseEntity.ok(this.objectMapper.readValue(resource.getContentAsByteArray(), Book.class)) ;
}
ObjectMapper#readValue方法有非常多的重载方法,可以将非常多的格式转换为对象。
2.通过URL转换为对象
如果你有一个URL返回的是JSON字符串,那么你可以直接通过ObjectMapper对象将返回的数据转换为对象,如下示例:
@GetMapping("/url")
public ResponseEntity<?> url() throws Exception {URL url = URI.create("http://localhost:8080/api/file").toURL() ;return ResponseEntity.ok(this.objectMapper.readValue(url, Book.class)) ;
}
3.安全的转换为Map集合
在实际开发中,经常会遇到需要解析 JSON 字符串但没有预先定义的实体类(POJO)的情况。此时,使用 Map 是一种灵活且常用的解决方案。然而,直接使用原始类型会导致类型不安全和潜在的运行时错误。
@GetMapping("/map")
public ResponseEntity<?> map() throws Exception {String json = "{\"id\":666,\"title\":\"Spring Boot3实战案例200讲\",\"author\":\"Pack_xg\",\"price\":70}";// ❌ 通过此种方式我们不能指定泛型类型,如果强制转换会报错// Map map = this.objectMapper.readValue(json, Map.class) ;// ✅ 通过此种方式可以指定Map的泛型类型;没有类型安全警告Map<String, Object> map = this.objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {}) ;return ResponseEntity.ok(map) ;
}
用 TypeReference 为 Map 注入泛型灵魂,让 Jackson 精准解析动态 JSON。
4.使用JsonNode提前字段
JsonNode 是 Jackson 提供的树模型节点,用于表示 JSON 元素。适用于解析未知结构、动态字段、部分提取或验证 JSON,灵活高效。
private final RestTemplate restTemplate ;@GetMapping("/jsonnode")
public ResponseEntity<?> jsonnode() throws Exception {URI uri = URI.create("http://localhost:8080/api/file") ;JsonNode jsonNode = this.restTemplate.getForObject(uri, JsonNode.class) ;return ResponseEntity.ok(Map.of("id", jsonNode.get("id").asLong(), "title", jsonNode.get("title").asText(),"author", jsonNode.get("author").asText(),"price", jsonNode.get("price").asDouble())) ;
}
结合 RestTemplate 可直接将 HTTP 响应解析为 JsonNode,便于灵活提取字段,避免创建实体类,适用于轻量级、动态或部分数据提取场景。
5.动态添加JSON字段
在构建动态 API 响应、日志数据组装或配置生成时,常需在运行时动态添加、修改或删除 JSON 字段。ObjectNode 作为 Jackson 的可变 JSON 节点,支持灵活的增删改操作,避免创建固定实体类,提升开发效率与代码适应性。
@GetMapping("/objectnode")
public ResponseEntity<?> objectnode() throws Exception {ObjectNode objectNode = this.objectMapper.createObjectNode();objectNode.put("id", 1L) ;objectNode.put("name", "Pack_xg");objectNode.put("age", 33) ;return ResponseEntity.ok(objectNode) ;
}
通过ObjectNode对象,非常适用于动态构建或修改 JSON。通过 put 添加字段,灵活生成响应,无需实体类,适合动态数据处理场景。
6.使用JsonParser自定义解析器
当你需要处理超大JSON时,可通过JsonParser流式处理防内存溢出、需精细控制字段解析/跳过、低层Token操作、特殊类型定制处理及未知字段灵活处理的场景,比反序列化更轻量高效。
@GetMapping("/jsonparser")
public ResponseEntity<Map<String, Object>> jsonparser() throws Exception {String json = """{"id": 666,"title": "Spring Boot3实战案例200讲","author": "Pack_xg","price": 70,"publishDate": "2023-01-01"}""";// 存储解析结果的MapMap<String, Object> result = new HashMap<>();try (JsonParser parser = new ObjectMapper().createParser(json)) {if (parser.nextToken() != JsonToken.START_OBJECT) {throw new IllegalStateException("Expected data to start with an object");}while (parser.nextToken() != JsonToken.END_OBJECT) {String fieldName = parser.currentName();parser.nextToken(); // 移动到字段值switch (fieldName) {case "id" -> result.put(fieldName, parser.getIntValue());case "title", "author" -> result.put(fieldName, parser.getText());case "price" -> result.put(fieldName, parser.getDecimalValue());default -> result.put(fieldName, parser.getValueAsString()); // 兜底处理};}}return ResponseEntity.ok(result);
}