一、MapStruct Plus 简介
MapStruct Plus 是基于 MapStruct 框架的增强工具,旨在通过注解驱动的方式,自动生成 Java 类型之间的映射接口,省略手动定义映射接口的步骤,使 Java 类型转换更加便捷、优雅。它继承了 MapStruct 的高性能特点,同时增强了便携性和快速开发的特性,尤其适合处理多层对象模型、复杂嵌套结构以及快速原型开发场景。
二、核心特性
- 自动化映射接口生成:通过
@AutoMapper注解自动生成两个类之间的映射接口,无需手动编写接口方法。 - 复杂对象深度转换支持:自动处理嵌套对象映射,无需手动定义每个层级的转换逻辑。
- Map 与对象互转增强:支持
Map转换为自定义类,甚至嵌套Map结构。 - 多目标对象配置:通过
@AutoMappers注解支持单个源对象映射到多个目标对象。 - 兼容性与扩展性:完全兼容 MapStruct,可直接替换依赖;支持 JDK 8~17 和 Spring Boot 2~3;提供 SPI 扩展点,允许自定义类型转换逻辑。
三、快速入门
1. 引入依赖
在 Maven 项目中,添加以下依赖:
<dependencies>
<!-- MapStruct Plus 核心依赖 -->
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus</artifactId>
<version>最新版本</version>
</dependency>
<!-- MapStruct Plus 处理器(编译时生成代码) -->
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-processor</artifactId>
<version>最新版本</version>
<scope>provided</scope>
</dependency>
</dependencies>
2. 基本使用
场景 1:简单对象转换
假设有两个类 UserDto 和 User,分别表示数据层对象和业务层对象:
// UserDto.java
public class UserDto {
private String username;
private int age;
private boolean young;
// getter、setter、toString、equals、hashCode
}
// User.java
public class User {
private String username;
private int age;
private boolean young;
// getter、setter、toString、equals、hashCode
}
使用 MapStruct Plus 进行转换:
- 方式 1:在其中一个类上添加
@AutoMapper注解
@AutoMapper(target = UserDto.class)
public class User {
// 字段定义
}
- 方式 2:定义映射接口(可选,若需自定义转换逻辑)
@AutoMapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
UserDto toDto(User user);
User toEntity(UserDto dto);
}
测试转换:
public class QuickStartTest {
private static Converter converter = new Converter();
@Test
public void testConversion() {
User user = new User();
user.setUsername("jack");
user.setAge(23);
user.setYoung(false);
// User -> UserDto
UserDto userDto = converter.convert(user, UserDto.class);
System.out.println(userDto); // UserDto{username='jack', age=23, young=false}
assert user.getUsername().equals(userDto.getUsername());
assert user.getAge() == userDto.getAge();
assert user.isYoung() == userDto.isYoung();
// UserDto -> User
User newUser = converter.convert(userDto, User.class);
System.out.println(newUser); // User{username='jack', age=23, young=false}
assert user.getUsername().equals(newUser.getUsername());
assert user.getAge() == newUser.getAge();
assert user.isYoung() == newUser.isYoung();
}
}
3. 高级特性
场景 2:复杂对象转换(嵌套结构)
// OrderDto.java
public class OrderDto {
private Long id;
private UserDto user;
// getter、setter
}
// Order.java
public class Order {
private Long id;
private User user;
// getter、setter
}
// 在 Order 或 User 类上添加 @AutoMapper 注解
@AutoMapper(target = OrderDto.class)
public class Order {
// 字段定义
}
测试嵌套转换:
@Test
public void testNestedConversion() {
Order order = new Order();
order.setId(1L);
User user = new User();
user.setUsername("jack");
order.setUser(user);
OrderDto orderDto = converter.convert(order, OrderDto.class);
System.out.println(orderDto); // OrderDto{id=1, user=UserDto{username='jack', age=0, young=false}}
assert order.getId().equals(orderDto.getId());
assert order.getUser().getUsername().equals(orderDto.getUser().getUsername());
}
场景 3:枚举和特殊规则处理
// Status.java
public enum Status {
ACTIVE, INACTIVE
}
// ProjectDto.java
public class ProjectDto {
private String name;
private Status status;
// getter、setter
}
// Project.java
public class Project {
private String name;
private String status; // 存储为字符串
// getter、setter
}
// 自定义转换逻辑
@AutoMapper
public interface ProjectMapper {
ProjectMapper INSTANCE = Mappers.getMapper(ProjectMapper.class);
@Mapping(target = "status", expression = "java(dto.getStatus().name())")
Project toEntity(ProjectDto dto);
@Mapping(target = "status", expression = "java(Status.valueOf(entity.getStatus()))")
ProjectDto toDto(Project entity);
}
测试枚举转换:
@Test
public void testEnumConversion() {
ProjectDto dto = new ProjectDto();
dto.setName("Project A");
dto.setStatus(Status.ACTIVE);
Project project = ProjectMapper.INSTANCE.toEntity(dto);
System.out.println(project); // Project{name='Project A', status='ACTIVE'}
assert dto.getName().equals(project.getName());
assert dto.getStatus().name().equals(project.getStatus());
ProjectDto newDto = ProjectMapper.INSTANCE.toDto(project);
System.out.println(newDto); // ProjectDto{name='Project A', status=ACTIVE}
assert project.getName().equals(newDto.getName());
assert project.getStatus().equals(newDto.getStatus().name());
}
场景 4:列表转换
@Test
public void testListConversion() {
List<User> users = new ArrayList<>();
users.add(new User("jack", 23, false));
users.add(new User("alice", 25, true));
List<UserDto> userDtos = converter.convertList(users, UserDto.class);
System.out.println(userDtos); // [UserDto{username='jack', age=23, young=false}, UserDto{username='alice', age=25, young=true}]
assert users.size() == userDtos.size();
assert users.get(0).getUsername().equals(userDtos.get(0).getUsername());
}
四、与 Spring Boot 集成
MapStruct Plus 可以与 Spring Boot 无缝集成,支持依赖注入和自动配置。
1. 添加 Spring Boot Starter依赖
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>1.5.0</version> <!-- 使用最新版本 -->
</dependency>
2. 配置组件模型
在 @AutoMapper 或 @Mapper 注解中指定 componentModel = "spring":
@AutoMapper(target = UserDto.class, componentModel = "spring")
public class User {
// 字段定义
}
或
@Mapper(componentModel = "spring")
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
UserDto toDto(User user);
User toEntity(UserDto dto);
}
3. 注入并使用 Converter
@SpringBootTest
public class SpringBootQuickStartTest {
@Autowired
private Converter converter;
@Test
public void testConversion() {
User user = new User();
user.setUsername("jack");
user.setAge(23);
user.setYoung(false);
UserDto userDto = converter.convert(user, UserDto.class);
System.out.println(userDto); // UserDto{username='jack', age=23, young=false}
}
}
五、最佳实践
- 合理使用
@AutoMapper和@Mapper:- 若需简单快速转换,且对控制粒度要求不高,使用
@AutoMapper。 - 若需自定义转换逻辑或处理复杂场景,使用
@Mapper定义接口。
- 若需简单快速转换,且对控制粒度要求不高,使用
- 处理字段名不一致:
- 使用
@Mapping注解指定字段映射关系:
- 使用
@Mapping(source = "userName", target = "username")
UserDto toDto(User user);
- 忽略字段:
- 使用
@Mapping(target = "fieldName", ignore = true)忽略不需要映射的字段。
- 使用
- 处理集合类型:
- MapStruct Plus 自动处理集合到集合的映射,无需特别配置。
- 性能优化:
- MapStruct Plus 生成的代码基于
getter/setter方法,性能接近手动编写代码。 - 避免在映射逻辑中执行复杂计算或数据库操作。
- MapStruct Plus 生成的代码基于
- 调试与错误处理:
- 编译时生成的代码位于
target/generated-sources/annotations目录下,可查看生成的实现类。 - 若映射错误,编译时会报错,根据错误信息调整映射逻辑。
- 编译时生成的代码位于
六、常见问题解答
- Q:MapStruct Plus 与 MapStruct 有什么区别?
- A:MapStruct Plus 是 MapStruct 的增强工具,通过
@AutoMapper注解自动生成映射接口,省略手动定义接口的步骤,使开发更加便捷。
- A:MapStruct Plus 是 MapStruct 的增强工具,通过
- Q:MapStruct Plus 支持哪些 Java 版本?
- A:支持 JDK 8~17。
- Q:MapStruct Plus 是否支持 Lombok?
- A:支持,但需确保 Lombok 注解处理器在编译时生效。
- Q:如何处理循环引用?
- A:MapStruct Plus 默认不支持循环引用,需手动处理或使用
@Context注解传递上下文。
- A:MapStruct Plus 默认不支持循环引用,需手动处理或使用
- Q:如何自定义类型转换逻辑?
- A:通过
@Mapper定义接口,并在接口方法中实现自定义逻辑;或使用expression属性指定 Java 表达式。
- A:通过
七、总结
MapStruct Plus 是一个强大的 Java 类型转换工具,通过注解驱动的方式自动生成映射接口,显著简化了复杂对象模型的转换流程。它继承了 MapStruct 的高性能特点,同时增强了便携性和快速开发的特性,尤其适合处理多层对象模型、复杂嵌套结构以及快速原型开发场景。
通过合理使用 @AutoMapper 和 @Mapper 注解,结合高级特性如枚举转换、列表转换等,可以高效地完成各种 Java 类型转换任务。


1577

被折叠的 条评论
为什么被折叠?



