Java中MapStruct對象映射的實現(xiàn)
簡介
MapStruct是一種實體類映射框架,能夠通過Java注解將一個實體類的屬性安全地賦值給另一個實體類。有了mapstruct,只需要定義一個映射器接口,聲明需要映射的方法,在編譯過程中,mapstruct會自動生成該接口的實現(xiàn)類,實現(xiàn)將源對象映射到目標對象的效果。
MapStruct是基于JSR 269實現(xiàn)的,JSR 269是JDK引進的一種規(guī)范。有了它,能夠實現(xiàn)在編譯期處理注解,并且讀取、修改和添加抽象語法樹中的內(nèi)容。JSR 269使用Annotation Processor在編譯期間處理注解,Annotation Processor相當于編譯器的一種插件,因此又稱為插入式注解處理。官網(wǎng)通道 | Github
優(yōu)點
安全性高:由于映射是在編譯期間實現(xiàn)的,如果編譯器能夠通過,運行期就不會報錯。
高性能:編譯時生成bean映射的實現(xiàn)類,通過使?普通?法(getter/setter)調(diào)??不是反射來快速執(zhí)?。
缺點
使用復雜度:對于更復雜的映射,需要開發(fā)人員編寫自定義映射接口和函數(shù)。
同類對比
映射工具 | 實現(xiàn)機制 | 性能對比 | 備注 |
Dozer | 反射機制 | 中 | 使用遞歸將數(shù)據(jù)從一個對象復制到另一個對象 |
Orika | 反射機制 | 中 | 同Dozer,不過Orika 使用字節(jié)碼生成 |
ModelMapper | 反射機制 | 中 | 簡單易用,它根據(jù)約定確定對象之間的映射方式 |
JMapper | 編譯生成 | 高 | 基于Javassist 的Java映射框架 |
MapStruct | 編譯生成 | 高 | 在編譯時生成bean映射,以確保高性能、徹底的錯誤檢查 |
快速入門
Maven依賴
<!-- 定義版本 -->
<properties>
<org.mapstruct.version>1.6.0</org.mapstruct.version>
<org.projectlombok.mapstruct.version>0.2.0</org.projectlombok.mapstruct.version>
</properties>
<!-- 依賴包 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<!--MapStruct會用到對象中的get、set方法,但get、set方法又需要lombok來生成。因此需要控制這兩者工作順序-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${org.projectlombok.mapstruct.version}</version>
</dependency>
編譯插件
<!-- 方式一-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</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>17</source>
<target>17</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>Model定義
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserDTO implements Serializable {
private Integer id;
private String userName;
private String password;
private Integer age;
private String address;
private String email;
private List<UserRole> roles;
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserVO implements Serializable {
private Integer id;
private String name;
private String pwd;
private Integer age;
private String email;
private List<UserRole> roles;
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserRole implements Serializable {
private Integer roleId;
private String roleName;
private String remark;
}
Mapper定義
//@Mapper(componentModel = "spring")
@Mapper
public interface MapStructMapper {
MapStructMapper INSTANCE = Mappers.getMapper(MapStructMapper.class);
/**
* 單個對象轉換
* @param userDTO
* @return
*/
UserVO userDtoToVO(UserDTO userDTO);
/**
* 集合對象轉換
* @param userDTO
* @return
*/
List<UserVO> userDtoToVOList(List<UserDTO> userDTO);
}重要:SpringBoot項目可以使用@Mapper(componentModel = "spring")的方式將bean交給spring容器進行管理,因此可以不用寫MapStructMapper INSTANCE = Mappers.getMapper(MapStructMapper.class);
轉換調(diào)用
public void mapStructConvertTest(){
// 初始化用戶
UserDTO userDTO = this.instanceUser();
UserVO userVO = MapStructMapper.INSTANCE.userDtoToVO(userDTO);
log.info("userVO:{}", JSON.toJSONString(userVO));
}
場景示例
常規(guī)映射
@Mapper
public interface MapStructMapper {
MapStructMapper INSTANCE = Mappers.getMapper(MapStructMapper.class);
UserVO userDtoToVO(UserDTO userDTO);
}集合映射
@Mapper
public interface MapStructMapper {
MapStructMapper INSTANCE = Mappers.getMapper(MapStructMapper.class);
List<UserVO> userDtoToVOList(List<UserDTO> userDTO);
}重要:集合轉換時,必須先有單個對象的轉換函數(shù)。并且Mapper中只能有一個同類的原對象與目標對象的轉換,否則集合轉換不知道取哪一個單對象轉換函數(shù)。
單字段映射
@Mapping(target = "pwd", source = "password") UserVO userDtoToVO(UserDTO userDTO);
多字段映射
@Mappings({
@Mapping(target = "pwd", source = "password"),
@Mapping(target = "name", source = "userName"),
})
UserVO userDtoToVOMoreField(UserDTO userDTO);忽略字段
@Mapping(target = "email", ignore = true) UserVO userDtoToVOIgnoreField(UserDTO userDTO);
常量值映射
@Mapping(target = "constant", constant = "OK") UserVO newUserWithConstant(UserDTO userDTO);
默認值映射
@Mapping(source = "email", target = "email", defaultValue = "默認值") UserVO userDtoToVONullDefaultValue(UserDTO userDTO);
表達式映射
@Mapping(target = "fullName", expression = "java(userDTO.getUserName() + ' ' + userDTO.getAddress())") UserVO userDtoToVOExpression(UserDTO userDTO);
@Mapping(target = "email", expression = "java(!userDTO.getEmail().isEmpty()? \"不為空\" : \"為空\")") UserVO userDtoToVOWithCondition(UserDTO userDTO);
執(zhí)行函數(shù)
@Mapping(target = "email", source = "email", qualifiedByName = "toUpperCase")
UserVO emailToUpperCase(UserDTO userDTO);
@Named("toUpperCase")
default String toUpperCase(String value) {
// 轉換大寫
return value == null ? null : value.toUpperCase();
}深拷貝
@Mapper(componentModel = "spring",mappingControl = DeepClone.class)
public interface MapStructMapper {
}說明:mappingControl = DeepClone.class 是指定深拷貝模式,不指定則默認淺拷貝,淺拷貝時集合類是底層是調(diào)用Array 的copy 方法。如果是深拷貝模式,MapStruct框架會生成集合遍歷代碼,集合中元素如果是引用類型會生成引用類型轉換代碼,層層轉換,深度拷貝。集合類拷貝的限制比較多,不支持多層嵌套集合類深拷貝,而且要求源字段和目標字段集合類型嚴格一致。
淺拷貝 :只復制對象的引用,而不會復制對象本身的內(nèi)容。如果更改了原始對象的一個地址,DTO中的地址也會跟著改變,因為它們指向的是同一個對象。
深拷貝:會遞歸地復制對象的所有內(nèi)容,包括嵌套的對象。即使你更改了原始對象中的數(shù)據(jù),DTO中的數(shù)據(jù)也不會受到影響。
逆向映射
/**
* 單個對象映射
* @param userDTO
* @return
*/
UserVO userDtoToVO(UserDTO userDTO);
/**
* 逆向映射
* @param userVO 源 VO 對象
* @return 目標 DTO 對象
*/
@InheritInverseConfiguration
UserDTO userVOToDto(UserVO userVO);說明:正向函數(shù)有業(yè)務邏輯處理或屬性類型不匹配的不能逆向映射
映射后執(zhí)行動作
@AfterMapping
default void afterMapping(UserDTO userDTO, @MappingTarget UserVO userVO) {
// Add custom post-mapping logic here
userVO.setId(10000);
System.out.println("afterMapping:id設置為:"+userVO.getId());
}
延伸內(nèi)容
MapStruct Plus 是 MapStruct 的增強工具,在 MapStruct 的基礎上,實現(xiàn)了自動生成 Mapper 接口的功能,并強化了部分功能,使 Java 類型轉換更加便捷、優(yōu)雅。官網(wǎng)通道 | GitHub
Maven依賴
<properties>
<mapstruct-plus.version>1.4.5</mapstruct-plus.version>
</properties>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>${mapstruct-plus.version}</version>
</dependency>新增配置類
@ComponentModelConfig(componentModel = "default")
public class MapperConfiguration {
}對象映射
@AutoMapper(target = UserDto.class)
@Data
public class User {
// ...
}轉換Map
@AutoMapMapper
@Data
public class MapModelB {
private Date date;
}一個類轉換為多個類
@Data
@AutoMappers({
@AutoMapper(target = UserDto.class),
@AutoMapper(target = UserVO.class)
})
public class User {
// fields
}循環(huán)嵌套
@Data
@AutoMapper(target = TreeNodeDto.class, cycleAvoiding = true)
public class TreeNode {
private TreeNode parent;
private List<TreeNode> children;
}
@Data
@AutoMapper(target = TreeNode.class, cycleAvoiding = true)
public class TreeNodeDto {
private TreeNodeDto parent;
private List<TreeNodeDto> children;
}到此這篇關于Java中MapStruct對象映射的實現(xiàn)的文章就介紹到這了,更多相關MapStruct對象映射內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
apollo更改配置刷新@ConfigurationProperties配置類
這篇文章主要為大家介紹了apollo更改配置刷新@ConfigurationProperties配置類示例解析,apollo更改配置刷新@ConfigurationProperties配置類2023-04-04

