在后端业务开发中,处理对象之间的转换是家常便饭。尽管MapStruct通过编译时生成代码的方式帮助我们提升了效率,但手动编写 @Mapper 接口和映射方法的步骤依然让开发者感到繁琐。有没有办法更进一步简化?MapStruct 的增强版—— MapStruct Plus 应运而生。它继承了原生 MapStruct 编译期生成、高性能的优势,并带来了诸如“自动生成 Mapper 接口”等革命性特性,让对象转换变得前所未有的简单。
🚀 MapStructPlus 核心优势:对比原生MapStruct
MapStruct Plus 基于原生 MapStruct 进行增强,遵循“只做增强,不做修改”的原则,旨在让对象映射更简单、更优雅:
- 零接口定义:无需手动编写
@Mapper 注解的接口。只需在实体类上添加一行 @AutoMapper 注解来声明映射关系,即可省去大量转换代码。
- 自动生成实现:在编译期自动生成高效的原生 Java 转换代码,其性能与手写代码几乎无差别。
- 多环境适配:完美支持 SpringBoot 环境,也兼容非 SpringBoot 项目,依赖配置极其简洁。
- 功能强化:针对原生 MapStruct 中需要复杂配置的场景(如嵌套对象映射、枚举映射、一对多转换),MapStruct Plus 仅通过注解即可轻松实现。

📌 快速入门
1️⃣ SpringBoot环境引入依赖
在 SpringBoot 项目中,引入以下依赖即可快速开始。starter 会自动引入必要的处理器。
<dependencies>
<!-- 核心 starter,自动引入处理器和依赖 -->
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>1.4.8</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>你的 hutool 版本</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>你的 Lombok 版本</version>
</path>
<path>
<!-- Lombok 与 MapStruct 绑定器(Lombok 1.18.16+ 版本需加上) -->
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
2️⃣ 配置与使用映射
核心流程非常简单:使用注解标记映射关系,然后通过自动注入的 Converter 工具类完成转换。
// 1. 在源类添加@AutoMapper注解,指定目标类
@Data
@AutoMapper(target = UserDto.class)
public class User {
// 字段同上
private String username;
private int age;
private boolean young;
//指定时间格式进行转换
@AutoMapping(dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date birthday;
}
@Data
public class UserDto {
private String username;
private int age;
private boolean young;
private String birthday; // 时间字段类型不一致(Date → String)
}
// 2. SpringBoot 环境测试(自动注入 Converter)
@SpringBootTest
public class QuickStartTest {
@Autowired
private Converter converter;
@Test
public void testConvert() {
User user = new User();
user.setUsername("jack");
user.setAge(23);
user.setYoung(false);
user.setBirthday(new Date());
// 实体转 DTO
UserDto userDto = converter.convert(user, UserDto.class);
System.out.println(userDto);
// 输出:UserDto(username=jack, age=23, young=false, birthday=2026-01-28 11:00:00)
// DTO 转实体(支持自动反向转换)
User newUser = converter.convert(userDto, User.class);
assert user.getUsername().equals(newUser.getUsername());
}
}
🔧 功能详解
一、字段映射自定义
当源类与目标类的字段名、类型不一致时,可以使用 @AutoMapping 注解进行精细化配置,支持格式转换、忽略字段等操作。
1. 字段名不一致映射
@Data
@AutoMapper(target = UserDto.class)
public class User {
private String username; // 源字段
@AutoMapping(target = “userAge”) // 目标字段名:userAge
private int age;
@AutoMapping(defaultValue = “false”)// 为 null 时,转换到目标类后的默认值
private boolean young;
}
2. 类型转换与格式指定
支持对日期、数字等类型进行自定义格式转换,无需手动编写转换逻辑。
@Data
@AutoMapper(target = UserDto.class)
public class User {
private String username;
// 数字格式:保留两位小数,前缀加 $
@AutoMapping(target = “assetsStr”, numberFormat = “$0.00”)
private double assets;
// 日期格式:自定义字符串格式
@AutoMapping(target = “birthdayStr”, dateFormat = “yyyy-MM-dd”)
private Date birthday;
}
3. 忽略指定字段
对于不需要参与映射的字段,可以直接标记 ignore = true。
@Data
@AutoMapper(target = UserDto.class)
public class User {
private String username;
private int age;
// 忽略密码字段,不参与映射
@AutoMapping(target = “password”, ignore = true)
private String password;
}
二、多类映射(一个类对应多个目标类)
当一个实体需要转换为多个不同的 DTO 或 VO 时,可以使用 @AutoMappers 注解进行批量配置,并支持为不同目标类指定差异化的映射规则。
@Data
@AutoMappers({
@AutoMapper(target = UserDto.class), // 对应 UserDto
@AutoMapper(target = UserVo.class) // 对应 UserVo
})
public class User {
private String username;
private int age;
private Date birthday;
// 对 UserDto 单独配置:生日转字符串格式
@AutoMapping(targetClass = UserDto.class, target = “birthday”, dateFormat = “yyyy-MM-dd”)
// 对 UserVo 单独配置:忽略生日字段
@AutoMapping(targetClass = UserVo.class, target = “birthday”, ignore = true)
private Date birthday;
// 未指定 targetClass,对所有目标类生效
@AutoMapping(target = “userName”, source = “username”)
private String username;
}
提示:targetClass 支持父类,其子类会自动继承映射规则(1.3.6 版本及以上支持)。
三、嵌套对象映射(支持多层级转换)
当类中包含嵌套对象(例如 User 包含 Order 列表)时,MapStruct Plus 能自动支持嵌套转换,无需额外配置。对于更复杂的场景,也可以自定义嵌套规则。
示例:嵌套对象转换
// 嵌套实体类:Order
@Data
@AutoMapper(target = OrderDto.class)
public class Order {
private Long orderId;
private BigDecimal amount;
}
// 源类:User(包含 Order 列表)
@Data
@AutoMapper(target = UserWithOrderDto.class)
public class User {
private String username;
private List<Order> orderList; // 嵌套列表
}
// 目标类:UserWithOrderDto(嵌套 DTO)
@Data
public class UserWithOrderDto {
private String username;
private List<OrderDto> orderList; // 嵌套 DTO 列表
}
// 测试:自动完成嵌套转换
@Test
public void testNestedConvert() {
User user = new User();
user.setUsername(“jack”);
Order order = new Order();
order.setOrderId(1L);
order.setAmount(new BigDecimal(“100.00”));
user.setOrderList(Collections.singletonList(order));
UserWithOrderDto dto = converter.convert(user, UserWithOrderDto.class);
// 自动将 Order 列表转为 OrderDto 列表
System.out.println(dto.getOrderList().get(0).getOrderId()); // 输出 1
}
四、枚举映射(轻松实现枚举转换)
实现枚举与基本类型(如 Integer、String)之间的转换,使用 @AutoEnumMapper 注解即可快速配置。
1. 基础枚举转换(枚举 ↔ 基本类型)
// 枚举类:指定唯一标识字段(state)
@Getter
@AllArgsConstructor
@AutoEnumMapper(“state”) // 标记枚举,指定映射字段
public enum GoodsStateEnum {
ENABLED(1, “启用”),
DISABLED(0, “禁用”);
private final Integer state; // 映射字段
private final String desc;
}
// 源类:Goods
@Data
@AutoMapper(target = GoodsVo.class)
public class Goods {
private String goodsName;
private GoodsStateEnum state; // 枚举字段
}
// 目标类:GoodsVo
@Data
public class GoodsVo {
private String goodsName;
private Integer state; // 枚举对应 Integer 类型
}
// 测试
@Test
public void testEnumConvert() {
Goods goods = new Goods();
goods.setGoodsName(“手机”);
goods.setState(GoodsStateEnum.ENABLED);
GoodsVo vo = converter.convert(goods, GoodsVo.class);
assert vo.getState().equals(1); // 枚举 → Integer
Goods newGoods = converter.convert(vo, Goods.class);
assert newGoods.getState().equals(GoodsStateEnum.ENABLED); // Integer → 枚举
}
2. 跨模块枚举映射
当枚举类与使用它的类不在同一个模块时,可以在 @AutoMapper 注解中通过 useEnums 属性指定依赖的枚举。
@Data
@AutoMapper(target = GoodsVo.class, useEnums = {GoodsStateEnum.class})
public class Goods {
private String goodsName;
private GoodsStateEnum state;
}
五、自定义类型转换器
当内置的转换规则无法满足特定需求时,你可以轻松地自定义转换器。
示例:自定义字符串转 List 转换器
// 自定义转换器:String(逗号分隔)→ List<String>
@Component
public class StringToListString {
public List<String> stringToListString(String str) {
return StrUtil.split(str);
}
}
// 应用转换器
@Data
@AutoMapper(target = UserDto.class, uses = StringToListStringConverter.class)
public class User {
private String username;
// 源字段:String(逗号分隔),目标字段:List<String>
@AutoMapping(target = “hobbyList”)
private String hobbies; // 例如:“篮球,足球,游泳”
}
@Data
public class UserDto {
private String username;
private List<String> hobbyList; // 转换后:[“篮球”,“足球”,“游泳”]
}
提示:当自定义的类型转换器中有多个方法时,可以通过 @AutoMapping 的 qualifiedByName 属性来指定具体的转换方法。
💡 最佳实践
- 编译期报错优先排查:MapStruct Plus 在编译期生成代码,出现错误可以直接定位问题源头。常见原因包括字段名拼写错误、类型不匹配且未配置转换器。
- 版本建议:建议使用 1.4.0 及以上版本,以获得更多高级功能和稳定性提升。
- 反向转换控制:默认支持反向转换。如果确定不需要从目标类反向转换回源类,可以在
@AutoMapper 中设置 reverseConvertGenerate = false,以减少生成的代码量。
🎉 总结
MapStruct Plus 将 MapStruct 的“极简配置”理念发挥到了极致。无论是基础的对象映射,还是复杂的嵌套转换、枚举映射,都能通过简单的注解“一句搞定”。相比原生 MapStruct,它彻底省去了手动定义 Mapper 接口和编写转换方法的冗余工作,让开发者能够更专注于核心业务逻辑的构建。
如果你在SpringBoot项目中被大量的对象转换代码所困扰,不妨试试 MapStruct Plus,它或许能成为你提升开发效率的又一得力助手。想了解更多高级用法和详细配置,可以访问其官网 https://www.mapstruct.plus/ 进行探索。在 云栈社区 也有许多关于提升开发效率的实战讨论,欢迎交流分享。