扩展Spring的BeanUtils,增加BeanUtils.copyProperties方法忽略 null 值

拷贝对象通常可以选择使用 Spring 或者 Apache 的  BeanUtils.copyProperties(Object source, Object target) 方法,将 source 对象中的所有属性拷贝到 target 对象中去。

应用场景,比如更新用户。

举例如下,编辑用户页面,可以修改用户名、密码、昵称Email和状态等字段,但不可以修改注册时间,上一次登录时间,上一次登录ip 等字段。

要正确更新用户的信息,保证用户信息不丢失。我们有两种方法。

方法一、设置隐藏域

  1. <input type="hidden" name="createTime" th:value="${user.createTime}">
  2. <input type="hidden" name="lastLoginTime" th:value="${user.lastLoginTime}">
  3. <input type="hidden" name="lastLoginIp" th:value="${user.lastLoginIp}">

这种方法,不是很好,因为如果无需修改的字段很多,那就要写很多,容易遗漏。

 

方法二、从数据库取出 targetUser 对象,然后将表单的里的 User 对象拷贝到 targetUser 中

  1. @Transactional(rollbackFor = Exception.class)
  2.   @Override
  3.   public void updateUser(User user) {
  4.       User targetUser = userRepository.findById(user.getId()).get();
  5.       BeanUtils.copyProperties(user, targetUser);
  6.       userRepository.save(targetUser);
  7.   }

但是,我们通过 Debug 发现,最终 targetUser 对象和 User 对象一模一样,即 targetUser 中原来有值的被覆盖为 null 了。

 

如果使为 source 对象中为  null 的字段不拷贝呢?

答案是 重写 copyProperties 方法。

  1. package com.liuyanzhao.forum.util;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.FatalBeanException;
  4. import org.springframework.util.Assert;
  5. import java.beans.PropertyDescriptor;
  6. import java.lang.reflect.Method;
  7. import java.lang.reflect.Modifier;
  8. /**
  9.  * @author 言曌
  10.  * @date 2018/3/25 下午2:27
  11.  */
  12. public abstract class BeanUtils extends org.springframework.beans.BeanUtils {
  13.     /**
  14.      * 将source中不为空的字段,拷贝(覆盖)到target中
  15.      * @param source
  16.      * @param target
  17.      * @throws BeansException
  18.      */
  19.     public static void copyProperties(Object source, Object target) throws BeansException {
  20.         Assert.notNull(source, "Source must not be null");
  21.         Assert.notNull(target, "Target must not be null");
  22.         Class<?> actualEditable = target.getClass();
  23.         PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
  24.         for (PropertyDescriptor targetPd : targetPds) {
  25.             if (targetPd.getWriteMethod() != null) {
  26.                 PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
  27.                 if (sourcePd != null && sourcePd.getReadMethod() != null) {
  28.                     try {
  29.                         Method readMethod = sourcePd.getReadMethod();
  30.                         if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
  31.                             readMethod.setAccessible(true);
  32.                         }
  33.                         Object value = readMethod.invoke(source);
  34.                         // 这里判断以下value是否为空 当然这里也能进行一些特殊要求的处理 例如绑定时格式转换等等
  35.                         if (value != null) {
  36.                             Method writeMethod = targetPd.getWriteMethod();
  37.                             if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
  38.                                 writeMethod.setAccessible(true);
  39.                             }
  40.                             writeMethod.invoke(target, value);
  41.                         }
  42.                     } catch (Throwable ex) {
  43.                         throw new FatalBeanException("Could not copy properties from source to target", ex);
  44.                     }
  45.                 }
  46.             }
  47.         }
  48.     }
  49. }

 

然后导入我们重写的 BeanUtils 类,使用我们自定义的 copyProperties() 方法,成功解决。

 

  • 微信
  • 赶快加我聊天吧
  • weinxin
  • 博客/Java交流群
  • 资源分享,问题解决,技术交流。群号:590480292
  • weinxin
广告也精彩
言曌
广告也精彩

发表评论

:?::razz::sad::evil::!::smile::oops::grin::eek::shock::???::cool::lol::mad::twisted::roll::wink::idea::arrow::neutral::cry::mrgreen: