在处理部分更新业务时,经常需要把前端传来的参数合并到现有对象中。这时候有个坑要注意:如果前端传了 null,直接拷贝会把数据库里的旧值覆盖掉。下面分享两种常用的解决思路。
基于 Spring BeanUtils 的过滤策略
Spring 提供的 BeanUtils.copyProperties 默认会复制所有属性,包括值为 null 的属性。为了避免空值污染目标对象,我们需要先找出源对象中哪些属性是空的,然后在拷贝时忽略它们。
核心逻辑是先遍历源对象的属性,收集那些值为 null 的字段名,再传给 copyProperties 方法。
public static void copyNonNullProperties(Object src, Object target) {
// 获取源对象中为 null 的属性名列表
String[] nullProps = getNullPropertyNames(src);
try {
// 拷贝时忽略这些空属性
BeanUtils.copyProperties(src, target, nullProps);
} catch (BeansException e) {
throw new RuntimeException("属性拷贝失败", e);
}
}
private static String[] getNullPropertyNames(Object source) {
final BeanWrapper src = new BeanWrapperImpl(source);
PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set<String> emptyNames = new HashSet<>();
for (PropertyDescriptor pd : pds) {
Object srcValue = src.getPropertyValue(pd.getName());
if (srcValue == null) {
emptyNames.add(pd.getName());
}
}
return emptyNames.toArray(new String[0]);
}
这种方式的好处是不依赖序列化,性能开销较小,适合对性能敏感的场景。但要注意,它只处理 Java 对象层面的 null,对于嵌套对象可能还需要递归处理。

