【java基础】BeanUtils.copyProperties 的使用介绍

464 阅读2分钟

BeanUtils.copyProperties 的使用介绍

背景

最近在做个项目,需要从Excel 中读取数据后,再做具体的业务处理,由于Excel 中的列表会出现变动的情况,常常是多一列或者是少一个列这种情况,所以需要分别建立两个对象,一个是workOrderReadExcel,另外一个就是workOrder。由于两个对象中存在较多相同的属性,之前我是一个一个属性去set 和get 去处理,而且属性多达30个以上,较为繁琐,且代码上较为冗余,于是想看看有没有什么简单的方法去处理?

处理

使用 org.springframework.beans.BeanUtilscopyProperties,其原理就是通过 反射机制,获取源对象和目标对象的属性,去分别映射,并将对应的属性去赋值,这样一定程度上大大减少了代码量,也提高了代码的可读性和维护性。

 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)

image.png

重点主要说一下,我自己犯过的错,引入的包的问题

 //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  

还有一个是性能问题,简单的setterBeanUtils.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 两种方法,性能上差不多。

image.png

题外

在了解BeanUtils.copyProperties 的使用背景时,有博主提到 VO、DTO、DO、PO,各种实体类用于不同业务层次间的交互,并会在层次内实现实体类之间的转化。自己对VO、DTO、DO、PO 相关概念不是很清楚,就找到资料查看了一下。

VO 是视图对象

DTO 是数据传输对象

DO 是领域对象

PO 是持久化对象

image.png

领域驱动模型 VO、DTO、DO、PO 概念及其区别 - 掘金 (juejin.cn)