Java實(shí)現(xiàn)MapStruct對(duì)象轉(zhuǎn)換的示例代碼
一、基本使用
1、Maven 引入
<properties> <lombok.version>1.18.30</lombok.version> <mapstruct.version>1.4.1.Final</mapstruct.version> </properties> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <optional>true</optional> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${mapstruct.version}</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${mapstruct.version}</version> </dependency> </dependencies>
2、基本使用
待轉(zhuǎn)換的類
@Data @Builder public class UserDTO { private Long id; private Integer age; private String name; }
轉(zhuǎn)換目標(biāo)類
@Data public class UserVO { private Long id; private Integer age; private String name; }
轉(zhuǎn)換器
import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @Mapper public interface Converter { // 后續(xù)通過 INSTANT 調(diào)用轉(zhuǎn)換方法 Converter INSTANT = Mappers.getMapper(Converter.class); UserVO convert(UserDTO userDTO); }
使用示例
public class Test { public static void main(String[] args) { UserDTO userDTO = UserDTO.builder().id(1L).age(18).name("scj").build(); UserVO userVO = Converter.INSTANT.convert(userDTO); System.out.println(userVO); } }
輸出結(jié)果
UserVO(id=1, age=18, name=scj)
可以看到在 target 生成 轉(zhuǎn)換器的實(shí)現(xiàn)類,并使用 get 和 set 進(jìn)行轉(zhuǎn)換,所以性能很高。
3、Spring Bean
MapStruct提供了依賴注入的機(jī)制,讓我們能夠在Spring的環(huán)境下,更優(yōu)雅的獲得Converter。
轉(zhuǎn)換器
import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @Mapper(componentModel = MappingConstants.ComponentModel.SPRING) public interface Converter { UserVO convert(UserDTO userDTO); }
使用示例
@RestController public class TestController { // 直接注入使用 @Autowired private Converter converter; @GetMapping("/test") public void mapstructTest() { UserDTO userDTO = UserDTO.builder().id(1L).age(18).name("scj").build(); UserVO userVO = converter.convert(userDTO); System.out.println(userVO); } }
輸出結(jié)果
UserVO(id=1, age=18, name=scj)
可以看到 target 中生成的實(shí)現(xiàn)類交給 Spring容器 管理了
二、類型一致的場(chǎng)景
1、字段名不一致
字段名不同,通過 target 和 source 屬性指定映射關(guān)系(字段名一致可以省略)
轉(zhuǎn)換器
@Mapper public interface Converter { Converter INSTANT = Mappers.getMapper(Converter.class); @Mapping(target = "userName", source = "name") UserVO convert(UserDTO userDTO); }
輸出結(jié)果
UserVO(id=1, age=18, username=scj)
2、ignore
不需要映射的字段,可以設(shè)置 ignore = true
轉(zhuǎn)換器
@Mapper public interface Converter { Converter INSTANT = Mappers.getMapper(Converter.class); // 不需要映射的字段,指定 ignore = true @Mapping(target = "name", ignore = true) @Mapping(target = "age", ignore = true) UserVO convert(UserDTO userDTO); }
輸出結(jié)果
UserVO(id=1, age=null, name=null)
3、defaultValue
通過 defaultValue 設(shè)置默認(rèn)值(僅當(dāng)源對(duì)象的該屬性值為 null 時(shí))
轉(zhuǎn)換器
@Mapper public interface Converter { Converter INSTANT = Mappers.getMapper(Converter.class); // 只有為 null 的才會(huì)生效 @Mapping(target = "id", defaultValue = "1") @Mapping(target = "age", defaultValue = "66") @Mapping(target = "name", defaultValue = "zs") UserVO convert(UserDTO userDTO); }
使用示例
public class Test { public static void main(String[] args) { // id = null UserDTO userDTO = UserDTO.builder().age(18).name("scj").build(); UserVO userVO = Converter.INSTANT.convert(userDTO); System.out.println(userVO); } }
輸出結(jié)果
UserVO(id=1, age=18, name=scj)
4、constant
通過 constant 為屬性設(shè)置常量值,無論源對(duì)象的該屬性值是否為 null
轉(zhuǎn)換器
@Mapper public interface Converter { Converter INSTANT = Mappers.getMapper(Converter.class); // 只有為 null 的才會(huì)生效 @Mapping(target = "id", constant = "6") @Mapping(target = "age", constant = "66") @Mapping(target = "name", constant = "zs") UserVO convert(UserDTO userDTO); }
使用示例
public class Test { public static void main(String[] args) { UserDTO userDTO = UserDTO.builder().id(1).age(18).name("scj").build(); UserVO userVO = Converter.INSTANT.convert(userDTO); System.out.println(userVO); } }
輸出結(jié)果
UserVO(id=6, age=66, name=zs)
三、類型不一致的場(chǎng)景
1、默認(rèn)轉(zhuǎn)換
對(duì)于部分?jǐn)?shù)據(jù)類型,如果屬性類型不一致,會(huì)做默認(rèn)的的轉(zhuǎn)換并賦值。
包裝類 相關(guān):基本數(shù)據(jù)類型、字符串、其他包裝類
// Integer -> int target.setIntegerValue( source.getIntegerValue() ); // Integer -> Long target.setIntegerValue( source.getIntegerValue().longValue() ); // Integer -> Double target.setIntegerValue( source.getIntegerValue().doubleValue() ); // Integer -> String target.setIntegerValue( String.valueOf( source.getIntegerValue() ) );
BigDecimal 相關(guān):
// BigDecimal -> Integer/int target.setDecimalValue( source.getDecimalValue().intValue() ); // BigDecimal -> Double/double target.setDecimalValue( source.getDecimalValue().doubleValue() ); // BigDecimal -> String target.setDecimalValue( source.getDecimalValue().toString() );
時(shí)間日期 相關(guān)
// Date -> LocalDateTime target.setDateValue( LocalDateTime.ofInstant( source.getDateValue().toInstant(), ZoneId.of( "UTC" ) ) ); // LocalDateTime -> Date target.setDateValue( Date.from( source.getDateValue().toInstant( ZoneOffset.UTC ) ) ); // Date -> String target.setDateValue( new SimpleDateFormat().format( source.getDateValue() ) ); // LocalDateTime -> String target.setDateValue( DateTimeFormatter.ISO_LOCAL_DATE_TIME.format( source.getDateValue() ) );
枚舉 相關(guān)
// Enum -> String target.setEnumValue( source.getEnumValue().name() );
String 相關(guān)
// String -> Long/long target.setStringValue( Long.parseLong( source.getStringValue() ) ); // String -> BigDecimal target.setStringValue( new BigDecimal( source.getStringValue() ) ); // String -> Date target.setStringValue( new SimpleDateFormat().parse( source.getStringValue() ) ); // String -> LocalDateTime target.setStringValue( LocalDateTime.parse( source.getStringValue() ) ); // String -> Enum target.setEnumValue( Enum.valueOf( Source.CustomEnum.class, source.getEnumValue() ) );
2、numberFormat
數(shù)字類型 轉(zhuǎn)換為 字符串 時(shí),可以通過 numberFormat 屬性指定 格式
@Mapper public interface Converter { Converter INSTANT = Mappers.getMapper(Converter.class); @Mapping(target = "integerValue", source = "integerValue", numberFormat = "#,##0") @Mapping(target = "doubleValue", source = "doubleValue", numberFormat = "#0.00") @Mapping(target = "decimalValue", source = "decimalValue", numberFormat = "#%") Target convert(Source source); }
#,##0
:表示數(shù)字使用千位分隔符。例如,1234567
將被格式化為1,234,567
。#0.00
:表示數(shù)字保留兩位小數(shù)。例如,666.666
將被格式化為666.67
。#%
:表示將數(shù)字視為百分比。例如,0.75
將被格式化為75%
。
3、dateFormat
時(shí)間日期 轉(zhuǎn)換為 字符串 時(shí),可以通過 dateFormat 屬性指定 pattern
待轉(zhuǎn)換的類
@Data public class Source { private Date dateValue = new Date(); private LocalDateTime localDateTimeValue = LocalDateTime.now(); }
轉(zhuǎn)換目標(biāo)類
@Data public class Target { private String dateValue; private String localDateTimeValue; }
轉(zhuǎn)換器
@Mapper public interface Converter { Converter INSTANT = Mappers.getMapper(Converter.class); @Mapping(target = "dateValue", source = "dateValue", dateFormat = "yyyy-MM-dd HH:mm:ss") @Mapping(target = "localDateTimeValue", source = "localDateTimeValue", dateFormat = "yyyy-MM-dd HH:mm:ss") Target convert(Source source); }
輸出結(jié)果
Target(dateValue=2024-09-26 19:27:41, localDateTimeValue=2024-09-26 19:27:41)
4、枚舉值處理
待轉(zhuǎn)換的類
@Data public class Source { private SexEnum sexEnum = SexEnum.MAN; }
轉(zhuǎn)換目標(biāo)類
@Data public class Target { private String sex; }
轉(zhuǎn)換器
@Mapper public interface Converter { Converter INSTANT = Mappers.getMapper(Converter.class); @Mapping(target = "sex", source = "sexEnum.desc") Target convert(Source source); }
四、其他場(chǎng)景
1、對(duì)象嵌套(字段一致)
如果字段完全一致,會(huì)自動(dòng)生成嵌套對(duì)象的 convert 方法。
待轉(zhuǎn)換的類
@Data public class Source { private Long id = 1L; private SourceInnerClass1 inner = new SourceInnerClass1(); } @Data class SourceInnerClass1 { private Long id = 11L; private List<SourceInnerClass2> innerList = Collections.singletonList(new SourceInnerClass2()); } @Data class SourceInnerClass2 { private Long id = 111L; private String value = "inner2"; }
轉(zhuǎn)換目標(biāo)類
@Data public class Target { private Long id; private TargetInnerClass1 inner; } @Data class TargetInnerClass1 { private Long id; private List<TargetInnerClass2> innerList; } @Data class TargetInnerClass2 { private Long id; private String value; }
轉(zhuǎn)換器
@Mapper public interface Converter { Converter INSTANT = Mappers.getMapper(Converter.class); Target convert(Source source); }
輸出
Target(id=1, inner=TargetInnerClass1(id=11, innerList=[TargetInnerClass2(id=111, value=inner2)]))
可以看到,所有嵌套對(duì)象的屬性都做了自動(dòng)映射
2、對(duì)象嵌套(字段不一致)
如果字段不一致,需要自己編寫對(duì)應(yīng)嵌套對(duì)象的 convert 方法,底層會(huì)自動(dòng)調(diào)用。
待轉(zhuǎn)換的類
@Data public class Source { private Long id; private SourceInnerClass1 inner; } @Data class SourceInnerClass1 { private Long id; private List<SourceInnerClass2> innerList; } @Data class SourceInnerClass2 { private Long id; private String value; }
轉(zhuǎn)換目標(biāo)類
@Data public class Target { private Long id0; private TargetInnerClass1 inner0; } @Data class TargetInnerClass1 { private Long id1; private List<TargetInnerClass2> innerList1; } @Data class TargetInnerClass2 { private Long id2; private String value2; }
轉(zhuǎn)換器
@Mapper public interface Converter { Converter INSTANT = Mappers.getMapper(Converter.class); @Mapping(target = "id0", source = "id") @Mapping(target = "inner0", source = "inner") Target convert(Source source); @Mapping(target = "id1", source = "id") @Mapping(target = "innerList1", source = "innerList") TargetInnerClass1 convert(SourceInnerClass1 source); @Mapping(target = "id2", source = "id") @Mapping(target = "value2", source = "value") TargetInnerClass2 convert(SourceInnerClass2 source); }
使用示例
public class Test { public static void main(String[] args) { final Source source = new Source(1L, 18L, "scj", new SourceInner(1L, 18)); final Target target = Converter.INSTANT.convert(source); System.out.println(target); } }
輸出
Target(id0=1, inner0=TargetInnerClass1(id1=11, innerList1=[TargetInnerClass2(id2=111, value2=inner2)]))
會(huì)按需調(diào)用對(duì)應(yīng)對(duì)象的 convert 方法
3、自定義轉(zhuǎn)換方法
使用 @Named 自定義轉(zhuǎn)換方法,通過 qualifiedByName 屬性指定,要和 @Named 的 value 對(duì)應(yīng)
待轉(zhuǎn)換的類
@Data public class Target { private UserDTO targetUserDTO; private String targetUserJson; }
轉(zhuǎn)換目標(biāo)類
@Data public class Source { private String sourceUserJson; private UserDTO sourceUserDTO; }
轉(zhuǎn)換器
@Mapper public interface Convert { Convert INSTANCE = Mappers.getMapper(Convert.class); @Mapping(target = "targetUserDTO", source = "sourceUserJson", qualifiedByName = "json2DTO") @Mapping(target = "targetUserJson", source = "sourceUserDTO", qualifiedByName = "dto2Json") Target convert(Source source); @Named("json2DTO") default UserDTO json2DTO(String userJson) { return JSON.parseObject(userJson, UserDTO.class); } @Named("dto2Json") default String dto2Json(UserDTO userDTO) { return JSON.toJSONString(userDTO); } }
轉(zhuǎn)換結(jié)果
Target(targetUserDTO=UserDTO(name=scj, age=18), targetUserJson={"age":66,"name":"zs"})
4、expression
通過
expression
可以指定java
表達(dá)式,可以直接調(diào)用對(duì)應(yīng)的方法。
轉(zhuǎn)換器
@Mapper public interface Convert { Convert INSTANCE = Mappers.getMapper(Convert.class); // 本類方法 @Mapping(target = "targetUserDTO", expression = "java(json2DTO(source.getSourceUserJson()))") // 非本類方法(類全名調(diào)用即可) @Mapping(target = "targetUserJson", expression = "java(com.alibaba.fastjson.JSON.toJSONString(source.getSourceUserDTO()))") // 枚舉 @Mapping(target = "sex", expression = "java(source.getSexEnum().getDesc())") Target convert(Source source); default UserDTO json2DTO(String userJson) { return JSON.parseObject(userJson, UserDTO.class); } }
轉(zhuǎn)換結(jié)果
Target(targetUserDTO=UserDTO(name=scj, age=18), targetUserJson={"age":66,"name":"zs"}, sex=男)
ConvertImpl
public class ConvertImpl implements Convert { @Override public Target convert(Source source) { if ( source == null ) { return null; } Target target = new Target(); target.setTargetUserDTO( json2DTO(source.getSourceUserJson()) ); target.setTargetUserJson( com.alibaba.fastjson.JSON.toJSONString(source.getSourceUserDTO()) ); target.setSex( source.getSexEnum().getDesc() ); return target; } }
5、多個(gè)參數(shù)
待轉(zhuǎn)換的類
@Data public class Target { // source1 private String strValue1; private Integer intValue1; // source2 private String strValue2; private Integer intValue2; // field private String strValue; private Integer intValue; }
轉(zhuǎn)換目標(biāo)類
@Data public class Source1 { private String strValue = "s1"; private Integer intValue = 1; } @Data public class Source2 { private String strValue = "s2"; private Integer intValue = 2; }
轉(zhuǎn)換器
@Mapper public interface Convert { Convert INSTANCE = Mappers.getMapper(Convert.class); @Mapping(target = "strValue1", source = "s1.strValue") @Mapping(target = "intValue1", source = "s1.intValue") @Mapping(target = "strValue2", source = "s2.strValue") @Mapping(target = "intValue2", source = "s2.intValue") @Mapping(target = "strValue", source = "strValue") @Mapping(target = "intValue", source = "intValue") Target convert(Source1 s1, Source2 s2, String strValue, Integer intValue); }
注意事項(xiàng):如果字段名全部沒有沖突,不需要 @Mapping,會(huì)自動(dòng)對(duì)應(yīng)。
五、推薦的IDEA插件
IDEA 搜索 MapStruct Support 安裝即可,可以在使用MapStruct時(shí)獲得更加豐富代碼提示。
到此這篇關(guān)于Java實(shí)現(xiàn)MapStruct對(duì)象轉(zhuǎn)換的示例代碼的文章就介紹到這了,更多相關(guān)Java MapStruct對(duì)象轉(zhuǎn)換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
oracle數(shù)據(jù)庫(kù)導(dǎo)入TXT文件方法介紹
這篇文章主要介紹了oracle數(shù)據(jù)庫(kù)導(dǎo)入TXT文件方法介紹,文中向大家展示了具體代碼示例,需要的朋友可以參考下。2017-09-09使用java批量寫入環(huán)境變量的實(shí)現(xiàn)
本文主要介紹了使用java批量寫入環(huán)境變量,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03k8s部署的java服務(wù)添加idea調(diào)試參數(shù)的方法
文章介紹了如何在K8S容器中的Java服務(wù)上進(jìn)行遠(yuǎn)程調(diào)試,包括配置Deployment、Service以及本地IDEA的調(diào)試設(shè)置,感興趣的朋友跟隨小編一起看看吧2025-02-02使用FeignClient調(diào)用遠(yuǎn)程服務(wù)時(shí)整合本地的實(shí)現(xiàn)方法
這篇文章主要介紹了使用FeignClient調(diào)用遠(yuǎn)程服務(wù)時(shí)整合本地的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03Java SpringMVC攔截器與異常處理機(jī)制詳解分析
SpringMVC是一種基于Java,實(shí)現(xiàn)了Web MVC設(shè)計(jì)模式,請(qǐng)求驅(qū)動(dòng)類型的輕量級(jí)Web框架,即使用了MVC架構(gòu)模式的思想,將Web層進(jìn)行職責(zé)解耦?;谡?qǐng)求驅(qū)動(dòng)指的就是使用請(qǐng)求-響應(yīng)模型,框架的目的就是幫助我們簡(jiǎn)化開發(fā),SpringMVC也是要簡(jiǎn)化我們?nèi)粘eb開發(fā)2021-10-10Java設(shè)計(jì)模式之創(chuàng)建者模式簡(jiǎn)介
這篇文章主要介紹了Java設(shè)計(jì)模式之創(chuàng)建者模式,需要的朋友可以參考下2014-07-07Android開發(fā)簡(jiǎn)單計(jì)算器實(shí)現(xiàn)代碼
這篇文章主要介紹了Android開發(fā)簡(jiǎn)單計(jì)算器實(shí)現(xiàn),本文放置了完整的Android開發(fā)電腦,通過部署項(xiàng)目可以直接按到效果,希望本篇文章可以對(duì)你有所幫助2021-06-06