使用res:bean属性复制避免null值覆盖版本

目录
  • res:bean属性复制避免null值覆盖版本
    • 前言
    • 代码 copyBeanPropertiesIgoreNull
  • BeanUtils.copyProperties解决null值覆盖
    • 可以自己拓展一个方法,汇总值为null的数据
    • 附demo:

res:bean属性复制避免null值覆盖版本

前言

  • 最近在设计通用的 Service 和 Controller 层
  • 设计过程中涉及到实体对象(JPA)的更新操作
  • 原因1:JPA 的 saveAndFlush 方法会将把 null 也更新上去
  • 原因2:spring 的 BeanUtils.copyBeanProperties 方法会把 src 所有属性值包括 null 覆盖到 dest,不符合要求
  • 所以,利用反射,写一个属性复制方法代替 spring 的工具方法
  • 另外,controller 层使用 @ModelAttribut 也可以解决这个问题,这就是另一个主题

代码 copyBeanPropertiesIgoreNull

/**
 * 对象属性值拷贝,null 值覆盖修复版
 * @param beanSrc
 * @param beanDest
 */
public static void copyBeanPropertiesIgoreNull(Object beanSrc, Object beanDest){
 Class<?> clazzSrc = beanSrc.getClass();
 Class<?> clazzDest = beanDest.getClass();
 //获取所有属性,包括私有的和继承的
 List<Field> allFields = getAllFields(beanSrc);
 try {
 for(Field field:allFields) {
  String fieldName = field.getName(); //属性名
  if("serialVersionUID".equals(fieldName)) {
   continue;
  }
  PropertyDescriptor pd1 = getPropertyDescriptor(fieldName, clazzSrc);
  if(pd1!=null) {
   Method rMethod = pd1.getReadMethod();
   if(rMethod!=null) {
    Object fieldValue = rMethod.invoke(beanSrc); //属性值,引用类型,所以一般实体的属性用 Integer instead of int
    if(fieldValue!=null) { //关键:属性值为 null 就不要覆盖了
     PropertyDescriptor pd2 = getPropertyDescriptor(fieldName, clazzDest);
     if(pd2!=null) {
      Method wMethod = pd2.getWriteMethod();
      if(wMethod!=null) {
        wMethod.invoke(beanDest, fieldValue);
      }
     }
    }
   }
  }
 }
 } catch (IllegalAccessException | InvocationTargetException e) {
  e.printStackTrace();
  throw new RuntimeException(">> copyPropertiesIgoreNull exception", e);
 }
}

BeanUtils.copyProperties解决null值覆盖

这里使用的是Spring提供的BeanUtils的工具类(commons-lang3可参考)。在做数据变更的时候,使用BeanUtils.copyProperties(newdata,dbdata)进行数据变更的时候,由于前台展示的数据不完整。

导致前台传递的数据将后台的原始数据全部覆盖掉。那么如何解决这种null值的覆盖呢。BeanUtils.copyProperties()可以通过添加可变长参数忽略掉具体的某些不需要更新的字段。比如BeanUtils.copyProperties(newdata,dbdata,“id”,“password”)。

那么如果字段比较多,使用上面的方法简直要疯掉了。有没有更好的方法呢?

可以自己拓展一个方法,汇总值为null的数据

public static String[] getNullPropertyNames (Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        PropertyDescriptor[] pds = src.getPropertyDescriptors();
        Set<String> emptyNames = new HashSet<String>();
        for(PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) emptyNames.add(pd.getName());
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }

通过这个方法就可以将null数据找到,然后在可变长参数中使用方法即可。

BeanUtils.copyProperties(newdata,dbdata,getNullPropertyNames(newdata));

附demo:

public static void main(String[] args) {
    U u = new U("1","zhangsan",null,null,null,"11");
    String[] nullPropertyNames = getNullPropertyNames(u);
    for (String nullPropertyName : nullPropertyNames) {
        System.out.println(nullPropertyName);
    }
}
public static String[] getNullPropertyNames (Object source) {
    final BeanWrapper src = new BeanWrapperImpl(source);
    PropertyDescriptor[] pds = src.getPropertyDescriptors();
    Set<String> emptyNames = new HashSet<String>();
    for(PropertyDescriptor pd : pds) {
        Object srcValue = src.getPropertyValue(pd.getName());
        if (srcValue == null) emptyNames.add(pd.getName());
    }
    String[] result = new String[emptyNames.size()];
    return emptyNames.toArray(result);
}
class U {
        private String id;
        private String name;
        private String field1;
        private String field2;
        private String field3;
        private String field4;
        public U(String id, String name) {
            this.id = id;
            this.name = name;
        }
        public String getId() {
            return id;
        }
        public void setId(String id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getField1() {
            return field1;
        }
        public void setField1(String field1) {
            this.field1 = field1;
        }
        public String getField2() {
            return field2;
        }
        public void setField2(String field2) {
            this.field2 = field2;
        }
        public String getField3() {
            return field3;
        }
        public void setField3(String field3) {
            this.field3 = field3;
        }
        public String getField4() {
            return field4;
        }
        public void setField4(String field4) {
            this.field4 = field4;
        }
        public U(String id, String name, String field1, String field2, String field3, String field4) {
            this.id = id;
            this.name = name;
            this.field1 = field1;
            this.field2 = field2;
            this.field3 = field3;
            this.field4 = field4;
        }
    }

打印的结果:

field1

field2

field3

好了问题解决!以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • BeanUtils.copyProperties在拷贝属性时忽略空值的操作

    BeanUtils.copyProperties忽略空值 使用spring开发的人,对这行代码肯定不陌生,常用于DTO.VO.PO之间的复制. /** * 全属性copy对象 * **/ BeanUtils.copyProperties(Object source, Object target) 但这行代码会将所有的属性都进行copy,有的时候我们想要个别属性不进行复制(比如:null值属性),这时就需要用到另一个方法: /** * 忽略某些属性copy对象 * **/ BeanUtils.co

  • java使用BeanUtils.copyProperties踩坑经历

    1. 原始转换 提起对象转换,每个程序员都不陌生,比如项目中经常涉及到的DO.DTO.VO之间的转换,举个例子,假设现在有个OrderDTO,定义如下所示: public class OrderDTO { private long id; private Long userId; private String orderNo; private Date gmtCreated; // 省略get.set方法 } 有个OrderVO,定义如下所示: public class OrderVO { pr

  • 解决Beanutils.copyproperties实体类对象不一致的问题

    今天给大家分析一个解决Beanutils.copyproperties实体类对象名不一致的解决方法,一般我们在两个对象拷贝的问题上,我个人用的比较多的就是Beanutils.copyproperties,字段名如果不一致的话就去实体类中使用重载,把当前实体类的对象赋值给另外一个对象,也有用到set(),当然这些也都能解决Beanutils.copyproperties实体类属性不一致的问题,不过今天要给大家分享的是,不用set()和实体类的重构,使用类的反射机制去完成! 话不多说直接开始: 我是

  • java Beanutils.copyProperties( )用法详解

    这是一篇开发自辩甩锅稿~~~~ 昨天测试小姐姐将我的一个bug单重开了,emmmm....内心OS:就调整下对象某个属性类型这么简单的操作,我怎么可能会出错呢,一定不是我的锅!!but再怎么抗拒,bug还是要改的,毕竟晚上就要发版本了~~ 老老实实将我前天改的部分跟了一遍,恩,完美,没有任何的缺失~~but本应success的测试数据,接口返还的结果确实是false来着,那还是老老实实debug吧. 一步步跟下来,恩,多么顺畅,就说一定不是我的锅~~诶?不对不对,这里的ID值,为啥是null?传

  • 普通类注入不进spring bean的解决方法

    解决问题:我在做移动端accessToken的使用遇到一个问题,就是普通类死活注入不进去spring bean,我和同事雷杰通过各种注解,xml配置搞了好久都搞不定,这里插个眼,有空补一下spring,得深入研究一下 解决办法:后面通过一个spring工具类搞定,这里贴上代码 1.引入这个springUtil类 2.通过构造方法注入 贴上SpringUtils代码: package com.dt.base.weixin.util; import org.springframework.aop.f

  • 使用res:bean属性复制避免null值覆盖版本

    目录 res:bean属性复制避免null值覆盖版本 前言 代码 copyBeanPropertiesIgoreNull BeanUtils.copyProperties解决null值覆盖 可以自己拓展一个方法,汇总值为null的数据 附demo: res:bean属性复制避免null值覆盖版本 前言 最近在设计通用的 Service 和 Controller 层 设计过程中涉及到实体对象(JPA)的更新操作 原因1:JPA 的 saveAndFlush 方法会将把 null 也更新上去 原因2

  • 解决JPA save()方法null值覆盖掉mysql预设的默认值问题

    目录 JPA save()方法null值覆盖掉mysql预设的默认值 覆盖原因 解决办法 data jpa动态插入(null为sql默认值,utime自动更新 ) JPA save()方法null值覆盖掉mysql预设的默认值 覆盖原因 save()方法在没有参数传进去的时候默认是null值,而mysql表中该字段设置为可以为null值,这时虽然我们设置了默认值,可null值还是会把默认值覆盖掉. 解决办法 将该字段设置为不允许null值即可,这样null值就会被替换为默认值. data jpa

  • Spring 实现给Bean属性注入null值

    目录 给Bean属性注入null值 Spring注入bean 为null的相关问题 问题描述 问题描述 如何处理? 给Bean属性注入null值 空字符串值可以使用<value/>元素可用来表示.例如: <bean class="ExampleBean"> <property name="email"><value/></property> </bean> 等同于Java代码: exampleB

  • Java基础将Bean属性值放入Map中的实例

    Java基础将Bean属性值放入Map中的实例 利用发射将Java对象的属性值以属性名称为键,存储到Map中的简单实现.包括自身属性及从父类继承得到的属性.Java类型的getField[s]方法只能获取public 类型的属性,getDeclaredFields则能获取所有声明的属性,同时,如果类的可见性非公有,则Field的get(Object)方法将取不到具体的属性值. package com.wood.util; import java.lang.reflect.Field; impor

  • SpringBoot项目中处理返回json的null值(springboot项目为例)

    在后端数据接口项目开发中,经常遇到返回的数据中有null值,导致前端需要进行判断处理,否则容易出现undefined的情况,如何便捷的将null值转换为空字符串? 以SpringBoot项目为例,SSM同理. 1.新建配置类(JsonConfig.java) import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.f

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

    问题发生 我们公司代码生成的时候,查询列表统一都是使用了setEntity() ,查询写法如下: public List<BasReservoirArea> selectList(BasReservoirArea basReservoirArea) { QueryWrapper<BasReservoirArea> where = new QueryWrapper<>(); where.setEntity(basReservoirArea); return baseMap

  • 关于Spring Bean实例过程中使用反射和递归处理的Bean属性填充问题

    一.前言 超卖.掉单.幂等,你的程序总是不抗揍! 想想,运营已经对外宣传了七八天的活动,满心欢喜的等着最后一天页面上线对外了,突然出现了一堆异常.资损.闪退,而用户流量稍纵即逝,最后想死的心都有! 就编程开发来讲,丢三落四.乱码七糟,可能这就是大部分初级程序员日常开发的真实写照,在即使有测试人员验证的情况下,也会出现带Bug上线的现象,只不过是当时没有发现而已!因为是人写代码,就一定会有错误,即使是老码农 就程序Bug来讲,会包括产品PRD流程上的Bug.运营配置活动时候的Bug.研发开发时功能

  • springboot响应json null值过滤方式

    目录 springboot响应json null值过滤 springboot处理返回json的null值 1.新建配置类(JsonConfig.java) 2.在启动类Application中 springboot响应json null值过滤 spring: jackson: default-property-inclusion: non_null 只需要在application.yml中配置以上内容即可. springboot处理返回json的null值 在后端数据接口项目开发中,经常遇到返回

  • MapStruct对象映射转换解决Bean属性拷贝性能问题

    目录 简介 适用场景 工作时机 使用案例 1.添加依赖 2.定义两个类 3.单元测试 核心总结 简介 MapStruct 是一个代码生成器(可以生成对象映射转换的代码),它基于约定优于配置的方法,极大地简化了 Java bean 类型之间的映射实现. 生成的映射代码使用普通的方法调用,因此速度快.类型安全且易于理解. 适用场景 多层应用程序通常需要在不同的对象模型(例如实体和 DTO)之间进行映射.编写这样的映射代码是一项乏味且容易出错的任务.MapStruct 旨在通过尽可能地自动化来简化这项

  • Spring Bean属性注入的两种方式详解

    目录 属性注入概念 一.构造器注入 示例1 注意点 二.setter注入 示例2 三.如何选择注入方式 属性注入概念 Spring 属性注入(DI依赖注入)有两种方式:setter注入,构造器注入. 这个注入的属性可以是普通属性(基本数据类型与String等),也可以是一个引用数据类型(主要是对象),或者是一个集合(list.map.set等) 下表是属性注入bean标签中常用的元素 元素名称 描述 constructor-arg 构造器注入.该元素的 index 属性指定构造参数的索引(从 0

随机推荐