【編程提效】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 方法屬性太多還容易漏,這裏不會
    • 名字不對應恰好又不想返回的屬性自動過濾,簡直不要太方便了

參考

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