Spring超詳細(xì)講解BeanUtils改造
1.基本原理
原理:http://www.dbjr.com.cn/article/252384.htm
淺拷貝:http://www.dbjr.com.cn/article/221283.htm
BeanUtils.copyProperties();確實(shí)為我們做了很多事情,雖然不能完美完成深拷貝,但是對(duì)于 po、vo、dto 的拷貝已經(jīng)足夠用了。但是其還是有一些不夠完美的地方。
不足幾點(diǎn)如下:
不能拷貝 list,而拷貝 list 的情況又大量存在,因此會(huì)有許多重復(fù)代碼。
for (S source : sources) { T target = new T(); copyProperties(source, target); list.add(target); }
有一些簡(jiǎn)單的查詢(xún),僅僅需要轉(zhuǎn)換一下 vo 也需要 new Vo()。
public Vo findById(Integer id) { Vo vo = new Vo(); Po po = dao.findById(id); copyProperties(po, vo); return vo; }
這種拷貝方式是沒(méi)有返回值的,jdk8 支持 stream() 操作之后,支持不是很友好,不方便 lambda 表達(dá)式的使用,因此我們決定通過(guò)集成 BeanUtils 類(lèi),自己造一個(gè)方便用的輪子。
2.使用
我們將新創(chuàng)建一個(gè)工具類(lèi) BeanConvertUtils,使用如下,當(dāng)我們要轉(zhuǎn)換 po、vo 時(shí),只需要:
// 使用前 public Vo findById(Integer id) { Vo vo = new Vo(); Po po = dao.findById(id); copyProperties(po, vo); return vo; } // 使用后 public Vo findById(Integer id) { return BeanConvertUtils.converTo(dao.findById(id), Vo::new); } // 使用后,通過(guò)lambda表達(dá)式特殊處理個(gè)別字段 public Vo findById(Integer id) { return BeanConvertUtils.converTo(dao.findById(id), Vo::new, (s, t) -> t.setName(s.getName)) ); }
當(dāng)我們要拷貝 list 的時(shí)候也很簡(jiǎn)單:
// 使用前 public List<Vo> findAll() { List<Vo> vos = new ArrayList(); List<Po> pos = dao.findAll(); for (Po po : Pos) { Vo vo = new Vo(); BeanUtis.copyProperties(po, vo); vos.add(vo); } return vos; } // 使用后 public List<Vo> findAll() { return BeanConvertUtils.converToList(dao.findAll(), Vo::new) } // 同樣支持自定義lambda public List<Vo> findAll() { return BeanConvertUtils.converToList(dao.findAll(), Vo::new, (s, t) -> t.setName(s.getName)) ) }
工具代碼如下:
import org.springframework.beans.BeanUtils; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; /** * Spring-BeanUtils轉(zhuǎn)換對(duì)象工具封裝(淺拷貝) */ public class BeanConvertUtils extends BeanUtils { /** * 拷貝對(duì)象 * @param source * @param targetSupplier * @param <S> * @param <T> * @return */ public static <S, T> T convertTo(S source, Supplier<T> targetSupplier) { return convertTo(source, targetSupplier, null); } /** * 拷貝list * * @param sources * @param targetSupplier * @param <S> * @param <T> * @return */ public static <S, T> List<T> convertListTo(List<S> sources, Supplier<T> targetSupplier) { return convertListTo(sources, targetSupplier, null); } /** * 轉(zhuǎn)換對(duì)象 * * @param source 源對(duì)象 * @param targetSupplier 目標(biāo)對(duì)象供應(yīng)方 * @param callBack 回調(diào)方法 * @param <S> 源對(duì)象類(lèi)型 * @param <T> 目標(biāo)對(duì)象類(lèi)型 * @return 目標(biāo)對(duì)象 */ public static <S, T> T convertTo(S source, Supplier<T> targetSupplier, ConvertCallBack<S, T> callBack) { if (null == source || null == targetSupplier) { return null; } T target = targetSupplier.get(); copyProperties(source, target); if (callBack != null) { callBack.callBack(source, target); } return target; } /** * 轉(zhuǎn)換對(duì)象 * * @param sources 源對(duì)象list * @param targetSupplier 目標(biāo)對(duì)象供應(yīng)方 * @param callBack 回調(diào)方法 * @param <S> 源對(duì)象類(lèi)型 * @param <T> 目標(biāo)對(duì)象類(lèi)型 * @return 目標(biāo)對(duì)象list */ public static <S, T> List<T> convertListTo(List<S> sources, Supplier<T> targetSupplier, ConvertCallBack<S, T> callBack) { if (null == sources || null == targetSupplier) { return null; } List<T> list = new ArrayList<>(sources.size()); for (S source : sources) { T target = targetSupplier.get(); copyProperties(source, target); if (callBack != null) { callBack.callBack(source, target); } list.add(target); } return list; } /** * 回調(diào)接口 * * @param <S> 源對(duì)象類(lèi)型 * @param <T> 目標(biāo)對(duì)象類(lèi)型 */ @FunctionalInterface public interface ConvertCallBack<S, T> { void callBack(S t, T s); } }
3.性能
由于只是 BeanUtils 的一個(gè)封裝,跟原來(lái)的代碼性能幾乎差不多,如果要說(shuō)差一點(diǎn)也沒(méi)錯(cuò),畢竟多了一層函數(shù)堆棧的調(diào)用,但是基本可以忽略不計(jì)。主要的性能還是由 BeanUtils 決定。
4.提醒
不知道大家對(duì)這個(gè) BeanConvertUtils 工具類(lèi)感覺(jué)怎么樣,自己在項(xiàng)目中倒是大量使用,也很方便。
但是有兩點(diǎn)要提醒:
- 此方法依舊不能解決深層次的深拷貝問(wèn)題,詳細(xì)的可以 google 一下 BeanUtils 的深拷貝問(wèn)題。
- 如果 source 或者 targetSupplier 只要有一個(gè)為 null,本工具類(lèi)不像 BeanUtils 一樣拋出異常,而是返回 null,因?yàn)楣P者認(rèn)為調(diào)用方如果把 null 進(jìn)行準(zhǔn)換,那就是想轉(zhuǎn)換為 null,為不為空應(yīng)該由調(diào)用方自己負(fù)責(zé)。
到此這篇關(guān)于Spring超詳細(xì)講解BeanUtils改造的文章就介紹到這了,更多相關(guān)Spring BeanUtils內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解SpringBoot中異步請(qǐng)求的實(shí)現(xiàn)與并行執(zhí)行
這篇文章主要為大家詳細(xì)介紹了在SpringBoot中如何是實(shí)現(xiàn)異步請(qǐng)求、并行執(zhí)行,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02SpringBoot報(bào)錯(cuò)Invalid?bound?statement?(not?found)問(wèn)題排查和解決方案
這篇文章主要介紹了SpringBoot報(bào)錯(cuò)Invalid?bound?statement?(not?found)問(wèn)題排查和解決方案,文中通過(guò)圖文結(jié)合的方式講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-03-03hadoop中實(shí)現(xiàn)java網(wǎng)絡(luò)爬蟲(chóng)(示例講解)
下面小編就為大家?guī)?lái)一篇hadoop中實(shí)現(xiàn)java網(wǎng)絡(luò)爬蟲(chóng)(示例講解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09詳解如何在SpringBoot中優(yōu)雅地重試調(diào)用第三方API
作為后端程序員,我們的日常工作就是調(diào)用一些第三方服務(wù),將數(shù)據(jù)存入數(shù)據(jù)庫(kù),返回信息給前端。本文為大家介紹了如何在SpringBoot中優(yōu)雅地重試調(diào)用第三方API,需要的可以參考一下2022-12-12Spring實(shí)戰(zhàn)之使用XML方式管理聲明式事務(wù)操作示例
這篇文章主要介紹了Spring實(shí)戰(zhàn)之使用XML方式管理聲明式事務(wù)操作,結(jié)合實(shí)例形式詳細(xì)分析了Spring XML方式管理聲明式事務(wù)具體步驟、配置、接口及使用技巧,需要的朋友可以參考下2020-01-01