事件回顧
分析探討
推薦方案
總結(jié)
前言
最近項目上要求升級一個工具包hutool的版本,以解決安全漏洞問題,這不升級還好,一升級反而捅出了更大的簍子,究竟是怎么回事呢?
基于 Spring Boot + MyBatis Plus + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
項目地址:https://github.com/YunaiV/ruoyi-vue-pro
視頻教程:https://doc.iocoder.cn/video/
事件回顧
我們項目原先使用的hutool版本是5.7.2,在代碼中,我們的數(shù)據(jù)傳輸對象DTO和數(shù)據(jù)實體對象中大量使用了工具包中的BeanUtil.copyProperties(), 大體代碼如下:
數(shù)據(jù)傳輸對象
@Data @ToString publicclassDiagramDTO{ //前端生產(chǎn)的字符串id privateStringid; privateStringcode; privateStringname; }
數(shù)據(jù)實體對象
@Data @ToString publicclassDiagram{ privateIntegerid; privateStringcode; privateStringname; }
業(yè)務(wù)邏輯
publicclassBeanCopyTest{ publicstaticvoidmain(String[]args){ //前端傳輸?shù)膶ο?DiagramDTOdiagramDTO=newDiagramDTO(); //如果前端傳入的id事包含e的,升級后就會報錯 diagramDTO.setId("3em3dgqsgmn0"); diagramDTO.setCode("d1"); diagramDTO.setName("圖表"); Diagramdiagram=newDiagram(); //關(guān)鍵點,數(shù)據(jù)拷貝 BeanUtil.copyProperties(diagramDTO,diagram); System.out.println("數(shù)據(jù)實體對象:"+diagram); //設(shè)置id為空,自增 diagram.setId(null); //保存到數(shù)據(jù)庫中TODO //diagramMapper.save(diagram); } }
升級前,hutool是5.7.2版本下,執(zhí)行結(jié)果如下圖。
BeanUtil.copyProperties雖然字段類型不一樣,但是做了兼容處理,所以業(yè)務(wù)沒有影響業(yè)務(wù)邏輯。
升級后,hutool是5.8.8版本,執(zhí)行結(jié)果如下圖所示:
執(zhí)行報錯,因為升級后的版本修改了實現(xiàn),增加了下面的邏輯,如果包含E, 就會拋錯,從而影響了業(yè)務(wù)邏輯,同時這個id是否包含e又是隨機因素,到了生產(chǎn)才發(fā)現(xiàn),就悲劇了。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
項目地址:https://github.com/YunaiV/yudao-cloud
視頻教程:https://doc.iocoder.cn/video/
分析探討
我發(fā)現(xiàn)大部分人寫代碼都喜歡偷懶,在上面的場景中,雖然BeanUtil.copyProperties用的一時爽,但有時候帶來的后果是很嚴(yán)重的,所以很不推薦這種方式。為什么這么說呢?
比如團隊中的某些人偷偷改了數(shù)據(jù)傳輸對象DTO,比如修改了類型、刪去了某個字段。用BeanUtil.copyProperties的方式壓根無法在編譯階段發(fā)現(xiàn),更別提修改的影響范圍了,這就只能把風(fēng)險暴露到生產(chǎn)上去了。那有什么更好的方法呢?
推薦方案
原始的get、set方式
我是比較推崇這種做法的,比如現(xiàn)在DiagramDTO刪去某個字段,編譯器就會報錯,就會引起你的注意了,讓問題提前暴露,無處遁形。
你可能覺得站著說話不腰疼,字段少好,如果字段很多還不得寫死啊,我這里推薦一個IDEA的插件,可以幫你智能生成這樣的代碼。
話不多說,自己玩兒去~~
使用開源庫ModelMapper
ModelMapper是一個開源庫,可以很方便、簡單地將對象從一種類型映射到另一種類型,底層是通過反射來自動確定對象之間的映射,還可以自定義映射規(guī)則。
privatestaticvoidtestModelMapper(){ ModelMappermodelMapper=newModelMapper(); DiagramDTOdiagramDTO=newDiagramDTO(); diagramDTO.setId("3em3dgqsgmn0"); diagramDTO.setCode("d1"); diagramDTO.setName("圖表"); Diagramdiagram=modelMapper.map(diagramDTO,Diagram.class); }
使用開源庫MapStruct
MapStruct也是Java中另外一個用于映射對象很流行的開源工具。它是在編譯階段生成對應(yīng)的映射代碼,相對于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中更多高級特性大家自己探索一下。
總結(jié)
小結(jié)一下,對象在不同層之間進行轉(zhuǎn)換映射,很不建議使用BeanUtil.copyProperties這種方式,更加推薦使用原生的set, get方式,不容易出錯。當(dāng)然這不是將BeanUtil.copyProperties一棒子打死,毫無用武之地,在特定場景,比如方法內(nèi)部對象的轉(zhuǎn)換等影響小的范圍還是很方便的。
-
代碼
+關(guān)注
關(guān)注
30文章
4803瀏覽量
68775 -
編譯
+關(guān)注
關(guān)注
0文章
659瀏覽量
32919
原文標(biāo)題:麻了!不要再動不動就用BeanUtil.copyProperties了!!
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論