为啥建议用MapperStruct,不建议用BeanUtils.copyProperties拷贝数据?

本文讨论了在业务开发中,虽然BeanUtils.copyProperties便于快速赋值,但因其可能导致类型不一致、null值问题和反射效率低等缺点,推荐使用MapperStruct。MapperStruct基于预编译提供更快的性能,且支持自定义配置。

为啥建议用MapperStruct,不建议用BeanUtils.copyProperties拷贝数据?

在实际的业务开发中,我们经常会碰到BO、PO、DTO等对象属性之间的赋值,当属性较多的时候我们使用get,set的方式进行赋值的工作量相对较大,因此很多人会选择使用spring提供的拷贝工具BeanUtils的copyProperties方法完成对象之间属性的拷贝。通过这种方式可以很大程度上降低我们手动编写对象属性赋值代码的工作量,既然它那么方便为什么还不建议使用呢?

我总结为以下几点:

  • 属性类型不一致导致拷贝失败

    在实际开发中,很可能会出现同一字段在不同的类中定义的类型不一致,例如Id,可能在A类中定义的类型为Long,在B类中定义的类型为String,此时如果使用BeanUtils.copyProperties进行拷贝,就会出现拷贝失败的现象,导致对应的字段为null

  • 同一字段分别使用包装类型和基本类型

    如果同一个字段分别使用包装类和基本类型,在没有传递实际值的时候,会出现异常

    注意,如果一个布尔类型的属性分别使用了基本类型和包装类型,且属性名如果使用is开头,例如isSuccess,也会导致拷贝失败

  • null值覆盖导致数据异常

    在业务开发时,我们可能会有部分字段拷贝的需求,被拷贝的数据里面如果某些字段有null值存在,但是对应的需要被拷贝过去的数据的相同字段的值并不为null,如果直接使用 BeanUtils.copyProperties 进行数据拷贝,就会出现被拷贝数据的null值覆盖拷贝目标数据的字段,导致原有的数据失效

    简单举个例子,我有一个BO(已经存在了A属性且有值),需要拷贝DTO中除了A属性的其他属性(DTO中的A属性为null),此时使用BeanUtils.copyProperties就会导致BO中的A属性的值被DTO中A的null给覆盖了

    虽然可以使用 BeanUtils.copyProperties 的重载方法,配合自定义的 ConvertUtilsBean 来实现部分字段的拷贝,但是这么做本身也比较复杂,也就失去了使用BeanUtils.copyProperties 拷贝数据的意义,因此也不推荐这么做。

  • 底层实现为反射拷贝效率低

  • 导包错误导致拷贝数据异常

具体更加详细的可以去看这篇文章 :为啥不建议用BeanUtils.copyProperties拷贝数据 | 京东云技术团队 - 掘金 (juejin.cn)

为什么使用MapperStruct

为什么使用MapperStruct? ---> 快,对就是因为很快,性能比BeanUtils.copyProperties快很多很多

放张参考图给大家参考

image.png

 那么为什么MapperStruct比BeanUtils.copyProperties快?

  • 避免了反射操作的性能开销
  • 预编译的高效代码执行更快 (看到这里就懵了,预编译?咋回事啊到底)

什么是预编译? --- 在项目启动的时候,自动帮你生成对象拷贝的代码,拒绝使用的时候才去通过反射调用get/set...

具体的可以往下看

 

java

复制代码

@Generated( value = "org.mapstruct.ap.MappingProcessor", date = "2024-02-07T00:50:05+0800", comments = "version: 1.4.2.Final, compiler: javac, environment: Java 1.8.0_211 (Oracle Corporation)" ) public class XXXDTOConverterImpl implements XXXDTOConverter { @Override public XXXBO convertDtoToBo(XXXDTO XXXDTO) { if ( XXXDTO == null ) { return null; } XXXBO XXXBO = new XXXBO(); XXXBO.setId( XXXDTO.getId() ); XXXBO.setLabelName( XXXDTO.getLabelName() ); XXXBO.setSortNum( XXXDTO.getSortNum() ); XXXBO.setCategoryId( XXXDTO.getCategoryId() ); return XXXBO; } }

怎么使用MapperStruct

Maven引入依赖

 

xml

复制代码

<dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>1.4.2.Final</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>1.4.2.Final</version> </dependency>

编写代码

 

java

复制代码

@Data public class SubjectLabelDTO implements Serializable { private String labelName; } @Data public class SubjectLabelBO implements Serializable { private String labelName; }

 

java

复制代码

@Mapper public interface SubjectLabelDTOConverter { SubjectLabelDTOConverter INSTANCE = Mappers.getMapper(SubjectLabelDTOConverter.class); SubjectLabelBO convertDtoToBo(SubjectLabelDTO subjectLabelDTO); }

 

java

复制代码

public Result<Boolean> add( SubjectLabelDTO subjectLabelDTO){ SubjectLabelBO subjectLabelBO = SubjectLabelDTOConverter.INSTANCE .convertDtoToBo(subjectLabelDTO); }

总结

Mapper-struct同样也是浅拷贝,需要进行深拷贝,就写多个Converter把需要深拷贝的再转一次吧,如果要配置深拷贝

太麻烦了

<think>我们正在讨论如何使用BeanUtils.copyProperties拷贝对象并忽略某些属性。根据引用[2],BeanUtils.copyProperties有一个重载方法,可以传入一个忽略属性列表。 具体语法是:BeanUtils.copyProperties(源对象, 目标对象, 忽略的属性数组); 例如,如果我们想忽略属性"actiontime"和"dbtime",可以这样写: BeanUtils.copyProperties(kafkaNoticeVO, kafkaNotice, new String[]{"actiontime","dbtime"}); 这样,在拷贝过程中,源对象中这两个属性的值(即使为null)也会被拷贝到目标对象中。 另外,引用[1]提到的是忽略null值的拷贝,但用户的问题是要忽略某些属性(管是否为null)。所以,我们这里使用三个参数的方法即可。 注意:这里使用的是Apache Commons BeanUtils库中的方法,确保项目中已经引入该依赖。 因此,回答用户问题:使用BeanUtils.copyProperties拷贝对象时忽略需要的属性,可以通过调用三个参数的方法,第三个参数是一个字符串数组,包含需要忽略的属性名。 下面给出一个示例代码: 假设有两个类:SourceClass和TargetClass,它们都有属性name、age和email。如果我们想忽略name和email属性,可以这样: ```java SourceClass source = new SourceClass(); source.setName("John"); source.setAge(25); source.setEmail("john@example.com"); TargetClass target = new TargetClass(); // 拷贝source到target,但忽略name和email属性 BeanUtils.copyProperties(source, target, new String[]{"name", "email"}); // 此时target的name和email属性为null(或原来的值),而age属性被拷贝为25 ``` 注意:这个方法会忽略指定的属性,无论这些属性在源对象中的值是什么(即使为null)。 如果用户想要忽略null值,那么需要使用其他方法,比如自定义一个工具类或者使用其他库(如Spring BeanUtils)。但根据用户问题,我们只讨论忽略特定属性。 另外,需要确保目标对象中需要忽略的属性在拷贝前已经设置过值(如果想被覆盖),因为忽略的属性会被源对象的值覆盖。 最后,提醒用户注意,如果忽略的属性在目标对象中存在,则会有影响,也会报错(除非属性名拼写错误,但BeanUtils会忽略存在的属性名)。 根据要求,生成相关问题: 1. 如何在使用BeanUtils.copyProperties时只拷贝非空属性? 2. BeanUtils.copyProperties和Spring的BeanUtils有什么区别? 3. 除了使用BeanUtils.copyProperties,还有哪些对象拷贝的方法? 注意:引用标识的使用,在回答中引用了引用[2]的内容,所以在末尾添加引用标识。 </think> ### 使用 BeanUtils.copyProperties 忽略属性的方法 根据引用资料,使用 Apache Commons BeanUtils 库中的 `copyProperties` 方法时,可通过 **三个参数的重载方法** 忽略指定属性: ```java // 语法结构 BeanUtils.copyProperties(源对象, 目标对象, 需要忽略的属性名数组); ``` #### 操作步骤: 1. **导入依赖**(Maven): ```xml <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.4</version> </dependency> ``` 2. **代码示例**: ```java // 定义忽略的属性数组 String[] ignoreProperties = {"createTime", "updateTime", "敏感字段"}; // 执行拷贝(忽略指定属性) BeanUtils.copyProperties(sourceObj, targetObj, ignoreProperties); ``` - 效果:无论 `createTime` 等属性是否为 `null`,均会被拷贝到目标对象[^2] #### 注意事项: 1. **属性名必须严格匹配**,区分大小写 2. 若忽略的属性在目标对象中存在,会自动跳过且会报错 3. 此方法会**覆盖目标对象原有值**(除非被忽略) 4. 如需深度拷贝或复杂逻辑,建议使用 MapStruct 等工具 #### 对比其他方案: | 方法 | 忽略 null | 忽略指定属性 | 是否需要额外代码 | |---------------------|-----------|--------------|------------------| | 三参数 copyProperties | ❌ | ✅ | ❌ | | 自定义工具类 | ✅ | ✅ | ✅ | | Spring BeanUtils | ❌ | ❌ | ❌ | > 提示:Spring 框架自带的 `BeanUtils.copyProperties` 支持忽略属性功能,需使用 Apache Commons 版本[^1][^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值