Java中的MapStruct知識點(diǎn)總結(jié)
1. 概念
在系統(tǒng)工程開發(fā)過程中,會有各個(gè)層之間的對象轉(zhuǎn)換,比如 VO、DTO、PO、DO 等,如果都是手動(dòng) setter、getter 特別浪費(fèi)時(shí)間,還可能操作錯(cuò)誤,所以選擇一個(gè)自動(dòng)化工具會更加方便。常見的有 json2Json、Apache 和 Spring 的 BeanUtils.copyProperties()、BeanCopier、JMapper 等
對象屬性轉(zhuǎn)換的操作無非是基于反射、AOP、CGlib、ASM、Javassist 在編譯時(shí)和運(yùn)行期進(jìn)行處理,再有好的思路就是在編譯前生成出對應(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. 實(shí)體類
定義幾個(gè) 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í)體類中的字段名稱是一致的,只需要寫方法簽名即可
- 如果參數(shù)名稱有變化,需要使用 @Maping 注解,source 為原參數(shù)名稱,target 為轉(zhuǎn)換后的類的參數(shù)名稱
- 隱式類型轉(zhuǎn)換
- 在許多情況下,MapStruct 會自動(dòng)處理類型轉(zhuǎn)換。如在 source 中是 int 類型但在 target 中是 String 類型,會自動(dòng)進(jìn)行轉(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); }
編譯后,會在同級目錄生成實(shí)現(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)換和默認(rèn)的一些轉(zhuǎn)換,假如需要特定的類型轉(zhuǎn)換,如將 java.sql.Timestamp
日期轉(zhuǎn)換為只保留年月日的字符串等,可以自定義轉(zhuǎn)換規(guī)則
6.1 使用 expression 表達(dá)式
1、創(chuàng)建一個(gè)轉(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
屬性標(biāo)識轉(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)建一個(gè)轉(zhuǎn)換規(guī)則類,在對應(yīng)的轉(zhuǎn)換方法上標(biāo)注 @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知識點(diǎn)總結(jié)的文章就介紹到這了,更多相關(guān)MapStruct知識點(diǎn)總結(jié)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java中MapStruct的使用詳解
- Java中MapStruct使用方法解析
- Java中的MapStruct的使用方法代碼實(shí)例
- Java中的MapStruct實(shí)現(xiàn)詳解
- Java中MapStruct入門使用及對比
- Java高效映射工具M(jìn)apStruct的使用示例
- Java中MapStruct映射處理器報(bào)錯(cuò)的問題解決
- Java高性能實(shí)體類轉(zhuǎn)換工具M(jìn)apStruct的使用教程詳解
- SpringBoot中MapStruct實(shí)現(xiàn)優(yōu)雅的數(shù)據(jù)復(fù)制
- SpringBoot使用MapStruct生成映射代碼的示例詳解
- MapStruct升級遇到的問題及解決方案
相關(guān)文章
一分鐘掌握J(rèn)ava?ElasticJob分布式定時(shí)任務(wù)
ElasticJob?是面向互聯(lián)網(wǎng)生態(tài)和海量任務(wù)的分布式調(diào)度解決方案,本文主要通過簡單的示例帶大家深入了解ElasticJob分布式定時(shí)任務(wù)的相關(guān)知識,需要的可以參考一下2023-05-05java實(shí)現(xiàn)合并單元格的同時(shí)并導(dǎo)出excel示例
這篇文章主要給大家介紹了關(guān)于java實(shí)現(xiàn)合并單元格的同時(shí)并導(dǎo)出excel的相關(guān)資料,文中先進(jìn)行了簡單的介紹,之后給出了詳細(xì)的示例代碼,相信對大家具有一定的參考價(jià)值,需要的朋友們下面來一起看看吧。2017-03-03SpringCloud環(huán)境搭建過程之Rest使用小結(jié)
這篇文章主要介紹了SpringCloud環(huán)境搭建之Rest使用,本文通過實(shí)例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08Lombok中@Builder和@SuperBuilder注解的用法案例
@Builder?是?lombok?中的注解,可以使用builder()構(gòu)造的Person.PersonBuilder對象進(jìn)行鏈?zhǔn)秸{(diào)用,給所有屬性依次賦值,這篇文章主要介紹了Lombok中@Builder和@SuperBuilder注解的用法,需要的朋友可以參考下2023-01-01關(guān)于@ComponentScan?TypeFilter自定義指定掃描bean的規(guī)則
這篇文章主要介紹了關(guān)于@ComponentScan?TypeFilter自定義指定掃描bean的規(guī)則,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09Spring Cloud Zuul自定義過濾器的實(shí)現(xiàn)
這篇文章主要介紹了自定義Spring Cloud Zuul過濾器的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03