在开发中经常遇到这样一个问题,从DAO层拿回DO实体对象,比如我们从数据库中查出的User实体类包含以下域:
@Getter
@Setter
@ToString
public class UserDO {
private Integer id;
private String name;
private Integer age;
private String gender;
private String address;
private String password;
private String nickName;
private Date birthday;
private Integer isDeleted;
}
但是我们服务需要返回的实体类VO,包含以下域:
@Getter
@Setter
@ToString
public class UserVO {
private Integer id;
private String name;
private Integer age;
private String gender;
private String address;
private String nickName;
private Date birthday;
private Integer clickCount;
}
很明显,VO中包含了DO中的大多数域数据,但也没有完全重合。开发中我们需要把DO实体类转成VO实体类,一般的方法可以这样处理:
public class TransformDemo {
private UserDO userDO = new UserDO();
@Before
public void init(){
userDO.setId(1);
userDO.setAge(18);
userDO.setName("zhuoli");
userDO.setAddress("shanghai");
userDO.setBirthday(Date.from(LocalDate.of(2000, 1, 1).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
userDO.setGender("male");
userDO.setNickName("卓立");
userDO.setPassword("123456");
userDO.setIsDeleted(0);
}
@Test
public void transformInCommonWay(){
UserVO userVO = new UserVO();
userVO.setId(userDO.getId());
userVO.setAge(userDO.getAge());
userVO.setName(userDO.getName());
userVO.setAddress(userDO.getAddress());
userVO.setBirthday(userDO.getBirthday());
userVO.setGender(userDO.getGender());
userVO.setNickName(userDO.getNickName());
userVO.setClickCount(99);
System.out.println(userVO);
}
}
先new一个VO对象,然后调用set方法一一将值塞进去,很不方便。另外分层的结构有个很鲜明的特点,DO和VO有很多重复的字段,我们是不是可以利用这个特点快捷的讲DO转成VO?下面就介绍一下可以完成这个工作的一个工具Dozer 。
1. Dozer简介
Dozer是Java Bean到Java Bean映射器,它以递归方式将数据从一个对象复制到另一个对象。支持简单属性映射,复杂类型映射,双向映射,隐式显式映射以及递归映射。另外,Dozer不仅支持属性名称之间的映射,还支持在类型之间自动转换。大多数转换方案都是开箱即用的,如果无法完成映射(比如使用属性名映射的时候,名称不同),还允许通过xml配置文件的形势配置映射规则。Dozer官方给出如下的使用场景:
Dozer通常用于整个系统的入口和出口,可以保证数据库中的内部域对象不会流入外部表示层或外部使用者,还可以帮助将域对象映射到外部API调用,反之亦然。
2. 自定义BeanMapper工具类
了解了Dozer常规使用后,下面我使用Dozer实现一个工具类,基于属性名称进行对象映射。至于类型映射和自定义映射配置这里就不讲解了,可以去看一下官方文档,很好理解。这里仅展现基于Dozer的对象转换工具类。
2.1 BeanMapper
public class BeanMapper {
private static DozerBeanMapper dozer = new DozerBeanMapper();
/**
* 普通对象转换 比如: ADO -> AVO
* @param: [source 源对象, destinationClass 目标对象class]
* @return: T
* @author: zhuoli
* @date: 2018/9/30 18:13
*/
public static <T> T map(Object source, Class<T> destinationClass) {
if (source == null) {
return null;
}
return dozer.map(source, destinationClass);
}
/**
* List转换 比如: List<ADO> -> List<AVO>
* @param: [sourceList 源对象List, destinationClass 目标对象class]
* @return: java.util.List<T>
* @author: zhuoli
* @date: 2018/9/30 18:14
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static <T> List<T> mapList(Collection sourceList, Class<T> destinationClass) {
List<T> destinationList = new ArrayList();
if (sourceList == null) {
return destinationList;
}
for (Object sourceObject : sourceList) {
if (sourceObject != null) {
T destinationObject = dozer.map(sourceObject, destinationClass);
destinationList.add(destinationObject);
}
}
return destinationList;
}
}
2.2 BeanMapper使用
@Test
public void transformInDozerWay(){
UserVO userVO = BeanMapper.map(userDO, UserVO.class);
userVO.setClickCount(99);
System.out.println(userVO);
}
UserVO(id=1, name=zhuoli, age=18, gender=male, address=shanghai, nickName=卓立, birthday=Sat Jan 01 00:00:00 CST 2000, clickCount=99)
使用工具类如上就可以方便地完成对象地转换,只要代码中使用统一的编码规范(在进行属性命名时,各层使用相同的名称),使用上述工具类进行对象转换是比较方便的。
示例代码:码云 – 卓立 – 对象转换工具