SpringBoot中使用Fastjson/Jackson对JSON序列化格式化输出的若干问题
Use-Fastjson-and-Jackson-to-Serialized-and-Formated-Output-of-JSON-in-SpringBoot
之前使用springboot-web编写rest接口,接口需要返回json数据,自己是个强迫症患者,看着默认输出的json字符串挤在一起,看着就难受,所以总想着把输出的json数据经过格式化处理后再输出。 目前国内比较常用的fastjson使用比较方便,但是SpringBoot默认使用的Jackson,替换的时候有时候因为其他组件也使用到了jackson,所以无法100%成功替换。 不喜欢使用jackson主要是jackson对格式化输出支持不太友好,自己使用的时候遇到许多坑,至今也没把坑填好,所以一直就不待见它,有时候又不得不用。 下面总结一下Fastjson/Jackson两种对json序列化+格式化输出的配置总结。

1.Jackson方式(SpringBoot中的默认方式):
 1.1application.yml配置文件
 spring:
 jackson:在这里插入代码片 #日期格式化
 date-format: yyyy-MM-dd HH:mm:ss
 serialization:
 #格式化输出
 indent_output: true
 网上提供的方案,可是实际配置并不能生效
 1.2使用JavaConfig文件配置Jackson格式化输出
 @Configuration
 public class JacksonConfig extends WebMvcConfigurationSupport {
 // 注释部分配置无效
 // @Bean
 // @Primary
 // @ConditionalOnMissingBean(ObjectMapper.class)
 // public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
 // ObjectMapper objectMapper = builder.createXmlMapper( false ).build();
 //
 // // 通过该方法对mapper对象进行设置,所有序列化的对象都将按改规则进行系列化
 // // Include.Include.ALWAYS 默认
 // // Include.NON_DEFAULT 属性为默认值不序列化
 // // Include.NON_EMPTY 属性为 空("") 或者为 NULL 都不序列化,则返回的json是没有这个字段的。这样对移动端会更省流量
 // // Include.NON_NULL 属性为NULL 不序列化
 // // objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
 // objectMapper.setSerializationInclusion( JsonInclude.Include.ALWAYS );
 // objectMapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
 // // 允许出现特殊字符和转义符
 // objectMapper.configure( JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true );
 // // 允许出现单引号
 // objectMapper.configure( JsonParser.Feature.ALLOW_SINGLE_QUOTES, true );
 // // 字段保留,将null值转为""
 // objectMapper.getSerializerProvider().setNullValueSerializer( new JsonSerializer() {
 // @Override
 // public void serialize(Object o, JsonGenerator jsonGenerator,
 // SerializerProvider serializerProvider)
 // throws IOException {
 // jsonGenerator.writeString( “” );
 // }
 // } );
 // // 格式化输出
 // objectMapper.configure( SerializationFeature.INDENT_OUTPUT, true );
 // return objectMapper;
 // }/**
 * 格式化输出配置
 * @param converters
 */
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    for (HttpMessageConverter<?> converter : converters) {
        if (converter instanceof MappingJackson2HttpMessageConverter) {
            MappingJackson2HttpMessageConverter jacksonConverter = (MappingJackson2HttpMessageConverter) converter;
            jacksonConverter.setPrettyPrint( true ); // 实际使用生效
        }
    }
}}
 2.Fastjson方式
 2.1引入fastjson,排除jackson在这里插入代码片<dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.56</version>
</dependency>

<!--排除jackson-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--,排除jackson(根据实际情况,下面的非必须)-->
<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
    <version>2.3.4.RELEASE</version>
    <!--<exclusions>-->
        <!--<exclusion>-->
            <!--<groupId>com.fasterxml.jackson.core</groupId>-->
            <!--<artifactId>jackson-databind</artifactId>-->
        <!--</exclusion>-->
    <!--</exclusions>-->
</dependency>
<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    <version>${spring-boot.version}</version>
    <scope>compile</scope>
    <!--<exclusions>-->
        <!--<exclusion>-->
            <!--<groupId>com.fasterxml.jackson.core</groupId>-->
            <!--<artifactId>jackson-databind</artifactId>-->
        <!--</exclusion>-->
    <!--</exclusions>-->
</dependency>2.2 使用JavaConfig配置
 SpringBoot中fastjson的配置有两种方式:
 2.2.1 方式一
 配置Bean 使用fastjson的方式实现HttpMessageConverters@Configuration
 public class FastJSONConfig {
 /**
 * Fastjson
 *
 * @return
 */
 @Bean
 public HttpMessageConverters fastJsonHttpMessageConverters() {
 FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
 FastJsonConfig fastJsonConfig = new FastJsonConfig();
 List mediaTypes = new ArrayList<>();
 mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
 fastJsonHttpMessageConverter.setSupportedMediaTypes(mediaTypes);
 fastJsonConfig.setSerializerFeatures(
 SerializerFeature.DisableCircularReferenceDetect, //禁用循环引用
 SerializerFeature.PrettyFormat,
 SerializerFeature.IgnoreNonFieldGetter
 );
 fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
 HttpMessageConverter<?> converter = fastJsonHttpMessageConverter;
 return new HttpMessageConverters(converter);
 }
 }
 2.2.2方式二
 Spring5.x中实现WebMvcConfigurer接口,并重写configureMessageConverters方法,向其中添加FastJsonHttpMessageConverter
 @Configuration
 public class FastJsonHttpConverterConfig implements WebMvcConfigurer {
 // fastjson配置
 @Override
 public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
 Iterator<HttpMessageConverter<?>> iterator = converters.iterator();
 while(iterator.hasNext()){
 HttpMessageConverter<?> converter = iterator.next();
 if(converter instanceof MappingJackson2HttpMessageConverter){
 iterator.remove();
 }
 }
 FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
 FastJsonConfig config = new FastJsonConfig();
 config.setSerializerFeatures(SerializerFeature.WriteNullListAsEmpty, // List类型字段为null时输出[]而非null
 SerializerFeature.WriteMapNullValue, // 显示空字段
 SerializerFeature.WriteNullStringAsEmpty, // 字符串类型字段为null时间输出""而非null
 SerializerFeature.WriteNullBooleanAsFalse, // Boolean类型字段为null时输出false而null
 SerializerFeature.PrettyFormat, // 美化json输出,否则会作为整行输出
 SerializerFeature.WriteNullNumberAsZero, // 数值字段如果为null,输出为0,而非null
 SerializerFeature.WriteNullBooleanAsFalse, // Boolean字段如果为null,输出为false,而非null
 SerializerFeature.WriteDateUseDateFormat, // 时间格式yyyy-MM-dd HH: mm: ss
 SerializerFeature.DisableCircularReferenceDetect); // 禁用循环引用检测
 converter.setFastJsonConfig(config);
 converters.add(converter);
 List supportedMediaTypes = new ArrayList<>();
 supportedMediaTypes.add(MediaType.APPLICATION_JSON);
 supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
 supportedMediaTypes.add(MediaType.APPLICATION_ATOM_XML);
 supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
 supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
 supportedMediaTypes.add(MediaType.APPLICATION_PDF);
 supportedMediaTypes.add(MediaType.APPLICATION_RSS_XML);
 supportedMediaTypes.add(MediaType.APPLICATION_XHTML_XML);
 supportedMediaTypes.add(MediaType.APPLICATION_XML);
 supportedMediaTypes.add(MediaType.IMAGE_GIF);
 supportedMediaTypes.add(MediaType.IMAGE_JPEG);
 supportedMediaTypes.add(MediaType.IMAGE_PNG);
 supportedMediaTypes.add(MediaType.TEXT_EVENT_STREAM);
 supportedMediaTypes.add(MediaType.TEXT_HTML);
 supportedMediaTypes.add(MediaType.TEXT_MARKDOWN);
 supportedMediaTypes.add(MediaType.TEXT_PLAIN);
 supportedMediaTypes.add(MediaType.TEXT_XML);
 converter.setSupportedMediaTypes(supportedMediaTypes);
 }
 }


2.2.3 总结
fastjson替换jackson并不能保证100%成功,但是都能最终实现格式化输出。HttpMessageConverter的具体实现需要深入阅读源码,从源码上进一步寻找答案。