【编程提效】MapStruct对象映射框架(Java Mapping Frameworks)

背景/场景

我们在编程过程中,经常存在实体类的转换。如数据库层对象pojo类 与 底层对外传输的对象 xxResponse类。一般常用的方式是每个值去get/set。幸运的是,我们有很多框架可以解决这种问题。

常见的工具类

  • Spring BeanUtils
  • Apache BeanUtils
  • Dozer
  • Orika
  • MapStruct
  • ModelMapper
  • JMapper
    那我们如何选择这些工具呢

性能对比

不啰嗦,直接上图
在这里插入图片描述
总之,就是 MapStruct性能在各种综合情况下最优

MapStruct使用

maven依赖引入

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.3.1.Final</version>
</dependency>
<!-- lombok插件 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>

打包

<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>1.3.1.Final</version>
                     </path>
                     <path>
                         <groupId>org.projectlombok</groupId>
                         <artifactId>lombok</artifactId>
                         <version>1.18.12</version>
                     </path>
                 </annotationProcessorPaths>
             </configuration>
         </plugin>
     </plugins>
 </build>

示例代码(拷贝到IDE可直接运行)

public class Test {
    public static void main(String[] args) {
        UserDo userDo = new UserDo("zhangsan", 20, "酒仙桥");
        UserResp userResp = SourceMapper.MAPPER.convert(userDo);
        System.out.println( JSON.toJSONString(userResp));
    }
}

/**
 * 原始对象
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
class UserDo {
    private String name;
    private int age;
    private String address;
}


/**
 * 返回给前端的对象
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
class UserResp {
    private String name;
    //这里故意少掉 age属性,看缺失字段是否会成功

	//这里故意写成 addr属性,测试名称不同能否转换
    private String addr;
}

/**
 * 转换器
 */
@Mapper
interface SourceMapper{
    SourceMapper MAPPER = Mappers.getMapper( SourceMapper.class );
	/**
     * 对象转换时参数不对应使用 @Mapping注解 显示指定值的对应关系
     * 如果存在多个可使用 @Mappings注解,里面是个集合
     * 如 @Mappings(value = {
     *             @Mapping(source = "aa", target = "bb" ),
     *             @Mapping(source = "cc", target = "dd" )})
     * @param userDo
     * @return
     */
    @Mapping( source = "address", target = "addr" )
    UserResp convert( UserDo userDo );
}

代码编译后

在 target/generated-sources/annotations 目录会自动生成 SourceMapper的实现类

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2020-05-23T13:08:56+0800",
    comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_60 (Oracle Corporation)"
)
class SourceMapperImpl implements SourceMapper {
    @Override
    public UserResp convert(UserDo userDo) {
        if ( userDo == null ) {
            return null;
        }
        UserResp userResp = new UserResp();
        userResp.setAddr( userDo.getAddress() );
        userResp.setName( userDo.getName() );
        return userResp;
    }
}

安装 MapStruct 插件

在 IDEA 中依次打开 File - > Settings - > Plugins
然后在 Markeyplace 搜索框中输入 mapstruct,点击 install,然后重启 IDE 即可,不再啰嗦啦

MapStruct技术总结

技术要领

  • 需要写个接口做转换器
  • 接口类上需要声明 @Mapper 注解
  • 接口中需声明 SourceMapper MAPPER = Mappers.getMapper( SourceMapper.class );
  • 接口中写要转换的接口:
    • 参数为原始对象,
    • 返回为 要返回的对象
    • 接口上声明要转换的具体参数

框架优点

  • 相对反射来说
    • 框架使用注解生成代码,运行时比较高效。
    • 反射debug困难,这里debug直接到生成的代码中了
  • 编写层面来说
    • 写法快捷高效
    • 手写 set 方法属性太多还容易漏,这里不会
    • 名字不对应恰好又不想返回的属性自动过滤,简直不要太方便了

参考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章