Java中MapStruct復(fù)制對象的具體使用
一、前言
大家在開發(fā)中,最讓人頭疼的就是:對象之間的拷貝,前端的VO和數(shù)據(jù)庫的Entity不一致!
性能最好的就是手動set
,主要是枯燥且無技術(shù)含量,不僅耗費大量時間而且很容易出錯;
所以我們要成為優(yōu)秀的程序員,要多借助輪子,開發(fā)效率事半功倍,開發(fā)技能也是增長不少!
如果系統(tǒng)性能沒有要求,怎么實現(xiàn)都是好的,但是我們要有追求哈,追求高質(zhì)量!
每個東西都有存在的價值,不要捧一踩一哈!
二、MapStruct簡介
MapStruct是基于JSR 269
的Java注釋處理器,用于生成類型安全的 Bean 映射類。
您所要做的就是定義一個映射器接口,該接口聲明任何所需的映射方法。在編譯過程中,MapStruct將生成此接口的實現(xiàn)
。此實現(xiàn)使用純 Java 方法調(diào)用在源對象和目標(biāo)對象之間進行映射,即無反射
或類似內(nèi)容。
與手動編寫映射代碼相比,MapStruct通過生成繁瑣且容易出錯的代碼來節(jié)省時間
。遵循配置方法的約定
,MapStruct使用合理的默認值,但在配置或?qū)崿F(xiàn)特殊行為時會步入歧途。
在這里插入圖片描述
三、優(yōu)勢
與動態(tài)映射框架相比,MapStruct具有以下優(yōu)點:
通過使用普通方法調(diào)用而
不是反射
快速執(zhí)行編譯時類型安全
:只能映射彼此映射的對象和屬性,不會意外地將訂單實體映射到客戶 DTO 等。在構(gòu)建時清除錯誤報告,如果
- 映射不完整(并非所有目標(biāo)屬性都已映射)
- 映射不正確(找不到正確的映射方法或類型轉(zhuǎn)換)
性能圖大家可以看一下:
四、整合實戰(zhàn)
0. 使用
@Mapper
將接口標(biāo)記為映射接口 對于源對象和目標(biāo)對象中具有不同名稱的屬性,可以使用注釋來配置名稱:@Mapping
按照約定,接口聲明一個成員Mappers INSTANCE
,為客戶端提供對映射器實現(xiàn)的訪問。下面我們來具體使用!
1. 導(dǎo)入依賴
這里使用最新的,如果引入了lombok可能會有問題,就是他們倆都是在編譯期運行的,mapstruct如果比lombok先執(zhí)行,就會找不到get、set方法,所以會有問題,官網(wǎng)已經(jīng)有了解決方案!現(xiàn)在是啟動不會報錯!
<dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>1.5.3.Final</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> </dependency>
2. 錯誤總結(jié)
- 不會自動生成impl實現(xiàn)類?
我們需要加上依賴:
<dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>1.5.3.Final</version> </dependency>
- 重新啟動就會出現(xiàn)和lombok的沖突問題:
java: No property named "name" exists in source parameter(s).
Type "UserVO" has no properties.
官網(wǎng)解決文章地址
<build> <pluginManagement> <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.5.3.Final</version> </path> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> </path> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok-mapstruct-binding</artifactId> <version>0.2.0</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </pluginManagement> </build>
3. 常用實戰(zhàn)1
用戶表:
@Data public class User { private Integer id; private String username; private Integer age; }
前端用戶VO:
@Data public class UserVO { private Integer id; private String name; private Integer age; }
我們創(chuàng)建接口進行兩個對象之間的映射:
import com.example.demo.mapstruct.entity.User; import com.example.demo.mapstruct.entity.UserVO; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; /** * @author wangzhenjun * @date 2023/1/28 16:05 */ @Mapper public interface UserMapper { UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); @Mapping(source ="name",target = "username") User userVOToUser(UserVO userVO); }
屬性多了可以嵌套:
@Mappings({ @Mapping(source ="name",target = "username"), @Mapping(source ="name1",target = "username1") })
也可以:
@Mapping(source ="name",target = "username") @Mapping(source ="name1",target = "username1")
編寫測試類:
@SpringBootTest class DemoApplicationTests { @Test void demoMapstruct(){ UserVO userVO = new UserVO(1,"小紅",18); User user = UserMapper.INSTANCE.userVOToUser(userVO); System.out.println(user); } }
我們看到拷貝沒有任何問題!
我們看看是怎么實現(xiàn)的:
mapstruct
會在編譯期自動生成實現(xiàn)類去幫助我們?nèi)ベx值,不指定默認策略,名稱一致進行copy!不一致可以按上面的進行指定,不指定則不會有set方法!
4. 常用實戰(zhàn)2
下面進行多個源參數(shù)的映射方法演示:
我們把user類加上一個字段:
private BigDecimal score;
新增加一個Score
類:
@Data @AllArgsConstructor public class Score { private Integer studentId; private BigDecimal score; }
調(diào)整上面的UserMapper
接口:
@Mappings({ @Mapping(source ="userVO.name",target = "username"), @Mapping(source ="score.score",target = "score") }) User userVOToUser(UserVO userVO, Score score);
測試代碼:
UserVO userVO = new UserVO(1,"小紅",18); Score score = new Score(1,new BigDecimal(100)); User user = UserMapper.INSTANCE.userVOToUser(userVO,score); System.out.println(user);
結(jié)果顯示正常:
5. 常用實戰(zhàn)3
我們再來看一個企業(yè)級能夠用得上的,就是自定義方法,然后進行賦值:
場景:一個商品有長寬高,我們把長寬高從cm變?yōu)閙!
還有很多String轉(zhuǎn)Integer、Float等等,都是按照下面這種自定義方法去實現(xiàn)!
VO和對象都是一樣的哈!
@Data @AllArgsConstructor public class ProductVO { private Integer id; private String name; private BigDecimal length; private BigDecimal width; private BigDecimal high; }
看清楚,別導(dǎo)錯包了!qualifiedByName
:指定自定義方法的名稱@Named("cmToM")
:起別名,不使用找不到方法
可以寫一起,也可以整一個工具類里寫方法,在這里進行引用!如果是使用spring,我們可以把接口作為bean進行注入調(diào)用(推薦) 加上參數(shù)即可開啟:@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
/** * @author wangzhenjun * @date 2023/1/28 17:13 */ @Mapper(componentModel = MappingConstants.ComponentModel.SPRING) public interface ProductMapper { @Mapping(source = "length",target = "length",qualifiedByName = "cmToM") @Mapping(source = "width",target = "width",qualifiedByName = "cmToM") @Mapping(source = "high",target = "high",qualifiedByName = "cmToM") Product productVOToPrduct(ProductVO productVO); @Named("cmToM") default BigDecimal cmToM (BigDecimal oldValue){ if (oldValue == null) { return BigDecimal.ZERO; } return oldValue.divide(new BigDecimal("100")); } }
測試:
@SpringBootTest class DemoApplicationTests { @Autowired private ProductMapper productMapper; @Test void demoMapstruct(){ ProductVO productVO = new ProductVO(1,"美麗家園地板",new BigDecimal(100),new BigDecimal(50),new BigDecimal(8)); Product product = productMapper.productVOToProduct(productVO); System.out.println(product); } }
完美轉(zhuǎn)化!
6. 常用實戰(zhàn)4
在實戰(zhàn)一個LocalDateTime、String相互轉(zhuǎn)化的
,后面大家可以去官網(wǎng)文檔去找你需要的:
在剛剛的商品類加個字段:
private String createdAt;
VO里也加上一個:
private LocalDateTime createdAt;
編寫個轉(zhuǎn)化類:這里交給spring管理了,因為ProductMapper也交給spring管理,不加的話會找不到此類!
@Component public class LocalDateTimeMapper { public String asString(LocalDateTime date) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); return date != null ? date.format(formatter): null; } public LocalDateTime asLocalDateTime(String date) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); return date != null ? LocalDateTime.parse(date,formatter) : null; } }
ProductMapper修改一下:
uses = LocalDateTimeMapper.class
使用咱們上面寫的類即可!
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING,uses = LocalDateTimeMapper.class) public interface ProductMapper { @Mapping(source = "length",target = "length",qualifiedByName = "cmToM") @Mapping(source = "width",target = "width",qualifiedByName = "cmToM") @Mapping(source = "high",target = "high",qualifiedByName = "cmToM") Product productVOToProduct(ProductVO productVO); @Named("cmToM") default BigDecimal cmToM (BigDecimal oldValue){ if (oldValue == null) { return BigDecimal.ZERO; } return oldValue.divide(new BigDecimal("100")); } }
測試一下:
ProductVO productVO = new ProductVO(1,"美麗家園地板", new BigDecimal(100),new BigDecimal(50), new BigDecimal(8), LocalDateTime.now()); Product product = productMapper.productVOToProduct(productVO); System.out.println(product);
完美轉(zhuǎn)化:
五、總結(jié)
通過簡介到實戰(zhàn),這時咱們就是優(yōu)雅的程序員了!
更多的例子可以去官網(wǎng)進行查看:
alue.divide(new BigDecimal(“100”)); } }
測試一下:
ProductVO productVO = new ProductVO(1,“美麗家園地板”, new BigDecimal(100),new BigDecimal(50), new BigDecimal(8), LocalDateTime.now()); Product product = productMapper.productVOToProduct(productVO); System.out.println(product);
mapstruct開發(fā)文檔:https://mapstruct.org/documentation/stable/reference/html/#Preface
到此這篇關(guān)于Java中MapStruct復(fù)制對象的具體使用的文章就介紹到這了,更多相關(guān)Java MapStruct復(fù)制對象內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring 使用JavaConfig實現(xiàn)配置的方法步驟
這篇文章主要介紹了Spring 使用JavaConfig實現(xiàn)配置的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01spring boot實現(xiàn)profiles動態(tài)切換的示例
Spring Boot支持在不同的環(huán)境下使用不同的配置文件,該技術(shù)非常有利于持續(xù)集成,在構(gòu)建項目的時候只需要使用不同的構(gòu)建命令就可以生成不同運行環(huán)境下war包,而不需要手動切換配置文件。2020-10-10給@Value設(shè)置默認值以及為static變量賦值問題
在Spring框架中,@Value注解用于屬性注入,可將配置文件中的值賦給變量,未指定默認值時,若配置文件缺少相應(yīng)屬性,程序啟動會報錯,可通過設(shè)定默認值防止此問題,對于靜態(tài)變量,由于@Value無法直接注入,需通過Set方法賦值,該方法也支持默認值設(shè)置2024-09-09SpringBoot利用自定義json序列化器實現(xiàn)敏感字段數(shù)據(jù)脫敏詳解
這篇文章主要介紹了SpringBoot利用自定義json序列化器實現(xiàn)敏感字段數(shù)據(jù)脫敏詳解,因為案例代碼用到了hutool提供的DesensitizedUtil數(shù)據(jù)脫敏工具類,這里要引入hutool的依賴,如果你需要自定義 數(shù)據(jù)脫敏的邏輯,可以不引入這個依賴,需要的朋友可以參考下2024-01-01Java實現(xiàn)DFA算法對敏感詞、廣告詞過濾功能示例
本篇文章主要介紹了Java實現(xiàn)DFA算法對敏感詞、廣告詞過濾功能示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11nacos gateway動態(tài)路由實戰(zhàn)
這篇文章主要介紹了nacos gateway動態(tài)路由實戰(zhàn),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09