3层开发以及不是多么新颖的开发思想了,但是呢,苦于开发的程序猿们,经常会被各个实例之间的转换弄得晕头转向,尤其是转换的次数多了,一下就蒙了,不知道转到哪里去了,博主也有这种困难,于是在网上到处找,找到了一些方法,并结合自身的开发使用,填补一些坑,希望对大家有所帮助!
下面宣布这次的主角:dozer
他是谁,一看英文名就不懂吧,其实他是一个大家都知道的一个角色,spring里面他可是家喻户晓的一个主角,没错就是beanUtils(其实,就是他的替身!)主要作用就是用来复制 JavaBean 属性的类库,什么叫复制,没错,就一模一样的再来一份,但是这样有一点点小小的区别,那就是,在使用的时候,需要指定一个“容器”(瞎说的,就是一个映射接受对象,也可以叫做目标)来存放,不然,复制到哪去,是不是。
这个时候呀,就有一个经纪人的出现,需要通过“经纪人”去代理复制,才能叫这个替身出来呀(专业替身30年,必须要有经纪人)
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.5.1</version>
</dependency>
好了,经纪人的名片已经发出,这个时候,找到剧组,咱们看看这个替身能不能胜任,能应用在哪些剧组,哪些场景!
第一种场景,完全一样:(咦,度一样了,那肯定好弄,又看不出来区别)
在各个实体是一样的情况下,是很容易的,直接上不就行啦,也不用做啥处理是不是:
直接是用原始替身(API方法)
Mapper mapper = new DozerBeanMapper();
DestinationObject destObject =
mapper.map(sourceObject, DestinationObject.class);
嘿嘿,换一下衣服,直接OK了(也就是使用mapper转换复制)
第二种场景,完全不一样:
求乞,完全不一样,这咋的弄呀,肯定得换替身,是不是!最起码找个相似的嘛(不用担心,咱们有化妆师呀,化妆走起!)
@Data
public class UserVo{
@Mapping("userName")
private String name;
@Mapping("password")
private String pwd;
}
看一下,是不是这个东西,好眼熟,没错,是咱们的vo
@Data
@TableName("user")
public class UserEntity implements Serializable {
@ApiModelProperty(value = "id")
@TableId(value = "id", type = IdType.INPUT)
private String id;
@ApiModelProperty(value = "用户名")
@Mapping("name")
private String userName;
@ApiModelProperty(value = "密码")
@Mapping("pwd")
private String password;
@ApiModelProperty(value = "登录名")
private String loginName;
@ApiModelProperty(value = "创建时间")
private Date createTime;
@ApiModelProperty(value = "修改时间")
private Date updateTime;
@ApiModelProperty(value = "版本号")
private Integer version;
@ApiModelProperty(value = "作废标记")
private Integer deleted;
}
这个呢,是咱们的实体对象(也就是数据库对象了)
看一下,是不是发小完全不一样呀!
这里呢,@Mappin充当了化妆品的角色,将每一个不同的细节进行遮盖,使其成为和原来的实例一模一样(也就是做了映射了)
@Mapping("userName")
private String name;
上面就是一个化妆处理,将name映射为userName
每一个地方处理完成后,直接上剧组,看看能不能不被发现
/**
* 转换实体为另一个指定的实体
* 任意一个参数为NULL时 会抛出NPE
*
* @param source 源实体 不能为NULL
* @param clazz 目标实体 不能为NULL
* @param <T> 泛型
* @return 转换后的结果
*/
@NonNull
public static <T> T convert(@NonNull Object source, @NonNull Class<T> clazz) {
return dozerMapper.map(source, clazz);
}
实例:
UserEntity userEntity = userMapper.selectOne(wrapper);
UserVo convert = null;
if(userEntity != null){
convert = Dozer.convert(userEntity, UserVo.class);
}
没错,这样就完成转换替身的操作了,结果是可以映射上的,各位可以试试哦!
第三种场景,一堆的不相同的替身(好难呀,一堆的不一样,不能找几个差不多的吗?)
针对于这种一堆的不一样的替身,dozer也有办法,通过JAVA8的stream流来进行化妆(化妆师牛,只能这么说)
/**
* 转换List实体为另一个指定的实体
* source如果为NULL 会使用空集合
* 在目标实体为NULL时 会抛出NPE
*
* @param source 源集合 可以为NULL
* @param clazz 目标实体 不能为NULL
* @param <T> 泛型
* @return 转换后的结果
*/
@Nullable
public static <T> List<T> convert(@Nullable List<?> source, @NonNull Class<T> clazz) {
return Optional.ofNullable(source)
.orElse(Collections.emptyList())
.stream()
.map(bean -> dozerMapper.map(bean, clazz))
.collect(Collectors.toList());
}
看见没,这样一弄,就OK了,咦,是不是发现化妆师dozerMapper从哪来的(这么牛的化妆师,召几个开化妆店去),博主告诉你,这个化妆师呀,并不是越多也好的(大家都知道,一样的对象,建立太多浪费空间),只需要建立一个全局唯一的就行了,博主带你们看一下化妆间就明白了(工具类来了)
package cn.yichehuoban.ycbb.platform.util.beanutils;
import org.dozer.Mapper;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Component
public class Dozer {
/**
* dozer转换的核心mapper对象
*/
public static final Mapper dozerMapper = new org.dozer.DozerBeanMapper();
/**
* 转换实体为另一个指定的实体
* 任意一个参数为NULL时 会抛出NPE
*
* @param source 源实体 不能为NULL
* @param clazz 目标实体 不能为NULL
* @param <T> 泛型
* @return 转换后的结果
*/
@NonNull
public static <T> T convert(@NonNull Object source, @NonNull Class<T> clazz) {
return dozerMapper.map(source, clazz);
}
/**
* 转换List实体为另一个指定的实体
* source如果为NULL 会使用空集合
* 在目标实体为NULL时 会抛出NPE
*
* @param source 源集合 可以为NULL
* @param clazz 目标实体 不能为NULL
* @param <T> 泛型
* @return 转换后的结果
*/
@Nullable
public static <T> List<T> convert(@Nullable List<?> source, @NonNull Class<T> clazz) {
return Optional.ofNullable(source)
.orElse(Collections.emptyList())
.stream()
.map(bean -> dozerMapper.map(bean, clazz))
.collect(Collectors.toList());
}
}
在给大家看一下我们的替身
@Data
public class UserVo{
@Mapping("userName")
private String name;
@Mapping("password")
private String pwd;
private String loginName;
private Integer version;
private Integer deleted;
private String id;
}
一样的地方直接就映射上了,不一样的地方使用 @Mapping注解,填写上源指定对象的字段名就行
这只是几种方法,还有其他双向映射,数据拷贝等,可以看看他的官方文档dozer