1. Предпосылки
мы вDO
,Model
,VO
Данные могут часто преобразовываться между данными слоя:
-
Entity
Соответствует структуре данных уровня сохраняемости (обычно модели отображения таблицы базы данных); -
Model
Соответствует структуре данных бизнес-уровня; -
VO
этоController
Структура данных, которая взаимодействует с клиентом.
Например: информация о пользователе (модель отображения таблицы), запрашиваемая из базы данных,
UserDO
, но нам нужно передать клиентуUserVO
, то необходимоUserDO
Свойства экземпляра назначаются одно за другимUserVO
в экземпляре.
Большое количество свойств может совпадать или не совпадать между этими структурами данных.
2. Копирование данных
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. Коллекционный экземпляр
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
Типы мальчиков/девочек.