BeanUtils 如何拷貝 List?

BeanUtils 如何拷貝 List?

一、背景

我們在DO、Model、VO層數(shù)據(jù)間可能經(jīng)常轉(zhuǎn)換數(shù)據(jù):

Entity對應(yīng)的是持久層數(shù)據(jù)結(jié)構(gòu)(一般是數(shù)據(jù)庫表的映射模型);

Model 對應(yīng)的是業(yè)務(wù)層的數(shù)據(jù)結(jié)構(gòu);

VO 就是Controller和客戶端交互的數(shù)據(jù)結(jié)構(gòu)。

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

在這些數(shù)據(jù)結(jié)構(gòu)之間很大一部分屬性都可能會相同,也可能不同。

二、數(shù)據(jù)拷貝

2.1、數(shù)據(jù)模型

UserDO.jav

@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、常規(guī)使用-BeanUtils

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

例如:我們把數(shù)據(jù)庫查詢出來的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)

通過打印結(jié)果我們可以發(fā)現(xiàn):除了類型不同的sex,其他數(shù)值都成功拷貝。

2.3、集合拷貝

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

日志打印如下:

....userVOList:[]

通過日志可以發(fā)現(xiàn),直接拷貝集合是無效的,那么怎么解決呢?

三、集合拷貝

3.1、暴力拷貝(不推薦)

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

測試方式??

@Test

public void listCopyCommon() {

List userDOList = new ArrayList();

userDOList.add(new UserDO(1L, "Van", 18, 1));

userDOList.add(new UserDO(2L, "VanVan", 20, 2));

List userVOList = new ArrayList();

userDOList.forEach(userDO ->{

UserVO userVO = new UserVO();

BeanUtils.copyProperties(userDO, userVO);

userVOList.add(userVO);

});

log.info("userVOList:{}",userVOList);

}

拷貝結(jié)果

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

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

3.2、優(yōu)雅拷貝(本文推薦)

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

定義一個函數(shù)式接口

函數(shù)式接口里是可以包含默認方法,這里我們定義默認回調(diào)方法。

@FunctionalInterface

public interface BeanCopyUtilCallBack {

/**

* 定義默認回調(diào)方法

* @param t

* @param s

*/

void callBack(S t, T s);

}

封裝一個數(shù)據(jù)拷貝工具類 BeanCopyUtil.java

public class BeanCopyUtil extends BeanUtils {

/**

* 集合數(shù)據(jù)的拷貝

* @param sources: 數(shù)據(jù)源類

* @param target: 目標類::new(eg: UserVO::new)

* @return

*/

public static List copyListProperties(List sources, Supplier target) {

return copyListProperties(sources, target, null);

}

/**

* 帶回調(diào)函數(shù)的集合數(shù)據(jù)的拷貝(可自定義字段拷貝規(guī)則)

* @param sources: 數(shù)據(jù)源類

* @param target: 目標類::new(eg: UserVO::new)

* @param callBack: 回調(diào)函數(shù)

* @return

*/

public static List copyListProperties(List sources, Supplier target, BeanCopyUtilCallBack callBack) {

List list = new ArrayList<>(sources.size());

for (S source : sources) {

T t = target.get();

copyProperties(source, t);

list.add(t);

if (callBack != null) {

// 回調(diào)

callBack.callBack(source, t);

}

}

return list;

}

}

簡單拷貝測試

@Test

public void listCopyUp() {

List userDOList = new ArrayList();

userDOList.add(new UserDO(1L, "Van", 18, 1));

userDOList.add(new UserDO(2L, "VanVan", 20, 2));

List userVOList = BeanCopyUtil.copyListProperties(userDOList, UserVO::new);

log.info("userVOList:{}",userVOList);

}

打印結(jié)果:

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

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

性別枚舉類

public enum SexEnum {

UNKNOW("未設(shè)置",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;

}

}

帶回調(diào)函數(shù)的拷貝

@Test

public void listCopyUpWithCallback() {

List userDOList = new ArrayList();

userDOList.add(new UserDO(1L, "Van", 18, 1));

userDOList.add(new UserDO(2L, "VanVan", 20, 2));

List userVOList = BeanCopyUtil.copyListProperties(userDOList, UserVO::new, (userDO, userVO) ->{

// 這里可以定義特定的轉(zhuǎn)換規(guī)則

userVO.setSex(SexEnum.getDescByCode(userDO.getSex()).getDesc());

});

log.info("userVOList:{}",userVOList);

}

打印結(jié)果:

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

通過打印結(jié)果可以發(fā)現(xiàn),UserDO.java 中Integer類型的sex復(fù)制到UserVO.java成了String類型的男生/女生。

想獲得 更多的學習資料 在評論下方評論【學習】就可以了哦

作者:Van_Fa

鏈接:https://juejin.im/post/5e1b18b1f265da3e140fa377

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 文章核心 其實,本不想把標題寫的那么恐怖,只是發(fā)現(xiàn)很多人干了幾年java以后,都自認為是一個不錯的java程序員了...
    java菜閱讀 1,978評論 6 49
  • BeanUtils是Apache commons組件的成員之一,主要用于簡化JavaBean封裝數(shù)據(jù)的操作。它可以...
    hddwsz閱讀 3,134評論 0 0
  • 懶得處理樣式了, 將就著看吧. 官網(wǎng)地址: https://developer.android.com/topic...
    Reddington_604e閱讀 1,912評論 0 1
  • 1、不安全的隨機數(shù)生成,在CSRF TOKEN生成、password reset token生成等,會造成toke...
    nightmare丿閱讀 3,994評論 0 1
  • 想要看其它章節(jié)的朋友請走這里:) ——八國戰(zhàn)記目錄 天子、上卿和大公伴隨奏樂上臺之后,太宰宣布祭天大典開始。 開場...
    Orange_yang閱讀 400評論 0 0

友情鏈接更多精彩內(nèi)容