MapStruct从入门到精通:Java对象映射的终极指南
引言
在Java开发中,对象之间的转换
(如DTO转Entity、VO转BO)是常见但繁琐的任务。传统的getter/setter
方式不仅繁琐且易错,而反射工具BeanUtils.copyProperties()
则存在性能问题。MapStruct
作为基于注解的代码生成器,提供了编译时
类型安全的优雅解决方案。本文将深入解析MapStruct的核心功能与最佳实践。
一、MapStruct核心优势
高性能
:编译期生成代码,无反射调用类型安全
:自动校验字段类型和名称匹配,减少低级错误灵活扩展
:支持自定义类型转换、忽略字段、表达式等高级操作零依赖
:仅需注解处理器,无运行时依赖
二、快速入门
1、添加依赖(Maven)
- 注意lombok依赖不能在MapStruct处理器依赖后面,否则生成代码
没有setXxx(无法转换)
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<!-- MapStruct 核心依赖 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>
<!-- MapStruct 处理器 (让 MapStruct 自动生成转换代码) -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
<scope>provided</scope><!-- 只在编译时使用,不打包 -->
</dependency>
2、定义实体和DTO
代码语言:javascript代码运行次数:0运行复制@Data
public class User {
private Long id;
private String name;
}
@Data
public class UserDTO {
private Long id;
private String name;
}
3、创建Mapper接口
@Mapper
:标记接口为映射器- 编译后,MapStruct自动生成
UserConverterImpl
类,实现属性复制逻辑
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper // 标记接口为映射器
public interface UserConverter {
// 获取自动生成的UserConverterImpl实现类
UserConverter INSTANCE = Mappers.getMapper(UserConverter.class);
// UserDTO转为User对象
User toEntity(UserDTO dto);
}
4、使用Mapper
代码语言:javascript代码运行次数:0运行复制public static void main(String[] args) {
UserDTO dto = new UserDTO();
dto.setId(1L);
dto.setName("xc");
User user = UserConverter.INSTANCE.toEntity(dto);
System.out.println(user); // User(id=1, name=xc)
}
- target编译自动生成实现类相同属性set
三、进阶技巧
1、处理字段名不一致
- 通过
@Mapping
注解显式指定源和目标字段
@Data
public class User {
private Long id;
private String username;
}
@Data
public class UserDTO {
private Long id;
private String name;
}
@Mapper
public interface UserConverter {
UserConverter INSTANCE = Mappers.getMapper(UserConverter.class);
@Mapping(source = "name", target = "username")
User toEntity(UserDTO dto);
}
2、集合映射
- 自动生成
List
或Set
的映射方法 - List之间不能使用@Mapping,如果有字段不一致,需要添加List的泛型类@Mapping的转换
@Mapper
public interface UserConverter {
UserConverter INSTANCE = Mappers.getMapper(UserConverter.class);
@Mapping(source = "name", target = "username")
User toEntity(UserDTO dto);
List<User> toEntityList(List<UserDTO> users);
}
3、表达式、常量、默认值
- 根据表达式结果赋值目标属性
- 生成的目标对象role始终为"admin"常量
- 若源对象的id为null,目标字段id设为"100L";否则使用源值
@Mapper
public interface UserConverter {
UserConverter INSTANCE = Mappers.getMapper(UserConverter.class);
@Mapping(target = "status", expression = "java(user.isActive() ? 1 : 0)")
@Mapping(target = "role", constant = "admin")
@Mapping(target = "id", defaultValue = "100L")
User toEntity(UserDTO dto);
}
4、自定义方法
- 在Mapper中定义默认方法实现
复杂逻辑
@Mapper
public interface UserConverter {
UserConverter INSTANCE = Mappers.getMapper(UserConverter.class);
UserDTO toDTO(User user);
default UserDTO merge(User user, UserDetails details) {
UserDTO dto = toDTO(user);
dto.setAge(details.getAge());
return dto;
}
}
4、多Mapper组合
- 通过uses参数引用其他Mapper
@Mapper(uses = {AddressConverter.class})
public interface UserConverter {
// 自动调用AddressMapper进行嵌套转换
UserDTO toDTO(User user);
}
四、与SpringBoot整合
1、配置组件模型
- 添加
componentModel = "spring"
,通过@Autowired注入Mapper
@Mapper(componentModel = "spring")
public interface UserConverter {
// 省略不用再写,spring自动生成
// UserConverter INSTANCE = Mappers.getMapper(UserConverter.class);
UserDTO toDTO(User user);
}
2、依赖注入
代码语言:javascript代码运行次数:0运行复制@Service
public class UserService {
@Autowired
private UserConverter userConverter;
public UserDTO getUser(Long id) {
return userConverter.toDTO(repository.findById(id));
}
}
总结
MapStruct通过其优雅
的设计和强大的功能,显著提升了Java对象映射的效率
。结合编译时安全检查和灵活的自定义能力,它是现代Java工程中不可或缺的工具。