Springboot 中使用 Gson 与 Fastjson 替换默认 Json 组件 Jackson


  !版权声明:本博客内容均均为原创,每篇博文作为知识积累,写博不易,转载请注明出处。

目录[-]


系统环境:

  • Java JDK 版本:1.8
  • SpringBoot 版本:2.2.6.RELEASE

示例项目地址:

一、简介

       在 Java 开发日常中,我们经常会写接口,尤其微服务流行的今天,各个服务都是通过接口相互调用配合,而接口实现的大部分都是基于 Http 协议,且使用 Json 数据格式,而在 Java 中最常用的就是 Jackson、Fastjson、Gson 三种 Json 解析器,它们各自有各自的特性,解析效率和稳定性都不相同,在开发中我们会经常会切换着用。

       SpringBoot 是现在非常流行的开源框架,也是我们在日常开发中经使用的框架,它默认的 Json 解析器是基于 Jackson 的,有时候我们需要将这个默认 Json 解析器替换为 FastJson 或者 Gson,替换起来也很简单,只需要移除 Jackson 的配置,然后自定义一个 HttpMessageConverters 就可以完成该项操作。

二、将 SpringBoot 默认 Json 组件替换为 FastJson

示例项目 Github 地址是:SpringBoot 中使用 Gson 替换默认 Json 组件 Jackson 示例,随手点个星哈 ^^~

1、Maven 引入 FastJson 依赖

Maven 中引入 SpringBoot 和 Fastjson 依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
    </parent>

    <groupId>club.mydlq</groupId>
    <artifactId>springboot-fastjson-example</artifactId>
    <version>0.0.1</version>
    <name>springboot-fastjson-example</name>
    <description>springboot fastjson example</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- SpringBoot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Fastjson -->
       <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.68</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2、自定义 Http 消息转换对象 Bean

自定义 Http 消息转换对象 Bean,引入 Fastjson 对象并配置,代码如下:

import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

@Configuration
public class JsonConfig {

    /**
     * 配置 HttpMessageConverters 来使用 Gson 实现 JSON 转换
     */
    @Bean
    public HttpMessageConverters customConverters() {
        // 创建 convert 消息转换对象
        Collection<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        // 创建与配置 Fastjson 对象
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
        fastConverter.setFastJsonConfig(fastJsonConfig);
        // 解决中文乱码
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON);
        fastConverter.setSupportedMediaTypes(fastMediaTypes);
        // 将convert 添加到 converters
        messageConverters.add(fastConverter);
        return new HttpMessageConverters(true, messageConverters);
    }

}

3、启动类中注解中移除 Jackson 配置

在启动类的 @SpringBootApplication 注解中,添加 exclude = {JacksonAutoConfiguration.class} 配置来移除默认的 Jackson 配置。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;

@SpringBootApplication(exclude = {JacksonAutoConfiguration.class})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

三、将 SpringBoot 默认 Json 组件替换为 Gson

示例项目 Github 地址是:SpringBoot 中使用 Gson 替换默认 Json 组件 Jackson 示例,随手点个星哈 ^^~

1、Maven 引入 Gson 依赖

Maven 中引入 SpringBoot 和 Gson 依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
    </parent>

    <groupId>club.mydlq</groupId>
    <artifactId>springboot-gson-example</artifactId>
    <version>0.0.1</version>
    <name>springboot-gson-example</name>
    <description>springboot gson example</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- SpringBoot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2、自定义 SpringBoot 中的 HttpMessageConverters 对象

自定义 Http 消息转换对象 Bean,引入 Gson 对象并配置,代码如下:

import com.google.gson.*;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import java.util.ArrayList;
import java.util.Collection;

@Configuration
public class JsonConfig {

    @Bean
    public HttpMessageConverters customConverters() {
        // 创建 convert 消息转换对象
        Collection<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
        GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter();
        // 创建与配置 Gson 对象
        Gson gson = new GsonBuilder()
                .setDateFormat("yyyy-MM-dd HH:mm:ss")
                .excludeFieldsWithoutExposeAnnotation()
                .disableHtmlEscaping()
                .create();
        gsonHttpMessageConverter.setGson(gson);
        // 将convert 添加到 converters
        messageConverters.add(gsonHttpMessageConverter);
        return new HttpMessageConverters(true, messageConverters);
    }

}

3、配置启动类并设置移除 Jackson 配置

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;

@SpringBootApplication(exclude = {JacksonAutoConfiguration.class})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

四、解决引入 Swagger 组件无法使用问题

       本人在测试中集成了 Swagger2 依赖,Swagger2 默认使用 Jackson,如果将 Json 解析器替换后 Swagger2 和 Swagger-ui 将不能正常进行 Json 转换。这个问题在 Fastjson 新版本中已经添加适配器进行解决,而 Gson 则需要按下面自定义其 Json 转换适配器,才能够使 Swgger2 正常使用。

1、Maven 中引入 Swagger 依赖发现问题

在引入 Gson 时如果也同时引入 Swagger 依赖:

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

引入后会发现 Swagger 界面无法正常打开:

2、引入 Swagger 后无法正常使用的问题分析并解决

       分析上面 Swagger 无法打开原因,经过查找相关资料和进行测试,其原因是 Gosn 中也开启了 excludeFieldsWithoutExposeAnnotation() 选项,而该选项的作用是只将实体类中添加 Gson 的 @Expose() 注解的变量进行 Json 序列化,而不添加该注解的变量则默认不进行 Json 序列化,而 Swagger 默认是基于 Jackson 的,接口实体类肯定是不会带上 Gson 的注解的,所以在将 Json 解析器替换为 Gson 且开启 excludeFieldsWithoutExposeAnnotation() 后,Swagger 的实体类中的属性都不会进行序列化。

       不过在 Gson 中提供了适配器配置,使用其可以帮助我们解决这个问题,具体可以按下面操作,修改上面的 Json 配置类,在 Gosn 配置中配置几个 Swagger 配器,操作如下:

import com.google.gson.*;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import springfox.documentation.service.ApiListing;
import springfox.documentation.service.ResourceListing;
import springfox.documentation.spring.web.json.Json;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.UiConfiguration;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;

@Configuration
public class JsonConfig {

    /**
     * 配置 HttpMessageConverters 来使用 Gson 实现 JSON 转换
     */
    @Bean
    public HttpMessageConverters customConverters() {
        // 创建 convert 消息转换对象
        Collection<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
        GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter();
        // 创建与配置 Gson 对象
        Gson gson = new GsonBuilder()
                .setDateFormat("yyyy-MM-dd HH:mm:ss")
                .excludeFieldsWithoutExposeAnnotation()
                .disableHtmlEscaping()
                // 使用 Gson 通过的适配器来适配 Swagger
                .registerTypeAdapter(Json.class, SwaggerJsonSerializer.INSTANCE)
                .registerTypeAdapter(ApiListing.class, SwaggerApiListingJsonSerializer.INSTANCE)
                .registerTypeAdapter(SwaggerResource.class, SwaggerResourceSerializer.INSTANCE)
                .registerTypeAdapter(ResourceListing.class, SwaggerResourceListingJsonSerializer.INSTANCE)
                .registerTypeAdapter(SwaggerResource.class, SwaggerResourceSerializer.INSTANCE)
                .registerTypeAdapter(SecurityConfiguration.class, SwaggerSecurityConfigurationSerializer.INSTANCE)
                .registerTypeAdapter(UiConfiguration.class, SwaggerUiConfigurationSerializer.INSTANCE)
                .create();
        gsonHttpMessageConverter.setGson(gson);
        // 将convert 添加到 converters
        messageConverters.add(gsonHttpMessageConverter);
        return new HttpMessageConverters(true, messageConverters);
    }

    static class SwaggerJsonSerializer implements JsonSerializer<Json> {
        public final static SwaggerJsonSerializer INSTANCE = new SwaggerJsonSerializer();

        @Override
        public JsonElement serialize(Json src, Type typeOfSrc, JsonSerializationContext context) {
            return JsonParser.parseString(src.value());
        }
    }

    static class SwaggerApiListingJsonSerializer implements JsonSerializer<ApiListing> {
        public final static SwaggerApiListingJsonSerializer INSTANCE = new SwaggerApiListingJsonSerializer();

        @Override
        public JsonElement serialize(ApiListing src, Type typeOfSrc, JsonSerializationContext context) {
            return new Gson().toJsonTree(src, typeOfSrc);
        }
    }

    static class SwaggerResourceSerializer implements JsonSerializer<SwaggerResource> {
        public final static SwaggerResourceSerializer INSTANCE = new SwaggerResourceSerializer();

        @Override
        public JsonElement serialize(SwaggerResource src, Type typeOfSrc, JsonSerializationContext context) {
            return new Gson().toJsonTree(src, typeOfSrc);
        }
    }

    static class SwaggerResourceListingJsonSerializer implements JsonSerializer<ResourceListing> {
        public final static SwaggerResourceListingJsonSerializer INSTANCE = new SwaggerResourceListingJsonSerializer();

        @Override
        public JsonElement serialize(ResourceListing src, Type typeOfSrc, JsonSerializationContext context) {
            return new Gson().toJsonTree(src, typeOfSrc);
        }
    }

    static class SwaggerSecurityConfigurationSerializer implements JsonSerializer<SecurityConfiguration> {
        public final static SwaggerSecurityConfigurationSerializer INSTANCE = new SwaggerSecurityConfigurationSerializer();

        @Override
        public JsonElement serialize(SecurityConfiguration src, Type typeOfSrc, JsonSerializationContext context) {
            return new Gson().toJsonTree(src, typeOfSrc);
        }
    }

    static class SwaggerUiConfigurationSerializer implements JsonSerializer<UiConfiguration> {
        public final static SwaggerUiConfigurationSerializer INSTANCE = new SwaggerUiConfigurationSerializer();

        @Override
        public JsonElement serialize(UiConfiguration src, Type typeOfSrc, JsonSerializationContext context) {
            return new Gson().toJsonTree(src, typeOfSrc);
        }
    }

}

然后在浏览器中再次访问 Swagger-ui 地址 http://localhost:8080/swagger-ui.html 可以看到已经能够正常访问 Swagger-ui 界面:

—END—