BeanUtils 如何拷貝 List?


摘自:https://www.cnblogs.com/vandusty/p/12184769.html

BeanUtils 如何拷貝 List?

一、背景

我們在DOModelVO層數據間可能經常轉換數據:

  1. Entity對應的是持久層數據結構(一般是數據庫表的映射模型);
  2. Model 對應的是業務層的數據結構;
  3. VO 就是Controller和客戶端交互的數據結構。

例如:數據庫查詢出來的用戶信息(表的映射模型)是UserDO,但是我們需要傳遞給客戶端的是UserVO,這時候就需要把UserDO實例的屬性一個一個賦值到UserVO實例中。

在這些數據結構之間很大一部分屬性都可能會相同,也可能不同。

二、數據拷貝

2.1、數據模型

  • UserDO.java
@Data public class UserDO { private Long userId; private String userName; private Integer age; private Integer sex; public UserDO() { } public UserDO(Long userId, String userName, Integer age, Integer sex) { this.userId = userId; this.userName = userName; this.age = age; this.sex = sex; } }
  • UserVO.java
@Data public class UserVO { private Long userId; private String userName; private Integer age; private String sex; }

注意:
UserDO.java 和UserVO.java 最后一個字段sex類型不一樣,分別是:Integer/String

2.2、常規使用-BeanUtils

Spring 提供了 org.springframework.beans.BeanUtils 類進行快速賦值。

例如:我們把數據庫查詢出來的UserDO.java 拷貝到 UserVO.java

@Test public void commonCopy() { UserDO userDO = new UserDO(1L, "Van", 18, 1); UserVO userVO = new UserVO(); BeanUtils.copyProperties(userDO, userVO); log.info("userVO:{}",userVO); }

日志打印:

.... userVO:UserVO(userId=1, userName=Van, age=18, sex=null)

通過打印結果我們可以發現:除了類型不同的sex,其他數值都成功拷貝。

2.3、集合拷貝

剛剛拷貝的是一個對象,但是有時候我們想拷貝一組UerDO.java,是一個集合的時候就不能這樣直接賦值了。如果還按照這種邏輯,如下:

@Test public void listCopyFalse() { List<UserDO> userDOList = new ArrayList(); userDOList.add(new UserDO(1L, "Van", 18, 1)); userDOList.add(new UserDO(2L, "VanVan", 18, 2)); List<UserVO> userVOList = new ArrayList(); BeanUtils.copyProperties(userDOList, userVOList); log.info("userVOList:{}",userVOList); }

日志打印如下:

.... userVOList:[]

通過日志可以發現,直接拷貝集合是無效的,那么怎么解決呢?

三、集合拷貝

3.1、暴力拷貝(不推薦)

將需要拷貝的集合遍歷,暴力拷貝。

  • 測試方式
@Test public void listCopyCommon() { List<UserDO> userDOList = new ArrayList(); userDOList.add(new UserDO(1L, "Van", 18, 1)); userDOList.add(new UserDO(2L, "VanVan", 20, 2)); List<UserVO> userVOList = new ArrayList(); userDOList.forEach(userDO ->{ UserVO userVO = new UserVO(); BeanUtils.copyProperties(userDO, userVO); userVOList.add(userVO); }); log.info("userVOList:{}",userVOList); }
  • 拷貝結果
.... userVOList:[UserVO(userId=1, userName=Van, age=18, sex=null), UserVO(userId=2, userName=VanVan, age=20, sex=null)]

雖然該方式可以解決,但是一點都不優雅,特別是寫起來麻煩。

3.2、優雅拷貝(本文推薦

通過JDK 8 的函數式接口封裝org.springframework.beans.BeanUtils

  • 定義一個函數式接口

函數式接口里是可以包含默認方法,這里我們定義默認回調方法。

@FunctionalInterface public interface BeanCopyUtilCallBack <S, T> { /** * 定義默認回調方法 * @param t * @param s */ void callBack(S t, T s); }
  • 封裝一個數據拷貝工具類 BeanCopyUtil.java
public class BeanCopyUtil extends BeanUtils { /** * 集合數據的拷貝 * @param sources: 數據源類 * @param target: 目標類::new(eg: UserVO::new) * @return */ public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target) { return copyListProperties(sources, target, null); } /** * 帶回調函數的集合數據的拷貝(可自定義字段拷貝規則) * @param sources: 數據源類 * @param target: 目標類::new(eg: UserVO::new) * @param callBack: 回調函數 * @return */ public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target, BeanCopyUtilCallBack<S, T> callBack) { List<T> list = new ArrayList<>(sources.size()); for (S source : sources) { T t = target.get(); copyProperties(source, t); list.add(t); if (callBack != null) { // 回調 callBack.callBack(source, t); } } return list; } }
  • 簡單拷貝測試
@Test public void listCopyUp() { List<UserDO> userDOList = new ArrayList(); userDOList.add(new UserDO(1L, "Van", 18, 1)); userDOList.add(new UserDO(2L, "VanVan", 20, 2)); List<UserVO> userVOList = BeanCopyUtil.copyListProperties(userDOList, UserVO::new); log.info("userVOList:{}",userVOList); }

打印結果:

.... userVOList:[UserVO(userId=1, userName=Van, age=18, sex=null), UserVO(userId=2, userName=VanVan, age=20, sex=null)]

通過如上方法,我們基本實現了集合的拷貝,但是從返回結果我們可以發現:屬性不同的字段無法拷貝。所以,我們這里需要借助剛定義的回調方法實現自定義轉換。

  • 性別枚舉類
public enum SexEnum { UNKNOW("未設置",0), MEN("男生", 1), WOMAN("女生",2), ; private String desc; private int code; SexEnum(String desc, int code) { this.desc = desc; this.code = code; } public static SexEnum getDescByCode(int code) { SexEnum[] typeEnums = values(); for (SexEnum value : typeEnums) { if (code == value.getCode()) { return value; } } return null; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } }
  • 帶回調函數的拷貝
@Test public void listCopyUpWithCallback() { List<UserDO> userDOList = new ArrayList(); userDOList.add(new UserDO(1L, "Van", 18, 1)); userDOList.add(new UserDO(2L, "VanVan", 20, 2)); List<UserVO> userVOList = BeanCopyUtil.copyListProperties(userDOList, UserVO::new, (userDO, userVO) ->{ // 這里可以定義特定的轉換規則 userVO.setSex(SexEnum.getDescByCode(userDO.getSex()).getDesc()); }); log.info("userVOList:{}",userVOList); }

打印結果:

... userVOList:[UserVO(userId=1, userName=Van, age=18, sex=男生), UserVO(userId=2, userName=VanVan, age=20, sex=女生)]

通過打印結果可以發現,UserDO.java 中Integer類型的sex復制到UserVO.java成了String類型的男生/女生。

四、更多

Github 源碼

  1. 風塵博客:https://www.dustyblog.cn
  2. 風塵博客-掘金
  3. 風塵博客-博客園
  4. Github
  5. 公眾號

    風塵博客

技術交流,歡迎掃一掃!

風塵博客

 
分類:  Spring
標簽:  Spring


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM