Java的属性拷贝工具类---Mapstruct

Java的属性拷贝工具类



一、BeanUtils.copyProperties的使用场景

涉及到的DO、DTO、VO之间的转换,我们大多使用Spring框架里的BeanUtils.copyProperties来做对象转换,以下举例对比使用工具和不使用工具:

DTO和VO的转换

@Data
public class OrderDTO {
    private long id;
 
    private Long userId;
 
    private String orderNo;
 
    private Date gmtCreated;
}
@Data
public class OrderVO {
    private long id;
 
    private long userId;
 
    private String orderNo;
 
    private Date gmtCreated;
}

不使用工具转换:

public static void main(String[] args) {
    OrderDTO orderDTO = new OrderDTO();
    orderDTO.setId(1L);
    orderDTO.setUserId(123L);
    orderDTO.setOrderNo("20210518000001");
    orderDTO.setGmtCreated(new Date());
 
    OrderVO orderVO = new OrderVO();
    orderVO.setId(orderDTO.getId());
    orderVO.setUserId(orderDTO.getUserId());
    orderVO.setOrderNo(orderDTO.getOrderNo());
    orderVO.setGmtCreated(orderDTO.getGmtCreated());
}

使用工具转换:

OrderVO orderVO = new OrderVO();
BeanUtils.copyProperties(orderDTO, orderVO);
 
//使用自定义工具---如下
OrderVO orderVO=BeanUtil.copyProperties(OrderVO.class, orderDTO);

以下是自定义的一个工具类:

BeanUtil(包装BeanUtils)

package com.test.utils;
 
import java.util.*
import org.springframword.beans.Beanutils;
import org.springframword.util.CollectionUtils;
 
public class BeanUtil extends BeanUtils(
    public BeanUtil(){
    }
    
    public statci<T, E> List<T> Dto2List(Class<T> destType, List<E> orig){
        List<T> dest = new ArratList();
        if (CollectionUtils.isEmpty(orig)){
            return dest;
        }else {
            Iterator it = orig.iterator();
            while(it.hasNext()){
                E e = it.next();
                T obj = BeanUtils.instantiateClase(destType);
                BeanUtils.copyProperties(e, obj);
                dest.add(obj);
            }
            return dest;
        }
   }
        
   public statci<T> T copyProperties(Class<T> destType, Object srcObject){
        if (srcObject == null){
            return null;
        } else {
            T obj = BeanUtils.instantiateClase(destType);
            BeanUtils.copyProperties(srcObject, obj);
            return obj;
        }
    }

二、BeanUtils.copyProperties的避坑

使用该方法是一种浅拷贝,会有坑:

  1. 包装类型转基本类型问题

例如OrderDTO的Long类型转换成OrderDO的long时,会抛java.lang.IllegalArgumentException异常

  1. 空格问题

OrderDTO的字段A带前后空格,转换成OrderDO仍然会有空格,造成脏数据。

  1. 查不到引用字段。

三、BeanUtils的替代工具类——Mapstruct

先上结论,Mapstruct的性能远远高于BeanUtils:

在这里插入图片描述

1. Mapstruct 依赖

使用Mapstruct需要依赖的包如下,mapstruct、mapstruct-processor、lombok,可以去仓库中查看最新版本。

<dependency>
	<groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.0.Final</version>
</dependency>
<dependency>
	<groupId>org.mapstruct</groupId>
	<artifactId>mapstruct-processor</artifactId>
	<version>1.5.0.Final</version>
</dependency>
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.18.12</version>
</dependency>

2. Mapstruct的属性拷贝

UserPo和UserEntity的属性类型和名称完全相同。

package mapstruct;
 
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
 
import java.util.Date;
 
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserPo {
    private Long id;
    private Date gmtCreate;
    private Date createTime;
    private Long buyerId;
    private Long age;
    private String userNick;
    private String userVerified;
}
package mapstruct;
 
import lombok.Data;
 
import java.util.Date;
 
@Data
public class UserEntity {
    private Long id;
    private Date gmtCreate;
    private Date createTime;
    private Long buyerId;
    private Long age;
    private String userNick;
    private String userVerified;
}

定义mapstruct接口,在接口上打上@Mapper注解。

接口中有一个常量和一个方法,常量的值是接口的实现类,这个实现类是Mapstruct默认帮我们实现的,下文会讲到。定义了一个po2entity的转换方法,表示把入参UserPo对象,转换成UserEntity。注意@Mapper是Mapstruct的注解。

package mapstruct;
 
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
 
@Mapper
public interface IPersonMapper {
    IPersonMapper INSTANCT = Mappers.getMapper(IPersonMapper.class);
    UserEntity po2entity(UserPo userPo);
}

3. Mapstruct 性能优于 BeanUtils 的原因

Java程序执行的过程,是由编译器先把java文件编译成class字节码文件,然后由JVM去解释执行class文件。Mapstruct正是在java文件到class这一步帮我们实现了转换方法,即做了预处理,提前编译好文件,如果用过lombok的同学一定能理解其好处,通过查看class文件,可以看出IPersonMapper被打上org.mapstruct.Mapper注解后,编译器自动会帮我们生成一个实现类IPersonMapperImpl,并实现了po2entity这个方法。

在这里插入图片描述
BeanUtils转换的原理是使用的反射,反射的效率相对来说是低的,因为jvm优化在这种场景下有可能无效,所以在对性能要求很高或者经常被调用的程序中,尽量不要使用。我们平时在研发过程中,也会遵守这个原则,非必要,不反射


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GeGe&YoYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值