Java案例怎么解析JSON数据?

wen java案例 10

Java案例怎么解析JSON数据?从入门到实战的完整指南

目录导读

  1. JSON数据与Java解析概述
  2. 主流Java JSON解析库对比
  3. 实战案例:使用Jackson解析JSON数据
  4. 实战案例:使用Gson解析JSON数据
  5. 复杂JSON结构解析技巧
  6. JSON解析常见问题与性能优化
  7. 扩展阅读:JSON Schema验证与Spring Boot集成

JSON数据与Java解析概述

JSON(JavaScript Object Notation)已成为Web API和现代应用中最主流的数据交换格式,在Java开发中,解析JSON数据是每个开发者必须掌握的技能,无论你是处理REST API响应、读取配置文件还是对接第三方服务,理解如何高效解析JSON都至关重要。

Java案例怎么解析JSON数据?

为什么需要解析JSON?
Java是强类型语言,而JSON是轻量级文本格式,解析过程本质上是将JSON字符串映射为Java对象,或将Java对象转换为JSON字符串(序列化与反序列化)。

核心概念

  • 序列化:Java对象 → JSON字符串
  • 反序列化:JSON字符串 → Java对象
  • 树模型:将JSON解析为树形结构(如JsonNode)
  • 流式解析:逐令牌处理,适合超大JSON

常见应用场景

  • 微服务间通信
  • 移动端与后端数据交互
  • 日志文件分析
  • 配置管理

主流Java JSON解析库对比

在选择解析库时,需要综合考虑性能、易用性、社区活跃度,以下是三大主流库的详细对比:

特性 Jackson Gson Fastjson
性能排名 第一梯队 第二梯队 第一梯队(但存在安全争议)
学习曲线 中等
自定义能力 极强(通过注解和模块) 中等(通过TypeAdapter) 中等
增强功能 YAML、XML、CSV支持
社区活跃度 最高(Spring Boot默认) 高(Google出品) 中等(阿里出品)
安全漏洞 曾出现高危漏洞

推荐选择标准

  • 新项目优先选择Jackson(Spring Boot生态支持)
  • 简单项目或老系统维护可继续使用Gson
  • Fastjson建议仅用于已知安全加固的旧项目

实战案例:使用Jackson解析JSON数据

环境准备
在pom.xml中添加依赖:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version>
</dependency>

案例1:解析简单JSON对象
假设有以下JSON:

{"name":"张三","age":28,"email":"zhangsan@example.com"}

Java实现:

import com.fasterxml.jackson.databind.ObjectMapper;
public class SimpleParse {
    public static void main(String[] args) throws Exception {
        String json = "{\"name\":\"张三\",\"age\":28,\"email\":\"zhangsan@example.com\"}";
        ObjectMapper mapper = new ObjectMapper();
        // 方式一:直接反序列化为Map
        Map<String, Object> map = mapper.readValue(json, Map.class);
        System.out.println("姓名: " + map.get("name"));
        // 方式二:反序列化为自定义对象
        User user = mapper.readValue(json, User.class);
        System.out.println("年龄: " + user.getAge());
    }
}

User类定义:

public class User {
    private String name;
    private int age;
    private String email;
    // getters/setters 省略(必须提供)
}

案例2:解析JSON数组

[{"city":"北京","temp":30},{"city":"上海","temp":35}]
String jsonArrayStr = "[{\"city\":\"北京\",\"temp\":30},{\"city\":\"上海\",\"temp\":35}]";
List<Weather> weatherList = mapper.readValue(jsonArrayStr, 
    new TypeReference<List<Weather>>(){});

核心技巧

  • 使用@JsonProperty注解处理字段名不一致问题
  • 对于未知字段使用@JsonIgnoreProperties(ignoreUnknown = true)
  • 处理空对象使用@JsonInclude(Include.NON_NULL)
  • 处理日期格式使用@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")

实战案例:使用Gson解析JSON数据

添加依赖

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

案例:解析嵌套JSON

{
  "code": 200,
  "message": "success",
  "data": {
    "list": [
      {"id": 1, "name": "产品A", "price": 99.9}
    ],
    "total": 1
  }
}

Java代码:

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class GsonNestedParse {
    public static void main(String[] args) {
        String complexJson = "..."; // 上述JSON字符串
        Gson gson = new Gson();
        // 解析为Map
        Map<String, Object> result = gson.fromJson(complexJson, Map.class);
        Map<String, Object> data = (Map<String, Object>) result.get("data");
        List<Map<String, Object>> list = (List<Map<String, Object>>) data.get("list");
        // 推荐方式:解析为泛型对象
        ApiResponse<DataResponse> response = gson.fromJson(complexJson, 
            new TypeToken<ApiResponse<DataResponse>>(){}.getType());
    }
}

Gson特殊场景处理

  • 处理null值:GsonBuilder().serializeNulls()
  • 日期格式:GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss")
  • 排除字段:使用@Expose注解配合GsonBuilder().excludeFieldsWithoutExposeAnnotation()

复杂JSON结构解析技巧

场景1:动态字段名
有时JSON的键名是动态生成的,如:

{"user_123":{"name":"测试"},"user_456":{"name":"示例"}}

解决方案:

Map<String, User> dynamicMap = mapper.readValue(json, 
    new TypeReference<Map<String, User>>(){});

场景2:深度嵌套与循环引用
使用@JsonManagedReference和@JsonBackReference处理双向关联,或启用循环引用检测:

ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.disable(SerializationFeature.FAIL_ON_SELF_REFERENCES);

场景3:超大JSON流式解析
当JSON文件超过内存限制时,使用JsonParser流式处理:

JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(new File("huge.json"));
while (parser.nextToken() != JsonToken.END_OBJECT) {
    String fieldName = parser.getCurrentName();
    if ("data".equals(fieldName)) {
        parser.nextToken(); // 进入数组
        while (parser.nextToken() != JsonToken.END_ARRAY) {
            // 逐条处理
        }
    }
}

JSON解析常见问题与性能优化

问题1:日期格式解析失败
不同系统可能使用不同日期格式,建议统一使用ISO 8601格式,并配置:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

问题2:忽略null值
传输大量null字段浪费带宽,配置Jackson全局忽略null:

mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

问题3:安全防范

  • 禁用Jackson的enableDefaultTyping()(防止反序列化攻击)
  • 使用Gson时设置GsonBuilder().disableHtmlEscaping()
  • 验证JSON输入长度,避免拒绝服务攻击

性能优化建议

  • 复用ObjectMapper实例(线程安全)
  • 使用字节流而非字符流处理大文件
  • 根据场景选择树模型或流模型
  • 开启Jackson的SMALL_AS_TEXT或者FAST模式

扩展阅读:JSON Schema验证与Spring Boot集成

JSON Schema验证
使用networknt的json-schema-validator库:

<dependency>
    <groupId>com.networknt</groupId>
    <artifactId>json-schema-validator</artifactId>
    <version>1.0.74</version>
</dependency>

验证示例:

JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4);
JsonSchema schema = factory.getSchema(new File("schema.json"));
ProcessingReport report = schema.validate(JsonLoader.fromString(jsonData));

Spring Boot中的JSON处理
Spring Boot自动配置了Jackson,只需在Controller中使用@RequestBody注解:

@PostMapping("/user")
public ResponseEntity<User> createUser(@RequestBody @Valid User user) {
    // 参数已自动反序列化
    return ResponseEntity.ok(userService.save(user));
}

配置Jackson行为
在application.yml中:

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: Asia/Shanghai
    serialization:
      write-dates-as-timestamps: false
    deserialization:
      fail-on-unknown-properties: false

问答环节

Q1:Jackson和Gson哪个更适合初学者?
A:Gson的学习曲线更低,API更直观,但考虑到Jackson是Spring Boot的默认解析器,建议初学者优先学习Jackson,后期迁移成本更低。

Q2:解析JSON时出现UnrecognizedPropertyException如何解决?
A:在POJO类上添加@JsonIgnoreProperties(ignoreUnknown = true)注解,或在ObjectMapper中配置mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)。

Q3:如何解析带下划线的JSON字段到驼峰命名的Java属性?
A:使用@JsonProperty("user_name")注解,或全局配置命名策略:mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)。

Q4:JSON解析性能和安全哪个更重要?
A:对于中小型应用(JSON小于10MB),性能差异可以忽略,安全性应优先考虑,建议始终禁用自动类型绑定,并限制JSON输入大小。

Q5:如何处理JSON中的超大数字导致精度丢失问题?
A:将对应字段类型改为BigDecimal,或使用Jackson的@JsonFormat(shape = JsonFormat.Shape.STRING)将数字序列化为字符串。

抱歉,评论功能暂时关闭!