SpringBoot项目如何把接口参数中的空白值替换为null值(推荐)

 更新时间:2021年01月14日 11:41:47   作者:Java知音号  
这篇文章主要介绍了SpringBoot项目如何把接口参数中的空白值替换为null值(推荐),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

问题发生

我们公司代码生成的时候,查询列表统一都是使用了setEntity() ,查询写法如下:

public List<BasReservoirArea> selectList(BasReservoirArea basReservoirArea) {
  QueryWrapper<BasReservoirArea> where = new QueryWrapper<>();
  where.setEntity(basReservoirArea);
  return baseMapper.selectList(where);
}

查询的方法是Get方法:

前端是通过url加参数传过来的,如果有一个参数值为空的时候,由于setEntity() 并不过滤空白,执行sql的时候 会把""作为参数去当做查询条件,查询就出现了问题:

于是我就想把空白转换为null来解决这个问题了。

初始解决

一开始自然而然想到在setEntity之前先判断, 如果BasReservoirArea这个实例有字段的值是空白就设置为null

//1.对象转map
Map<Object, Object> map = MapUtil.beanToMap(test);
//2.移除空值
MapUtil.removeNullValue(map);
//3.map转回对象
Test entity = JSON.parseObject(JSON.toJSONString(map), Test.class);

用到的工具类如下

/**
* 将对象属性转化为map结合
*/
public static <T> Map<Object, Object> beanToMap(T bean) {
 Map<Object, Object> map = new HashMap<>();
 if (bean != null) {
 BeanMap beanMap = BeanMap.create(bean);
 for (Object key : beanMap.keySet()) {
  map.put(key, beanMap.get(key));
 }
 }
 return map;
}
/**
* 移除map中的value空值
*
* @param map
* @return
*/
public static void removeNullValue(Map map) {
 Set set = map.keySet();
 for (Iterator iterator = set.iterator(); iterator.hasNext(); ) {
 Object obj = (Object) iterator.next();
 Object value = (Object) map.get(obj);
 remove(value, iterator);
 }
}

问题解决了。

优化

由于感觉上面的解决方案不够专业,不够优雅,所以先寻找更好的解决办法,在后端接收参数值的时候,如果接收的是空白,直接设置为null, 这样就不需要再次转换了。

解决问题首先要考虑两种情况,一种是前端通过Get请求,路径上带参数;另一种是Post请求,带着Request报文。

Post请求报文体

由于笔者熟悉Post中报文体的转换,知道是MappingJackson2HttpMessageConverter结合Jackson实现报文体转换为实例的,而且也研究过Jackson, 所以解决办法如下

创建一个针对于String.class的Jackson的反序列类:

public class StringDescrializer extends JsonDeserializer<String> {
  @Override
  public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
    String value = jsonParser.getValueAsString();
    if (value == null || "".equals(value.trim())) {
      return null;
    }
    return value;
  }
}

创建一个MappingJackson2HttpMessageConverter Bean:

@Bean
@Primary
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
 MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
 //设置解析JSON工具类
 ObjectMapper objectMapper = new ObjectMapper();
 objectMapper.getSerializerProvider().setNullValueSerializer(
 new JsonSerializer<Object>() {
  @Override
  public void serialize(Object value, JsonGenerator jsonGenerator, SerializerProvider    serializerProvider) throws IOException {
   jsonGenerator.writeString("");
  }
 }
 );
 
 SimpleModule simpleModule = new SimpleModule();
 simpleModule.addDeserializer(String.class, new StringDescrializer());
  //注册自定义的StringDescrializer
  //registerModules函数可以注册多个Module
 objectMapper.registerModule(simpleModule);

  //忽略未知属性 防止解析报错
  objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

  jsonConverter.setObjectMapper(objectMapper);
  List<MediaType> list = new ArrayList<>();
  list.add(MediaType.APPLICATION_JSON_UTF8);
  jsonConverter.setSupportedMediaTypes(list);
  return jsonConverter;
}

对于Post报文体来说,测试成功了。

Get路径带参数

上面的解决方法不适用于Get方法路径带参数的情况,所以需要另外想办法了。

由于我使用过@InitBinder注解,知道可以注入自定义的PropertyEditor, 在Editor里面可以自定义格式或者返回值,于是,自定义一个StringEditor来处理空白的问题:、

public class StringEditor extends PropertyEditorSupport {
  //setAsText完成字符串到具体对象类型的转换,
  @Override
  public void setAsText(String text) throws IllegalArgumentException {
    if (text == null || "".equals(text.trim())) {
      text = null;
    }
    setValue(text);
  }

  //getAsText完成具体对象类型到字符串的转换。
  @Override
  public String getAsText() {
    if (getValue() != null) {
      return getValue().toString();
    }
    return null;
  }
}

想要全局controller共享这个Databinder:

@ControllerAdvice
public class GlobalControllerAdiviceController {
  //WebDataBinder是用来绑定请求参数到指定的属性编辑器,可以继承WebBindingInitializer
  //来实现一个全部controller共享的dataBiner 
  @InitBinder
  public void dataBind(WebDataBinder binder) {
    ///給指定类型注册类型转换器操作
    binder.registerCustomEditor(String.class, new StringEditor());
  }
}

对于Get路径带参数来说,测试也成功了

思考

解决完问题后,还是觉得不够优雅,觉得spring 应该会考虑到这种情况,终于在spring 的文档中查阅到StringTrimmerEditor(https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-beans) 可以实现「Get」方法时参数去除空格:

只不过这个editor缺省没有注册,需要手工注册。

@ControllerAdvice
public class GlobalControllerAdiviceController {
  //WebDataBinder是用来绑定请求参数到指定的属性编辑器,可以继承WebBindingInitializer
  //来实现一个全部controller共享的dataBiner Java代码
  @InitBinder
  public void dataBind(WebDataBinder binder) {
    ///注册
    binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
  }
}

注意,StringTrimmerEditor构造方法中有一个参数,如果传入true,则会将空白转换为null. 这样前面写的StringEditor就不用了,spring 已经帮我们写好了。

对于「Post」报文体来说,实际上我只需要改变的是「Jackson ObjectMapper」,不需要自定义整个MappingJackson2HttpMessageConverter ,只需要自定义Jackson ObjectMapper.百度了一下,果然有同学已经有了解决方案:

@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
  return new Jackson2ObjectMapperBuilderCustomizer() {
    @Override
    public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
      jacksonObjectMapperBuilder
          .deserializerByType(String.class, new StdScalarDeserializer<String>(String.class) {
            @Override
            public String deserialize(JsonParser jsonParser, DeserializationContext ctx)
                throws IOException {
              // 重点在这儿:如果为空白则返回null
              String value = jsonParser.getValueAsString();
              if (value == null || "".equals(value.trim())) {
                return null;
              }
              return value;
            }
          });
    }
  };
}

把上面的自定义StringDescrializer和MappingJackson2HttpMessageConverter去掉, 只保留上面的就行。

后记

好多问题,其实spring 都已经提供了解决方案,但是spring体系目前太庞大了,所以好多API和功能都不为人知。所以碰上问题就记录下来是个很好的习惯

到此这篇关于SpringBoot项目如何优雅的把接口参数中的空白值替换为null值的文章就介绍到这了,更多相关SpringBoot空白值替换为null值内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中枚举类enum的values()方法举例详解

    Java中枚举类enum的values()方法举例详解

    这篇文章主要给大家介绍了关于Java中枚举类enum的values()方法举例详解,作为一种常用方法,可以在枚举中对数组里的枚举值进行遍历,这就是values()方法的使用,需要的朋友可以参考下
    2023-11-11
  • 带你了解Java数据结构和算法之栈

    带你了解Java数据结构和算法之栈

    这篇文章主要为大家介绍了Java数据结构和算法之栈 ,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • 利用JAVA反射,读取数据库表名,自动生成对应实体类的操作

    利用JAVA反射,读取数据库表名,自动生成对应实体类的操作

    这篇文章主要介绍了利用JAVA反射,读取数据库表名,自动生成对应实体类的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • Spring Boot实现web.xml功能示例详解

    Spring Boot实现web.xml功能示例详解

    这篇文章主要介绍了Spring Boot实现web.xml功能,通过本文介绍我们了解到,在Spring Boot应用中,我们可以通过注解和编程两种方式实现web.xml的功能,包括如何创建及注册Servlet、Filter以及Listener等,需要的朋友可以参考下
    2023-09-09
  • JAVA中SpringBoot启动流程分析

    JAVA中SpringBoot启动流程分析

    这篇文章主要介绍了JAVA中SpringBoot启动流程分析的相关资料,需要的朋友可以参考下
    2023-01-01
  • java基础的详细了解第一天

    java基础的详细了解第一天

    这篇文章对Java编程语言的基础知识作了一个较为全面的汇总,在这里给大家分享一下。需要的朋友可以参考,希望能给你带来帮助
    2021-08-08
  • SpringCloud gateway跨域配置的操作

    SpringCloud gateway跨域配置的操作

    这篇文章主要介绍了SpringCloud gateway跨域配置的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • 关于springboot中nacos动态路由的配置

    关于springboot中nacos动态路由的配置

    这篇文章主要介绍了springboot中nacos动态路由的配置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • 使用SpringBoot和JPA实现批量处理新增、修改

    使用SpringBoot和JPA实现批量处理新增、修改

    最近项目需要在JPA中使用ID进行批量更新,所以下面这篇文章主要给大家介绍了关于使用SpringBoot和JPA实现批量处理新增、修改的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-06-06
  • 解决idea 暂存文件或idea切换分支代码丢失的问题

    解决idea 暂存文件或idea切换分支代码丢失的问题

    这篇文章主要介绍了解决idea 暂存文件或idea切换分支代码丢失的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02

最新评论