事件回顧
分析探討
推薦方案
總結
前言
最近項目上要求升級一個工具包hutool的版本,以解決安全漏洞問題,這不升級還好,一升級反而捅出了更大的簍子,究竟是怎么回事呢?
基于 Spring Boot + MyBatis Plus + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能
項目地址:https://github.com/YunaiV/ruoyi-vue-pro
視頻教程:https://doc.iocoder.cn/video/
事件回顧
我們項目原先使用的hutool版本是5.7.2,在代碼中,我們的數據傳輸對象DTO和數據實體對象中大量使用了工具包中的BeanUtil.copyProperties(), 大體代碼如下:
數據傳輸對象
@Data @ToString publicclassDiagramDTO{ //前端生產的字符串id privateStringid; privateStringcode; privateStringname; }
數據實體對象
@Data @ToString publicclassDiagram{ privateIntegerid; privateStringcode; privateStringname; }
業務邏輯
publicclassBeanCopyTest{ publicstaticvoidmain(String[]args){ //前端傳輸的對象 DiagramDTOdiagramDTO=newDiagramDTO(); //如果前端傳入的id事包含e的,升級后就會報錯 diagramDTO.setId("3em3dgqsgmn0"); diagramDTO.setCode("d1"); diagramDTO.setName("圖表"); Diagramdiagram=newDiagram(); //關鍵點,數據拷貝 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又是隨機因素,到了生產才發現,就悲劇了。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能
項目地址:https://github.com/YunaiV/yudao-cloud
視頻教程:https://doc.iocoder.cn/video/
分析探討
我發現大部分人寫代碼都喜歡偷懶,在上面的場景中,雖然BeanUtil.copyProperties用的一時爽,但有時候帶來的后果是很嚴重的,所以很不推薦這種方式。為什么這么說呢?
比如團隊中的某些人偷偷改了數據傳輸對象DTO,比如修改了類型、刪去了某個字段。用BeanUtil.copyProperties的方式壓根無法在編譯階段發現,更別提修改的影響范圍了,這就只能把風險暴露到生產上去了。那有什么更好的方法呢?
推薦方案
原始的get、set方式
我是比較推崇這種做法的,比如現在DiagramDTO刪去某個字段,編譯器就會報錯,就會引起你的注意了,讓問題提前暴露,無處遁形。
你可能覺得站著說話不腰疼,字段少好,如果字段很多還不得寫死啊,我這里推薦一個IDEA的插件,可以幫你智能生成這樣的代碼。
話不多說,自己玩兒去~~
使用開源庫ModelMapper
ModelMapper是一個開源庫,可以很方便、簡單地將對象從一種類型映射到另一種類型,底層是通過反射來自動確定對象之間的映射,還可以自定義映射規則。
privatestaticvoidtestModelMapper(){ ModelMappermodelMapper=newModelMapper(); DiagramDTOdiagramDTO=newDiagramDTO(); diagramDTO.setId("3em3dgqsgmn0"); diagramDTO.setCode("d1"); diagramDTO.setName("圖表"); Diagramdiagram=modelMapper.map(diagramDTO,Diagram.class); }
使用開源庫MapStruct
MapStruct也是Java中另外一個用于映射對象很流行的開源工具。它是在編譯階段生成對應的映射代碼,相對于ModelMapper底層放射的方案,性能更好。
@Mapper publicinterfaceDiagramMapper{ DiagramMapperINSTANCE=Mappers.getMapper(DiagramMapper.class); DiagramDTOtoDTO(Diagramdiagram); DiagramtoEntity(DiagramDTOdiagram); } privatestaticvoidtestMapStruct(){ DiagramDTOdiagramDTO=newDiagramDTO(); diagramDTO.setId("3em3dgqsgmn0"); diagramDTO.setCode("d1"); diagramDTO.setName("圖表"); Diagramdiagram=DiagramMapper.INSTANCE.toEntity(diagramDTO); }
DiagramMapper接口使用了@Mapper注解,用來表明使用MapStruct處理
MapStruct中更多高級特性大家自己探索一下。
總結
小結一下,對象在不同層之間進行轉換映射,很不建議使用BeanUtil.copyProperties這種方式,更加推薦使用原生的set, get方式,不容易出錯。當然這不是將BeanUtil.copyProperties一棒子打死,毫無用武之地,在特定場景,比如方法內部對象的轉換等影響小的范圍還是很方便的。
-
代碼
+關注
關注
30文章
4828瀏覽量
69063 -
編譯
+關注
關注
0文章
661瀏覽量
33048
原文標題:麻了!不要再動不動就用BeanUtil.copyProperties了!!
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
Python高級特性:迭代器切片的應用
對象轉換工具:MapStruct 庫
LabVIEW中調用DLL的高級技巧后續資源包
Trace32的高級功能特性
![Trace32的<b class='flag-5'>高級</b>功能<b class='flag-5'>特性</b>](https://file.elecfans.com/web2/M00/49/33/pYYBAGKhtD6AccFcAAAMJ3vMfCI624.jpg)
在設計中如何使用高級PCB模塊
STMCube.AI的高級特性
![STMCube.AI的<b class='flag-5'>高級</b><b class='flag-5'>特性</b>](https://file.elecfans.com/web2/M00/1A/36/pYYBAGF6CJKAS5x-AAASsxfokjM963.png)
STM32Cube.AI庫的高級特性
![STM32Cube.AI庫的<b class='flag-5'>高級</b><b class='flag-5'>特性</b>](https://file.elecfans.com/web2/M00/1D/C7/pYYBAGGTc3KAf4QeAAASsxfokjM750.png)
SOK將HugeCTR中的高級特性進行包裝使用
![SOK將HugeCTR<b class='flag-5'>中</b>的<b class='flag-5'>高級</b><b class='flag-5'>特性</b>進行包裝使用](https://file.elecfans.com/web2/M00/3B/C9/pYYBAGJOmyGAEKlZAACdxZaXMq8920.png)
英特爾高級鏈路分析器全新混合行為模式,兼“雙優”特性
別再用BeanUtils了,這款PO VO DTO轉換神器不香么?
![別再用BeanUtils了,這款PO VO DTO轉換神器不香么?](https://file1.elecfans.com/web2/M00/8C/5B/wKgaomSrcWyAC9xRAAAhQr_6DcQ304.png)
評論