作为一名后端开发者,我们深知数据安全的重要性,尤其是像手机号、身份证号等关键数据。
为了防止关键数据泄露,JAVA领域,基本都采用了 VO(Value Object)和 DTO(Data Transfer Object)的模式,VO(Value Object)通常只会回传最关键的属性,而DTO(Data Transfer Object)一般则包含表的所有字段数据。因此,DTO和VO之间通常需要进行关键字段的数据复制。今天,我们就来分享一个工具类——BeanUtils,并剖析其数据复制的源码。
一、BeanUtils工具类
BeanUtils是Spring框架提供的用于处理JavaBean的静态工具方法类,如实例化bean、检查bean属性类型、复制bean属性等。
1. 核心方法
- instantiateClass(Class clazz):根据给定的类创建一个新的实例。
- copyProperties(Object source, Object target, String… ignoreProperties):将一个对象的属性值复制到另一个对象中,可以指定忽略的属性。
- findPropertyType(String propertyName, @Nullable Class<?>… beanClasses):获取指定Bean属性的类型。
2. 数据复制场景
想象一下这样的场景:我们从数据库中获取了完整的用户数据,存储在 DTO 中。但是,当我们要将这些数据展示给前端页面时,我们并不希望将所有的字段都暴露出去,只需要传递一些关键的信息。这时,我们就可以利用 BeanUtils 工具类,将 DTO 中这些关键的属性复制到 VO 中,然后将 VO 传递给前端。这样,既保证了数据的安全性,又提高了数据传输的效率。
二、copyProperties方法分析
copyProperties方法的核心可总结为两步。
- 获取目标对象及其getter和setter方法
Class<?> actualEditable = target.getClass();
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
- 遍历目标对象的所有属性,并通过反射机制从源对象中获取对应属性的值,最后赋值给目标对象
for (PropertyDescriptor targetPd : targetPds) {Method writeMethod = targetPd.getWriteMethod();// 确保write方法存在if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());if (sourcePd != null) {Method readMethod = sourcePd.getReadMethod();// 确保read方法存在if (readMethod != null &&ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {try {// 设置读方法的可访问性if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {readMethod.setAccessible(true);}// 获取source类对应属性的值Object value = readMethod.invoke(source);// 设置写方法的可访问性if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {writeMethod.setAccessible(true);}// 赋值writeMethod.invoke(target, value);}catch (Throwable ex) {throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", ex);}}}}}
通过上述步骤,copyProperties方法能够有效地实现对象间属性值的复制,同时支持忽略指定属性,从而满足不同场景下的需求。
三、总结
BeanUtils类的copyProperties方法,在保证数据安全的前提下,高效地实现了 DTO 和 VO 之间的数据复制。在实际开发中,我们要充分理解和掌握它的原理和使用方法,同时注意可能出现的问题,如属性名称匹配、类型兼容性((《MyBatis 数据表与实体映射的隐藏陷阱》))和性能优化等。