前言

最近项目上要求升级一个工具包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. SSD目标检测网络解读(含网络结构和内容解读)

    SSD实现思路 SSD具有如下主要特点: 从YOLO中继承了将detection转化为regression的思路,一次完成目标定位与分类 基于Faster RCNN中的Anchor,提出了相似的Pri ...

  2. 纯前端实现后端给数据进行文件导出——angular里面的使用

    interface dataList { cmd_cnt: number; risk_name: string; user_cnt: number; risk_type:string; } listO ...

  3. NOIP2011普及组

    T2  统计单词数 也是一道经典题 字符串匹配 #include<iostream> #include<cstdio> #include<map> #include ...

  4. Qt滚动条样式

    Qt手动设置滚动条的qss样式 QScrollBar:vertical { width: 14px; margin: 16px 0 16px 0; background: #eaeaea; } QSc ...

  5. Matlab %伍

    第五章:初级绘图进阶 Special Plots  loglog semilogx semilogy plotyy hist bar pie polar Logarithm Plots  x = lo ...

  6. 用requests库的get( )函数访问搜狗网站20次

    代码: import requests from bs4 import BeautifulSoup def getHTMLText(url): try: r=requests.get(url,time ...

  7. C#中Socket连接请求的超时设置

    C#中Socket连接请求的超时设置 <转载> C#中, 对于Socket的请求,无论是同步还是异步,都没有提供超时机制,SendTimeout,ReceiveTimeout均无用.. 对 ...

  8. habse与Hadoop兼容性问题

    今天大数据实验课被血坑,在第一步hbase的安装时就卡住了,之后处理了一整节实验课,也未能解决,回到宿舍后才解决(这里不得不说"度娘"不行了,出现的问题完全找不到,最好还是在chr ...

  9. pip安装报错 cannot uninstall a distutils installed project

    sudo pip install --ignore-installed xxx 在安装jupyter notebook的时候,遇到了这个问题,于是上网搜索,搜到了靠谱答案github解决方案 sudo ...

  10. unidbgrid默认列排序

    UniDBGrid -> ClientEvents -> ExtEvents ->... function reconfigure(sender, store, columns, o ...