业务场景: 设计规范前提下,我们数据层传输承载的是用DTO,而到控制层返回给前端会对应定义一个VO对象,比如是一个问题单数据集合list<DTO>,数据层接收的是DTO对对象,到控制层接收后需要转换成list<VO>,这里就涉及到要转换对象数据
对象复制的类库工具有很多 Orika是目前性能最强,同时也最流行的对象映射工具,Orika底层采用了javassist类库生成Bean映射的字节码,之后直接加载执行生成的字节码文件,在速度上比使用反射进行赋值会快很多。
阿里巴巴开发手册上强制规定避免使用Apache BeanUtils
- 原因在于
Apache BeanUtils
底层源码为了追求完美,加了过多的包装,使用了很多反射,做了很多校验,所以导致性能较差
- 添加依赖
<!-- 对象属性拷贝 -->
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.4</version>
</dependency>
定义工具类OrikaUtils
package com.hjycommunity.common.utils;
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.ClassMapBuilder;
import ma.glasnost.orika.metadata.Type;
import ma.glasnost.orika.metadata.TypeFactory;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 对象复制工具类
**/
public class OrikaUtils {
//构造一个MapperFactory
private static final MapperFactory FACTORY = new DefaultMapperFactory.Builder().build();
/**
* 缓存实例集合
*/
private static final Map<String, MapperFacade> CACHE_MAPPER = new ConcurrentHashMap<>();
private final MapperFacade mapper;
public OrikaUtils(MapperFacade mapper) {
this.mapper = mapper;
}
/**
* 字段一致实体转换函数
* @param sourceEntity 源实体
* @param targetClass 目标类对象
* @param <S> 源泛型
* @param <T> 目标泛型
* @return 目标实体
*/
public static <S, T> T convert(S sourceEntity, Class<T> targetClass) {
return convert(sourceEntity, targetClass, null);
}
/**
* 字段不一致实体转换函数(需要字段映射)
* @param sourceEntity 源实体
* @param targetClass 目标类对象
* @param refMap 配置源类与目标类不同字段名映射
* @param <S> 源泛型
* @param <T> 目标泛型
* @return 目标实体
*/
public static <S, T> T convert(S sourceEntity, Class<T> targetClass, Map<String, String> refMap) {
if (sourceEntity == null) {
return null;
}
return classMap(sourceEntity.getClass(), targetClass, refMap).map(sourceEntity, targetClass);
}
/**
* 字段一致集合转换函数
* @param sourceEntityList 源实体集合
* @param targetClass 目标类对象
* @param <S> 源泛型
* @param <T> 目标泛型
* @return 目标实体集合
*/
public static <S, T> List<T> convertList(List<S> sourceEntityList, Class<T> targetClass) {
return convertList(sourceEntityList, targetClass, null);
}
/**
* 字段不一致集合转换函数 (需要字段映射)
*
* @param sourceEntityList 源实体集合
* @param targetClass 目标类对象
* @param refMap 配置源类与目标类不同字段名映射
* @param <S> 源泛型
* @param <T> 目标泛型
* @return 目标实体集合
*/
public static <S, T> List<T> convertList(List<S> sourceEntityList, Class<T> targetClass, Map<String, String> refMap) {
if (sourceEntityList == null) {
return null;
}
if (sourceEntityList.size() == 0) {
return new ArrayList<>(0);
}
return classMap(sourceEntityList.get(0).getClass(), targetClass, refMap).mapAsList(sourceEntityList, targetClass);
}
/**
* 字段属性转换
* @param source 源类
* @param target 目标类
* @param refMap 属性转换
*/
public static <V, P> void register(Class<V> source, Class<P> target,Map<String, String> refMap){
if (CollectionUtils.isEmpty(refMap)) {
FACTORY.classMap(source, target).byDefault().register();
} else {
ClassMapBuilder<V, P> classMapBuilder = FACTORY.classMap(source, target);
refMap.forEach(classMapBuilder::field);
classMapBuilder.byDefault().register();
}
}
/**
* 属性名称一致可用
* @param source 源数据
* @param target 目标对象
* @return OrikaUtils
*/
private static <V, P> OrikaUtils classMap(Class<V> source, Class<P> target) {
return classMap(source, target, null);
}
/**
* 属性名称不一致可用
*
* @param source 原对象
* @param target 目标对象
* @return OrikaUtils
*/
private static synchronized <V, P> OrikaUtils classMap(Class<V> source, Class<P> target, Map<String, String> refMap) {
String key = source.getCanonicalName() + ":" + target.getCanonicalName();
if (CACHE_MAPPER.containsKey(key)) {
return new OrikaUtils(CACHE_MAPPER.get(key));
}
register(source,target,refMap);
MapperFacade mapperFacade = FACTORY.getMapperFacade();
CACHE_MAPPER.put(key, mapperFacade);
return new OrikaUtils(mapperFacade);
}
/**
* Orika复制对象
* @param source 源数据
* @param target 目标对象
* @return target
*/
private <V, P> P map(V source, Class<P> target) {
return mapper.map(source, target);
}
/**
* 复制List
* @param source 源对象
* @param target 目标对象
* @return P
*/
private <V, P> List<P> mapAsList(List<V> source, Class<P> target) {
return CollectionUtils.isEmpty(source) ? Collections.emptyList() : mapper.mapAsList(source, target);
}
}
实例应用 Service接口实现
- List<HjyCommunityDto> dtoList = hjyCommunityMapper.queryList(community); 调用mapper接口的查询数据方法,此时的接收类型是DTO
- 利用stream流方式将dto数据集合,调用OrikaUtils 工具类的转换方法convert() 转换成HjyCommunityVo 作为service接口方法的返回类型
/**
* 获取小区下拉列表
* @param community
* @return: com.msb.hjycommunity.community.domain.vo.HjyCommunityVo
*/
List<HjyCommunityVo> queryPullDown(HjyCommunity community);
@Override
public List<HjyCommunityVo> queryPullDown(HjyCommunity community) {
List<HjyCommunityDto> dtoList = hjyCommunityMapper.queryList(community);
List<HjyCommunityVo> voList = dtoList.stream().map(dto -> {
//对象拷贝
HjyCommunityVo communityVo = OrikaUtils.convert(dto, HjyCommunityVo.class);
return communityVo;
}).collect(Collectors.toList());
return voList;
}
反射方式
- 通过反射给 caseProblemListVO对象属性赋值
- 这里举例通过map循环赋值,注意目标对象与源对象的字段需要保存一致
//是获取caseProblemListVO实体对象的某一个属性,entry.getKey().trim() 就是某个属性的名字
Field field = caseProblemListVO.getClass().getDeclaredField(entry.getKey().trim());
//设置可赋值属性变量
field.setAccessible(true);
// 将entry.getValue() 赋值给caseProblemListVO类当前对象的属性变量
field.set(caseProblemListVO, entry.getValue());
BeanUtils.copyProperties浅拷贝
- 利用 spring的内置API :BeanUtils.copyProperties ,传参(源端对象,目标对象),即可实现复制到目标对象值 这里也是需要属性名一致
package com.utils;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import org.springframework.beans.BeanUtils;
import java.util.List;
import java.util.Map;
/**
* MyBeanUtils
*
*/
/**
* 对象之间的转换工具类
*
* @see JsonUtils
*/
public class MyBeanUtils {
// 浅拷贝
/**
* shallowCopy
*
* @param source source
* @param target target
*/
public static void shallowCopy(Object source, Object target) {
BeanUtils.copyProperties(source, target);
}
/**
* 强转为List(常用于强转前端参数)
*
* @param obj 实际类型为List的Object
*/
public static <T> List<T> castList(Object obj) {
String json = JsonUtils.objectToJson(obj);
return JSONObject.parseObject(json, new TypeReference<List<T>>(){});
}
/**
* 强转为Map(常用于强转前端参数)
*
* @param obj 实际类型为Map的Object
*/
public static <K,V> Map<K,V> castMap(Object obj) {
String json = JsonUtils.objectToJson(obj);
return JSONObject.parseObject(json, new TypeReference<Map<K,V>>(){});
}
}