• 对象转换工具Mapstruct的用法
  • 发布于 2个月前
  • 240 热度
    0 评论
  • 李明发
  • 19 粉丝 37 篇博客
  •   
一. 引言
目前主流的开发项目是采用了分层结构,比如server、core、api三层,其依赖关系为:server-> core -> api这种从上到下关系,因此在高层级定义的对象,低层不可以引用,这保证各层之间相互解耦。为了实现相互解耦,就提出各种XXXDO、XXXVO、XXXBO对象,当在不同层之间传输数据时,不可避免地经常需要将这些对象进行相互转换。

处理的方式一般有几种:
1.使用set方法转换
2.使用现有的工具类进行转换,比如常见的BeanUtil.copyPoroperties("targetObject", "sourceObject")
第一种方式如果对象属性比较多时,需要写很多的set代码,较为繁琐,影响代码观感。第二种方式看起来简洁来很多,但是因为其使用了反射,需要运行时依赖,性能不太好,在高并发的常见下并不常采用。

接下来就来介绍一下MapStruct是如何解决以上两种方式缺点的,并且带来性能提升。

二. MapStruct简介
MapStruct  是一个注解处理器,用于生成类型安全、高性能和无依赖的 Bean 映射代码,其基于约定优于配置方法极大地简化了 Java bean 类型之间映射的实现。源码仓库 Github 地址 MapStruct。总的来说,有如下三个特点:
1.基于注解
2.在编译期自动生成映射转换代码,这是代码性能提升的关键

3.类型安全、高性能、无依赖性


三. MapStruct 使用方法
以下的步骤采用SpringBoot和Maven框架来演示。
① 引入依赖
...
<properties>
    <org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
</properties>
...
<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
</dependencies>
...
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>
...
② 创建相关的转换对象
这里模拟从前端传入的DeviceParam对象,将该对象转为和数据库对应的DO
/**
 * @堆代码 duidaima.com
 * @date 2023-08-07
*/
@Data
public class DeviceParam {
    // 设备id
    private Long applianceId;
    
    // 设备名字
    private String name;
}
/**
 * @date 2023-08-07
*/
@Data
public class DeviceDO {
    // 设备id
    private Long applianceId;
    
    // 设备名字
    private String name;
}
③ 创建转换方法
如下采用来@Mapper注解的方式来实现来两个对象数据的装换
/**
 * @堆代码 duidaima.com
 * @date 2023-08-07
*/
@Mapper
public interface DeviceMapper {

  DeviceMapper INSTANCE = Mappers.getMapper(DeviceMapper.class);

  DeviceDO toDO(DeviceParam param);
}
使用方式
DeviceParam param = new DeviceParam();
param.setApplianceId("123456");
param.setName("客厅电视");
// 调用方式
DeviceDO deviceDO = DeviceMapper.INSTANCE.toDO(param);
// 打印
System.out.println(deviceDO.toString);
经过如上简单的配置后,就实现来param到DO的装换,真的简单方便呀。

四. 原理浅析
如上, MapStruct 通过简单的三步就实现了 DeviceParam 到 DeviceDO 的转换,那么,它是如何做到的呢?其实通过我们定义的转换器可以发现,转换器是接口类型的,而在 Java规范中,接口只是负责功能定义,并不能直接提供功能操作,具体干活的还得需要其实现类。基于此,我们将以上的注解配置经过编译后,发现,每个接口都有个实现类,那就是MapStruct帮忙我们实现了接口。
public class DeviceMapperImpl implements DeviceMapper {
    @Override
    public DeviceDO toDO(DeviceParam param) {
        if(param == null){
            return null;
        }
        DeviceDO deivceDO = new DeviceDO();
        if(param.getApplianceId() != null){
            deviceDO.setApplianceId(param.getApplianceId());
        }
        if(param.getName() != null){
            deviceDO.setApplianceId(param.getName());
        }
        return deviceDO;
    }
}
五. 其他使用场景
当对象属性类型相同但是属性名称不一样时,通过 @Mapping 注解来手动指定转换。示例代码如下:
/**
 * @堆代码 duidaima.com
 * @date 2023-08-07
*/
@Data
public class DeviceParam {
    // 设备id
    private Long applianceId;
    
    // 设备名字
    private String deviceName;
}
/**
 * @author codejames
 * @date 2023-08-07
*/
@Data
public class DeviceDO {
    // 设备id
    private Long applianceId;
    
    // 设备名字
    private String name;
}
/**
 * @date 2023-08-07
*/
@Mapper
public interface DeviceMapper {

  DeviceMapper INSTANCE = Mappers.getMapper(DeviceMapper.class);

  @Mapping(source = "deviceName", target = "name")
  DeviceDO toDO(DeviceParam param);
}
除了单个对象的转换,MapStruct也支持List等类型的转换。

六. 小结
综上所述,简单介绍了对象转换工具 Mapstruct 库,以安全优雅的方式来减少我们的转换代码,使用非常方便。并且MapStruct是在编译期的时候实现代码装换,没有运行时依赖,故其执行的效率很高。
用户评论