转载: spring boot定义返回json过滤null值/空值不序列化不生效

 

增加配置:

     

package com.wm.auth.config;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.List;

/***
 * @ClassName: WebAppConfigurer
 * @Description: 跨域本地测试, 线上使用nginx处理
 * @Author: wm_yu
 * @Create_time: 15:01 2020-3-13
 */
@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {

    /**
     * 跨域处理
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                //.allowedOrigins("http://192.168.89.89")
                //rest集中请求方式
                .allowedMethods("GET", "POST","DELETE")
                .allowCredentials(false).maxAge(36000);
    }

     @Override
     public void addResourceHandlers(ResourceHandlerRegistry registry) {
                 registry.addResourceHandler("swagger-ui.html")
                         .addResourceLocations("classpath:/META-INF/resources/");

                 registry.addResourceHandler("/webjars/**")
                         .addResourceLocations("classpath:/META-INF/resources/webjars/");
             }


    @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();
            }
        }
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

        // 将long类型的数据转为String类型
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        simpleModule.addSerializer(long.class, ToStringSerializer.instance);
        mapper.registerModule(simpleModule);

        converter.setObjectMapper(mapper);

        converters.add(converter);
    }



}

效果:

     

{
  "code": 200,
  "msg": "操作成功",
  "data": [
    {
      "id": "4",
      "parentId": "-1",
      "sort": 0,
      "type": "md-home",
      "createDate": "2020-03-17 11:49:28",
      "modifyDate": "2020-03-17 11:49:28",
      "delFlag": 0,
      "text": "系统管理",
      "children": [
        {
          "id": "5",
          "name": "menu",
          "parentId": "4",
          "sort": 1,
          "type": "md-home",
          "createDate": "2020-03-17 14:02:20",
          "modifyDate": "2020-03-17 14:02:20",
          "delFlag": 0,
          "text": "菜单管理"
        },
        {
          "id": "1240211721989435393",
          "name": "roleAdmin",
          "parentId": "4",
          "sort": 2,
          "type": "md-home",
          "createDate": "2020-03-18 17:41:31",
          "modifyDate": "2020-03-18 17:41:31",
          "delFlag": 0,
          "text": "角色管理"
        }
      ]
    },
    {
      "id": "3",
      "name": "home",
      "parentId": "-1",
      "sort": 1,
      "type": "md-home",
      "createDate": "2020-03-17 11:34:07",
      "modifyDate": "2020-03-17 11:34:07",
      "delFlag": 0,
      "text": "主页q"
    },
    {
      "id": "1",
      "parentId": "-1",
      "sort": 2,
      "type": "md-home",
      "createDate": "2020-03-17 11:19:35",
      "modifyDate": "2020-03-17 11:19:35",
      "delFlag": 0,
      "text": "二级菜单啊",
      "children": [
        {
          "id": "2",
          "name": "t1",
          "parentId": "1",
          "sort": 1,
          "type": "md-home",
          "createDate": "2020-03-17 11:20:06",
          "modifyDate": "2020-03-17 11:20:06",
          "delFlag": 0,
          "text": "表格"
        }
      ]
    }
  ]
}

     可以看到完全去除了,null值/空值的属性

 

 

 

下面是转载的部分

首先在网络上查看资料,开始配置时,老是不生效,最后看到这位大佬的文章:  

 

 

记一次踩坑:springboot2.0.2配置fastjson不生效

最近在尝试搭建springboot+dubbo+shiro基于注解的一个项目,突发奇想想把消息转换器从jackson换成fastjson,于是就开始了折腾之路.

轻车熟路的去自定了一个SpringMvcConfigure去继承WebMvcConfigurerAdapter,然后就发现这个WebMvcConfigurerAdapter竟然过时了?what?点进去看源码:

/**
 * An implementation of {@link WebMvcConfigurer} with empty methods allowing
 * subclasses to override only the methods they're interested in.
 *
 * @author Rossen Stoyanchev
 * @since 3.1
 * @deprecated as of 5.0 {@link WebMvcConfigurer} has default methods (made
 * possible by a Java 8 baseline) and can be implemented directly without the
 * need for this adapter
 */
@Deprecated
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {}

可以看到从spring5.0开始就被@Deprecated,原来是java8中支持接口中有默认方法,所以我们现在可以直接实现WebMvcConfigurer,然后选择性的去重写某个方法,而不用实现它的所有方法.

于是就实现了WebMvcConfigurer:

@Configuration
public class SpringMvcConfigure implements WebMvcConfigurer {

    /**
     * 配置消息转换器
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        //自定义配置...
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
                SerializerFeature.WriteEnumUsingToString,
                /*SerializerFeature.WriteMapNullValue,*/
                SerializerFeature.WriteDateUseDateFormat,
                SerializerFeature.DisableCircularReferenceDetect);
        fastJsonHttpMessageConverter.setFastJsonConfig(config);
        converters.add(fastJsonHttpMessageConverter);
    }

}

本以为这样子配置就可以完事儿,但是诡异的事情发生了,我明明注释了SerializerFeature.WriteMapNullValue,可是返回的json中仍然有为null的字段,然后我就去com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter中的writewriteInternal打了断点,再次执行,竟然什么都没有发生,根本没有走这两个方法,于是在自定义的SpringMvcConfigureconfigureMessageConverters方法内打了断点,想看看这个方法参数converters里边到底有什么:
converters

看到这里就想到,肯定是我自己添加的fastjson在后边,所以没有生效,所以就加了以下代码:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters = converters.stream()
                .filter((converter)-> !(converter instanceof MappingJackson2HttpMessageConverter))
                .collect(Collectors.toList());
    FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
    //自定义配置...
    FastJsonConfig config = new FastJsonConfig();
    config.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
            SerializerFeature.WriteEnumUsingToString,
            /*SerializerFeature.WriteMapNullValue,*/
            SerializerFeature.WriteDateUseDateFormat,
            SerializerFeature.DisableCircularReferenceDetect);
    fastJsonHttpMessageConverter.setFastJsonConfig(config);
    converters.add(fastJsonHttpMessageConverter);
}

竟然还没有生效,后来开始追踪,开始方法是从org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport类中的一个bean配置:

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
    RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
    adapter.setContentNegotiationManager(mvcContentNegotiationManager());
    //就是从这里开始设置converters的,然后从这里一路追踪下去.
    adapter.setMessageConverters(getMessageConverters());
    adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
    adapter.setCustomArgumentResolvers(getArgumentResolvers());
    adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

    if (jackson2Present) {
        adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
        adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
    }

    AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
    configureAsyncSupport(configurer);
    if (configurer.getTaskExecutor() != null) {
        adapter.setTaskExecutor(configurer.getTaskExecutor());
    }
    if (configurer.getTimeout() != null) {
        adapter.setAsyncRequestTimeout(configurer.getTimeout());
    }
    adapter.setCallableInterceptors(configurer.getCallableInterceptors());
    adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

    return adapter;
}

getMessageConverters()方法:

protected final List<HttpMessageConverter<?>> getMessageConverters() {
    if (this.messageConverters == null) {
        this.messageConverters = new ArrayList<>();
        configureMessageConverters(this.messageConverters);//进入这一步
        if (this.messageConverters.isEmpty()) {
            addDefaultHttpMessageConverters(this.messageConverters);
        }
        extendMessageConverters(this.messageConverters);
    }
    return this.messageConverters;
}

org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration:

@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    this.configurers.configureMessageConverters(converters);
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    for (WebMvcConfigurer delegate : this.delegates) {
        delegate.configureMessageConverters(converters);
    }
}

this.delegates包含了springboot的一个默认配置类类:org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration里边有一个参数

private final HttpMessageConverters messageConverters;

for循环里的delegate.configureMessageConverters(converters)调用了WebMvcAutoConfiguration中的configureMessageConverters方法:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.addAll(this.messageConverters.getConverters());
}

执行完这个后,就给converters中添加了10个转换器了,就是上图中的10个.
this.delegates中还有一个就是我们自定义的那个,执行完后,在我们自定义的那个SpringMvcConfigure发现我添加的fastjson添加进去了,但是org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.getMessageConverters(),发现converters并没有发现我们添加进去的FastJsonHttpMessageConverter,这时突然又想起来:java8的stream api每次都是生成一个新的对象,所以导致converters已经不是传递过来的那个converters的引用了(这里也证明了java是值传递,不是引用传递).

于是再次改变那个lambda表达式为普通的增强for循环:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    /*converters = converters.stream().
            filter((converter)-> !(converter instanceof MappingJackson2HttpMessageConverter))
            .collect(Collectors.toList());*/
    for (HttpMessageConverter<?> converter : converters) {
        if (converter instanceof MappingJackson2HttpMessageConverter){
            converters.remove(converter);
        }
    }
    FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
    //自定义配置...
    FastJsonConfig config = new FastJsonConfig();
    config.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
            SerializerFeature.WriteEnumUsingToString,
            /*SerializerFeature.WriteMapNullValue,*/
            SerializerFeature.WriteDateUseDateFormat,
            SerializerFeature.DisableCircularReferenceDetect);
    fastJsonHttpMessageConverter.setFastJsonConfig(config);
    converters.add(fastJsonHttpMessageConverter);
}

再次运行,wtf?报错了:ConcurrentModificationException,原来使用for循环遍历过程中不能进行remove操作,于是换成Iterator:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    /*converters = converters.stream()
            .filter((converter)-> !(converter instanceof MappingJackson2HttpMessageConverter))
            .collect(Collectors.toList());
    for (HttpMessageConverter<?> converter : converters) {
        if (converter instanceof MappingJackson2HttpMessageConverter){
            converters.remove(converter);
        }
    }*/
    Iterator<HttpMessageConverter<?>> iterator = converters.iterator();
    while(iterator.hasNext()){
        HttpMessageConverter<?> converter = iterator.next();
        if(converter instanceof MappingJackson2HttpMessageConverter){
            iterator.remove();
        }
    }
    FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
    //自定义配置...
    FastJsonConfig config = new FastJsonConfig();
    config.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
            SerializerFeature.WriteEnumUsingToString,
            /*SerializerFeature.WriteMapNullValue,*/
            SerializerFeature.WriteDateUseDateFormat,
            SerializerFeature.DisableCircularReferenceDetect);
    fastJsonHttpMessageConverter.setFastJsonConfig(config);
    converters.add(fastJsonHttpMessageConverter);
}

再次运行,我去,终于解决了,先是删除MappingJackson2HttpMessageConverter,然后添加FastJsonHttpMessageConverter,但是不是到为什么进过一系列操作后,MappingJackson2HttpMessageConverter还是添加进去了,但是由于FastJsonHttpMessageConverterMappingJackson2HttpMessageConverter之前添加,所以对结果不影响.至此,解决了这个问题.

总结

  1. 最重要的还是解决了springboot2.0.2配置fastjson不生效的问题
  2. 更加明白stream api返回的都是全新的对象
  3. 更理解java是值传递而不是引用传递
  4. 了解到想要在迭代过程中对集合进行操作要用Iterator,而不是直接简单的for循环或者增强for循环

如有不正确的地方还请指出,谢谢.

 

 

 

 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值