杰瑞科技汇

Java JSON字符串格式如何规范与校验?

JSON 字符串的基本格式

要明确一点:JSON 字符串 本质上是一个用单引号或双引号包裹的、符合 JSON 规范的 普通 Java 字符串

Java JSON字符串格式如何规范与校验?-图1
(图片来源网络,侵删)

它的格式完全遵循 JSON (JavaScript Object Notation) 的标准,核心是键值对的集合。

基本结构

  1. 对象: 使用花括号 表示,是一个无序的“键/值”对集合。

    • 键必须是字符串(必须用双引号 包裹)。
    • 值可以是字符串、数字、布尔值、数组、对象,甚至是 null
    • 键值对之间用逗号 分隔。
  2. 数组: 使用方括号 [] 表示,是一个有序的值列表。

    • 数组中的值可以是字符串、数字、布尔值、数组、对象,甚至是 null
    • 值之间用逗号 分隔。

数据类型示例

一个典型的 JSON 字符串可能包含以下几种数据类型:

Java JSON字符串格式如何规范与校验?-图2
(图片来源网络,侵删)
{
  "name": "张三",
  "age": 30,
  "isStudent": false,
  "address": {
    "city": "北京",
    "street": "中关村大街1号"
  },
  "courses": [
    "Java编程",
    "数据库原理",
    "计算机网络"
  ],
  "phone": null
}

在 Java 中的表现形式

在 Java 代码中,这个 JSON 结构会被表示为一个 String 类型,为了可读性,通常会进行格式化(缩进和换行)。

String jsonString = "{\n" +
    "  \"name\": \"张三\",\n" +
    "  \"age\": 30,\n" +
    "  \"isStudent\": false,\n" +
    "  \"address\": {\n" +
    "    \"city\": \"北京\",\n" +
    "    \"street\": \"中关村大街1号\"\n" +
    "  },\n" +
    "  \"courses\": [\n" +
    "    \"Java编程\",\n" +
    "    \"数据库原理\",\n" +
    "    \"计算机网络\"\n" +
    "  ],\n" +
    "  \"phone\": null\n" +
    "}";

关键点:

  • 整个 JSON 结构是一个字符串,所以最外层用双引号 包裹。
  • JSON 内部的字符串(如 "张三")也必须用双引号 包裹。
  • 在 Java 字符串中,双引号 是一个特殊字符,需要用反斜杠 \ 进行转义,即 \"
  • JSON 中没有 charlongDate 等类型,它们会被表示为字符串、数字或特定格式的字符串。

如何在 Java 中处理 JSON 字符串

手动拼接 JSON 字符串非常繁琐且容易出错,在实际开发中,我们通常使用成熟的 JSON 库来完成 Java 对象与 JSON 字符串之间的转换。

最主流的三个库是:

  1. Jackson: 性能最好,功能最强大,是 Spring Boot 的默认选择。
  2. Gson: Google 出品,API 简洁易用,对复杂类型的处理非常友好。
  3. Fastjson: 阿里巴巴出品,解析速度极快,但在早期版本中存在一些安全漏洞,新版本已修复。

下面我们分别介绍这三个库的使用方法。

示例 Java 对象

为了演示,我们先创建一个与上面 JSON 结构对应的 Java 类(POJO)。

// Address.java
public class Address {
    private String city;
    private String street;
    // Getters, Setters, toString() 等方法...
    // 为了简洁,这里省略,实际开发中必须添加
}
// Student.java
public class Student {
    private String name;
    private int age;
    private boolean isStudent;
    private Address address;
    private List<String> courses;
    private String phone;
    // Getters, Setters, toString() 等方法...
    // 为了简洁,这里省略,实际开发中必须添加
}

1 使用 Jackson

添加 Maven 依赖:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version> <!-- 使用最新稳定版本 -->
</dependency>

将 Java 对象 转换为 JSON 字符串 (序列化)

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonExample {
    public static void main(String[] args) {
        // 1. 创建 ObjectMapper 实例
        ObjectMapper objectMapper = new ObjectMapper();
        // 2. 创建 Java 对象
        Address address = new Address();
        address.setCity("北京");
        address.setStreet("中关村大街1号");
        Student student = new Student();
        student.setName("张三");
        student.setAge(30);
        student.setStudent(false);
        student.setAddress(address);
        student.setCourses(Arrays.asList("Java编程", "数据库原理", "计算机网络"));
        student.setPhone(null);
        try {
            // 3. 将对象转换为 JSON 字符串
            // objectMapper.writeValueAsString() 会将对象序列化为紧凑格式的 JSON 字符串
            String jsonString = objectMapper.writeValueAsString(student);
            System.out.println("紧凑格式:");
            System.out.println(jsonString);
            // 4. 格式化输出 (美化 JSON)
            // 使用 writerWithDefaultPrettyPrinter() 可以生成格式化的、易读的 JSON
            String prettyJsonString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(student);
            System.out.println("\n格式化输出:");
            System.out.println(prettyJsonString);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
}

将 JSON 字符串 转换为 Java 对象 (反序列化)

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonExample {
    public static void main(String[] args) {
        String jsonString = "{\"name\":\"张三\",\"age\":30,\"isStudent\":false,\"address\":{\"city\":\"北京\",\"street\":\"中关村大街1号\"},\"courses\":[\"Java编程\",\"数据库原理\",\"计算机网络\"],\"phone\":null}";
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            // 将 JSON 字符串转换为 Student 对象
            Student student = objectMapper.readValue(jsonString, Student.class);
            System.out.println(student);
            System.out.println("学生姓名: " + student.getName());
            System.out.println("所在城市: " + student.getAddress().getCity());
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
}

2 使用 Gson

添加 Maven 依赖:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.10.1</version> <!-- 使用最新稳定版本 -->
</dependency>

将 Java 对象 转换为 JSON 字符串 (序列化)

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class GsonExample {
    public static void main(String[] args) {
        // 1. 创建 Gson 实例
        // 默认是紧凑格式
        Gson gson = new Gson();
        // 创建一个可以格式化输出的 Gson 实例
        Gson prettyGson = new GsonBuilder().setPrettyPrinting().create();
        // 2. 创建 Java 对象 (同上)
        Address address = new Address();
        address.setCity("北京");
        address.setStreet("中关村大街1号");
        Student student = new Student();
        student.setName("张三");
        student.setAge(30);
        student.setStudent(false);
        student.setAddress(address);
        student.setCourses(Arrays.asList("Java编程", "数据库原理", "计算机网络"));
        student.setPhone(null);
        // 3. 将对象转换为 JSON 字符串
        String jsonString = gson.toJson(student);
        System.out.println("紧凑格式:");
        System.out.println(jsonString);
        String prettyJsonString = prettyGson.toJson(student);
        System.out.println("\n格式化输出:");
        System.out.println(prettyJsonString);
    }
}

将 JSON 字符串 转换为 Java 对象 (反序列化)

import com.google.gson.Gson;
public class GsonExample {
    public static void main(String[] args) {
        String jsonString = "{\"name\":\"张三\",\"age\":30,\"isStudent\":false,\"address\":{\"city\":\"北京\",\"street\":\"中关村大街1号\"},\"courses\":[\"Java编程\",\"数据库原理\",\"计算机网络\"],\"phone\":null}";
        Gson gson = new Gson();
        // 将 JSON 字符串转换为 Student 对象
        Student student = gson.fromJson(jsonString, Student.class);
        System.out.println(student);
        System.out.println("学生姓名: " + student.getName());
        System.out.println("所在城市: " + student.getAddress().getCity());
    }
}

最佳实践和注意事项

  1. 永远不要手动拼接 JSON

    • 可读性差:代码像一团乱麻。
    • 易出错:忘记转义引号、逗号,导致 JSON 格式错误。
    • 维护困难:增删字段时修改成本高。
    • 正确做法:定义好 Java 实体类,使用 Jackson/Gson 等库进行序列化和反序列化。
  2. 处理日期和时间

    • JSON 本身没有日期类型,默认情况下,Jackson/Gson 会将日期序列化为时间戳(如 1678886400000)或 ISO-8601 格式的字符串(如 "2025-03-15T10:00:00Z")。
    • 如果需要自定义格式,可以使用注解:
      • Jackson: @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
      • Gson: @SerializedName("create_time") 和自定义 TypeAdapter
  3. 处理循环引用

    • 如果两个对象相互引用(如 A 包含 BB 又包含 A),在序列化时会无限递归,最终导致 StackOverflowError
    • 解决方案
      • Jackson: 使用 @JsonIgnore 注解在其中一个引用上,或者使用 @JsonManagedReference@JsonBackReference
      • Gson: 使用 ExclusionStrategy 或自定义 TypeAdapter 来处理。
  4. 处理 null

    • 默认情况下,序列化时会包含 null 字段(如 "phone": null)。
    • 如果希望省略 null 字段,可以这样配置:
      • Jackson: objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
      • Gson: new GsonBuilder().serializeNulls().create(); (默认包含,excludeFieldsWithModifiers() 可以排除)
  5. 安全性

    • JSON 数据来源于不可信的用户(如网络请求),要警惕 反序列化攻击,攻击者可能会构造恶意的 JSON 数据,导致服务器在反序列化时执行任意代码。
    • 解决方案
      • Jackson: 使用 ObjectMapper.enableDefaultTyping()@JsonTypeInfo 等功能时要非常小心,它们可能带来风险,最佳实践是禁用默认类型,只反序列化已知的、可信的类型。
      • Fastjson: 旧版有严重漏洞,建议升级到最新版本并遵循其安全配置指南。
      • 通用做法: 对输入数据进行严格的校验和过滤。
特性 手动拼接 Jackson Gson
易用性 极差
性能 - 优秀 良好
功能 - 非常强大 功能齐全
集成度 - Spring Boot 默认 需要手动集成
推荐场景 不推荐 企业级应用、Spring Boot 项目首选 简单项目、Google 生态项目

对于任何严肃的 Java 项目,强烈推荐使用 JacksonGson 这样的专业库来处理 JSON,这能让你从繁琐且易错的字符串操作中解放出来,专注于业务逻辑本身。

分享:
扫描分享到社交APP
上一篇
下一篇