MapStruct的几个注解介绍
Mapper是基础,定义映射接口和全局配置;@Mapping(及@Mappings)配置单个字段的映射细节;用于更新已有对象,简化双向映射;@Named处理自定义转换逻辑;控制方法级全局行为,专门处理枚举映射。掌握这些注解后,可灵活应对大多数对象转换场景,大幅减少手动编写的工作量。
文章目录
MapStruct 的核心能力通过一系列注解实现,这些注解用于定义映射规则、配置转换行为、处理特殊场景(如字段名不匹配、类型转换等)。以下是最常用的几个注解及其用法:
1. @Mapper
作用:标记一个接口为 MapStruct 的映射接口,MapStruct 会在编译期为该接口生成实现类(包含具体的转换逻辑)。
核心属性:
componentModel:指定生成的实现类的“组件模型”,用于集成到依赖注入框架(如 Spring、CDI)。常见取值:default:默认值,生成的实现类无特殊注解,需手动实例化(如UserMapper INSTANCE = Mappers.getMapper(UserMapper.class))。spring:生成的实现类会添加@Component注解,可通过 Spring 的@Autowired注入。cdi:适用于 CDI 容器,生成的类会添加@Named注解。
uses:指定当前映射接口依赖的其他映射器(当需要调用其他映射器的方法进行嵌套转换时使用)。unmappedTargetPolicy:配置“目标对象存在未映射字段”时的处理策略(如报错、警告),默认忽略。取值:ERROR(编译报错)、WARN(编译警告)、IGNORE(忽略)。
示例:
// 生成 Spring 组件,依赖其他映射器(AddressMapper),未映射字段报错
@Mapper(
componentModel = "spring",
uses = AddressMapper.class,
unmappedTargetPolicy = ReportingPolicy.ERROR
)
public interface UserMapper {
// 映射方法...
}
2. @Mapping
作用:配置单个字段的映射规则(如源字段与目标字段的对应关系、类型转换方式等),用在映射方法上。
核心属性:
source:源对象的字段名(如实体类的userName)。target:目标对象的字段名(如 DTO 的name),若与source同名,可省略。ignore:是否忽略该字段(true表示不映射该字段)。defaultValue:当源字段为null时,目标字段的默认值(如defaultValue = "unknown")。defaultExpression:更灵活的默认值表达式(基于 Java 表达式),如defaultExpression = "java(java.time.LocalDate.now())"(默认当前日期)。qualifiedByName:指定用于转换的“命名方法”(配合@Named注解,解决同一类型的不同转换逻辑)。dateFormat:日期类型转换的格式(如dateFormat = "yyyy-MM-dd",将String与LocalDate互转)。
示例:
@Mapper(componentModel = "spring")
public interface UserMapper {
// 映射 UserEntity 到 UserDTO
@Mapping(source = "userName", target = "name") // 字段名不同:userName → name
@Mapping(source = "birthday", target = "birthdayStr", dateFormat = "yyyy-MM-dd") // 日期格式化
@Mapping(source = "age", target = "age", defaultValue = "0") // 源为null时默认0
@Mapping(source = "gender", target = "genderDesc", qualifiedByName = "genderToDesc") // 调用自定义方法
@Mapping(source = "password", target = "password", ignore = true) // 忽略密码字段
UserDTO entityToDto(UserEntity entity);
}
3. @Mappings
作用:当一个映射方法需要配置多个字段的映射规则时,用 @Mappings 包裹多个 @Mapping 注解(Java 8 及以上支持重复注解,可省略 @Mappings,直接写多个 @Mapping)。
示例:
// 方式1:用 @Mappings 包裹(兼容旧版本)
@Mappings({
@Mapping(source = "userName", target = "name"),
@Mapping(source = "birthday", target = "birthdayStr", dateFormat = "yyyy-MM-dd")
})
UserDTO entityToDto(UserEntity entity);
// 方式2:直接写多个 @Mapping(Java 8+ 支持)
@Mapping(source = "userName", target = "name")
@Mapping(source = "birthday", target = "birthdayStr", dateFormat = "yyyy-MM-dd")
UserDTO entityToDto(UserEntity entity);
4. @MappingTarget
作用:指定一个“已存在的目标对象”作为转换的目标,MapStruct 会将源对象的字段值更新到该目标对象中(而非创建新的目标对象)。常用于“部分更新”场景(如根据源对象更新目标对象的部分字段)。
示例:
@Mapper(componentModel = "spring")
public interface UserMapper {
// 将 entity 的字段更新到已存在的 dto 中(不创建新 dto)
@Mapping(source = "userName", target = "name")
void updateDtoFromEntity(UserEntity entity, @MappingTarget UserDTO dto);
}
// 使用时:
UserEntity entity = ...; // 源对象(包含最新数据)
UserDTO existingDto = ...; // 已存在的目标对象(需要更新)
userMapper.updateDtoFromEntity(entity, existingDto); // existingDto 的字段会被更新
5. @InheritInverseConfiguration
作用:“继承反向映射规则”,用于简化“双向映射”的配置。例如:若已定义 entityToDto 方法,那么 dtoToEntity 方法可通过该注解自动继承反向的映射规则(无需重复配置 source 和 target)。
示例:
@Mapper(componentModel = "spring")
public interface UserMapper {
// 正向映射:entity → dto
@Mapping(source = "userName", target = "name")
@Mapping(source = "birthday", target = "birthdayStr", dateFormat = "yyyy-MM-dd")
UserDTO entityToDto(UserEntity entity);
// 反向映射:dto → entity,继承正向映射的反向规则
@InheritInverseConfiguration(name = "entityToDto") // 指定继承哪个方法的反向规则
@Mapping(target = "id", ignore = true) // 额外忽略 id 字段(反向映射时不处理)
UserEntity dtoToEntity(UserDTO dto);
}
上述代码中,dtoToEntity 会自动应用 entityToDto 的反向规则:name → userName、birthdayStr → birthday(并自动使用 yyyy-MM-dd 解析字符串为日期)。
6. @Named
作用:为“自定义转换方法”命名,配合 @Mapping 的 qualifiedByName 属性使用,用于区分同一类型的不同转换逻辑(如同一字段在不同场景下需要不同的转换方式)。
示例:
@Mapper(componentModel = "spring")
public interface UserMapper {
// 定义两个不同的日期转换方法(用 @Named 命名)
@Named("dateToStrShort")
default String dateToStrShort(LocalDate date) {
return date.format(DateTimeFormatter.ofPattern("yyyy-MM")); // 短格式:2023-10
}
@Named("dateToStrLong")
default String dateToStrLong(LocalDate date) {
return date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); // 长格式:2023-10-01
}
// 映射时通过 qualifiedByName 指定使用哪个方法
@Mapping(source = "birthday", target = "birthdayShort", qualifiedByName = "dateToStrShort")
@Mapping(source = "birthday", target = "birthdayLong", qualifiedByName = "dateToStrLong")
UserDTO entityToDto(UserEntity entity);
}
7. @BeanMapping
作用:配置整个映射方法的全局行为(而非单个字段),如忽略未显式配置的字段、设置映射优先级等。
核心属性:
ignoreByDefault:是否默认忽略所有未显式配置的字段(true表示只映射@Mapping显式配置的字段)。resultType:指定映射方法的返回类型(当方法返回值是接口/父类时,指定具体实现类)。
示例:
@Mapper(componentModel = "spring")
public interface UserMapper {
// 只映射显式配置的字段(其他字段忽略)
@BeanMapping(ignoreByDefault = true)
@Mapping(source = "userName", target = "name") // 只映射 name 字段
@Mapping(source = "age", target = "age") // 只映射 age 字段
UserDTO entityToSimpleDto(UserEntity entity);
}
8. @ValueMapping
作用:用于枚举类型的映射,指定源枚举值与目标枚举值的对应关系(解决枚举值名称/含义不同的转换)。
示例:
// 源枚举
public enum GenderEntity {
MALE, FEMALE, UNKNOWN
}
// 目标枚举
public enum GenderDto {
MAN, WOMAN, OTHER
}
@Mapper(componentModel = "spring")
public interface GenderMapper {
// 枚举值映射:MALE→MAN,FEMALE→WOMAN,其他值→OTHER
@ValueMapping(source = "MALE", target = "MAN")
@ValueMapping(source = "FEMALE", target = "WOMAN")
@ValueMapping(source = MappingConstants.ANY_REMAINING, target = "OTHER") // 剩余值默认映射到 OTHER
GenderDto entityToDto(GenderEntity gender);
}
9. @BeforeMapping
作用:用于在映射方法执行前进行预处理操作。它允许开发者对源对象或其他相关数据进行修改、验证等操作,确保映射过程能基于符合预期的数据进行。
10. @AfterMapping
作用:用于在映射方法执行后进行后处理操作。通常用于对映射后的目标对象进行额外的修改、填充等操作,使目标对象更符合业务要求。
总结
MapStruct 的注解围绕“字段映射规则”和“转换行为配置”展开:
@Mapper是基础,定义映射接口和全局配置;@Mapping(及@Mappings)配置单个字段的映射细节;@MappingTarget用于更新已有对象,@InheritInverseConfiguration简化双向映射;@Named+qualifiedByName处理自定义转换逻辑;@BeanMapping控制方法级全局行为,@ValueMapping专门处理枚举映射。
掌握这些注解后,可灵活应对大多数对象转换场景,大幅减少手动编写 getter/setter 的工作量。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)