Java开发中超好用Orika属性映射工具
本帖最后由 mabin 于 2024-3-14 17:39 编辑## Orika属性映射工具
### 引入pom依赖
```xml
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.4</version>
</dependency>
```
### 上干货
> 封装的工具类:`OriUtils`
```java
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.ClassMapBuilder;
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;
/**
* @Description: Orika封装的工具类
* @date 2021/7/2 16:16
* @AuThor mb
*/
public class OrikaUtils {
private static final MapperFactory FACTORY = new DefaultMapperFactory.Builder().build();
/**
* 缓存实例集合
*/
private static Map<String, MapperFacade> cacheMapper = new ConcurrentHashMap<>();
private MapperFacade mapper;
public OrikaUtils(MapperFacade mapper) {
this.mapper = mapper;
}
/**
* 转换实体函数
*
* @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 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 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 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 source
* @param target
* @param <V>
* @param <P>
* @return
*/
public static <V, P> OrikaUtils classMap(Class<V> source, Class<P> target) {
return classMap(source, target, null);
}
/**
* 属性名称一致可用
*
* @param source
* @param target
* @param <V>
* @param <P>
* @return
*/
public static synchronized <V, P> OrikaUtils classMap(Class<V> source, Class<P> target, Map<String, String> refMap) {
String key = source.getCanonicalName() + ":" + target.getCanonicalName();
if (cacheMapper.containsKey(key)) {
return new OrikaUtils(cacheMapper.get(key));
}
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();
}
MapperFacade mapperFacade = FACTORY.getMapperFacade();
cacheMapper.put(key, mapperFacade);
return new OrikaUtils(mapperFacade);
}
/**
* 复制对象
*
* @param source
* @param target
* @param <V>
* @param <P>
* @return
*/
public <V, P> P map(V source, Class<P> target) {
return mapper.map(source, target);
}
/**
* 复制List
*
* @param source
* @param target
* @param <V>
* @param <P>
* @return
*/
public <V, P> List<P> mapAsList(List<V> source, Class<P> target) {
return CollectionUtils.isEmpty(source) ? Collections.emptyList() : mapper.mapAsList(source, target);
}
}
```
> 演示示例:
>
> - 单个对象属性映射
> - List集合属性映射
```java
// 单个对象属性映射
Map<String, String> refMap = new HashMap<>(2);
// 属性名的对应关系(属性名不一致的情况下使用)
refMap.put("postId", "blogId");
Comment com = OrikaUtils.convert(comment, Comment.class, refMap);
```
```java
@Override
public List<ResponseSimpleTopic> queryTopicList(Integer desc) {
if (desc.equals(1)) {
return baseMapper.queryTopicList();
}
LambdaQueryWrapper<Topic> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.select(Topic::getId, Topic::getTopicName);
List<Topic> topics = this.list(queryWrapper);
// List集合属性映射
return OrikaUtils.classMap(Topic.class, ResponseSimpleTopic.class)
.mapAsList(topics, ResponseSimpleTopic.class);
}
``` javabean 的拷贝问题,之前还真研究过,写了一个博客,感兴趣的可以看看:https://developer.aliyun.com/article/1403855?spm=a2c6h.24874632.expert-profile.112.2c9834e4HCseiV
大多数开发场景来说 ,BeanCopier + 缓存, 是最优解, 为六边形解决方案。 a928418 发表于 2024-3-14 16:45
这个和原生的BeanUtils有什么区别!?
apache和spring的BeanUtils工具,都是基于反射特性进行的,大数据量时,性能堪忧,而且都是浅拷贝的
这个orika带有自定义转换器,不同名属性也可拷贝,而且是深拷贝,性能也更优 可以可以,学习一下 直接 Mapstruct走起:lol 这个框架支持深拷贝吗? houzhanwu 发表于 2024-3-14 13:10
直接 Mapstruct走起
相比 Mapstruct 的话,减少了各种Mapper实例的配置,但是性能方面,还是 Mapstruct 最顶{:301_1000:} Lidaigua229 发表于 2024-3-14 16:14
也就是简化了部分操作,但牺牲了一定的性能
一定程度上是这样的 这个工具类不错 可以,挺不错。 学到了,去研究研究,看看底层原理是啥 :victory: