首頁 > 軟體

Spring超詳細講解BeanUtils改造

2022-06-21 14:10:02

1.基本原理

原理:https://www.jb51.net/article/252384.htm

淺拷貝:https://www.jb51.net/article/221283.htm

BeanUtils.copyProperties();確實為我們做了很多事情,雖然不能完美完成深拷貝,但是對於 po、vo、dto 的拷貝已經足夠用了。但是其還是有一些不夠完美的地方。

不足幾點如下:

不能拷貝 list,而拷貝 list 的情況又大量存在,因此會有許多重複程式碼。

for (S source : sources) {
    T target = new T();
    copyProperties(source, target);
    list.add(target);
}

有一些簡單的查詢,僅僅需要轉換一下 vo 也需要 new Vo()。

public Vo findById(Integer id) {
 Vo vo = new Vo();
 Po po = dao.findById(id);
 copyProperties(po, vo);
 return vo;
}

這種拷貝方式是沒有返回值的,jdk8 支援 stream() 操作之後,支援不是很友好,不方便 lambda 表示式的使用,因此我們決定通過整合 BeanUtils 類,自己造一個方便用的輪子。

2.使用

我們將新建立一個工具類 BeanConvertUtils,使用如下,當我們要轉換 po、vo 時,只需要:

// 使用前
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);
}
// 使用後,通過lambda表示式特殊處理個別欄位
public Vo findById(Integer id) {
 return BeanConvertUtils.converTo(dao.findById(id), Vo::new, 
  (s, t) -> t.setName(s.getName))
 );
}

當我們要拷貝 list 的時候也很簡單:

// 使用前
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轉換物件工具封裝(淺拷貝)
 */
public class BeanConvertUtils extends BeanUtils {
    /**
     * 拷貝物件
     
     * @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);
    }
    /**
     * 轉換物件
     *
     * @param source         源物件
     * @param targetSupplier 目標物件供應方
     * @param callBack       回撥方法
     * @param <S>            源物件型別
     * @param <T>            目標物件型別
     * @return 目標物件
     */
    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;
    }
    /**
     * 轉換物件
     *
     * @param sources        源物件list
     * @param targetSupplier 目標物件供應方
     * @param callBack       回撥方法
     * @param <S>            源物件型別
     * @param <T>            目標物件型別
     * @return 目標物件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;
    }
    /**
     * 回撥介面
     *
     * @param <S> 源物件型別
     * @param <T> 目標物件型別
     */
    @FunctionalInterface
    public interface ConvertCallBack<S, T> {
        void callBack(S t, T s);
    }
}

3.效能

由於只是 BeanUtils 的一個封裝,跟原來的程式碼效能幾乎差不多,如果要說差一點也沒錯,畢竟多了一層函數堆疊的呼叫,但是基本可以忽略不計。主要的效能還是由 BeanUtils 決定。

4.提醒

不知道大家對這個 BeanConvertUtils 工具類感覺怎麼樣,自己在專案中倒是大量使用,也很方便。

但是有兩點要提醒:

  • 此方法依舊不能解決深層次的深拷貝問題,詳細的可以 google 一下 BeanUtils 的深拷貝問題。
  • 如果 source 或者 targetSupplier 只要有一個為 null,本工具類不像 BeanUtils 一樣丟擲異常,而是返回 null,因為筆者認為呼叫方如果把 null 進行準換,那就是想轉換為 null,為不為空應該由呼叫方自己負責。

到此這篇關於Spring超詳細講解BeanUtils改造的文章就介紹到這了,更多相關Spring BeanUtils內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com