MapStruct 1.5.5类型转换(复杂对象映射)
下文笔者讲述MapStruce1.5.5的简介说明,如下所示
MapStruce1.5.5简介
MapStruct 1.5.5 是一款编译期的 Java 类型映射工具,
核心用于解决 POJO / 实体 / DTO 之间的对象转换问题,
相比反射式工具(如 BeanUtils):
核心优势:
编译期生成类型安全的映射代码,无运行时反射开销,
性能高;
编译时即可发现字段映射错误,避免运行时问题。
核心能力:
支持基础字段映射、嵌套对象递归映射、
自定义转换(日期 / 枚举 / 多字段组合)、
集合(list/Set)映射,
可集成 Spring 容器,
兼容 Lombok。
使用方式:
通过 @Mapper 定义映射接口,
@Mapping 注解指定字段映射规则,
框架自动生成实现类,
无需手动编写转换代码。
=================================================
MapStruct 1.5.5 是编译期映射工具,
性能高、类型安全,
替代手动编写转换代码。
核心通过注解定义映射规则,
支持基础/嵌套/自定义/集合
等多场景对象转换。
兼容 Spring 和 Lombok,
是Java 开发中对象转换的主流选择
MapStruct 1.5.5使用方法
引入maven依赖
<!-- MapStruct 核心依赖 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>
<!-- 注解处理器(编译期生成实现类) -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
<scope>provided</scope>
</dependency>
<!-- Lombok 可选(如果用了Lombok,需注意版本兼容) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
场景1:嵌套对象映射(基础)
当有以下嵌套结构的实体和 DTO:
// 子实体
@Data
public class Address {
private Long id;
private String province;
private String city;
}
// 主实体
@Data
public class User {
private Long userId;
private String userName;
private Integer age;
private Address userAddress; // 嵌套对象
}
// 子DTO
@Data
public class AddressDTO {
private Long addressId; // 字段名与实体不一致
private String province;
private String city;
}
// 主DTO
@Data
public class UserDTO {
private Long id; // 字段名与实体不一致
private String name; // 字段名与实体不一致
private Integer age;
private AddressDTO address; // 嵌套DTO
}
映射器编写:
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;
// componentModel = "spring" 表示生成的实现类交给Spring管理,也可以用默认的 "default"
@Mapper(componentModel = "spring")
public interface UserMapper {
// 单例实例(非Spring环境使用)
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
// 主对象映射:指定字段映射关系,嵌套对象会自动递归映射(字段名匹配时)
@Mapping(source = "userId", target = "id")
@Mapping(source = "userName", target = "name")
@Mapping(source = "userAddress", target = "address") // 显式指定嵌套对象映射(可选,字段名匹配时可省略)
UserDTO userToUserDTO(User user);
// 嵌套对象映射:处理字段名不一致的情况
@Mapping(source = "id", target = "addressId")
AddressDTO addressToAddressDTO(Address address);
// 反向映射(可选)
@Mapping(source = "id", target = "userId")
@Mapping(source = "name", target = "userName")
@Mapping(source = "address", target = "userAddress")
User userDTOToUser(UserDTO userDTO);
}
场景2:自定义复杂转换(如枚举、日期、多字段组合)
假设需要将 `User` 中的 `age` 和 `userName` 组合成 `UserDTO` 的 `desc` 字段,且处理日期类型转换:
//扩展User和UserDTO
@Data
public class User {
// 原有字段...
private Date createTime; // 日期类型
private Integer age;
private String userName;
}
@Data
public class UserDTO {
// 原有字段...
private String createTimeStr; // 格式化后的日期字符串
private String desc; // 组合字段:姓名+年龄
}
// 映射器增强
@Mapper(componentModel = "spring", imports = {SimpleDateFormat.class})
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
// 自定义字段转换:使用expression或qualifiedByName
@Mapping(source = "userId", target = "id")
@Mapping(source = "userName", target = "name")
@Mapping(source = "userAddress", target = "address")
@Mapping(source = "createTime", target = "createTimeStr", dateFormat = "yyyy-MM-dd HH:mm:ss") // 日期格式化
@Mapping(target = "desc", qualifiedByName = "buildDesc") // 自定义方法转换
UserDTO userToUserDTO(User user);
// 自定义转换方法(命名规则:@Named 注解匹配 qualifiedByName)
@Named("buildDesc")
default String buildDesc(User user) {
return user.getUserName() + ",年龄:" + (user.getAge() == null ? "未知" : user.getAge());
}
// 也可以用expression(直接写Java代码)
// @Mapping(target = "desc", expression = "java(user.getUserName() + \",年龄:\" + (user.getAge() == null ? \"未知\" : user.getAge()))")
// 嵌套对象映射(不变)
@Mapping(source = "id", target = "addressId")
AddressDTO addressToAddressDTO(Address address);
}
场景3:集合映射(复杂对象列表)
MapStruct支持集合(List/Set/Map)自动映射
只需定义单个对象的映射方法,
集合映射会自动生成:
@Mapper(componentModel = "spring")
public interface UserMapper {
// 单个对象映射(基础)
@Mapping(source = "userId", target = "id")
@Mapping(source = "userName", target = "name")
UserDTO userToUserDTO(User user);
// 集合映射:无需手动实现,MapStruct自动生成
List<UserDTO> userListToUserDTOList(List<User> userList);
// Set/Map同理
Set<UserDTO> userSetToUserDTOSet(Set<User> userSet);
Map<Long, UserDTO> userMapToUserDTOMap(Map<Long, User> userMap);
}
例
@SpringBootTest
public class MapStructTest {
@Autowired
private UserMapper userMapper;
@Test
public void testComplexMapping() {
// 构造测试数据
Address address = new Address();
address.setId(1L);
address.setProvince("北京");
address.setCity("朝阳区");
User user = new User();
user.setUserId(1001L);
user.setUserName("张三");
user.setAge(25);
user.setUserAddress(address);
user.setCreateTime(new Date());
// 转换
UserDTO userDTO = userMapper.userToUserDTO(user);
System.out.println(userDTO);
// 输出示例:UserDTO(id=1001, name=张三, age=25, address=AddressDTO(addressId=1, province=北京, city=朝阳区), createTimeStr=2026-01-14 10:00:00, desc=张三,年龄:25)
}
}
MapStruct关键注意事项
1. MapStruct是编译期生成实现类,
而非运行时反射,
因此性能高、类型安全,编译时就能发现字段映射错误。
2. 嵌套对象映射时,
若字段名不一致,
需显式定义嵌套对象的映射方法(如 `addressToAddressDTO`)。
3. 自定义转换方法可以是 `default` 方法(MapStruct 1.4+ 支持)
也可以单独写一个转换工具类,通过 `uses` 属性引入:
@Mapper(componentModel = "spring", uses = {CustomConverter.class})
public interface UserMapper { ... }
4. 版本兼容:
MapStruct 1.5.5 对 Lombok 兼容性较好,
但需确保 Lombok 版本 ≥ 1.18.16,避免编译期生成代码异常。
==============================================================
1. 复杂对象映射核心:通过 `@Mapping` 指定字段映射关系,
嵌套对象可自动递归映射,字段名不一致时
需显式定义嵌套对象的映射方法。
2. 自定义转换:使用`dateFormat` 处理日期、
`qualifiedByName`/`expression` 处理多字段组合/特殊逻辑,
`uses` 引入外部转换工具类。
3. 集合映射:只需定义单个对象的映射方法,
MapStruct 自动生成集合映射的实现,
无需手动编写循环。
MapStruct 1.5.5 版本的复杂对象映射核心是“约定优于配置”,
大部分场景下只需少量注解即可完成映射,
仅在特殊转换时需自定义逻辑,
既高效又保证代码的可维护性
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。


