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
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
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
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、暴力拷貝(不推薦)
將需要拷貝的集合遍歷,暴力拷貝。
測試方式??
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