最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java MapStruct使用配置實(shí)戰(zhàn)指南

 更新時(shí)間:2025年11月06日 10:15:56   作者:猩火燎猿  
MapStruct是一個(gè)高效、類(lèi)型安全的JavaBean映射工具,通過(guò)編譯時(shí)注解處理器生成映射代碼,它支持自動(dòng)映射、自定義轉(zhuǎn)換、嵌套對(duì)象和集合的映射,并且可以與Spring集成,文章介紹了MapStruct的使用方法,以及與BeanUtils、Dozer、ModelMapper等框架的比較,感興趣的朋友一起看看吧

一、MapStruct 簡(jiǎn)介

MapStruct 是一個(gè)編譯期注解處理器,它會(huì)在編譯時(shí)自動(dòng)生成類(lèi)型安全、無(wú)反射的 Java Bean 映射代碼。
核心優(yōu)勢(shì):

  • 高性能:無(wú)運(yùn)行時(shí)反射,生成代碼直接調(diào)用 getter/setter。
  • 類(lèi)型安全:編譯期檢查,映射出錯(cuò)時(shí)編譯直接報(bào)錯(cuò)。
  • 易于集成:只需引入依賴,配合注解即可。

二、MapStruct 工作原理

  1. 編寫(xiě) Mapper 接口,使用 @Mapper 注解。
  2. 編譯時(shí),MapStruct 的注解處理器根據(jù)接口定義自動(dòng)生成實(shí)現(xiàn)類(lèi)(通常在 target/generated-sources/annotations 下)。
  3. 運(yùn)行時(shí),調(diào)用自動(dòng)生成的實(shí)現(xiàn)類(lèi)進(jìn)行對(duì)象轉(zhuǎn)換。

三、快速入門(mén)示例

1. 添加依賴

Maven:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.5.Final</version>
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.5.5.Final</version>
    <scope>provided</scope>
</dependency>

2. 定義源對(duì)象和目標(biāo)對(duì)象

// Entity
public class UserEntity {
    private Long id;
    private String name;
    private String email;
    // getter/setter
}
// DTO
public class UserDTO {
    private Long id;
    private String name;
    // getter/setter
}

3. 編寫(xiě) Mapper 接口

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface UserMapper {
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
    UserDTO entityToDto(UserEntity entity);
    UserEntity dtoToEntity(UserDTO dto);
}

4. 使用 Mapper

UserEntity entity = new UserEntity();
entity.setId(1L);
entity.setName("Tom");
entity.setEmail("tom@example.com");
UserDTO dto = UserMapper.INSTANCE.entityToDto(entity);
// dto.id = 1, dto.name = "Tom"

四、進(jìn)階用法

1. 字段名不一致

public class UserEntity {
    private String userName;
    //...
}
public class UserDTO {
    private String name;
    //...
}
@Mapper
public interface UserMapper {
    @Mapping(source = "userName", target = "name")
    UserDTO entityToDto(UserEntity entity);
}

2. 嵌套對(duì)象映射

public class AddressEntity { ... }
public class AddressDTO { ... }
public class UserEntity {
    private AddressEntity address;
}
public class UserDTO {
    private AddressDTO address;
}
@Mapper
public interface UserMapper {
    UserDTO entityToDto(UserEntity entity);
}

MapStruct 會(huì)自動(dòng)遞歸調(diào)用同名映射方法。

3. 集合映射

List<UserDTO> entityListToDtoList(List<UserEntity> entities);

4. 自定義轉(zhuǎn)換

@Mapper
public interface UserMapper {
    @Mapping(target = "createTime", expression = "java(new java.util.Date())")
    UserDTO entityToDto(UserEntity entity);
}

五、常見(jiàn)問(wèn)題

  • 生成代碼找不到?
    • 檢查 IDE 的 annotation processing 是否開(kāi)啟,代碼在 target/generated-sources/annotations 下。
  • 自定義方法怎么用?
    • 可以在 Mapper 里定義 default 方法,或用 @Named 結(jié)合 @Mapping 的 qualifiedByName。
  • 與 Spring 集成?
    • 用 @Mapper(componentModel = "spring"),Mapper 會(huì)注冊(cè)為 Spring Bean,可自動(dòng)注入。

六、MapStruct 與 BeanUtils/Dozer/ModelMapper 比較

框架性能類(lèi)型安全反射編譯期檢查代碼生成
MapStruct很高
BeanUtils一般
Dozer較低
ModelMapper較低

七. Spring 集成與依賴注入

讓 Mapper 變成 Spring Bean,只需加 @Mapper(componentModel = "spring")

@Mapper(componentModel = "spring")
public interface UserMapper {
    UserDTO entityToDto(UserEntity entity);
}

然后就可以在 Spring 中自動(dòng)注入:

@Autowired
private UserMapper userMapper;

如果 Mapper 之間有依賴,可以直接注入其他 Mapper:

@Mapper(componentModel = "spring", uses = {AddressMapper.class})
public interface UserMapper { ... }

八. 多級(jí)嵌套對(duì)象映射

比如 DTO 和 Entity 里都包含 Address 對(duì)象:

public class UserEntity {
    private AddressEntity address;
}
public class UserDTO {
    private AddressDTO address;
}
@Mapper
public interface AddressMapper {
    AddressDTO entityToDto(AddressEntity entity);
}
@Mapper(uses = {AddressMapper.class})
public interface UserMapper {
    UserDTO entityToDto(UserEntity entity);
}

MapStruct 會(huì)自動(dòng)調(diào)用 AddressMapper 的方法。

九. 枚舉類(lèi)型映射

如果枚舉名一致,MapStruct 會(huì)自動(dòng)映射;如果不一致,可以手動(dòng)指定:

public enum StatusEnum { ENABLED, DISABLED }
public enum StatusDTO { ON, OFF }
@Mapper
public interface StatusMapper {
    @Mapping(source = "ENABLED", target = "ON")
    @Mapping(source = "DISABLED", target = "OFF")
    StatusDTO toDto(StatusEnum status);
}

十. 自定義類(lèi)型轉(zhuǎn)換(QualifiedByName、@Named)

比如把 String 轉(zhuǎn)成 Date:

@Mapper
public interface UserMapper {
    @Mapping(source = "dateStr", target = "date", qualifiedByName = "stringToDate")
    UserDTO entityToDto(UserEntity entity);
    @Named("stringToDate")
    default Date stringToDate(String dateStr) {
        // 你自己的轉(zhuǎn)換邏輯
        return new SimpleDateFormat("yyyy-MM-dd").parse(dateStr);
    }
}

十一. 更新已有對(duì)象(@MappingTarget)

有時(shí)需要把 DTO 的值“更新”到已存在的 Entity:

@Mapper
public interface UserMapper {
    void updateEntityFromDto(UserDTO dto, @MappingTarget UserEntity entity);
}

這樣不會(huì)新建對(duì)象,而是直接修改傳入的 entity。

十二. 表達(dá)式與常量映射

如果目標(biāo)字段是常量或需要表達(dá)式:

@Mapper
public interface UserMapper {
    @Mapping(target = "status", expression = "java(entity.isActive() ? \"ACTIVE\" : \"INACTIVE\")")
    @Mapping(target = "role", constant = "USER")
    UserDTO entityToDto(UserEntity entity);
}

十三. 映射繼承與多態(tài)

可以通過(guò)接口繼承復(fù)用映射:

@Mapper
public interface BaseMapper<E, D> {
    D toDto(E entity);
    E toEntity(D dto);
}
@Mapper
public interface UserMapper extends BaseMapper<UserEntity, UserDTO> { }

十四. 常見(jiàn)坑及調(diào)試方法

  • IDE未生成 Mapper 實(shí)現(xiàn)類(lèi)?
    • 檢查 annotation processing 是否打開(kāi),Maven/IDEA/VSCode 都要設(shè)置。
  • 字段名不一致未映射?
    • 用 @Mapping(source, target) 明確指定。
  • 集合、嵌套類(lèi)型未自動(dòng)轉(zhuǎn)換?
    • 檢查是否正確配置 uses,相關(guān) Mapper 是否存在。
  • 調(diào)試生成代碼?
    • 直接到 target/generated-sources/annotations 查看生成的實(shí)現(xiàn)類(lèi),理解 MapStruct 的處理邏輯。
  • 復(fù)雜類(lèi)型轉(zhuǎn)換報(bào)錯(cuò)?
    • 用 @Named,qualifiedByName 明確指定轉(zhuǎn)換方法。

十五、其他擴(kuò)展

1. LocalDate/LocalDateTime 映射

場(chǎng)景:DTO 里是 String,Entity 里是 LocalDate。

public class UserEntity {
    private LocalDate birthday;
}
public class UserDTO {
    private String birthday; // "2024-07-11"
}

Mapper 寫(xiě)法:

@Mapper
public interface UserMapper {
    @Mapping(source = "birthday", target = "birthday", qualifiedByName = "stringToLocalDate")
    UserEntity dtoToEntity(UserDTO dto);
    @Named("stringToLocalDate")
    default LocalDate stringToLocalDate(String dateStr) {
        return LocalDate.parse(dateStr);
    }
}

反向轉(zhuǎn)換:

@Mapping(source = "birthday", target = "birthday", qualifiedByName = "localDateToString")
@Named("localDateToString")
default String localDateToString(LocalDate date) {
    return date != null ? date.toString() : null;
}

2. BigDecimal 映射

場(chǎng)景:DTO 是 String 或 Double,Entity 是 BigDecimal。

public class ProductEntity {
    private BigDecimal price;
}
public class ProductDTO {
    private String price;
}

Mapper 寫(xiě)法:

@Mapper
public interface ProductMapper {
    @Mapping(source = "price", target = "price", qualifiedByName = "stringToBigDecimal")
    ProductEntity dtoToEntity(ProductDTO dto);
    @Named("stringToBigDecimal")
    default BigDecimal stringToBigDecimal(String price) {
        return price != null ? new BigDecimal(price) : null;
    }
}

反向同理,寫(xiě)個(gè) bigDecimalToString 方法。

3. 枚舉類(lèi)型映射

場(chǎng)景:DTO 和 Entity 枚舉名不同/枚舉類(lèi)型不同。

public enum StatusEntity { ENABLED, DISABLED }
public enum StatusDTO { ON, OFF }

Mapper 寫(xiě)法:

@Mapper
public interface StatusMapper {
    @Mapping(source = "ENABLED", target = "ON")
    @Mapping(source = "DISABLED", target = "OFF")
    StatusDTO toDto(StatusEntity status);
}

或者用自定義方法:

@Named("statusToDto")
default StatusDTO statusToDto(StatusEntity status) {
    switch (status) {
        case ENABLED: return StatusDTO.ON;
        case DISABLED: return StatusDTO.OFF;
        default: return null;
    }
}

4. 嵌套集合映射

場(chǎng)景:DTO 和 Entity 都有嵌套集合,如 List、Set。

public class OrderEntity {
    private List<ItemEntity> items;
}
public class OrderDTO {
    private List<ItemDTO> items;
}

Mapper 寫(xiě)法:

@Mapper
public interface ItemMapper {
    ItemDTO entityToDto(ItemEntity entity);
}
@Mapper(uses = ItemMapper.class)
public interface OrderMapper {
    OrderDTO entityToDto(OrderEntity entity);
    List<OrderDTO> entityListToDtoList(List<OrderEntity> entities);
}

MapStruct 會(huì)自動(dòng)將集合中的每個(gè)元素遞歸映射。

5. 常見(jiàn) MapStruct 報(bào)錯(cuò)及解決

(1)找不到映射方法

報(bào)錯(cuò)內(nèi)容:

No property named 'xxx' exists in source parameter(s).

原因: DTO/Entity 字段名不一致或拼寫(xiě)錯(cuò)誤。
解決: 用 @Mapping(source = "xxx", target = "yyy") 顯式指定。

(2)類(lèi)型不兼容

報(bào)錯(cuò)內(nèi)容:

Can't map property "java.lang.String price" to "java.math.BigDecimal price".

原因: MapStruct 不知道怎么轉(zhuǎn)換 String 到 BigDecimal。
解決: 寫(xiě)自定義轉(zhuǎn)換方法,并用 qualifiedByName 指定。

(3)嵌套集合或?qū)ο笪醋詣?dòng)映射

報(bào)錯(cuò)內(nèi)容:

No implementation for method entityToDto(ItemEntity entity) found.

原因: ItemMapper 沒(méi)有被 uses 引用,或沒(méi)有實(shí)現(xiàn)方法。
解決: 在主 Mapper 上加 uses = {ItemMapper.class},并實(shí)現(xiàn)相關(guān)方法。

(4)編譯未生成實(shí)現(xiàn)類(lèi)

原因: IDEA/Maven 未開(kāi)啟 annotation processing。
解決:

  • IDEA: Settings -> Build, Execution, Deployment -> Compiler -> Annotation Processors -> Enable。
  • Maven: mvn clean compile,確保 target/generated-sources/annotations 下有實(shí)現(xiàn)類(lèi)。

(5)自定義方法未被調(diào)用

原因: 沒(méi)有用 @Named 和 qualifiedByName 關(guān)聯(lián)。
解決: 方法加 @Named("xxx"),@Mapping 里加 qualifiedByName = "xxx"。

6. 進(jìn)階建議

  • 對(duì)于復(fù)雜類(lèi)型轉(zhuǎn)換,建議都用 @Named 標(biāo)記方法,方便復(fù)用和維護(hù)。
  • 對(duì)于枚舉、日期、金額等類(lèi)型,推薦寫(xiě)專(zhuān)門(mén)的 Mapper 或 Converter 類(lèi)。
  • 多層嵌套/集合映射時(shí),合理拆分 Mapper,避免主 Mapper 過(guò)于龐大。

參考示例

@Mapper
public interface UserMapper {
    @Mapping(source = "birthday", target = "birthday", qualifiedByName = "stringToLocalDate")
    @Mapping(source = "balance", target = "balance", qualifiedByName = "stringToBigDecimal")
    UserEntity dtoToEntity(UserDTO dto);
    @Named("stringToLocalDate")
    default LocalDate stringToLocalDate(String dateStr) {
        return dateStr != null ? LocalDate.parse(dateStr) : null;
    }
    @Named("stringToBigDecimal")
    default BigDecimal stringToBigDecimal(String val) {
        return val != null ? new BigDecimal(val) : null;
    }
}

到此這篇關(guān)于Java MapStruct使用配置實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)Java MapStruct使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springBoot使用mybatis-plus插件實(shí)現(xiàn)分頁(yè)過(guò)程

    springBoot使用mybatis-plus插件實(shí)現(xiàn)分頁(yè)過(guò)程

    本文介紹了MyBatisPlus的集成步驟,包括項(xiàng)目結(jié)構(gòu)調(diào)整、pom.xml依賴添加、MyBatisPlusConfig配置文件創(chuàng)建與配置、具體代碼實(shí)現(xiàn)(controller、service、dao、xml)、SQL結(jié)果打印、自定義分頁(yè)等環(huán)節(jié),此經(jīng)驗(yàn)總結(jié)供讀者參考學(xué)習(xí)
    2026-04-04
  • Java對(duì)文本文件MD5加密并ftp傳送到遠(yuǎn)程主機(jī)目錄的實(shí)現(xiàn)方法

    Java對(duì)文本文件MD5加密并ftp傳送到遠(yuǎn)程主機(jī)目錄的實(shí)現(xiàn)方法

    這篇文章主要給大家介紹了關(guān)于Java對(duì)文本文件MD5加密并ftp傳送到遠(yuǎn)程主機(jī)目錄的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-08-08
  • 詳解SpringBoot和Mybatis配置多數(shù)據(jù)源

    詳解SpringBoot和Mybatis配置多數(shù)據(jù)源

    本篇文章主要介紹了詳解SpringBoot和Mybatis配置多數(shù)據(jù)源,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-05-05
  • springboot實(shí)現(xiàn)maven多模塊和打包部署

    springboot實(shí)現(xiàn)maven多模塊和打包部署

    本文主要介紹了springboot實(shí)現(xiàn)maven多模塊和打包部署,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • MyBatis如何實(shí)現(xiàn)流式查詢的示例代碼

    MyBatis如何實(shí)現(xiàn)流式查詢的示例代碼

    這篇文章主要介紹了MyBatis 如何實(shí)現(xiàn)流式查詢的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • InterlliJ IDEA2020新建java web項(xiàng)目找不到Static Web的解決

    InterlliJ IDEA2020新建java web項(xiàng)目找不到Static Web的解決

    這篇文章主要介紹了InterlliJ IDEA2020新建java web項(xiàng)目找不到Static Web的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java中線程狀態(tài)+線程安全問(wèn)題+synchronized的用法詳解

    Java中線程狀態(tài)+線程安全問(wèn)題+synchronized的用法詳解

    這篇文章主要介紹了Java中線程狀態(tài)+線程安全問(wèn)題+synchronized的用法詳解,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • 如何使用Spring RestTemplate訪問(wèn)restful服務(wù)

    如何使用Spring RestTemplate訪問(wèn)restful服務(wù)

    這篇文章主要介紹了如何使用Spring RestTemplate訪問(wèn)restful服務(wù),詳細(xì)的介紹了什么是RestTemplate以及簡(jiǎn)單實(shí)現(xiàn),非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2018-10-10
  • Mybatis動(dòng)態(tài)SQL foreach標(biāo)簽用法實(shí)例

    Mybatis動(dòng)態(tài)SQL foreach標(biāo)簽用法實(shí)例

    這篇文章主要介紹了Mybatis動(dòng)態(tài)SQL foreach標(biāo)簽用法實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Java concurrency集合之CopyOnWriteArraySet_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java concurrency集合之CopyOnWriteArraySet_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    CopyOnWriteArraySet基于CopyOnWriteArrayList實(shí)現(xiàn),其唯一的不同是在add時(shí)調(diào)用的是CopyOnWriteArrayList的addIfAbsent(若沒(méi)有則增加)方法
    2017-06-06

最新評(píng)論

忻城县| 永吉县| 南岸区| 汤阴县| 南木林县| 乌拉特后旗| 宜春市| 汕头市| 思茅市| 庄浪县| 拉萨市| 乌兰察布市| 积石山| 城固县| 陇川县| 北碚区| 新泰市| 简阳市| 宜都市| 湛江市| 康马县| 化州市| 永修县| 望奎县| 澜沧| 化隆| 麻栗坡县| 武宣县| 河南省| 全州县| 青岛市| 河间市| 安龙县| 平和县| 临猗县| 镇康县| 太和县| 堆龙德庆县| 探索| 东乡县| 周至县|