Java實(shí)現(xiàn)MapStruct對象轉(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容器 管理了

二、類型一致的場景
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)源對象的該屬性值為 null 時(shí))
轉(zhuǎn)換器
@Mapper
public interface Converter {
Converter INSTANT = Mappers.getMapper(Converter.class);
// 只有為 null 的才會生效
@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è)置常量值,無論源對象的該屬性值是否為 null
轉(zhuǎn)換器
@Mapper
public interface Converter {
Converter INSTANT = Mappers.getMapper(Converter.class);
// 只有為 null 的才會生效
@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)
三、類型不一致的場景
1、默認(rèn)轉(zhuǎn)換
對于部分?jǐn)?shù)據(jù)類型,如果屬性類型不一致,會做默認(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);
}
四、其他場景
1、對象嵌套(字段一致)
如果字段完全一致,會自動生成嵌套對象的 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)]))
可以看到,所有嵌套對象的屬性都做了自動映射


2、對象嵌套(字段不一致)
如果字段不一致,需要自己編寫對應(yīng)嵌套對象的 convert 方法,底層會自動調(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)]))
會按需調(diào)用對應(yīng)對象的 convert 方法

3、自定義轉(zhuǎn)換方法
使用 @Named 自定義轉(zhuǎn)換方法,通過 qualifiedByName 屬性指定,要和 @Named 的 value 對應(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)用對應(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,會自動對應(yīng)。
五、推薦的IDEA插件
IDEA 搜索 MapStruct Support 安裝即可,可以在使用MapStruct時(shí)獲得更加豐富代碼提示。

到此這篇關(guān)于Java實(shí)現(xiàn)MapStruct對象轉(zhuǎn)換的示例代碼的文章就介紹到這了,更多相關(guān)Java MapStruct對象轉(zhuǎn)換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Tomcat正常啟動,訪問所有頁面均報(bào)404異常,404異??偨Y(jié)分析
今天遇到一個(gè)問題:Tomcat正常啟動,訪問所有頁面均報(bào)404異常,究竟該如何解決這個(gè)問題呢?下邊小編將為大家介紹一下解決方法,需要的朋友可以參考下2013-07-07
spring boot@EnableXXXX注解編程模型講解
這篇文章主要介紹了spring boot@EnableXXXX注解編程模型,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Java并發(fā)編程之柵欄(CyclicBarrier)實(shí)例介紹
這篇文章主要介紹了Java并發(fā)編程之柵欄(CyclicBarrier)實(shí)例介紹,柵欄類似閉鎖,但是它們是有區(qū)別的,需要的朋友可以參考下2015-04-04
SpringBoot實(shí)現(xiàn)版本升級到2.7.18
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)版本升級到2.7.18全過程,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
java實(shí)現(xiàn)的海盜算法優(yōu)化版
這篇文章主要介紹了java實(shí)現(xiàn)的海盜算法優(yōu)化版,結(jié)合實(shí)例形式分析了java海盜算法的具體實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-07-07
SpringBoot中實(shí)現(xiàn)大文件分片下載和斷點(diǎn)續(xù)傳功能的完整指南
在Spring Boot中實(shí)現(xiàn)大文件分片下載和斷點(diǎn)續(xù)傳功能,需結(jié)合HTTP Range協(xié)議和文件流處理技術(shù),本文將展示完整的實(shí)現(xiàn)方法,有需要的小伙伴可以參考一下2025-09-09

