在项目开发时,前期推荐我们使用 ModelMapper 对 DO-DTO-VO 进行转换,没 PO,我们也从中尝到了甜头,因为总体代码量少,映射有问题就会提示;但是到了中后期,发现 ModelMapper 转换产生的 bug 不易排查,甚至产生了未知原因的 bug。为啥说是未知呢,首先我们的服务是微服务,每个服务都是多实例的保证高可用,但是在其中一个实例上 ModelMapper 转换对象时就报错,其他实例正常。
关于如何使用 ModelMapper 可以参考我写的一篇博客:ModelMapper 的高级使用 ,也可以百度,可以百度出一堆出来。
ModelMapper 之所以能够在 Domain Driven Design 占据一席之地,说明是有其他工具没有的优点。但在说优点前先说说 ModelMapper 的缺点:
ModelMapper 的优点:
我先直接上代码:
BeanUtils.copyProperties(userInfo, user);
对于上述代码,我想大家都能看懂,将 userInfo 复制到 user ,但是有没有想过,如果 userInfo 中字段名和 user 中字段名不一致会怎么样,如果一致但类型不一致又会怎么样,我在这说一下,会导致 user 中独有的字段值为 null,程序还不会报错。对于粗心的人来说,这绝对是个大 bug,但如果用 ModelMapper 就不会产生这种问题,为啥呢?因为 ModelMapper 会检查,会提示你,在你启动项目的时候直截了当的甩个报错信息给你,类似于下面的报错信息
1) Unmapped destination properties found in TypeMap[UserInfo-> setDel]:
com.dao.entity.UserInfo.setDel()
1 error
这时你就知道了吧,你这转换时映射有问题,你快去看一下。当然,除了上面能够将映射错误的信息提示你之外,还可以这样:
modelMapper.createTypeMap(UpdateUserInfoRequestVO.class, UpdateUserInfoDTO.class)
.addMappings(mapper -> mapper.using((Converter<List<String>, String>) context -> {
if (CollectionUtils.isEmpty(context.getSource())) {
return "";
}
return String.join(";", context.getSource());
}).map(UpdateUserInfoRequestVO::getCaseCharacter, UpdateUserInfoDTO::setCaseNature));
这样:
modelMapper.createTypeMap(UpdateUserInfoRequestVO.class, UpdateUserInfoDTO.class)
.addMappings(new PropertyMap<UpdateUserInfoRequestVO, UpdateUserInfoDTO>() {
@Override
protected void configure() {
this.using(ctx -> {
UpdateUserInfoRequestVOsource = (UpdateUserInfoRequestVO) ctx.getSource();
if (source == null) {
return null;
}
List<String> applyPersons = source.getApplyPersonIdList();
if (CollectionUtils.isEmpty(applyPersons)) {
return null;
}
return String.join(",", applyPersons);
}).map(source).setApplyPersonId(null);
}
});
通过在转换是增加逻辑,而减少在业务处理的 Service 中增加这样的逻辑。
综上,我建议对于老手来说可以考虑使用 ModelMapper ,而对于新手来说是不建议的,另外,在生产环境不建议使用 ModelMapper,因为万一发生一个未知错误,就gg了,到时技术经理问你为什么,别到时你只会说“我本地测试没有问题,在测试环境测试也没有问题的”。