JSON-框架的具体使用

非 SpringBoot 项目

Jackson

Jackson 是另一个流行的JSON 序列化和反序列化库,具有以下特点

  • 速度快:Jackson 采用了高效的JSON 解析算法和字节码生成技术,使得其序列化和反序列化速度非常快。
  • 支持全类型序列化:Jackson 能够序列化所有类型的对象,包括复杂类型和自定义类型。
  • 功能强大:Jackson 提供了很多高级特性,如 JSON 映射、注解和 JSON 树模型等,使得其在企业级应用中得到广泛应用。
  • 依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    <!-- 测试 JSON 框架时项目所有依赖 -->
    <dependencies>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.26</version>
    </dependency>
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>compile</scope>
    </dependency>
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.13.0</version>
    </dependency>
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.0</version>
    </dependency>
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.13.0</version>
    </dependency>
    </dependencies>
  • 使用示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package org.example.demo;

    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    public class JacksonExample {

    public static void main(String[] args) throws JsonProcessingException {
    // 将 Java 对象转换为 JSON 字符串
    User user = new User("Tom", 18);
    ObjectMapper mapper = new ObjectMapper();
    String json = mapper.writeValueAsString(user);
    System.out.println(json); // {"name":"Tom","age":18}

    // 将 JSON 字符串转换为 Java 对象
    String jsonStr = "{\"name\":\"Tom\",\"age\":18}";
    User user2 = mapper.readValue(jsonStr, User.class);
    System.out.println(user2.getName() + " " + user2.getAge()); // Tom 18
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    static class User {
    private String name;
    private int age;
    }
    }

Gson

GsonGoogle 提供的 JSON 序列化和反序列化库。Gson 也是一个非常流行的 JSON 序列化和反序列化库,具有以下特点

  • 简单易用:Gson 的使用非常简单,只需要在项目中引入 gson.jar,即可开始使用。

  • 高度灵活性:Gson 可以很方便地处理各种类型的对象,包括 Java 8 的新特性,如LocalDate LocalDateTime

  • 扩展性强:Gson 提供了很多扩展点,可以方便地进行自定义扩展。

  • 依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <!-- 测试 JSON 框架时项目所有依赖 -->
    <dependencies>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.26</version>
    </dependency>
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>compile</scope>
    </dependency>
    <dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.9</version>
    </dependency>
    </dependencies>

  • 使用示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package org.example.demo;

    import com.google.gson.Gson;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    public class GsonExample {

    public static void main(String[] args) {
    // 将 Java 对象转换为 JSON 字符串
    User user = new User("Tom", 18);
    Gson gson = new Gson();
    String json = gson.toJson(user);
    System.out.println(json); // {"name":"Tom","age":18}
    // 将 JSON 字符串转换为 Java 对象
    String jsonStr = "{\"name\":\"Tom\",\"age\":18}";
    User user2 = gson.fromJson(jsonStr, User.class);
    System.out.println(user2.getName() + " " + user2.getAge()); // Tom 18
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    static class User {
    private String name;
    private int age;

    }
    }

Fastjson

Fastjson 是阿里巴巴开源的 JSON 序列化和反序列化库,由于其高效性和稳定性,成为目前使用最广泛的 JSON 序列化和反序列化库之一。以下是 Fastjson 的主要特点

  • 高性能:Fastjson 采用了许多优化措施,如字节码生成和对象池,使得其反序列化速度非常快,序列化速度也很快。

  • 支持全类型序列化:Fastjson 能够序列化所有类型的对象,包括复杂类型和自定义类型。

  • 兼容性好:Fastjson 支持 JSON 标准规范,并且与其他 JSON 库兼容。

  • 使用方便:Fastjson 的使用非常简单,几乎不需要配置,只需要在项目中引入 fastjson.jar,即可开始使用。

  • 依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <dependencies>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.26</version>
    </dependency>
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>compile</scope>
    </dependency>
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.78</version>
    </dependency>
    </dependencies>
  • 用法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    package org.example.demo;

    import com.alibaba.fastjson.JSON;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    public class FastjsonExample {

    public static void main(String[] args) {
    // 将 Java 对象转换为 JSON 字符串
    User user = new User("Tom", 18);
    String json = JSON.toJSONString(user);
    System.out.println(json); // {"age":18,"name":"Tom"}

    // 将 JSON 字符串转换为 Java 对象
    String jsonStr = "{\"age\":18,\"name\":\"Tom\"}";
    User user2 = JSON.parseObject(jsonStr, User.class);
    System.out.println(user2.getName() + " " + user2.getAge()); // Tom 18
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    static class User {
    private String name;
    private int age;
    }
    }

SpringBoot项目中使用

Jackson

  • 介绍

    Spring Boot 中,JSON 序列化和反序列化默认使用 Jackson 库,因此不需要额外配置 Jackson 的依赖。但如果想使用 FastjsonGson 库,可以通过以下方式配置 Maven 依赖

  • 依赖导入未发生变化

  • Jackson: 不需要添加,因为当添加spring-boot-starter-web 的依赖时内部已经添加了

    jackson

Gson

  • 因为使用spring-boot-starter-web 内部已经有jackson,为了使用gson,所以排除jackson 的依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
    <exclusion>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-json</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
    <dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.9</version>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    </dependency>

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    </dependencies>
  • yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 可以配置的一些参数
    spring:
    gson:
    # 用于指定日期格式化的格式字符串,将 Java 对象中的日期类型属性转换成对应的字符串形式。示例配置 yyyy-MM-dd HH:mm:ss 表示使用标准的日期格式将日期类型属性转换成字符串形式。如果不配置该属性,则使用 Gson 默认的日期格式化方式。
    date-format: yyyy-MM-dd HH:mm:ss
    # disable-html-escaping:用于指定是否禁用 HTML 转义,当序列化 HTML 内容时,开启该选项可以防止 XSS 攻击。该属性默认值为 false,即默认启用 HTML 转义。
    disable-html-escaping: true
    # disable-inner-class-serialization:用于指定是否禁用序列化内部类,默认值为 false,即序列化内部类。
    disable-inner-class-serialization: true
    # enable-complex-map-key-serialization:用于指定是否启用复杂类型的 Map 键的序列化,默认值为 false,即禁用复杂类型的 Map 键的序列化。
    enable-complex-map-key-serialization: true
    # exclude-fields-without-expose-annotation:用于指定是否排除未标注 @Expose 注解的字段,默认值为 false,即不排除未标注 @Expose 注解的字段。
    exclude-fields-without-expose-annotation: true
    # field-naming-policy:用于指定字段命名策略,默认值为 IDENTITY,即使用 Java 对象中的字段名称作为 Gson 中的字段名称。其他可选值包括 LOWER_CASE_WITH_UNDERSCORES、UPPER_CAMEL_CASE 和 UPPER_CAMEL_CASE_WITH_SPACES 等。
    field-naming-policy: LOWER_CASE_WITH_UNDERSCORES
    # serialize-nulls:用于指定是否序列化 null 值,默认值为 false,即不序列化 null 值。
    serialize-nulls: true

  • 也可以通过GsonBuilder 实现,两种方式选择一种

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Configuration
    public class GsonConfig {
    @Bean
    public GsonBuilder gsonBuilder() {
    GsonBuilder builder = new GsonBuilder();
    builder.setDateFormat("yyyy-MM-dd HH:mm:ss");
    return builder;
    }
    }
    配置前 配置后(builder.setDateFormat("yyyy-MM-dd HH:mm:ss");)

Fastjson

  • 使用程度较低

  • 排除依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
    <exclusion>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-json</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.78</version>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    </dependency>

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    </dependencies>
  • 注意点

    需要注意的是,使用 Fastjson 或 Gson 时,要保证它们的依赖包的版本与 Spring Boot 的依赖包版本兼容,避免出现不必要的冲突和错误。

    SpringMVC 框架 中,jackson gson 已经自动配置好了,只需要添加相应的依赖,而Fastjson 则需要开发者手动配置HttpMessageConverter,直接启动会出现如下错误

    Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]
    • 解决方法

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      package com.example.jsondemo.config;

      import com.alibaba.fastjson.serializer.SerializerFeature;
      import com.alibaba.fastjson.support.config.FastJsonConfig;
      import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.http.converter.HttpMessageConverter;
      import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

      import java.util.List;

      @Configuration
      public class WebMvcConfig implements WebMvcConfigurer {

      /**
      * 使用 Fastjson 作为 HTTP 消息转换器
      */
      @Override
      public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
      FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
      converter.setFastJsonConfig(getFastJsonConfig());
      converters.add(converter);
      }

      /**
      * 配置 Fastjson
      */
      private FastJsonConfig getFastJsonConfig() {
      FastJsonConfig config = new FastJsonConfig();
      config.setSerializerFeatures(SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.WriteDateUseDateFormat);
      // 也可以直接在 yml 文件中配置
      config.setDateFormat("yyyy-MM-dd HH:mm:ss");
      return config;
      }
      }

      配置前 配置后
    • yml

      1
      2
      3
      spring:
      fastjson:
      date-format: yyyy-MM-dd HH:mm:ss
  • 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @SpringBootTest
    class JsonDemoApplicationTests {

    @Test
    void contextLoads() {
    User user = new User();
    user.setUid("1001");
    user.setUname("coder-itl");
    user.setAddress("http://coderitl.github.io");
    user.setCreateTime(new Date(System.currentTimeMillis()));
    String toJSONString = JSON.toJSONString(user);
    System.out.println(toJSONString);
    // 反序列化
    }
    }

    • 输出

      测试序列化

序列化和反序列化

  • 序列化: 对象转换为JSON

  • 反序列化: JSON 转换为对象

  • 如何实现序列化和反序列化这个过程的?

    • 由转换器:HttpMessageConverter 实现

      Spring 框架中,HttpMessageConverter 是一个用于在消息传递时将消息从一种格式转换为另一种格式的接口。它的主要作用是帮助在不同的客户端和服务之间传递消息,并确保消息在传递过程中能够正确地序列化和反序列化。

      Spring 框架中提供了多个预定义的 HttpMessageConverter 实现,可以根据不同的需求选择使用。常用的消息格式包括 JSON、XML、二进制等。

      配置 HttpMessageConverter 可以通过在 Spring 应用程序上下文中注册 HttpMessageConverter 类型的 Bean 来实现。具体语法如下

      1
      2
      3
      4
      5
      6
      7
      8
      9
      @Configuration
      @EnableWebMvc
      public class WebConfig implements WebMvcConfigurer {

      @Override
      public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
      converters.add(new MappingJackson2HttpMessageConverter());
      }
      }

      上面的示例配置了一个 MappingJackson2HttpMessageConverter 对象,用于将 Java 对象转换为 JSON 格式的消息。在这个例子中,我们使用了 Spring 的 Java 配置方式,并实现了 WebMvcConfigurer 接口中的 configureMessageConverters() 方法来注册我们自己的 MessageConverter 实现。

      需要注意的是,当我们自定义 MessageConverter 时,必须添加到 converters 列表的前面,以确保它是在默认的转换器之前被调用的。此外,我们也可以通过重写 extendMessageConverters() 方法来添加自定义的 MessageConverter,这个方法会在默认的转换器之后调用。