Java中基于注解的代碼生成工具MapStruct映射使用詳解
介紹
在 Java 開發(fā)中,我們經(jīng)常需要在不同的 Java Bean 之間進行數(shù)據(jù)映射,比如從實體類(Entity)到數(shù)據(jù)傳輸對象(DTO)的轉換。傳統(tǒng)的做法是手動編寫大量的 setter 和 getter 方法來完成屬性的賦值,這種方式不僅繁瑣,而且容易出錯。MapStruct 作為一個基于注解的代碼生成工具,為我們提供了一種更加優(yōu)雅、高效的解決方案。它在編譯時自動生成映射代碼,避免了運行時反射帶來的性能開銷,同時保證了類型安全。
優(yōu)缺點
優(yōu)點
- 高性能:MapStruct 在編譯階段生成映射代碼,運行時直接調(diào)用這些代碼,避免了反射的使用,從而顯著提高了性能。
- 類型安全:由于映射代碼是在編譯時生成的,編譯器會對類型進行檢查,因此可以在編譯階段發(fā)現(xiàn)類型不匹配等錯誤,避免了運行時異常。
- 代碼簡潔:使用 MapStruct 只需要定義映射接口和使用注解進行配置,無需手動編寫大量的映射邏輯,大大減少了代碼量,提高了開發(fā)效率。
缺點
- 學習成本:需要學習 MapStruct 提供的各種注解及其使用方法,對于初學者來說可能有一定的學習曲線。
- 依賴管理:需要在項目中引入 MapStruct 的相關依賴,增加了項目的依賴管理復雜度。
核心注解及詳細使用語法說明
@Mapper
- 作用:用于標記一個接口為映射接口,MapStruct 會在編譯時為該接口生成具體的實現(xiàn)類。
- 使用語法:
import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @Mapper public interface UserMapper { // 通過 Mappers.getMapper 方法獲取映射接口的實例 UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); // 定義從 UserEntity 到 UserDTO 的映射方法 UserDTO toDTO(UserEntity entity); // 定義從 UserDTO 到 UserEntity 的映射方法 UserEntity toEntity(UserDTO dto); }
@Mapping
- 作用:用于指定源對象和目標對象之間的屬性映射關系,當源對象和目標對象的屬性名
不一致
時,可以使用該注解進行顯式映射
。 - 使用語法:
import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @Mapper public interface UserMapper { UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); // 使用 @Mapping 注解指定 entityId 映射到 id,entityName 映射到 name @Mapping(source = "entityId", target = "id") @Mapping(source = "entityName", target = "name") UserDTO toDTO(UserEntity entity); // 反向映射 @Mapping(source = "id", target = "entityId") @Mapping(source = "name", target = "entityName") UserEntity toEntity(UserDTO dto); }
@Mappings
- 作用:@Mappings 是 @Mapping 的集合形式,用于一次性指定
多個屬性映射
關系。 - 使用語法:
import org.mapstruct.Mapper; import org.mapstruct.Mappings; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @Mapper public interface UserMapper { UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); @Mappings({ @Mapping(source = "entityId", target = "id"), @Mapping(source = "entityName", target = "name") }) UserDTO toDTO(UserEntity entity); @Mappings({ @Mapping(source = "id", target = "entityId"), @Mapping(source = "name", target = "entityName") }) UserEntity toEntity(UserDTO dto); }
@Context
- 作用:用于在映射過程中傳遞上下文信息,比如一些輔助對象,這些對象可以在映射方法中使用。
- 使用語法:
import org.mapstruct.Mapper; import org.mapstruct.Context; import org.mapstruct.factory.Mappers; import java.util.Locale; @Mapper public interface UserMapper { UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); // 使用 @Context 注解傳遞 Locale 對象作為上下文信息 UserDTO toDTO(UserEntity entity, @Context Locale locale); }
@AfterMapping
- 作用:用于在映射完成后執(zhí)行自定義的邏輯,比如對目標對象的某些屬性進行額外的處理。
- 使用語法:
import org.mapstruct.Mapper; import org.mapstruct.AfterMapping; import org.mapstruct.MappingTarget; import org.mapstruct.factory.Mappers; @Mapper public interface UserMapper { UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); UserDTO toDTO(UserEntity entity); // 使用 @AfterMapping 注解定義映射完成后的自定義邏輯 @AfterMapping default void afterMapping(@MappingTarget UserDTO dto, UserEntity entity) { // 將源對象的 firstName 和 lastName 拼接后賦值給目標對象的 fullName 屬性 dto.setFullName(entity.getFirstName() + " " + entity.getLastName()); } }
Demo示例
公共基本類定義
import lombok.Data; // 用戶實體類 @Data public class UserEntity { private Long id; private String name; private Integer age; private String firstName; private String lastName; private AddressEntity address; private Long entityId; private String entityName; } // 用戶數(shù)據(jù)傳輸對象類 @Data public class UserDTO { private Long id; private String name; private Integer age; private String fullName; private AddressDTO address; private Long entityId; private String entityName; } // 地址實體類 @Data public class AddressEntity { private String street; private String city; } // 地址數(shù)據(jù)傳輸對象類 @Data public class AddressDTO { private String street; private String city; }
簡單映射示例
import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @Mapper public interface UserMapper { // 獲取映射接口的實例 UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); // 從 UserEntity 到 UserDTO 的映射方法 UserDTO toDTO(UserEntity entity); // 從 UserDTO 到 UserEntity 的映射方法 UserEntity toEntity(UserDTO dto); } // 測試代碼 public class MainSimpleMapping { public static void main(String[] args) { UserEntity userEntity = new UserEntity(); userEntity.setId(1L); userEntity.setName("John"); userEntity.setAge(25); // 使用映射接口的實例進行映射 UserDTO userDTO = UserMapper.INSTANCE.toDTO(userEntity); System.out.println("簡單映射示例結果:"); System.out.println("UserDTO: id=" + userDTO.getId() + ", name=" + userDTO.getName() + ", age=" + userDTO.getAge()); } }
輸出結果:
簡單映射示例結果:
UserDTO: id=1, name=John, age=25
字段名不一致的映射示例
import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @Mapper public interface UserMapper { UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); @Mapping(source = "entityId", target = "id") @Mapping(source = "entityName", target = "name") UserDTO toDTO(UserEntity entity); @Mapping(source = "id", target = "entityId") @Mapping(source = "name", target = "entityName") UserEntity toEntity(UserDTO dto); } // 測試代碼 public class MainFieldNameMismatch { public static void main(String[] args) { UserEntity userEntity = new UserEntity(); userEntity.setEntityId(1L); userEntity.setEntityName("John"); userEntity.setAge(25); UserDTO userDTO = UserMapper.INSTANCE.toDTO(userEntity); System.out.println("字段名不一致映射示例結果:"); System.out.println("UserDTO: id=" + userDTO.getId() + ", name=" + userDTO.getName() + ", age=" + userDTO.getAge()); } }
輸出結果:
字段名不一致映射示例結果:
UserDTO: id=1, name=John, age=25
嵌套對象映射示例
import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @Mapper public interface UserMapper { UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); UserDTO toDTO(UserEntity entity); UserEntity toEntity(UserDTO dto); AddressDTO toDTO(AddressEntity entity); AddressEntity toEntity(AddressDTO dto); } // 測試代碼 public class MainNestedObjectMapping { public static void main(String[] args) { AddressEntity addressEntity = new AddressEntity(); addressEntity.setStreet("123 Main St"); addressEntity.setCity("New York"); UserEntity userEntity = new UserEntity(); userEntity.setId(1L); userEntity.setName("John"); userEntity.setAddress(addressEntity); UserDTO userDTO = UserMapper.INSTANCE.toDTO(userEntity); System.out.println("嵌套對象映射示例結果:"); System.out.println("UserDTO: id=" + userDTO.getId() + ", name=" + userDTO.getName()); System.out.println("AddressDTO: street=" + userDTO.getAddress().getStreet() + ", city=" + userDTO.getAddress().getCity()); } }
輸出結果:
嵌套對象映射示例結果:
UserDTO: id=1, name=John
AddressDTO: street=123 Main St, city=New York
自定義映射邏輯示例
import org.mapstruct.Mapper; import org.mapstruct.AfterMapping; import org.mapstruct.MappingTarget; import org.mapstruct.factory.Mappers; @Mapper public interface UserMapper { UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); UserDTO toDTO(UserEntity entity); @AfterMapping default void afterMapping(@MappingTarget UserDTO dto, UserEntity entity) { dto.setFullName(entity.getFirstName() + " " + entity.getLastName()); } } // 測試代碼 public class MainCustomMappingLogic { public static void main(String[] args) { UserEntity userEntity = new UserEntity(); userEntity.setId(1L); userEntity.setFirstName("John"); userEntity.setLastName("Doe"); UserDTO userDTO = UserMapper.INSTANCE.toDTO(userEntity); System.out.println("自定義映射邏輯示例結果:"); System.out.println("UserDTO: id=" + userDTO.getId() + ", fullName=" + userDTO.getFullName()); } }
輸出結果:
自定義映射邏輯示例結果:
UserDTO: id=1, fullName=John Doe
使用上下文示例
import org.mapstruct.Mapper; import org.mapstruct.Context; import org.mapstruct.factory.Mappers; import java.util.Locale; @Mapper public interface UserMapper { UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); UserDTO toDTO(UserEntity entity, @Context Locale locale); default String localize(String value, @Context Locale locale) { // 根據(jù) locale 進行本地化處理 return value; } } // 測試代碼 public class MainWithContext { public static void main(String[] args) { UserEntity userEntity = new UserEntity(); userEntity.setId(1L); userEntity.setName("John"); Locale locale = Locale.US; UserDTO userDTO = UserMapper.INSTANCE.toDTO(userEntity, locale); System.out.println("使用上下文示例結果:"); System.out.println("UserDTO: id=" + userDTO.getId() + ", name=" + userDTO.getName()); } }
輸出結果:
使用上下文示例結果:
UserDTO: id=1, name=John
通過以上示例可以看到,使用 MapStruct 能夠方便快捷地完成 Java Bean 之間的映射,同時結合 Lombok 的 @Data 注解進一步簡化了代碼。并且從輸出結果可以直觀地驗證各個映射場景的正確性。
到此這篇關于Java中基于注解的代碼生成工具MapStruct映射使用詳解的文章就介紹到這了,更多相關Java MapStruct內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
輸出java進程的jstack信息示例分享 通過線程堆棧信息分析java線程
通過ps到java進程號將進程的jstack信息輸出。jstack信息是java進程的線程堆棧信息,通過該信息可以分析java的線程阻塞等問題。2014-01-01java通過模擬post方式提交表單實現(xiàn)圖片上傳功能實例
這篇文章主要介紹了java通過模擬post方式提交表單實現(xiàn)圖片上傳功能實例,涉及Java針對表單的提交操作響應及文件傳輸?shù)南嚓P技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-11-11JAVA WEB中Servlet和Servlet容器的區(qū)別
這篇文章主要介紹了JAVA WEB中Servlet和Servlet容器的區(qū)別,文中示例代碼非常詳細,供大家參考和學習,感興趣的朋友可以了解下2020-06-06