Skip to content

Orika

1. 概述

Orika 是一个简单、快速的 JavaBean 拷贝框架,它能够递归地将数据从一个 JavaBean 复制到另一个 JavaBean,这在多层应用开发中是非常有用的。

官方使用指南:http://orika-mapper.github.io/orika-docs/index.html

2. 基本使用

2.1 Maven 项目增加依赖包

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

2.2 A 对象复制到 B 对象

java
User userA = new User().setId(1).setName("麻子哥");

MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
User userB = mapperFactory.getMapperFacade().map(userA, User.class);

log.debug("userB - {}", userB);

上述代码中,MapperFactory 是映射工厂,用来定义转换规则(任何字段映射、注册转换器、自定义映射器、用于抽象/接口类型的具体类型)并生成 MapperFacadeMapperFacade 是映射门面,进行对象转换的实际执行器。

2.3 A 集合复制到 B 集合

java
List<User> userListA = Arrays.asList(new User().setId(1).setName("张三"));

MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
List<User> userListB = mapperFactory.getMapperFacade().mapAsList(userListA, User.class);

log.debug("userListB - {}", userListB);

3. 高级用法

3.1 对象属性名称不一致

java
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();

mapperFactory.classMap(User.class, UserVo.class)
    .field("name", "userName")
    .field("age", "ageOne")
    .exclude("secretKey")
    .byDefault()
    .register();

UserVo userVo = mapperFactory.getMapperFacade().map(userA, UserVo.class);
  • classMap(A, B) 方法定义了相互转换的类,不分源对象和目标对象。

  • field("name", "fullName") 表示 A、B 类中 name 和 fullName 字段的双向映射,如果只想要 A 对象 name 赋值给 B 对象的 fullName,则需要使用 fieldAToB("fullName", "name")

  • byDefault() 方法表示当 A、B 对象的字段名一致时,自动赋值,如果没有该方法则不会赋值。

  • exclude("secretKey") 显示地排除了 secretKey 字段的赋值。

3.2 集合中属性名称不一致

同对象属性名称不一致的处理,只不过最后一行代码中调用的 map() 方法替换为 mapAsList()

java
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();

mapperFactory.classMap(User.class, UserVo.class)
    .field("name", "userName")
    .field("age", "ageOne")
    .exclude("secretKey")
    .byDefault()
    .register();

List<UserVo> userVos = mapperFactory.getMapperFacade().mapAsList(userListA, UserVo.class);

3.3 指定需要使用的特定构造函数

orika 提供了 constructorAconstructorB 方法用于使用有参构造器生成新类,例如下面的代码中在生成 A 对象时优先使用构造方法 public BasicPerson(Long id, String name) 完成。

java
mapperFactory.classMap(BasicPerson.class, BasicPersonDto.class)
   .constructorA("id", "name")
   //...
   .register();

3.4 映射嵌套字段

嵌套属性可以使用“.”来引用,例如 BasicPerson 对象中的姓名是一个对象 private Name name,可以使用下面语法进行字段值的转换。

java
mapperFactory.classMap(BasicPerson.class, BasicPersonDto.class)
   .field("name.first", "firstName")
   .register();

3.5 使用 BoundMapperFacade

如果需要频繁进行 AB 对象的转换,可以使用特定的 BoundMapperFacade 以追求更好的性能。

java
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();

// 设置该facade是由ApproveSubmitRequest向ApprovalEntry转换
BoundMapperFacade<ApproveSubmitRequest, ApprovalEntry> facade = mapperFactory
    .getMapperFacade(ApproveSubmitRequest.class, ApprovalEntry.class);

// 进行字段映射
ApprovalEntry entry = facade.map(request);

3.6 自定义转换规则

有时候,我们不是要简单的转换,比如说我们希望转换后的 brand 统一变成大写,那么这个时候,我们就可以自定义转换规则做些额外的处理。

java
OrderDTO orderDTO = new OrderDTO("1", "kfc", "南京路", "666");

DefaultMapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();

// 如果存在字段名不一致,手动告诉orika他们之间的映射关系
mapperFactory.classMap(OrderDTO.class,OrderDO.class)
    .field("orderId","id")
    .field("mobile","phone")
    .field("orderItem.itemId","orderItem.id")
    .byDefault()
    // 自定义我们的转换规则
    .customize(new CustomMapper<OrderDTO, OrderDO>() {
        @Override
        public void mapAtoB(OrderDTO orderDTO, OrderDO orderDO, MappingContext context) {
            // 将品牌转换成大写
            orderDO.setBrand(orderDTO.getBrand().toUpperCase(Locale.ROOT));
        }
    })
    .register();

OrderDO order = mapperFactory.getMapperFacade().map(orderDTO, OrderDO.class);

System.out.println(order);