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

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

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

一、MapStruct 簡介

MapStruct 是一個編譯期注解處理器,它會在編譯時自動生成類型安全、無反射的 Java Bean 映射代碼。
核心優(yōu)勢:

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

二、MapStruct 工作原理

  1. 編寫 Mapper 接口,使用 @Mapper 注解。
  2. 編譯時,MapStruct 的注解處理器根據(jù)接口定義自動生成實現(xiàn)類(通常在 target/generated-sources/annotations 下)。
  3. 運行時,調(diào)用自動生成的實現(xiàn)類進行對象轉(zhuǎ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. 定義源對象和目標(biāo)對象

// 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. 編寫 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"

四、進階用法

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. 嵌套對象映射

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 會自動遞歸調(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);
}

五、常見問題

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

六、MapStruct 與 BeanUtils/Dozer/ModelMapper 比較

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

七. Spring 集成與依賴注入

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

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

然后就可以在 Spring 中自動注入:

@Autowired
private UserMapper userMapper;

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

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

八. 多級嵌套對象映射

比如 DTO 和 Entity 里都包含 Address 對象:

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 會自動調(diào)用 AddressMapper 的方法。

九. 枚舉類型映射

如果枚舉名一致,MapStruct 會自動映射;如果不一致,可以手動指定:

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);
}

十. 自定義類型轉(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);
    }
}

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

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

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

這樣不會新建對象,而是直接修改傳入的 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)

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

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

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

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

十五、其他擴展

1. LocalDate/LocalDateTime 映射

場景:DTO 里是 String,Entity 里是 LocalDate

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

Mapper 寫法:

@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 映射

場景:DTO 是 String 或 Double,Entity 是 BigDecimal。

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

Mapper 寫法:

@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;
    }
}

反向同理,寫個 bigDecimalToString 方法。

3. 枚舉類型映射

場景:DTO 和 Entity 枚舉名不同/枚舉類型不同。

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

Mapper 寫法:

@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. 嵌套集合映射

場景:DTO 和 Entity 都有嵌套集合,如 List、Set。

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

Mapper 寫法:

@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 會自動將集合中的每個元素遞歸映射。

5. 常見 MapStruct 報錯及解決

(1)找不到映射方法

報錯內(nèi)容:

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

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

(2)類型不兼容

報錯內(nèi)容:

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

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

(3)嵌套集合或?qū)ο笪醋詣佑成?/h4>

報錯內(nèi)容:

No implementation for method entityToDto(ItemEntity entity) found.

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

(4)編譯未生成實現(xiàn)類

原因: IDEA/Maven 未開啟 annotation processing。
解決:

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

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

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

6. 進階建議

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

參考示例

@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使用配置實戰(zhàn)指南的文章就介紹到這了,更多相關(guān)Java MapStruct使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springBoot使用mybatis-plus插件實現(xiàn)分頁過程

    springBoot使用mybatis-plus插件實現(xiàn)分頁過程

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

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

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

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

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

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

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

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

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

    InterlliJ IDEA2020新建java web項目找不到Static Web的解決

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

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

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

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

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

    Mybatis動態(tài)SQL foreach標(biāo)簽用法實例

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

    Java concurrency集合之CopyOnWriteArraySet_動力節(jié)點Java學(xué)院整理

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

最新評論

米脂县| 丰镇市| 本溪市| 扬州市| 凤翔县| 株洲市| 太原市| 南丰县| 绿春县| 同心县| 淮滨县| 大城县| 北京市| 石柱| 南阳市| 安新县| 炉霍县| 江口县| 桂阳县| 嵩明县| 东台市| 石景山区| 山丹县| 内丘县| 冀州市| 天等县| 普安县| 霍林郭勒市| 辽源市| 定边县| 东宁县| 马关县| 石狮市| 德钦县| 祁阳县| 桃园县| 临洮县| 来宾市| 庆安县| 淅川县| 皮山县|