BeanUtils.copyProperties 的使用介绍
背景
最近在做个项目,需要从Excel 中读取数据后,再做具体的业务处理,由于Excel 中的列表会出现变动的情况,常常是多一列或者是少一个列这种情况,所以需要分别建立两个对象,一个是workOrderReadExcel,另外一个就是workOrder。由于两个对象中存在较多相同的属性,之前我是一个一个属性去set 和get 去处理,而且属性多达30个以上,较为繁琐,且代码上较为冗余,于是想看看有没有什么简单的方法去处理?
处理
使用 org.springframework.beans.BeanUtils的copyProperties,其原理就是通过 反射机制,获取源对象和目标对象的属性,去分别映射,并将对应的属性去赋值,这样一定程度上大大减少了代码量,也提高了代码的可读性和维护性。
List<workOrderReadExcel> dataList = (List<workOrderReadExcel>)result;
for (workOrderReadExcel row : dataList) {
workOrder workorder = new workOrder();
try {
BeanUtils.copyProperties(workorder,row);
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
}
}
问题
具体的问题如下,可以参考捡田螺的小男孩这篇文章 BeanUtils.copyProperties的11个坑 - 掘金 (juejin.cn)
重点主要说一下,我自己犯过的错,引入的包的问题
//org.springframework.beans.BeanUtils(源对象在左边,目标对象在右边)
public static void copyProperties(Object source, Object target) throws BeansException
//org.apache.commons.beanutils.BeanUtils(源对象在右边,目标对象在左边)
public static void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException
还有一个是性能问题,简单的setter和BeanUtils.copyProperties对比,setter要快的很多.
处理方案
第一种使用原始的setter 和 getter 方法,可以使用generaterAllSetter 插件,一键生成。
第二种使用映射工具库,MapStruct、ModelMapper等,可以自动生成属性映射代码。
ModelMaper
(1)引入 maven
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>1.1.0</version>
</dependency>
(2)代码简单操作
//创建 ModelMapper 类
ModelMapper modelMapper = new ModelMapper();
// S 实体相同字段映射到 T 实体
T map = modelMapper.map(S s, T.class);
MapStruct
(1)引入 maven
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.2.0.Final</version>
</dependency>
(2)代码简单操作
@Mapper
public interface SourceTargetMapper {
SourceTargetMapper INSTANCE = Mappers.getMapper(SourceTargetMapper.class);
@Mapping(source = "name", target = "name")
@Mapping(source = "age", target = "age")
Target mapToTarget(Source source);
}
Target target = SourceTargetMapper.INSTANCE.mapToTarget(source);
最后,经过测试ModelMaper 与 MapStruct 两种方法,性能上差不多。
题外
在了解BeanUtils.copyProperties 的使用背景时,有博主提到 VO、DTO、DO、PO,各种实体类用于不同业务层次间的交互,并会在层次内实现实体类之间的转化。自己对VO、DTO、DO、PO 相关概念不是很清楚,就找到资料查看了一下。
VO 是视图对象
DTO 是数据传输对象
DO 是领域对象
PO 是持久化对象