👆 这是第 338 篇不掺水的原创,想要了解更多,请戳下方卡片关注我们吧~
我们复制对象最常用的方法是使用 BeanCopy 工具类,这是一种常见的 DTO 对象复制方法。然而,BeanCopy 在处理复杂继承和嵌套类型时常常出现问题,导致开发人员需要花费大量时间来手动处理 DTO 对象之间的映射关系。
举个例子:
假设您有一个源对象 User 和一个目标对象 UserDTO ,它们的属性如下所示:
public class User {
private Long id;
private String givenName;
private String email;
private List<Role> roles;
// constructor, getters and setters
}
public class UserDto {
private Long id;
private String firstName;
private String email;
private List<Role> roles;
// constructor, getters and setters
}
如果要将一个 User 对象拷贝到另一个 UserDTO 对象中,可以使用 Bean Copy 的方式,如下:
User sourceUser = new User();
sourceUser.setId(1L);
sourceUser.setGivenName("John");
sourceUser.setEmail("johndoe@example.com");
sourceUser.setRoles(roles);
UserDTO targetUserDTO = new UserDTO();
BeanUtils.copyProperties(sourceUser, targetUserDTO);
System.out.println(targetUserDTO.getFirstName()); // Output: null
但是,使用 Bean Copy 的方式会造成以下问题:
MapStruct 是一个代码生成器,它可以自动生成映射器代码,可以解决 BeanCopy 存在的问题。接下来,我们来看看如何使用 MapStruct 来解决这个问题。需要先定义一个 Mapper 接口,代码如下:
@Mapper
public interface UserConverter {
UserConverter INSTANCE = Mappers.getMapper(UserConverter.class);
@Mapping(target = "firstName", source = "givenName")
UserDTO toDto(User user);
List<UserDTO> toDtoList(List<User> userList);
}
在上面的例子中,使用注解 @Mapper 定义了一个接口 UserConveter,该接口编译时会由 MapStruct 动态生成实现类,使用该实现类进行 Java Bean 对象的拷贝。并且使用 @Mapping 注解指定了 User 对象的 givenName 和 UserDTO 对象 firstName 的映射关系。
使用 MapStruct 进行 User 对象拷贝:
UserDTO dto = UserConverter.INSTANCE.toDto(user);
使用 MapStruct 的主要优点如下:
下面列一下 MapStruct 的常见的一些用法
@Mapper(componentModel = "spring")
public interface UserConverter {
// ...
}
使用
@Autowired
private UserConverter userConverter;
// 转化
UserDTO userDTO = userConverter.toDto(user);
public interface EmployeeMapper {
@Mapping(target = "name", source = "person.name")
@Mapping(target = "age", source = "person.age")
@Mapping(target = "employeeId", source = "employeeId")
EmployeeDTO employeeToEmployeeDTO(Employee employee);
@InheritInverseConfiguration
Employee employeeDTOToEmployee(EmployeeDTO employeeDTO);
}
public interface EmployeeMapper {
@Mapping(target = "age", expression = "java(LocalDate.now().getYear() - employee.getBirthDate().getYear())")
EmployeeDTO employeeToEmployeeDTO(Employee employee);
}
将 EpPlanApply 对象中逗号分隔的字符串 auditUserIds 转化为 PlanApply 中的 Set
PlanApply poToDomain(EpPlanApply planApply);
@AfterMapping
default void afterPoToDomain(@MappingTarget PlanApply planApply, EpPlanApply epPlanApply) {
String auditUserIdsStr = epPlanApply.getAuditUserIds();
if (StringUtils.isNotBlank(auditUserIdsStr)) {
Set<Long> auditUserIds = new HashSet<>();
for (String split : auditUserIdsStr.split(",")) {
auditUserIds.add(Long.valueOf(split));
}
planApply.setAuditUserIds(auditUserIds);
}
}
Bean Copy 和 MapStruct 都是 Java 中用于对象之间复制属性的工具,它们可以大大简化代码的编写和维护。
MapStruct 的性能更高,因为它在编译时生成代码,而 Bean Copy 需要使用反射机制获取对象的属性信息。但是MapStruct 的学习成本相对较高,因为需要了解注解的使用方法以及如何配置和生成代码。
BeanCopy 适用于简单的属性复制场景,而 MapStruct 则适用于复杂的属性复制场景,尤其是在需要频繁进行属性复制的情况下,使用 MapStruct 可以提高代码的执行效率。选择使用哪种工具取决于具体的业务需求和开发团队的技术水平。
如果你觉得这篇内容对你挺有启发,我想邀请你帮我两件小事
1.点个「在看」,让更多人也能看到这篇内容(点了「在看」,bug -1 😊)
招贤纳士
政采云技术团队(Zero),Base 杭州,一个富有激情和技术匠心精神的成长型团队。规模 500 人左右,在日常业务开发之外,还分别在云原生、区块链、人工智能、低代码平台、中间件、大数据、物料体系、工程平台、性能体验、可视化等领域进行技术探索和实践,推动并落地了一系列的内部技术产品,持续探索技术的新边界。此外,团队还纷纷投身社区建设,目前已经是 google flutter、scikit-learn、Apache Dubbo、Apache Rocketmq、Apache Pulsar、CNCF Dapr、Apache DolphinScheduler、alibaba Seata 等众多优秀开源社区的贡献者。
如果你想改变一直被事折腾,希望开始折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊……如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的技术团队的成长过程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 zcy-tc@cai-inc.com