Java中的MapStruct知識點總結(jié)
1. 概念
在系統(tǒng)工程開發(fā)過程中,會有各個層之間的對象轉(zhuǎn)換,比如 VO、DTO、PO、DO 等,如果都是手動 setter、getter 特別浪費時間,還可能操作錯誤,所以選擇一個自動化工具會更加方便。常見的有 json2Json、Apache 和 Spring 的 BeanUtils.copyProperties()、BeanCopier、JMapper 等
對象屬性轉(zhuǎn)換的操作無非是基于反射、AOP、CGlib、ASM、Javassist 在編譯時和運行期進行處理,再有好的思路就是在編譯前生成出對應(yīng)的 setter、getter,就像手寫出來的一樣。MapStruct 就是直接在編譯期生成對應(yīng)的 setter、getter,性能更好、使用方便
2. POM
導(dǎo)入依賴
<dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>1.5.0.RC1</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>1.5.0.RC1</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-jdk8</artifactId> <version>1.5.0.RC1</version> </dependency>
可以選擇在 IDEA 中下載其插件

3. 實體類
定義幾個 DO 和 DTO
// UserDO
@Data
@Builder
public class UserDO {
private Integer id;
private String name;
private Integer age;
private String address;
private String birthday;
private String phone;
private String userDOGender;
private Date createTime;
private Map<String, String> map;
private List<PersonDO> personList;
}
// UserDTO
@Data
@Builder
public class UserDTO {
private Integer id;
private String name;
private Integer age;
private String address;
private String userDTOGender;
private Date createTime;
private Map<String, String> map;
private List<PersonDO> personList;
}
// PersonDO
@Data
@Builder
public class PersonDO {
private Integer id;
private String name;
private String job;
private String remark;
private Date createTime;
}
// PersonDTO
@Data
@Builder
public class PersonDTO {
private Integer id;
private String name;
private String job;
}
4. 映射器
- 如果 DTO 和實體類中的字段名稱是一致的,只需要寫方法簽名即可
- 如果參數(shù)名稱有變化,需要使用 @Maping 注解,source 為原參數(shù)名稱,target 為轉(zhuǎn)換后的類的參數(shù)名稱
- 隱式類型轉(zhuǎn)換
- 在許多情況下,MapStruct 會自動處理類型轉(zhuǎn)換。如在 source 中是 int 類型但在 target 中是 String 類型,會自動進行轉(zhuǎn)換。以及所有 Java 基本數(shù)據(jù)類型及其相應(yīng)的包裝類型,如 int 和 Integer,boolean 和 Boolean 等。還有所有 Java Number類型和包裝器類型之間,如 int 和 long 或 byte 和 Integer
@Mapper // 直接使用
@Mapper(componentModel = "spring") // 整合 Spring,設(shè)置 componentModel = "spring",需要使用的地方直接通過 @Resource 注入即可
public interface MapStruct {
MapStruct INSTANCE = Mappers.getMapper(MapStruct.class);
@Mapping(source = "userDOGender", target = "userDTOGender")
UserDTO userDOToUserDTO(UserDO userDO);
@Mapping(source = "userDTOGender", target = "userDOGender")
UserDO UserDTOToUserDO(UserDTO userDTO);
PersonDTO personDOToPersonDTO(PersonDO personDO);
PersonDO PersonDTOToPersonDO(PersonDTO personDTO);
}
編譯后,會在同級目錄生成實現(xiàn)類:

@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-03-22T12:16:06+0800",
comments = "version: 1.5.0.RC1, compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)"
)
public class MapStructImpl implements MapStruct {
@Override
public UserDTO userDOToUserDTO(UserDO userDO) {
if ( userDO == null ) {
return null;
}
UserDTO.UserDTOBuilder userDTO = UserDTO.builder();
userDTO.userDTOGender( userDO.getUserDOGender() );
userDTO.id( userDO.getId() );
userDTO.name( userDO.getName() );
userDTO.age( userDO.getAge() );
userDTO.address( userDO.getAddress() );
userDTO.createTime( userDO.getCreateTime() );
Map<String, String> map = userDO.getMap();
if ( map != null ) {
userDTO.map( new LinkedHashMap<String, String>( map ) );
}
List<PersonDO> list = userDO.getPersonList();
if ( list != null ) {
userDTO.personList( new ArrayList<PersonDO>( list ) );
}
return userDTO.build();
}
@Override
public UserDO UserDTOToUserDO(UserDTO userDTO) {
if ( userDTO == null ) {
return null;
}
UserDO.UserDOBuilder userDO = UserDO.builder();
userDO.userDOGender( userDTO.getUserDTOGender() );
userDO.id( userDTO.getId() );
userDO.name( userDTO.getName() );
userDO.age( userDTO.getAge() );
userDO.address( userDTO.getAddress() );
userDO.createTime( userDTO.getCreateTime() );
Map<String, String> map = userDTO.getMap();
if ( map != null ) {
userDO.map( new LinkedHashMap<String, String>( map ) );
}
List<PersonDO> list = userDTO.getPersonList();
if ( list != null ) {
userDO.personList( new ArrayList<PersonDO>( list ) );
}
return userDO.build();
}
@Override
public PersonDTO personDOToPersonDTO(PersonDO personDO) {
if ( personDO == null ) {
return null;
}
PersonDTO.PersonDTOBuilder personDTO = PersonDTO.builder();
personDTO.id( personDO.getId() );
personDTO.name( personDO.getName() );
personDTO.job( personDO.getJob() );
return personDTO.build();
}
@Override
public PersonDO PersonDTOToPersonDO(PersonDTO personDTO) {
if ( personDTO == null ) {
return null;
}
PersonDO.PersonDOBuilder personDO = PersonDO.builder();
personDO.id( personDTO.getId() );
personDO.name( personDTO.getName() );
personDO.job( personDTO.getJob() );
return personDO.build();
}
}
5. 測試
public class Test {
public static void main(String[] args) {
UserDO userDO = UserDO.builder().id(1)
.name("張三")
.age(18)
.birthday("2003-01-04")
.phone("12343")
.userDOGender("男")
.createTime(new Date(System.currentTimeMillis()))
.map(new HashMap<String, String>(){
{
this.put("key", "value");
}
})
.personList(new ArrayList<PersonDO>(){
{
this.add(PersonDO.builder().id(11).build());
}
}).build();
UserDTO userDTO = Mappers.getMapper(MapStruct.class).userDOToUserDTO(userDO);
System.out.println(userDTO);
PersonDTO personDTO = PersonDTO.builder().id(11)
.name("李四")
.job("開發(fā)").build();
PersonDO personDO = MapStruct.INSTANCE.PersonDTOToPersonDO(personDTO);
System.out.println(personDO);
}
}

6. 自定義轉(zhuǎn)換規(guī)則
MapStruct 只提供了隱式類型轉(zhuǎn)換和默認的一些轉(zhuǎn)換,假如需要特定的類型轉(zhuǎn)換,如將 java.sql.Timestamp 日期轉(zhuǎn)換為只保留年月日的字符串等,可以自定義轉(zhuǎn)換規(guī)則
6.1 使用 expression 表達式
1、創(chuàng)建一個轉(zhuǎn)換規(guī)則類
public class MapStructRule {
public static String toDate(Timestamp date) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
return simpleDateFormat.format(date);
}
}
2、在映射器對應(yīng)的轉(zhuǎn)換方法上使用 @Mapping 注解的 expression 屬性標識轉(zhuǎn)換規(guī)則,這里的屬性值為需要寫 全類名.方法名(參數(shù)),使用了 expression 就不需要 source 屬性
@Mapper(componentModel = "spring") // 整合 Spring,設(shè)置 componentModel = "spring",需要使用的地方直接通過 @Resource 注入即可
public interface MapStruct {
MapStruct INSTANCE = Mappers.getMapper(MapStruct.class);
@Mapping(target = "createTime", expression = "java(fan.fanblog.utils.MapStructRule.toDate(menuDO.getCreateTime()))")
@Mapping(target = "updateTime", expression = "java(fan.fanblog.utils.MapStructRule.toDate(menuDO.getUpdateTime()))")
MenuVO MenuDOToMenuVO(MenuDO menuDO);
}
3、測試類
public class Demo {
public static void main(String[] args) {
MenuDO menuDO = new MenuDO();
menuDO.setCreateTime(new Timestamp(System.currentTimeMillis()));
menuDO.setUpdateTime(new Timestamp(System.currentTimeMillis()));
System.out.println(menuDO);
MenuVO menuVO = MapStruct.INSTANCE.MenuDOToMenuVO(menuDO);
System.out.println(menuVO);
}
}

6.2 使用 @Named 注解
1、創(chuàng)建一個轉(zhuǎn)換規(guī)則類,在對應(yīng)的轉(zhuǎn)換方法上標注 @Named 注解表示轉(zhuǎn)換方法名
public class MapStructRule {
@Named("toDate")
public static String toDate(Timestamp date) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(date);
}
}
2、在映射器上使用 @Mapper 的 uses 屬性,屬性值為轉(zhuǎn)換規(guī)則類的 Class 對象,然后再映射器對應(yīng)的方法上使用 @Mapping 注解的 qualifiedByName 屬性,屬性值為轉(zhuǎn)換規(guī)則類 @Named 定義的方法名
@Mapper(componentModel = "spring", uses = MapStructRule.class) // 整合 Spring,設(shè)置 componentModel = "spring",需要使用的地方直接通過 @Resource 注入即可
public interface MapStruct {
MapStruct INSTANCE = Mappers.getMapper(MapStruct.class);
@Mapping(target = "createTime", source = "createTime", qualifiedByName = "toDate")
@Mapping(target = "updateTime", source = "updateTime", qualifiedByName = "toDate")
MenuVO MenuDOToMenuVO(MenuDO menuDO);
}
3、測試類
public class Demo {
public static void main(String[] args) {
MenuDO menuDO = new MenuDO();
menuDO.setCreateTime(new Timestamp(System.currentTimeMillis()));
menuDO.setUpdateTime(new Timestamp(System.currentTimeMillis()));
System.out.println(menuDO);
MenuVO menuVO = MapStruct.INSTANCE.MenuDOToMenuVO(menuDO);
System.out.println(menuVO);
}
}

7. 忽略屬性不轉(zhuǎn)換
@Mapper(componentModel = "spring", uses = MapStructRule.class) // 整合 Spring,設(shè)置 componentModel = "spring",需要使用的地方直接通過 @Resource 注入即可
public interface MapStruct {
MapStruct INSTANCE = Mappers.getMapper(MapStruct.class);
@Mapping(target = "createTime", ignore = true)
@Mapping(target = "updateTime", ignore = true)
MenuDO MenuVOToMenuDO(MenuVO menuVO);
}
到此這篇關(guān)于Java中的MapStruct知識點總結(jié)的文章就介紹到這了,更多相關(guān)MapStruct知識點總結(jié)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java中MapStruct的使用詳解
- Java中MapStruct使用方法解析
- Java中的MapStruct的使用方法代碼實例
- Java中的MapStruct實現(xiàn)詳解
- Java中MapStruct入門使用及對比
- Java高效映射工具MapStruct的使用示例
- Java中MapStruct映射處理器報錯的問題解決
- Java高性能實體類轉(zhuǎn)換工具MapStruct的使用教程詳解
- SpringBoot中MapStruct實現(xiàn)優(yōu)雅的數(shù)據(jù)復(fù)制
- SpringBoot使用MapStruct生成映射代碼的示例詳解
- MapStruct升級遇到的問題及解決方案
相關(guān)文章
Java實現(xiàn)帶有權(quán)重隨機算法的示例詳解
這篇文章主要為大家詳細介紹了Java如何實現(xiàn)帶有權(quán)重隨機算法,文中的示例代碼講解詳細,具有一定的學(xué)習價值,感興趣的小伙伴可以跟隨小編一起學(xué)習一下2023-10-10
Spring Cloud使用Feign進行遠程調(diào)用的操作指南
本文介紹了Feign作為聲明式HTTP客戶端在SpringCloud中的使用,從簡介、對比RestTemplate的問題、使用步驟,到日志配置、性能優(yōu)化和實際應(yīng)用進行了詳細講解,包括如何通過Feign簡化接口調(diào)用,以及解決啟動時找不到FeignClient的問題,需要的朋友可以參考下2025-02-02
Springmvc nginx實現(xiàn)動靜分離過程詳解
這篇文章主要介紹了Springmvc nginx實現(xiàn)動靜分離過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友可以參考下2020-09-09
Java實現(xiàn)簡易生產(chǎn)者消費者模型過程解析
這篇文章主要介紹了Java實現(xiàn)簡易生產(chǎn)者消費者模型過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友可以參考下2020-06-06

