摘要
當前web後端開發,都是使用多層工程結構,需要在VO,BO,DTO,DO等各種資料結構中相互轉換。這些轉換程式碼都是些比較簡單的欄位對映,型別轉換,重複性工作比較高,可以使用一些工具解放我們的雙手
技術方案
實現類轉換的方案很多,不同方案有優缺點,需要開發者自行取捨
方案 | 優點 | 缺點 |
---|---|---|
手寫程式碼 | 1. 靈活性高 2.方便後續重構 | 1. 重複性工作多 2. 手寫程式碼容易遺漏掉有些欄位 |
BeanUtils.copyProperties 使用反射實現 | 1. 使用簡單 2. Apache 的包效率比較低,spring的包效率可以接受 | 1. 複雜場景支援不足,控制copy粒度太粗 2. 不易重構 |
mapstruct | 1. 靈活性高支援簡單,複雜,巢狀,自定義擴充套件等多種手段 2. 編譯期生成,沒有效率問題 | 不方便後續重構 |
方便後續重構
方便後續重構的意思是當你需要更改DTO欄位時,可以利用編譯器的引用關係直接refactor掉
綜上考慮mapstruct方案優於beanutils.copy,和手寫方案對比,有一定劣勢,需要取捨。個人意見,對於改欄位重構,這種應該通過測試用例去保證,而不是依賴編輯器的功能。此外使用mapstruct進行轉換後,類引用關係還在,重構可以通過識別類的粒度,來保證不出錯。如果再考慮到手工黨的出錯概率,和開發效率mapstruct顯然更優。
實現
- 引入依賴包
<properties>
<org.mapstruct.version>1.3.1.Final</org.mapstruct.version>
</properties>
...
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
</dependencies>
- 為maven compile plugin 設定annotation processor
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source> <!-- depending on your project -->
<target>1.8</target> <!-- depending on your project -->
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</path>
<!-- other annotation processors -->
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
- IDEA 安裝一個mapstruct 外掛
有了這個外掛後,可以找到對映類的屬性,一些拼寫校驗
常用用法
預設情況下,當屬性值與目標實體的名稱相同時,就會隱式對映
其他通用轉換
屬性值不相同時
@Mapping(target="dateEnd", source="end")
ExampleVO doToVO(ExampleDO do);
Collection物件轉換
@Mapping(target="dateEnd", source="end")
ExampleVO doToVO(ExampleDO do);
List<ExampleVO> doToVOS(List<ExampleDO> dos)
JAVA 構造器
通過expression 來呼叫Java代表
@Mapping(target="dateEnd", expression="java(new java.util.Date())"
ExampleVO doToVO(ExampleDO do);
qualifiedByName
如果構造器滿足不了,還可以自定義方法,然後再呼叫
@Mapping(target="dateEnd", qualifiedByName="format", source="end")
ExampleVO doToVO(ExampleDO do);
@Named("format")
default Date formatDate(Long date) {
xxx
}
介面預設實現
mapstruct是使用者定義介面,然後自動生成實現類,如果轉換類中有非常定製的轉換,不想通過mapstruct來轉換,我們可以直接使用介面預設實現
當然還有其他功能可以使用,比如Decorator,這裡不再一一列舉,更多豐富的功能可以檢視mapstruct 細節使用