Java中基于注解的代碼生成工具M(jìn)apStruct映射使用詳解
介紹
在 Java 開發(fā)中,我們經(jīng)常需要在不同的 Java Bean 之間進(jìn)行數(shù)據(jù)映射,比如從實(shí)體類(Entity)到數(shù)據(jù)傳輸對(duì)象(DTO)的轉(zhuǎn)換。傳統(tǒng)的做法是手動(dòng)編寫大量的 setter 和 getter 方法來完成屬性的賦值,這種方式不僅繁瑣,而且容易出錯(cuò)。MapStruct 作為一個(gè)基于注解的代碼生成工具,為我們提供了一種更加優(yōu)雅、高效的解決方案。它在編譯時(shí)自動(dòng)生成映射代碼,避免了運(yùn)行時(shí)反射帶來的性能開銷,同時(shí)保證了類型安全。
優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
- 高性能:MapStruct 在編譯階段生成映射代碼,運(yùn)行時(shí)直接調(diào)用這些代碼,避免了反射的使用,從而顯著提高了性能。
- 類型安全:由于映射代碼是在編譯時(shí)生成的,編譯器會(huì)對(duì)類型進(jìn)行檢查,因此可以在編譯階段發(fā)現(xiàn)類型不匹配等錯(cuò)誤,避免了運(yùn)行時(shí)異常。
- 代碼簡潔:使用 MapStruct 只需要定義映射接口和使用注解進(jìn)行配置,無需手動(dòng)編寫大量的映射邏輯,大大減少了代碼量,提高了開發(fā)效率。
缺點(diǎn)
- 學(xué)習(xí)成本:需要學(xué)習(xí) MapStruct 提供的各種注解及其使用方法,對(duì)于初學(xué)者來說可能有一定的學(xué)習(xí)曲線。
- 依賴管理:需要在項(xiàng)目中引入 MapStruct 的相關(guān)依賴,增加了項(xiàng)目的依賴管理復(fù)雜度。
核心注解及詳細(xì)使用語法說明
@Mapper
- 作用:用于標(biāo)記一個(gè)接口為映射接口,MapStruct 會(huì)在編譯時(shí)為該接口生成具體的實(shí)現(xiàn)類。
- 使用語法:
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface UserMapper {
// 通過 Mappers.getMapper 方法獲取映射接口的實(shí)例
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
// 定義從 UserEntity 到 UserDTO 的映射方法
UserDTO toDTO(UserEntity entity);
// 定義從 UserDTO 到 UserEntity 的映射方法
UserEntity toEntity(UserDTO dto);
}
@Mapping
- 作用:用于指定源對(duì)象和目標(biāo)對(duì)象之間的屬性映射關(guān)系,當(dāng)源對(duì)象和目標(biāo)對(duì)象的屬性名
不一致時(shí),可以使用該注解進(jìn)行顯式映射。 - 使用語法:
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 的集合形式,用于一次性指定
多個(gè)屬性映射關(guān)系。 - 使用語法:
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
- 作用:用于在映射過程中傳遞上下文信息,比如一些輔助對(duì)象,這些對(duì)象可以在映射方法中使用。
- 使用語法:
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 對(duì)象作為上下文信息
UserDTO toDTO(UserEntity entity, @Context Locale locale);
}
@AfterMapping
- 作用:用于在映射完成后執(zhí)行自定義的邏輯,比如對(duì)目標(biāo)對(duì)象的某些屬性進(jìn)行額外的處理。
- 使用語法:
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) {
// 將源對(duì)象的 firstName 和 lastName 拼接后賦值給目標(biāo)對(duì)象的 fullName 屬性
dto.setFullName(entity.getFirstName() + " " + entity.getLastName());
}
}
Demo示例
公共基本類定義
import lombok.Data;
// 用戶實(shí)體類
@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ù)傳輸對(duì)象類
@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;
}
// 地址實(shí)體類
@Data
public class AddressEntity {
private String street;
private String city;
}
// 地址數(shù)據(jù)傳輸對(duì)象類
@Data
public class AddressDTO {
private String street;
private String city;
}
簡單映射示例
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface UserMapper {
// 獲取映射接口的實(shí)例
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
// 從 UserEntity 到 UserDTO 的映射方法
UserDTO toDTO(UserEntity entity);
// 從 UserDTO 到 UserEntity 的映射方法
UserEntity toEntity(UserDTO dto);
}
// 測(cè)試代碼
public class MainSimpleMapping {
public static void main(String[] args) {
UserEntity userEntity = new UserEntity();
userEntity.setId(1L);
userEntity.setName("John");
userEntity.setAge(25);
// 使用映射接口的實(shí)例進(jìn)行映射
UserDTO userDTO = UserMapper.INSTANCE.toDTO(userEntity);
System.out.println("簡單映射示例結(jié)果:");
System.out.println("UserDTO: id=" + userDTO.getId() + ", name=" + userDTO.getName() + ", age=" + userDTO.getAge());
}
}
輸出結(jié)果:
簡單映射示例結(jié)果:
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);
}
// 測(cè)試代碼
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("字段名不一致映射示例結(jié)果:");
System.out.println("UserDTO: id=" + userDTO.getId() + ", name=" + userDTO.getName() + ", age=" + userDTO.getAge());
}
}
輸出結(jié)果:
字段名不一致映射示例結(jié)果:
UserDTO: id=1, name=John, age=25
嵌套對(duì)象映射示例
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);
}
// 測(cè)試代碼
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("嵌套對(duì)象映射示例結(jié)果:");
System.out.println("UserDTO: id=" + userDTO.getId() + ", name=" + userDTO.getName());
System.out.println("AddressDTO: street=" + userDTO.getAddress().getStreet() + ", city=" + userDTO.getAddress().getCity());
}
}
輸出結(jié)果:
嵌套對(duì)象映射示例結(jié)果:
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());
}
}
// 測(cè)試代碼
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("自定義映射邏輯示例結(jié)果:");
System.out.println("UserDTO: id=" + userDTO.getId() + ", fullName=" + userDTO.getFullName());
}
}
輸出結(jié)果:
自定義映射邏輯示例結(jié)果:
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 進(jìn)行本地化處理
return value;
}
}
// 測(cè)試代碼
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("使用上下文示例結(jié)果:");
System.out.println("UserDTO: id=" + userDTO.getId() + ", name=" + userDTO.getName());
}
}
輸出結(jié)果:
使用上下文示例結(jié)果:
UserDTO: id=1, name=John
通過以上示例可以看到,使用 MapStruct 能夠方便快捷地完成 Java Bean 之間的映射,同時(shí)結(jié)合 Lombok 的 @Data 注解進(jìn)一步簡化了代碼。并且從輸出結(jié)果可以直觀地驗(yàn)證各個(gè)映射場(chǎng)景的正確性。
到此這篇關(guān)于Java中基于注解的代碼生成工具M(jìn)apStruct映射使用詳解的文章就介紹到這了,更多相關(guān)Java MapStruct內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用log4j2打印mybatis的sql執(zhí)行日志方式
這篇文章主要介紹了使用log4j2打印mybatis的sql執(zhí)行日志方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
Hibernate中實(shí)現(xiàn)增刪改查的步驟詳解
本篇文章主要介紹了Hibernate中實(shí)現(xiàn)增刪改查的步驟與方法,具有很好的參考價(jià)值,下面跟著小編一起來看下吧2017-02-02
SpringBoot配置連接兩個(gè)或多個(gè)數(shù)據(jù)庫的實(shí)現(xiàn)
本文主要介紹了SpringBoot配置連接兩個(gè)或多個(gè)數(shù)據(jù)庫的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
一文快速了解spring?boot中的@idempotent注解
idempotence注解是RESTful API設(shè)計(jì)中一個(gè)重要的概念,它可以保證操作的可靠性和一致性,下面這篇文章主要給大家介紹了關(guān)于spring?boot中@idempotent注解的相關(guān)資料,需要的朋友可以參考下2024-01-01
Springboot項(xiàng)目與vue項(xiàng)目整合打包的實(shí)現(xiàn)方式
這篇文章主要介紹了Springboot項(xiàng)目與vue項(xiàng)目整合打包的實(shí)現(xiàn)方式,本文通過兩種方式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07
Java代碼缺陷的自動(dòng)化檢測(cè)與跟蹤的管理指南
本文系統(tǒng)解析Java代碼缺陷類型及危害,涵蓋靜態(tài)分析工具檢測(cè)方法,動(dòng)態(tài)監(jiān)控技術(shù)(異常處理、性能指標(biāo)),缺陷跟蹤系統(tǒng)與CI/CD自動(dòng)化集成方案,助力提升代碼質(zhì)量與安全防護(hù),需要的朋友可以參考下2025-07-07
java 實(shí)現(xiàn)讀取txt文本數(shù)據(jù)并以數(shù)組形式一行一行取值
今天小編就為大家分享一篇java 實(shí)現(xiàn)讀取txt文本數(shù)據(jù)并以數(shù)組形式一行一行取值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-07-07

