当前位置: 首页 > 工具软件 > ModelMapper > 使用案例 >

关于在项目中使用 ModelMapper 的利弊

郎和通
2023-12-01

一、背景

在项目开发时,前期推荐我们使用 ModelMapper 对 DO-DTO-VO 进行转换,没 PO,我们也从中尝到了甜头,因为总体代码量少,映射有问题就会提示;但是到了中后期,发现 ModelMapper 转换产生的 bug 不易排查,甚至产生了未知原因的 bug。为啥说是未知呢,首先我们的服务是微服务,每个服务都是多实例的保证高可用,但是在其中一个实例上 ModelMapper 转换对象时就报错,其他实例正常。

二、如何使用 ModelMapper

关于如何使用 ModelMapper 可以参考我写的一篇博客:ModelMapper 的高级使用 ,也可以百度,可以百度出一堆出来。

三、ModelMapper 之利弊

ModelMapper 之所以能够在 Domain Driven Design 占据一席之地,说明是有其他工具没有的优点。但在说优点前先说说 ModelMapper 的缺点:

  • ModelMapper 使用的是反射原理,在性能上肯定没有 get/set 快(MapStruct、BeanUtils等),MapStruct 本质也是用的 get/set;
  • 第二个缺点是 bug 排查难,主要由于某些字段在转换前后引起值的变化,对应新手排查问题是一个困难的事和难以发现的事;
  • 学习成本相对较高。

ModelMapper 的优点:

  • 对于 DO-DTO-VO 转换中属性一致的对象转换基本一行代码搞定;
  • 能够快速修正遗漏字段,保证数据一致性,运用场景有:数据清洗、数据同步;
  • 可在转换时增加自定义逻辑;

四、感受

我先直接上代码:

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了,到时技术经理问你为什么,别到时你只会说“我本地测试没有问题,在测试环境测试也没有问题的”。

 类似资料: