java使用BeanUtils.copyProperties踩坑經(jīng)歷
1. 原始轉(zhuǎn)換
提起對(duì)象轉(zhuǎn)換,每個(gè)程序員都不陌生,比如項(xiàng)目中經(jīng)常涉及到的DO、DTO、VO之間的轉(zhuǎn)換,舉個(gè)例子,假設(shè)現(xiàn)在有個(gè)OrderDTO,定義如下所示:
public class OrderDTO { private long id; private Long userId; private String orderNo; private Date gmtCreated; // 省略get、set方法 }
有個(gè)OrderVO,定義如下所示:
public class OrderVO { private long id; private long userId; private String orderNo; private Date gmtCreated; // 省略get、set方法 }
如果不使用任何轉(zhuǎn)換工具,代碼是下面這樣的:
public static void main(String[] args) { OrderDTO orderDTO = new OrderDTO(); orderDTO.setId(1L); orderDTO.setUserId(123L); orderDTO.setOrderNo("20210518000001"); orderDTO.setGmtCreated(new Date()); OrderVO orderVO = new OrderVO(); orderVO.setId(orderDTO.getId()); orderVO.setUserId(orderDTO.getUserId()); orderVO.setOrderNo(orderDTO.getOrderNo()); orderVO.setGmtCreated(orderDTO.getGmtCreated()); System.out.println(orderVO.getId()); System.out.println(orderVO.getUserId()); System.out.println(orderVO.getOrderNo()); System.out.println(orderVO.getGmtCreated()); }
運(yùn)行結(jié)果:
2. 使用BeanUtils.copyProperties轉(zhuǎn)換
因?yàn)轫?xiàng)目中類似上面的轉(zhuǎn)換多而繁瑣,所以很多公司的項(xiàng)目中會(huì)使用Spring框架里的BeanUtils.copyProperties來做對(duì)象轉(zhuǎn)換,代碼如下所示:
OrderVO orderVO = new OrderVO(); BeanUtils.copyProperties(orderDTO, orderVO);
一行代碼搞定,很方便,運(yùn)行結(jié)果也和原來一模一樣。
不過這個(gè)工具帶來便利的同時(shí),也帶來了很多問題,稍微不注意就會(huì)踩坑,接下來就總結(jié)下使用這個(gè)工具常見的幾個(gè)坑。
3. 踩坑經(jīng)歷
3.1 包裝類型轉(zhuǎn)基本類型問題
java.lang.IllegalArgumentException
細(xì)心的你可能會(huì)發(fā)現(xiàn),OrderDTO中的userId字段,我定義的是Long類型:
而OrderVO中的userId字段,我定義的是long類型:
然后我們運(yùn)行下下面所示的代碼:
public static void main(String[] args) { OrderDTO orderDTO = new OrderDTO(); orderDTO.setId(1L); orderDTO.setUserId(null); orderDTO.setOrderNo("20210518000001"); orderDTO.setGmtCreated(new Date()); OrderVO orderVO = new OrderVO(); BeanUtils.copyProperties(orderDTO, orderVO); }
會(huì)看到代碼拋了java.lang.IllegalArgumentException
異常:
3.2 空格問題
假設(shè)OrderVO的orderNo字段,是用戶自定義的,用戶不小心輸入了空格,使用BeanUtils.copyProperties后,空格會(huì)帶入到OrderDTO的orderNo字段,如果不小心,就會(huì)把臟數(shù)據(jù)落到數(shù)據(jù)庫(kù)(而我們希望的是去除空格再落庫(kù)的),造成一系列后續(xù)問題:
public static void main(String[] args) { OrderVO orderVO = new OrderVO(); orderVO.setId(1L); orderVO.setUserId(123L); // 模擬空格場(chǎng)景 orderVO.setOrderNo(" 20210518000001 "); orderVO.setGmtCreated(new Date()); OrderDTO orderDTO = new OrderDTO(); BeanUtils.copyProperties(orderVO, orderDTO); System.out.println(orderDTO.getOrderNo()); }
運(yùn)行結(jié)果:
3.3 查找不到字段引用
使用BeanUtils.copyProperties后,會(huì)看到字段并沒有引用,其實(shí)是有用到的,如下圖所示:
有些小伙伴在看代碼時(shí),看到字段沒有地方引用,可能就忍不住想刪掉,結(jié)果就導(dǎo)致真正使用該字段的地方取不到值,產(chǎn)生bug。
3.4 前端誤傳字段,直接把數(shù)據(jù)庫(kù)覆蓋了
如果接口定義的比較嚴(yán)謹(jǐn),理論上是不應(yīng)該存在這種情況的,不過凡事總有特殊,這里舉個(gè)接口不嚴(yán)謹(jǐn)導(dǎo)致數(shù)據(jù)被覆蓋的例子。
假如OrderVO和OrderDTO有如下2個(gè)字段:
/** * 已收金額 * 單位:分 */ private Long receivedAmount; /** * 備注 */ private String remark;
正常情況下,后端只應(yīng)該使用前端傳遞的remark字段,receivedAmount字段不應(yīng)該使用,但假如用戶修改訂單備注時(shí),前端不小心傳遞了receivedAmount字段,并且賦值為null,這時(shí)使用BeanUtils.copyProperties后,OrderDTO里的receivedAmount字段就也為null,如果后端不知道前端傳遞了這個(gè)字段并且操作DB不夠嚴(yán)謹(jǐn),就會(huì)導(dǎo)致訂單的已收金額被清空,很恐怖,而且不好排查原因。
4. 插件推薦
雖然BeanUtils.copyProperties
工具提供了便利,但帶來的問題也很多,因此很多公司(包含我現(xiàn)在所在的公司)都禁止在項(xiàng)目中使用該工具。
但重復(fù)的寫對(duì)象轉(zhuǎn)換,實(shí)在是太繁瑣,效率太低了,這里推薦一個(gè)IDEA的插件GenerateAllSetter,可以一鍵生成對(duì)象的set方法,非常方便,如下圖所示:
插件使用:
在需要生成set方法的對(duì)象上,按快捷鍵Option+Enter(Windows是Alt+Enter),會(huì)看到下圖所示的選項(xiàng):
點(diǎn)擊后會(huì)自動(dòng)生成所有字段(沒有默認(rèn)值)的賦值語(yǔ)句:
如果生成賦值語(yǔ)句時(shí)想帶默認(rèn)值,可以使用另一個(gè)選項(xiàng):
效果如下所示:
到此這篇關(guān)于java使用BeanUtils.copyProperties踩坑經(jīng)歷的文章就介紹到這了,更多相關(guān)BeanUtils.copyProperties踩坑內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot中@Async默認(rèn)線程池導(dǎo)致OOM問題
這篇文章主要介紹了springboot中@Async默認(rèn)線程池導(dǎo)致OOM問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06SpringBoot FreeWorker模板技術(shù)解析
這篇文章主要介紹了SpringBoot FreeWorker模板技術(shù)解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11Java設(shè)計(jì)模式之中介者模式(Mediator Pattern)簡(jiǎn)介
這篇文章主要介紹了Java設(shè)計(jì)模式之中介者模式(Mediator Pattern),需要的朋友可以參考下2014-07-07feign調(diào)用返回object類型轉(zhuǎn)換方式
這篇文章主要介紹了feign調(diào)用返回object類型轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06