前言

最近项目上要求升级一个工具包hutool的版本,以解决安全漏洞问题,这不升级还好,一升级反而捅出了更大的篓子,究竟是怎么回事呢?

事件回顾

我们项目原先使用的hutool版本是5.7.2,在代码中,我们的数据传输对象DTO和数据实体对象中大量使用了工具包中的BeanUtil.copyProperties(), 大体代码如下:

  1. 数据传输对象
@Data
@ToString
public class DiagramDTO { // 前端生产的字符串id
private String id; private String code; private String name;
}
  1. 数据实体对象
@Data
@ToString
public class Diagram { private Integer id; private String code; private String name;
}
  1. 业务逻辑
public class BeanCopyTest {

    public static void main(String[] args) {
// 前端传输的对象
DiagramDTO diagramDTO = new DiagramDTO();
// 如果前端传入的id事包含e的,升级后就会报错
diagramDTO.setId("3em3dgqsgmn0");
diagramDTO.setCode("d1");
diagramDTO.setName("图表"); Diagram diagram = new Diagram();
// 关键点,数据拷贝
BeanUtil.copyProperties(diagramDTO, diagram);
System.out.println("数据实体对象:" + diagram);
//设置id为空,自增
diagram.setId(null);
//保存到数据库中 TODO
//diagramMapper.save(diagram);
}
}

升级前,hutool是5.7.2版本下,执行结果如下图。

  • BeanUtil.copyProperties虽然字段类型不一样,但是做了兼容处理,所以业务没有影响业务逻辑。

升级后,hutool是5.8.8版本,执行结果如下图所示:

  • 执行报错,因为升级后的版本修改了实现,增加了下面的逻辑,如果包含E, 就会抛错,从而影响了业务逻辑,同时这个id是否包含e又是随机因素,到了生产才发现,就悲剧了。

分析探讨

我发现大部分人写代码都喜欢偷懒,在上面的场景中,虽然BeanUtil.copyProperties用的一时爽,但有时候带来的后果是很严重的,所以很不推荐这种方式。为什么这么说呢?

比如团队中的某些人偷偷改了数据传输对象DTO,比如修改了类型、删去了某个字段。用BeanUtil.copyProperties的方式压根无法在编译阶段发现,更别提修改的影响范围了,这就只能把风险暴露到生产上去了。那有什么更好的方法呢?

推荐方案

  1. 原始的getset方式

我是比较推崇这种做法的,比如现在DiagramDTO删去某个字段,编译器就会报错,就会引起你的注意了,让问题提前暴露,无处遁形。

你可能觉得站着说话不腰疼,字段少好,如果字段很多还不得写死啊,我这里推荐一个IDEA的插件,可以帮你智能生成这样的代码。

话不多说,自己玩儿去~~

  1. 使用开源库ModelMapper

ModelMapper是一个开源库,可以很方便、简单地将对象从一种类型映射到另一种类型,底层是通过反射来自动确定对象之间的映射,还可以自定义映射规则。

 private static void testModelMapper() {
ModelMapper modelMapper = new ModelMapper();
DiagramDTO diagramDTO = new DiagramDTO();
diagramDTO.setId("3em3dgqsgmn0");
diagramDTO.setCode("d1");
diagramDTO.setName("图表");
Diagram diagram = modelMapper.map(diagramDTO, Diagram.class);
}
  1. 使用开源库MapStruct

MapStruct也是Java中另外一个用于映射对象很流行的开源工具。它是在编译阶段生成对应的映射代码,相对于ModelMapper底层放射的方案,性能更好。

@Mapper
public interface DiagramMapper {
DiagramMapper INSTANCE = Mappers.getMapper(DiagramMapper.class); DiagramDTO toDTO(Diagram diagram); Diagram toEntity(DiagramDTO diagram);
} private static void testMapStruct() {
DiagramDTO diagramDTO = new DiagramDTO();
diagramDTO.setId("3em3dgqsgmn0");
diagramDTO.setCode("d1");
diagramDTO.setName("图表");
Diagram diagram = DiagramMapper.INSTANCE.toEntity(diagramDTO);
}
  • DiagramMapper接口使用了@Mapper注解,用来表明使用MapStruct处理
  • MapStruct中更多高级特性大家自己探索一下。

总结

小结一下,对象在不同层之间进行转换映射,很不建议使用BeanUtil.copyProperties这种方式,更加推荐使用原生的set, get方式,不容易出错。当然这不是将BeanUtil.copyProperties一棒子打死,毫无用武之地,在特定场景,比如方法内部对象的转换等影响小的范围还是很方便的,如果你有其他的想法,也可以留下你的想法,一起探讨交流。

欢迎关注个人公众号【JAVA旭阳】交流学习!!

麻了,不要再动不动就BeanUtil.copyProperties!!!的更多相关文章

  1. 12种 vo2dto 方法,就 BeanUtils.copyProperties 压测最拉胯!【快双11了,别用错喽】

    作者:小傅哥 博客:https://bugstack.cn 原文:https://mp.weixin.qq.com/s/Xq7oQg7dYESMYxHVnxX8Dw 沉淀.分享.成长,让自己和他人都能 ...

  2. 推荐几个牛逼的 IDEA 插件,还带动图!

    阅读本文大概需要 2.3 分钟. 作者:纪莫, cnblogs.com/jimoer 这里只是推荐一下好用的插件,具体的使用方法不一一详细介绍. JRebel for IntelliJ 一款热部署插件 ...

  3. IDEA 破解_补丁永久_2018.3

           主要是Eclipse我已经玩坏了三次了,切换jdk8到jdk10,再切换到jdk8,大量文件乱码,怎么改都没用,有的时候Eclipse久了不用,项目放在里面发霉了,坏掉了,MMP,换到I ...

  4. 推荐几个IDEA插件,Java开发者撸码利器(转载)

    推荐几个IDEA插件,Java开发者撸码利器.   这里只是推荐一下好用的插件,具体的使用方法不一一详细介绍. JRebel for IntelliJ 一款热部署插件,只要不是修改了项目的配置文件,用 ...

  5. IDEA Java开发常用插件

    这里只是推荐一下好用的插件,具体的使用方法就不一一详细介绍了. JRebel for IntelliJ 一款热部署插件,只要不是修改了项目的配置文件,用它都可以实现热部署.收费的,破解比较麻烦.不过功 ...

  6. IDEA常用插件记录

    让我们来记录一下常用的IDEA插件:(从其他博客中取了许多图片,出处见图片水印) 1.JRebel for IntelliJ 热部署神器2.Free MyBatis plugin 实现dao层方法与x ...

  7. 利用双重检查锁定和CAS算法:解决并发下数据库的一致性问题

    背景 ​ 最近有一个场景遇到了数据库的并发问题.现在先由我来抽象一下,去掉不必要的繁杂业务. ​ 数据库表book存储着每本书的阅读量,一开始数据库是空的,不存在任何的数据.当用户访问接口的时候,判断 ...

  8. IntelliJ IDEA 插件推荐

    1.GenerateAllSetter 自动生成类set方法 2.GsonFormat 根据JSON创建实体 3.Lombok plugin 简化代码 4. .ignore 忽略git提交文件 5.A ...

  9. 用 Java 实现人脸识别功能(附源码)

    整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 更多优选 一口气说出 9种 分布式ID生成方式,面试官有点懵了 ...

  10. 推荐 10个 NB的 IDEA 插件,开发效率至少提升一倍

    友情提示:插件虽好,可不要贪装哦,装多了会 卡 .卡 .卡 ~ 正经干活用的 分享一点自己工作中得心应手的IDEA插件,可不是在插件商店随随便便搜的,都经过实战检验,用过的都说好.可能有一些大家用过的 ...

随机推荐

  1. 第12组 Beta冲刺 (3/5)

    1.1基本情况 ·队名:美少女战士 ·组长博客:https://www.cnblogs.com/yaningscnblogs/p/14016611.html ·作业博客:https://edu.cnb ...

  2. vue iview前端直接上传OSS

    1. 首先安装oss npm install ali-oss --save 2. // template部分 <Upload ref="upload" type=" ...

  3. 微信小程序开发-购物商城

    1.搭建首页tabbar结构 自定义组件实现搜索框 2.分类页面 加载分类页面数据 点击左侧菜单,右侧数据动态渲染 使用scroll-view组件 3.商品列表页面 点击商品 展示列表页面 加载商品数 ...

  4. Linux配置NTP时间同步

    1.检查系统是否安装了NTP包(linux系统一般自带NTP4.2)没有安装我们直接使用yum命令在线安装:yum install ntp2.NTP服务端配置文件编辑vim /etc/ntp.conf ...

  5. commons-lang3

    字符串的处理类(StringUtils) //判断是否为空(注:isBlank与isEmpty 区别) StringUtils.isBlank(null);StringUtils.isBlank(&q ...

  6. python 每天一个知识点 对文件的操作

    对文件的操作: 操作 功能 文件对象 = open(file,mode,encoding) 打开文件获取文件对象 文件对象.read(num) 读取指定长度字节,不指定num读取文件全部 文件对象.r ...

  7. Safari 浏览器下打印PDF, 打印预览显示为空白

    重现代码 const iframe = document.createElement('iframe'); iframe.onload = () => { iframe.focus(); ifr ...

  8. 推荐2020年最好用的JavaScript代码压缩工具

    今天就为大家分享一篇关于推荐2020年最好用的JavaScript代码压缩工具,觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随来看看吧 JavaScript 代码压缩是指去除 ...

  9. lua脚本概述

    1.lua脚本非常简单,轻量级,易于c/c++调用 2. 协程 是什么,与线程有啥区别 ??

  10. 配置环境变量在history中显示时间

    1.1.临时显示(断电丢失) 配置变量HISTTIMEFORMAT,加入"%F %T ". 示例: [root@CentOS8 ~]# HISTTIMEFORMAT='%F %T ...