使用 orika 干掉 get,set

简介

我们在业务中,经常需要转换对象,来解决各种 POJO,VO,DTO 之间的转换,在不使用工具类的情况下,需要写大量的 Get,Set 方法,代码看起来很臃肿.现在也有很多工具类可以让我们来使用,解决这个问题,常用的有 mapstruct、Spring BeanUtils、Apache BeanUtils、dozer 等,今天要介绍的是 orika

Orika是一个简单、快速的JavaBean拷贝框架,它能够递归地将数据从一个JavaBean复制到另一个JavaBean,这在多层应用开发中是非常有用的。Orika 底层采用了javassist类库生成Bean映射的字节码,之后直接加载执行生成的字节码文件,因此在速度上比使用反射进行赋值会快很多

使用

要使用 orika 实现需要添加他的依赖

<!--  复制类工具      -->
<dependency>
    <groupId>ma.glasnost.orika</groupId>
    <artifactId>orika-core</artifactId>
    <version>1.4.6</version>
</dependency>
复制代码

定义两个实体类 user 和 userVo 用来转换

@Data
public class User {

    private Integer id;
    private String name;
    private String phone;
    private Integer age;
    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
    private Date date;
}
复制代码
@Data
public class UserVo {

    private Integer id;
    private String name;
    private String telephone;
    private String myAge;
    private String date;
    private String addr;
    private String ip;
    
}
复制代码

编写一个测试方法 使用 orika

@GetMapping("/testOrika")
public HttpResult testOrika() {
    User user = new User();
    user.setId(1);
    user.setName("哈哈");
    user.setPhone("1234567");
    user.setAge(18);
    user.setDate(DateUtil.date());
    System.out.println("user:"+user);
    MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
    UserVo userVo = mapperFactory.getMapperFacade().map(user, UserVo.class);
    System.out.println("userVo:"+userVo);
    return HttpResult.ok(userVo);
}
复制代码

执行结果 image.png

可以看到字段名一致的都可以映射到,并且date类的时间也成功转换成字符串的时间

那么怎么把字段不一致的也映射到对应的字段里呢,毕竟平时不同实体类字段名经常是不一致的

不同字段名映射

@GetMapping("/testOrika")
public HttpResult testOrika() {
    User user = new User();
    user.setId(1);
    user.setName("哈哈");
    user.setPhone("1234567");
    user.setAge(18);
    user.setDate(DateUtil.date());
    System.out.println("user:"+user);
    MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
    mapperFactory.classMap(User.class,UserVo.class)
                .field("phone","telephone")
                .field("age","myAge")
                .byDefault().register();
    UserVo userVo = mapperFactory.getMapperFacade().map(user, UserVo.class);
    System.out.println("userVo:"+userVo);
    return HttpResult.ok(userVo);
}
复制代码

在这里添加了字段的映射 结果:

image.png

可以看到不同字段名也映射到了数据

当我们反过来映射数据用 userVo 转换 user 测试

@GetMapping("/testOrika2")
public HttpResult testOrika2() {
    UserVo userVo = new UserVo();
    userVo.setId(1);
    userVo.setName("哈哈");
    userVo.setTelephone("123456");
    userVo.setMyAge("20");
    userVo.setDate("2021-12-01 10:00:00");
    userVo.setAddr("xx");
    userVo.setIp("xx");
    System.out.println("userVo:"+userVo);
    MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
    mapperFactory.classMap(UserVo.class,User.class)
            .field("telephone","phone")
            .field("myAge","age")
            .byDefault().register();
    User user = mapperFactory.getMapperFacade().map(userVo, User.class);
    System.out.println("user:"+user);
    return HttpResult.ok(user);
}
复制代码

结果:

image.png

系统报错了,出现了反射异常 这是由于用 字符串转换时间类型时无法转换导致报错.

如何解决呢,我们可以实现一个自定义转换器,来让他转换时间

实现自定义转换器

public class DateConverter extends BidirectionalConverter<String, Date> {
    @Override
    public Date convertTo(String str, Type<Date> date) {
        return DateUtil.parseDateTime(str);
    }

    @Override
    public String convertFrom(Date date, Type<String> type) {
        return DateUtil.formatDateTime(date);
    }
}
复制代码

实现 BidirectionalConverter 类 重写他里面的方法,自定义返回结果

改造一下 testOrika2 方法

@GetMapping("/testOrika2")
public HttpResult testOrika2() {
    UserVo userVo = new UserVo();
    userVo.setId(1);
    userVo.setName("哈哈");
    userVo.setTelephone("123456");
    userVo.setMyAge("20");
    userVo.setDate("2021-12-01 10:00:00");
    userVo.setAddr("xx");
    userVo.setIp("xx");
    System.out.println("userVo:"+userVo);
    MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
    mapperFactory.getConverterFactory().registerConverter("dateConverter",new DateConverter());
    mapperFactory.classMap(UserVo.class,User.class)
            .field("telephone","phone")
            .field("myAge","age")
            .fieldMap("date","date").converter("dateConverter").add()
            .byDefault().register();
    User user = mapperFactory.getMapperFacade().map(userVo, User.class);
    System.out.println("user:"+user);
    return HttpResult.ok(user);
}
复制代码

执行结果:

image.png

可以看到时间也成功转换了

orika 还可以直接转换集合 更多的方法可以去他的官网了解 orika-mapper.github.io/orika-docs/…

可以自己封装工具类使用

public class BeanCopyUtil {

    /**
     * 
     * @param sourceObject 数据源
     * @param destinationClass 要转换的数据类型
     * @param <S>
     * @param <D>
     * @return
     */
    public static <S,D>D map(S sourceObject, Class<D> destinationClass) {
        MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
        MapperFacade mapperFacade = mapperFactory.getMapperFacade();
        return mapperFacade.map(sourceObject,destinationClass);
    }

    /**
     * 
     * @param sourceObject 数据源
     * @param destinationClass 要转换的数据类型
     * @param converter 类型转换器
     * @param converMap 要转换的字段集合
     * @param <S>
     * @param <D>
     * @return
     */
    public static <S,D>D map(S sourceObject, Class<D> destinationClass, BidirectionalConverter converter, Map<String, String> converMap) {
        MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
        if (converter != null && !converMap.isEmpty()) {
            mapperFactory.getConverterFactory().registerConverter("dateConverter",new DateConverter());
            ClassMapBuilder<?, D> classMapBuilder = mapperFactory.classMap(sourceObject.getClass(), destinationClass);
            for (Map.Entry<String, String> entry : converMap.entrySet()) {
                classMapBuilder.fieldMap(entry.getKey(),entry.getValue()).converter("dateConverter").add();
            }
            classMapBuilder.byDefault().register();
        }
        MapperFacade mapperFacade = mapperFactory.getMapperFacade();
        return mapperFacade.map(sourceObject,destinationClass);
    }

    /**
     * 
     * @param sourceObject 数据源
     * @param destinationClass 要转换的数据类型
     * @param fieldMap 不同名的字段映射集合
     * @param <S>
     * @param <D>
     * @return
     */
    public static <S,D>D map(S sourceObject, Class<D> destinationClass, Map<String, String> fieldMap) {
        MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
        if (!fieldMap.isEmpty()) {
            ClassMapBuilder<?, D> classMapBuilder = mapperFactory.classMap(sourceObject.getClass(), destinationClass);
            for (Map.Entry<String, String> entry : fieldMap.entrySet()) {
                classMapBuilder.field(entry.getKey(),entry.getValue());
            }
            classMapBuilder.byDefault().register();
        }
      return mapperFactory.getMapperFacade().map(sourceObject,destinationClass);
    }

    /***
     * 
     * @param sourceObject 数据源
     * @param destinationClass 要转换的数据类型
     * @param fieldMap 不同名的字段映射集合
     * @param converter 类型转换器
     * @param converMap 要转换的字段集合
     * @param <S>
     * @param <D>
     * @return
     */
    public static <S,D>D map(S sourceObject, Class<D> destinationClass, Map<String, String> fieldMap, BidirectionalConverter converter, Map<String, String> converMap) {
        MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
        ClassMapBuilder<?, D> classMapBuilder = mapperFactory.classMap(sourceObject.getClass(), destinationClass);
        if (!fieldMap.isEmpty()) {
            for (Map.Entry<String, String> entry : fieldMap.entrySet()) {
                classMapBuilder.field(entry.getKey(),entry.getValue());
            }
        }
        if (converter != null && !converMap.isEmpty()) {
            mapperFactory.getConverterFactory().registerConverter("dateConverter",new DateConverter());
            for (Map.Entry<String, String> entry : converMap.entrySet()) {
                classMapBuilder.fieldMap(entry.getKey(),entry.getValue()).converter("dateConverter").add();
            }
        }
        classMapBuilder.byDefault().register();
        return mapperFactory.getMapperFacade().map(sourceObject,destinationClass);
    }
}
复制代码

猜你喜欢

转载自juejin.im/post/7036965055061032996