当前位置: 首页 > 工具软件 > Orika > 使用案例 >

Orika做对象映射或者说对象Bean的复制转换

窦华晖
2023-12-01

一、Orika介绍

        Orika是java Bean映射框架,可以实现从一个对象递归拷贝数据至另一个对象。在开发多层应用程序中非常有用。在这些层之间交换数据时,通常为了适应不同API需要转换一个实例至另一个实例。

        有很多方法可以实现:硬代码拷贝或Dozer实现bean映射等。总之,需要简化不同层对象之间映射过程。

        Orika使用字节码生成器创建开销最小的快速映射,比其他基于反射方式实现(如,Dozer)更快。之前使用Bean Copy 性能非常慢,发现在这个领域业界还是有很多新秀的。 Orika 应该就算一个比较好的吧。

优势:

  1. 简单
      Orika的代码短小精悍, 而且可读性非常强, Dozer如果要加减一个功能, 不才完全没有信心, Orika 我还是可以偶尔在Orika里面打几个酱油的。

  2. 内存消耗
      大概是Dozer内存消耗的一半多点。 为什么做到这点的还没想清楚, 估计是因为运行期不需要维护复杂的Mapping 关系。 不需要大量的Mapping 关系查找以及需要的对这些查找优化所消耗的空间。

  3. 性能
      大概是Dozer的8-10 倍, 这个上面的已经做了描述

二、项目引入Orika

  • Maven项目依赖包:POM文件直接依赖进去即可。
<dependency>
    <groupId>ma.glasnost.orika</groupId>
    <artifactId>orika-core</artifactId>
    <version>1.4.2</version>
</dependency>
  • 创建mapperFactory对象,然后注册转换对象或者规则
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();

mapperFactory.classMap(类名.class, 类名2.class)
.field("属性", "属性2")
.field("属性a", "属性a2")
.byDefault().register();
  • 集合的话使用使用mapAsList
List<XxxVo> xxxVos = mapperFactory.getMapperFacade().mapAsList(当前对象, XxxVo.class);

三、使用

简单使用

  • 创建两个Bean对象,用于复制使用。

UserVo

@Data //Set GET方法
@Accessors(chain = true)
public class UserVo {
private String id;
private String name;
}

User

@Data
@Accessors(chain = true)
public class User {
private String id;
private String name;
}

1.A对象复制到B对象(对象复制)

//业务场景,将A对象复制B对象中
//1.普通逻辑处理
User A = new User().setId("123").setName("1231");
UserVo B = new UserVo().setId(A.getId()).setName(A.getName());
System.out.println("普通方式将A对象复制B对象中:"+B);
 
//使用orika复制工具将A复制到B对象中
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
UserVo map = mapperFactory.getMapperFacade().map(A, UserVo.class);
System.out.println("orika复制对象:"+map);

2.A集合复制到B集合(集合复制)

//1.普通逻辑处
//A对象
List<User> A = Arrays.asList(new User().setId("123").setName("张三"));
//B对象
List<UserVo> B = new ArrayList<>();
//将A集合数据复制到B集合中
A.forEach(x->{
B.add( new UserVo().setId(x.getId()).setName(x.getName()));
});
System.out.println("将A集合中数据set到B集合中数据打印");
 
//使用orika复制工具将A集合复制到B集合中
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
List<UserVo> userVo = mapperFactory.getMapperFacade().mapAsList
mapperFactory.getMapperFacade().mapAsList(A, UserVo.class);
System.out.println("orika直接复制对象集合打印结果:"+userVo);

高级使用方法

  • 创建两个Bean对象,用于复制使用。

UserVo对象

@Data //Set GET方法
@Accessors(chain = true)
public class UserVo {
private String id;
private String userName;
private int ageOne;
}

User对象

@Data
@Accessors(chain = true)
public class User {
private String id;
private String name;
private int age;
}

1.A对象复制到B对象,对象中属性不一样时

//业务场景,将A对象复制B对象中,A对象中的字段与B对象中的字段不一致
//1.普通逻辑处理
User A = new User().setId("123").setName("张三").setAge(20);
UserVo B = new UserVo().setId(A.getId()).setUserName(A.getName()).setAgeOne(A.getAge());
System.out.println("普通方式将A对象处理B对象中:"+B);.
 
//使用orika复制工具将A复制到B对象中
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
mapperFactory.classMap(User.class, UserVo.class)
.field("name", "userName")
.field("age", "ageOne")
.byDefault().register();
UserVo userVo = mapperFactory.getMapperFacade().map(A, UserVo.class);
System.out.println("orika复制对象:"+userVo);

2.A集合对象复制到B集合对象,对象中属性不一样时

//1.普通逻辑处里A对象中与B对象字段不一致处理
//A对象
List<User> A = Arrays.asList(new User().setId("123").setName("张三").setAge(20));
//B对象
List<UserVo> B = new ArrayList<>();
//将A集合数据复制到B集合中
A.forEach(x->{
B.add(new UserVo().setId(x.getId()).setUserName(x.getName()).setAgeOne(x.getAge()));
});
System.out.println("将A集合中数据set到B集合中数据打印"+B);
 
//使用orika复制工具将A集合复制到B集合中
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
mapperFactory.classMap(User.class, UserVo.class)
.field("name", "userName")
.field("age", "ageOne")
.byDefault().register();
List<UserVo> userVos = mapperFactory.getMapperFacade().mapAsList(A, UserVo.class);
System.out.println("orika复制对象:"+userVos);
  • 关键步骤!!!
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
mapperFactory.classMap(User.class, UserVo.class)
.field("name", "userName")
.field("age", "ageOne")
.byDefault().register();
//集合复制--使用mapAsList
List<UserVo> userVos = mapperFactory.getMapperFacade().mapAsList(A, UserVo.class);
//对象复制--使用map
UserVo userVos = mapperFactory.getMapperFacade().map(A, UserVo.class);
  • 当遇到复杂的两个对象属性类型不一致,或者存在json、对象类型时

思路是:先注册转化处理的converter,然后再调用注册对象。

例如:

 
mapperFactory
            .getConverterFactory()
            .registerConverter("bookTypeConvert", new BidirectionalConverter<BookType, Byte>() {
                @Override
                public Byte convertTo(BookType bookType, Type<Byte> type, MappingContext mappingContext) {
                    return bookType.getVal();
                }
                @Override
                public BookType convertFrom(Byte aByte, Type<BookType> type, MappingContext mappingContext) {
                    return BookType.getSelf(aByte);
                }
            });
 

这样orika每次看到 BookType和 Byte之间的转化就会使用这个转换器来“拷贝”值了。

对于Json 和 String类型的转换,我定义了一个更加通用的Convert,这里Json的序列化工具使用的是fastjson

 
public class JsonConfigConvert<T> extends BidirectionalConverter<T, String> {
    @Override
    public String convertTo(T source, Type<String> destinationType, MappingContext mappingContext) {
        return JSON.toJSONString(source);
    }
    @Override
    public T convertFrom(String source, Type<T> destinationType, MappingContext mappingContext) {
        return JSON.parseObject(source, destinationType.getRawType());
    }
}
 

在配置中这样写:

 
mapperFactory
            .getConverterFactory()
            .registerConverter("bookInfoConvert", new JsonConfigConvert<BookInfo>());
 
mapperFactory
            .classMap(BookEntity.class, BookDTO.class)
            .field("authorName", "author.name")
            .field("authorBirthday", "author.birthday")
            .fieldMap("type", "bookType").converter("bookTypeConvert").add()
            .fieldMap("bookInformation", "bookInfo").converter("bookInfoConvert").add()
            .byDefault()
            .register();
 

实例(复杂的对象间映射)

import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.MappingContext;
import ma.glasnost.orika.converter.BidirectionalConverter;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.Type;

import java.util.Date;
public class orikaTest {

    public static void main(String[] args) {
        //得到mapperFactory工厂对象
        MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
        //得到转换或者映射工厂对象,去注册转换或者映射的方法或者标签
        mapperFactory.getConverterFactory().registerConverter("bookTypeConvert", new BidirectionalConverter<BookType,Byte>() {
            @Override
            public Byte convertTo(BookType bookType, Type<Byte> type, MappingContext mappingContext) {
                return bookType.value;
            }

            @Override
            public BookType convertFrom(Byte aByte, Type<BookType> type, MappingContext mappingContext) {
                return BookType.getName(aByte);
            }
        });
        
        mapperFactory.getConverterFactory().registerConverter("bookConvert", new BidirectionalConverter<String,BookInfo>() {
            @Override
            public BookInfo convertTo(String s, Type<BookInfo> type, MappingContext mappingContext) {
                return new BookInfo(s,10);
            }

            @Override
            public String convertFrom(BookInfo bookInfo, Type<String> type, MappingContext mappingContext) {
                return bookInfo.toString();
            }
        });
        //DO
        User user = new User();
        user.setBookName("平凡的世界");
        user.setAuthorName("路遥");
        user.setAuthorBirthday(new Date());
        user.setBookInformation("一部全景式地表现中国当代城乡社会生活的百万字长篇小说");
        user.setType((byte)2);
        //声明两个对象间 映射属性并注册
        mapperFactory.classMap(User.class,UserVo.class).field("authorName","author.name")
                .field("authorBirthday","author.birthday")
                .fieldMap("type","bookType").converter("bookTypeConvert").add()
                .fieldMap("bookInformation","bookInfo").converter("bookConvert").add()
                .byDefault()
                .register();
        //User ->  UserVo
        UserVo userVo = mapperFactory.getMapperFacade().map(user, UserVo.class);
        System.out.println(userVo);

        //UserVo ->  User
        User user1 = mapperFactory.getMapperFacade().map(userVo, User.class);
        System.out.println(user1);
    }
}

相比项目中大量的setter和getter,利用orika这种操作方式显然会节约大量的代码。

 类似资料: