Springboot使用jackson或fastjson时过滤null值

Jackson全局过滤null值

  • 方法一:使用yml配置方式
  • 方法二:使用Bean注入方式配置
  • 方法三:重写WebMvcConfigurationSupport的configureMessageConverters
  • 方法四:重写WebMvcConfigurer的configureMessageConverters
  • 使用前三种种方式配置时需注意:
  • FastJson全局过滤null值
  • 方法一:实现WebMvcConfigurer
  • 方法二:继承WebMvcConfigurationSupport

Jackson全局过滤null值

方法一:使用yml配置方式

spring:
  jackson:
    default-property-inclusion: non_null

方法二:使用Bean注入方式配置

@Configuration
public class MyJacksonConfig {
    @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.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 允许出现单引号
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        return objectMapper;
    }
}

方法三:重写WebMvcConfigurationSupport的configureMessageConverters

public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        for (HttpMessageConverter converter : converters) {
            if (converter instanceof MappingJackson2HttpMessageConverter) {
                ObjectMapper mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
                mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            }
        }
    }

方法四:重写WebMvcConfigurer的configureMessageConverters

public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        for (HttpMessageConverter converter : converters) {
            if (converter instanceof MappingJackson2HttpMessageConverter) {
                ObjectMapper mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
                mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            }
        }
    }

使用前三种种方式配置时需注意:

只要使用@EnableWebMvc这个注解或者是继承WebMvcConfigurationSupport类,则以上三种配置无效。 这是因为加了@EnableWebMvc加了这个注解后Springboot加载的是WebMvcConfigurationSupport中的配置项,而不使用WebMvcAutoConfiguration引入的配置项。也就是说无论是使用@EnableWebMvc还是WebMvcConfigurationSupport,都会禁止Spring Boot的自动装配,同时也不能自动读取 application.properties 或 application.yml 文件中的配置(更详细的解释参考这篇博客),所以前两种方法也就无效啦。 那么为什么第三种方法也无效呢?阅读官方文档,发现官方的解释如下:

Finally, if you opt out of the Spring Boot default MVC configuration by providing your own @EnableWebMvc configuration, you can take control completely and do everything manually by using getMessageConverters from WebMvcConfigurationSupport.

也就是说可以使用 WebMvcConfigurationSupport 中的 getMessageConverters 手动执行所有操作,但是这样的话显然要麻烦得多,不如直接实现WebMvcConfigurer来得快。 终上所述,大多数时我们在SpringBoot中并不需要使用@EnableWebMvc注解或者继承WebMvcConfigurationSupport类,因为这样的话会是自动配置失效从而需要手动进行配置,而使用Springboot的自动配置就可以满足大部分的要求,以下是官方文档的描述:

Spring Boot provides auto-configuration for Spring MVC that works well with most applications. If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components. If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

FastJson全局过滤null值

方法一:实现WebMvcConfigurer

原先的配置是:

@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    	//创建fastJson消息转换器
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        //创建配置类
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        //修改配置返回内容的过滤
        //WriteNullListAsEmpty  :List字段如果为null,输出为[],而非null
        //WriteNullStringAsEmpty : 字符类型字段如果为null,输出为"",而非null
        //DisableCircularReferenceDetect :消除对同一对象循环引用的问题,默认为false(如果不配置有可能会进入死循环)
        //WriteNullBooleanAsFalse:Boolean字段如果为null,输出为false,而非null
        //WriteMapNullValue:是否输出值为null的字段,默认为false
        fastJsonConfig.setSerializerFeatures(
                SerializerFeature.QuoteFieldNames,
                SerializerFeature.DisableCircularReferenceDetect,
                SerializerFeature.WriteEnumUsingToString,
//                SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat
        );
        fastConverter.setFastJsonConfig(fastJsonConfig);
        //将fastjson添加到视图消息转换器列表内
        converters.add(fastConverter);
    }

}

但是运行后发现并没有过滤null值:

java JSONAarray过滤 json过滤null数据_java

参考这篇博客:记一次踩坑:springboot2.0.2配置fastjson不生效。原因是Springboot自带的jackson的converter把我们配置的fastjson的converter覆盖了,所以需要保证我们配置的fastjson的converter在jackson的后面即可,因此将配置修改为:

@Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
	    	Iterator<HttpMessageConverter<?>> iterator = converters.iterator();
	        while(iterator.hasNext()){
	            HttpMessageConverter<?> converter = iterator.next();
	            if(converter instanceof MappingJackson2HttpMessageConverter){
	            	//将springboot的jackson的消息转换器移除
	                iterator.remove();
	            }
	        }
            //创建fastJson消息转换器
            FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
            //创建配置类
            FastJsonConfig fastJsonConfig = new FastJsonConfig();
            //修改配置返回内容的过滤
            //WriteNullListAsEmpty  :List字段如果为null,输出为[],而非null
            //WriteNullStringAsEmpty : 字符类型字段如果为null,输出为"",而非null
            //DisableCircularReferenceDetect :消除对同一对象循环引用的问题,默认为false(如果不配置有可能会进入死循环)
            //WriteNullBooleanAsFalse:Boolean字段如果为null,输出为false,而非null
            //WriteMapNullValue:是否输出值为null的字段,默认为false
            fastJsonConfig.setSerializerFeatures(
                    SerializerFeature.QuoteFieldNames,
                    SerializerFeature.DisableCircularReferenceDetect,
                    SerializerFeature.WriteEnumUsingToString,
    //                SerializerFeature.WriteMapNullValue,
                    SerializerFeature.WriteDateUseDateFormat
            );
            fastConverter.setFastJsonConfig(fastJsonConfig);
            //将fastjson添加到视图消息转换器列表内
            converters.add(fastConverter);
    }

原以为成功了,但是调用接口时报了错:

java.lang.IllegalArgumentException: Content-Type cannot contain wildcard type '*'

参考这篇博客后,将配置信息修改为:

@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();
            }
        }
        //创建fastJson消息转换器
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        //升级最新版本需加=============================================================
        List<MediaType> supportedMediaTypes = new ArrayList<>();
        supportedMediaTypes.add(MediaType.APPLICATION_JSON);
        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);
        fastConverter.setSupportedMediaTypes(supportedMediaTypes);
        //创建配置类
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        //修改配置返回内容的过滤
        //WriteNullListAsEmpty  :List字段如果为null,输出为[],而非null
        //WriteNullStringAsEmpty : 字符类型字段如果为null,输出为"",而非null
        //DisableCircularReferenceDetect :消除对同一对象循环引用的问题,默认为false(如果不配置有可能会进入死循环)
        //WriteNullBooleanAsFalse:Boolean字段如果为null,输出为false,而非null
        //WriteMapNullValue:是否输出值为null的字段,默认为false
        fastJsonConfig.setSerializerFeatures(
                SerializerFeature.QuoteFieldNames,
                SerializerFeature.DisableCircularReferenceDetect,
                SerializerFeature.WriteEnumUsingToString,
//                SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat
        );
        fastConverter.setFastJsonConfig(fastJsonConfig);
        //将fastjson添加到视图消息转换器列表内
        converters.add(fastConverter);
    }

经过千辛万苦后终于过滤null值:

java JSONAarray过滤 json过滤null数据_java_02

方法二:继承WebMvcConfigurationSupport

同样实现configureMessageConverters方法,配置与方法一的最终配置一样。但是考虑到使用WebMvcConfigurationSupport方式来实现会产生一些问题(如前所述),所以还是使用implements WebMvcConfigurer方式比较保险。