mabin 发表于 2024-3-14 09:43

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);
    }
```

Naylor 发表于 2024-11-21 11:33

javabean 的拷贝问题,之前还真研究过,写了一个博客,感兴趣的可以看看:https://developer.aliyun.com/article/1403855?spm=a2c6h.24874632.expert-profile.112.2c9834e4HCseiV

大多数开发场景来说 ,BeanCopier + 缓存, 是最优解, 为六边形解决方案。

mabin 发表于 2024-3-14 17:12

a928418 发表于 2024-3-14 16:45
这个和原生的BeanUtils有什么区别!?

apache和spring的BeanUtils工具,都是基于反射特性进行的,大数据量时,性能堪忧,而且都是浅拷贝的

这个orika带有自定义转换器,不同名属性也可拷贝,而且是深拷贝,性能也更优

xiaoyi151 发表于 2024-3-14 13:10

可以可以,学习一下

houzhanwu 发表于 2024-3-14 13:10

直接   Mapstruct走起:lol

code2t 发表于 2024-3-14 13:21

这个框架支持深拷贝吗?

mabin 发表于 2024-3-14 15:36

houzhanwu 发表于 2024-3-14 13:10
直接   Mapstruct走起

相比 Mapstruct 的话,减少了各种Mapper实例的配置,但是性能方面,还是 Mapstruct 最顶{:301_1000:}

mabin 发表于 2024-3-14 16:26

Lidaigua229 发表于 2024-3-14 16:14
也就是简化了部分操作,但牺牲了一定的性能

一定程度上是这样的

icookie1314 发表于 2024-3-14 17:15

这个工具类不错

starryskyhello 发表于 2024-3-16 09:48

可以,挺不错。

sihehe 发表于 2024-3-28 16:55

学到了,去研究研究,看看底层原理是啥 :victory:
页: [1] 2 3
查看完整版本: Java开发中超好用Orika属性映射工具