• 我们为什么推荐使用 Bean 映射工具对属性赋值
  • 发布于 1周前
  • 22 热度
    0 评论
  • 雾月
  • 0 粉丝 4 篇博客
  •   
对于三层架构的系统,考虑到层之间的解耦隔离以及每一层对数据的不同需求,通常每一层都会有自己的 POJO 作为数据实体。比如,数据访问层的实体一般叫作 DataObject 或 DO,业务逻辑层的实体一般叫作 Domain,表现层的实体一般叫作Data Transfer Object或 DTO。

这里我们需要注意的是,如果手动写这些实体之间的赋值代码,同样容易出错。

对于复杂的业务系统,实体有几十甚至几百个属性也很正常。就比如ComplicatedOrderDTO这个数据传输对象,描述的是一个订单中的几十个属性。如果我们要把这个 DTO 转换为一个类似的 DO,复制其中大部分的字段,然后把数据入库,势必需要进行很多属性映射赋值操作。就像这样,密密麻麻的代码是不是已经让你头晕了?
ComplicatedOrderDTO orderDTO = new ComplicatedOrderDTO();  
ComplicatedOrderDO orderDO = new ComplicatedOrderDO();  
orderDO.setAcceptDate(orderDTO.getAcceptDate());  
orderDO.setAddress(orderDTO.getAddress());  
orderDO.setAddressId(orderDTO.getAddressId());  
orderDO.setCancelable(orderDTO.isCancelable());  
orderDO.setCommentable(orderDTO.isComplainable()); //属性错误  
orderDO.setComplainable(orderDTO.isCommentable()); //属性错误  
orderDO.setCancelable(orderDTO.isCancelable());  
orderDO.setCouponAmount(orderDTO.getCouponAmount());  
orderDO.setCouponId(orderDTO.getCouponId());  
orderDO.setCreateDate(orderDTO.getCreateDate());  
orderDO.setDirectCancelable(orderDTO.isDirectCancelable());  
orderDO.setDeliverDate(orderDTO.getDeliverDate());  
orderDO.setDeliverGroup(orderDTO.getDeliverGroup());  
orderDO.setDeliverGroupOrderStatus(orderDTO.getDeliverGroupOrderStatus());  
orderDO.setDeliverMethod(orderDTO.getDeliverMethod());  
orderDO.setDeliverPrice(orderDTO.getDeliverPrice());  
orderDO.setDeliveryManId(orderDTO.getDeliveryManId());  
orderDO.setDeliveryManMobile(orderDO.getDeliveryManMobile()); //对象错误  
如果不是代码中有注释,你能看出其中的诸多问题吗?如果原始的 DTO 有 100 个字段,我们需要复制 90 个字段到 DO 中,保留 10 个不赋值,最后应该如何校验正确性呢?数数吗?即使数出有 90 行代码,也不一定正确,因为属性可能重复赋值。

有的时候字段命名相近,比如complainable和commentable,容易搞反(第 7 和第 8 行),或者对两个目标字段重复赋值相同的来源字段(比如第 28 行),明明要把 DTO 的值赋值到 DO 中,却在 set 的时候从 DO 自己取值(比如第 20 行),导致赋值无效。

这段代码并不是我随手写出来的,而是一个真实案例。有位同学就像代码中那样把经纬度赋值反了,因为落库的字段实在太多了。这个 Bug 很久都没发现,直到真正用到数据库中的经纬度做计算时,才发现一直以来都存错了。

修改方法很简单,可以使用类似 BeanUtils 这种 Mapping 工具来做 Bean 的转换,copyProperties方法还允许我们提供需要忽略的属性:
ComplicatedOrderDTO orderDTO = new ComplicatedOrderDTO();  
ComplicatedOrderDO orderDO = new ComplicatedOrderDO();  
BeanUtils.copyProperties(orderDTO, orderDO, "id");  
return orderDO; 

 总结:

业务代码中常见的 DO、DTO、VO 转换时大量字段的手动赋值,遇到有上百个属性的复杂类型,非常非常容易出错。我的建议是,不要手动进行赋值,考虑使用 Bean 映射工具进行。此外,还可以考虑采用单元测试对所有字段进行赋值正确性校验。

用户评论