Java对象转换工具-orika

1.概述

Orika是java Bean映射框架,可以实现从一个对象递归拷贝数据至另一个对象,它使用字节码生成器创建开销最小的快速映射,比其他基于反射方式实现更快。对于名称不相同或类型不一样,则需要单独映射

2.实战演练

2.1环境准备

新建一个SpringBoot的项目,导入需要的依赖

<dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
</dependency>
 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
</dependency>

2.2引入orika

1)导入依赖

<dependency>
     <groupId>ma.glasnost.orika</groupId>
     <artifactId>orika-core</artifactId>
     <version>1.5.1</version>
</dependency>

2)创建对象UserDto,作为源对象

package com.zxh.test;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserDto {
    private String id;
    private String name;
    private Integer age;
}

3)创建对象UserVo,作为目标对象

package com.zxh.test;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserVo {
    private String id;
    private String name;
    private Integer userAge;
}

4)编写容器注入类,避免重复创建映射工厂类

package com.zxh.test.config;

import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MapperFactoryAutoWire {

    @Bean
    public MapperFactory getFactory(){
        return new DefaultMapperFactory.Builder().build();
    }

}

2.3与dozer的比较

由于后面章节会对其方法进行封装,故这里直接与dozer进行对比

    //注入
    @Resource
    private ma.glasnost.orika.MapperFactory mapperFactory;

    @Test
    public void test() {
        Integer t = 1000000;
        List<UserDto> list = new ArrayList<>();
        for (int i = 0; i < t; i++) {
            UserDto userDto = new UserDto("10" + i, "", 20);
            list.add(userDto);
        }
        StopWatch watch = new StopWatch();
        watch.start("orika");
        // 因为存在字段不一样,需要手动映射一下。如果所有字段一样,则不用写mapperFactory.classMap()方法
        mapperFactory.classMap(UserDto.class, UserVo.class)
                .field("age", "userAge")//不一样的字段映射,源字段->目标字段
                .byDefault()
                .register();
        list.stream().forEach(item -> {
            UserVo userVo = mapperFactory.getMapperFacade().map(item, UserVo.class);
        });
        watch.stop();
        System.out.println("orika复制用时:" + watch.getLastTaskTimeMillis());
        watch.start("dozer");
        list.stream().forEach(item -> {
            UserVo userVo = mapper.map(item, UserVo.class);
        });
        watch.stop();
        System.out.println("dozer复制用时:" + watch.getLastTaskTimeMillis());
    }

打印的结果如下:

在上述的案例中,为了性能的比较,故分别进行100万次的对象复制,可以很明显的看出两者的性能差异,显而易见,orika的性能优于dozer。

那么orika有没有对集合的快速复制呢?答案是有,下面使用普通的foreach和其自带的集合复制进行对比:

    @Test
    public void test9() {
        Integer t = 100000;
        List<UserDto> list = new ArrayList<>();
        for (int i = 0; i < t; i++) {
            UserDto userDto = new UserDto("10" + i, "", 20);
            list.add(userDto);
        }
        StopWatch watch = new StopWatch();
        // 因为存在字段不一样,需要手动映射一下。如果所有字段一样,则不用写mapperFactory.classMap()方法
        mapperFactory.classMap(UserDto.class, UserVo.class)
                .field("age", "userAge")//不一样的字段映射,源字段->目标字段
                .byDefault()
                .register();

        watch.start("orika1");
        list.stream().forEach(item -> {
            UserVo userVo = mapperFactory.getMapperFacade().map(item, UserVo.class);
        });
        watch.stop();
        System.out.println("orika-map复制用时:" + watch.getLastTaskTimeMillis());
        watch.start("orika2");
        List<UserVo> userVos = mapperFactory.getMapperFacade().mapAsList(list, UserVo.class);
        watch.stop();
        System.out.println("orika-list复制用时:" + watch.getLastTaskTimeMillis());
    }

打印的结果如下:

虽然只进行了10万次的复制,但性能就显现出来了。

3.封装使用

package com.zxh.test.util;

import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.metadata.ClassMapBuilder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author zhongyushi
 */
@Component
public class OrikaUtil {
    @Resource
    private MapperFactory mapperFactory;

    /**
     * 字段映射
     *
     * @param aType  源对象类型
     * @param bType  目标对象类型
     * @param fields 不同字段映射值
     * @param <A>
     * @param <B>
     */
    private <A, B> void filedMap(Class<A> aType, Class<B> bType, Map<String, String> fields) {
        ClassMapBuilder<A, B> mapBuilder = mapperFactory.classMap(aType, bType);
        if (fields != null && fields.size() > 0) {
            Set<Map.Entry<String, String>> entries = fields.entrySet();
            for (Map.Entry<String, String> entry : entries) {
                mapBuilder.field(entry.getKey(), entry.getValue());
            }
        }
        mapBuilder.byDefault().register();
    }

    /**
     * 对象的复制
     *
     * @param aType  源对象类型
     * @param bType  目标对象类型
     * @param fields 不同字段映射值
     * @param source 要复制的对象
     * @param <A>
     * @param <B>
     * @return
     */
    public <A, B> B beanCopy(Class<A> aType, Class<B> bType, Map<String, String> fields, A source) {
        filedMap(aType, bType, fields);
        B target = mapperFactory.getMapperFacade().map(source, bType);
        return target;
    }

    /**
     * 对象的复制
     *
     * @param aType  源对象类型
     * @param bType  目标对象类型
     * @param source 要复制的对象
     * @param <A>
     * @param <B>
     * @return
     */
    public <A, B> B beanCopy(Class<A> aType, Class<B> bType, A source) {
        return beanCopy(aType, bType, null, source);
    }

    /**
     * 集合的复制
     *
     * @param aType  源对象类型
     * @param bType  目标对象类型
     * @param fields 不同字段映射值
     * @param source 要复制的对象
     * @param <A>
     * @param <B>
     * @return
     */
    public <A, B> List<B> beanListCopy(Class<A> aType, Class<B> bType, Map<String, String> fields, Iterable<A> source) {
        filedMap(aType, bType, fields);
        List<B> bList = mapperFactory.getMapperFacade().mapAsList(source, bType);
        return bList;
    }

    /**
     * 集合的复制
     *
     * @param aType  源对象类型
     * @param bType  目标对象类型
     * @param source 要复制的对象
     * @param <A>
     * @param <B>
     * @return
     */
    public <A, B> List<B> beanListCopy(Class<A> aType, Class<B> bType, Iterable<A> source) {
        return beanListCopy(aType, bType, null, source);
    }
}

对其方法进行进一步的封装,在使用的地方注入使用:

    @Autowired
    private OrikaUtil orikaUtil;

    @Test
    public void test0() {
        UserDto userDto = new UserDto("10", "", 20);
        Map<String, String> map = new HashMap<>();
        map.put("age", "userAge");
        UserVo userVo = orikaUtil.beanCopy(UserDto.class, UserVo.class, map, userDto);
        System.out.println(userVo);
    }

    @Test
    public void test1() {
        Integer t = 10;
        List<UserDto> list = new ArrayList<>();
        for (int i = 0; i < t; i++) {
            UserDto userDto = new UserDto("10" + i, "", 20);
            list.add(userDto);
        }
        Map<String, String> map = new HashMap<>();
        map.put("age", "userAge");
        System.out.println(orikaUtil.beanListCopy(UserDto.class, UserVo.class, map, list));
    }

使用起来也格外的方便。

posted @ 2022-12-26 14:46  钟小嘿  阅读(1598)  评论(0编辑  收藏  举报