我们之前说到项目中会用到各种object,vo,bo,dto等等。我们需要在不同的对象上复制属性。

一、BeanUtils和PropertyUtils

我们最常用的就是Common包里面的BeanUtils,或者Spring里面的BeanUtils.

BeanUtils.copyProperties(dest, orig);

还有一个PropertyUtils

PropertyUtils.copyProperties(dest, orig);

它俩区别:

  • BeanUtils和PropertyUtils复制对象时,根据属性名进行复制。

  • 如果属性名相同,但类型不同,BeanUtils会直接转换; 而PropertyUtils会直接抛出异常。

二、自己写转换Builder

上面的BeanUtils和PropertyUtils代码写起来很方便简洁,但是它的实现原理是基于反射,效率不是很高。如果是对服务响应要求很高的应用,用它们就不太合适。有一种方法,自己写转换关系,一个一个set。

public class PersonBuilder {

    public static Person newPerson(Context context) {
Person person = new Person();
person.setDelRepeat(context.getDelRepeat());
person.setSendName(context.getSendName());
person.setSendType(context.getSendType());
person.setInputMdnList(context.getInputMdnList());
person.setSceneId(context.getSceneId());
person.setGroupIdList(context.getGroupIdList());
person.setContent(context.getContent());
person.setImportFile(context.getImportFile());
return person;
} public static PersonVO newPersonVO(Context context) { ... ...

这种方法没有性能问题,但是效率不高,字段少的话工作量还行,如果字段很多,会写的很头疼

三、mapStruct

mapStruct的原理是基于第二种方法,但是它只用写一个接口和方法,会自动生成实现类,工作量和第一种相当,效率和第二种方法一样。

1、举个官方的例子

引入maven依赖包

...
<properties>
<org.mapstruct.version>1.4.0.Beta2</org.mapstruct.version>
</properties>
...
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
</dependencies>

定义Car.java

public class Car {

    private String make;
private int numberOfSeats;
private CarType type; //constructor, getters, setters etc.
}

定义CarDto.java

public class CarDto {

    private String make;
private int seatCount;
private String type; //constructor, getters, setters etc.
}

定义mapper

@Mapper
public interface CarMapper { CarMapper INSTANCE = Mappers.getMapper( CarMapper.class ); @Mapping(source = "numberOfSeats", target = "seatCount")
CarDto carToCarDto(Car car);
}

使用mapper

@Test
public void shouldMapCarToDto() {
//given
Car car = new Car( "Morris", 5, CarType.SEDAN ); //when
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car ); //then
assertThat( carDto ).isNotNull();
assertThat( carDto.getMake() ).isEqualTo( "Morris" );
assertThat( carDto.getSeatCount() ).isEqualTo( 5 );
assertThat( carDto.getType() ).isEqualTo( "SEDAN" );
}

2、更新

mapStruct还可以更新已有的bean

@Mapper
public interface CarMapper { void updateCarFromDto(CarDto carDto, @MappingTarget Car car);
}

3、支持数据类型转换

比如int转String

@Mapper
public interface CarMapper { @Mapping(source = "price", numberFormat = "$#.00")
CarDto carToCarDto(Car car); @IterableMapping(numberFormat = "$#.00")
List<String> prices(List<Integer> prices);
}

4、支持map,set,list

public interface SourceTargetMapper {

    @MapMapping(valueDateFormat = "dd.MM.yyyy")
Map<String, String> longDateMapToStringStringMap(Map<Long, Date> source);
} @Mapper
public interface CarMapper { Set<String> integerSetToStringSet(Set<Integer> integers); List<CarDto> carsToCarDtos(List<Car> cars); CarDto carToCarDto(Car car);
}

5、支持Stream

@Mapper
public interface CarMapper { Set<String> integerStreamToStringSet(Stream<Integer> integers); List<CarDto> carsToCarDtos(Stream<Car> cars); CarDto carToCarDto(Car car);
}

6、自定义origin和dest的名称

@Mapper
public interface OrderMapper { OrderMapper INSTANCE = Mappers.getMapper( OrderMapper.class ); @ValueMappings({
@ValueMapping(source = "EXTRA", target = "SPECIAL"),
@ValueMapping(source = "STANDARD", target = "DEFAULT"),
@ValueMapping(source = "NORMAL", target = "DEFAULT")
})
ExternalOrderType orderTypeToExternalOrderType(OrderType orderType);
}

7、支持自定义的工厂模式生成bean

用这种方式就不会new,而是用工厂的createXXX方法

public class DtoFactory {

     public CarDto createCarDto() {
return // ... custom factory logic
}
} public class EntityFactory { public <T extends BaseEntity> T createEntity(@TargetType Class<T> entityClass) {
return // ... custom factory logic
}
} @Mapper(uses= { DtoFactory.class, EntityFactory.class } )
public interface CarMapper { CarMapper INSTANCE = Mappers.getMapper( CarMapper.class ); CarDto carToCarDto(Car car); Car carDtoToCar(CarDto carDto);
}

8、其它

还有其它的高级功能,自行到官网探索



推荐关注此文作者公众号:丰极,关注后回复“面试资料”即可获取百度阿里美团等大厂面试资料。

属性复制神器-mapstruct的更多相关文章

  1. C#反射——模仿BeanUtil属性复制

    反射工具类请参见:https://www.cnblogs.com/threadj/p/10535796.html using System; using System.Collections.Gene ...

  2. 利用Java反射实现JavaBean对象相同属性复制并初始化目标对象为空的属性的BeanUtils

    有时遇到将数据传输对象转换成JSON串会将属性值为空的属性去掉,利用Java反射实现JavaBean对象数据传输对象的相同属性复制并初始化数据传输对象属性为空的属性,然后转换成JSON串 packag ...

  3. cp 带着属性复制过去,

    sudo cp -ra store_bak/* store/ -r   所有文件循环都复制 -a  带着属性复制过去

  4. neo4j 将一个节点的属性复制到另一个节点上

    在使用Python操作Neo4j数据库的时候,经常会遇到重复的节点,需要将一个节点的属性复制到另一个节点,之后将该节点删除. def copy_node_properties(source_node_ ...

  5. 跨浏览器复制神器 ZeroClipboard 2.x快速入门详解

    有些时候,我们希望让用户在网页上完成某个操作就能自动将指定的内容复制到用户计算机的剪贴板中.但是出于安全原因,大多数现代浏览器都未提供通用的剪贴板复制接口(或即便有,也默认被禁用).只有IE浏览器可以 ...

  6. 使用BeanUtils类实现DTO之间的同名属性复制

    开发中经常碰到这样的场景,从数据库查询出来全部的字段,但是有些字段是不想给 客户端看到,这时就需要将属性从DAO复制到传给客户端的DTO对象,如果采用get/set, 那显得很麻烦.可使用反射实现. ...

  7. bean属性复制到另外一个bean

    import org.springframework.beans.BeanUtils; BeanUtils.copyProperties(maker.getBaseInfo(), newBasInfo ...

  8. 一个高性能的对象属性复制类,支持不同类型对象间复制,支持Nullable<T>类型属性

    由于在实际应用中,需要对大量的对象属性进行复制,原来的方法是通过反射实现,在量大了以后,反射的性能问题就凸显出来了,必须用Emit来实现. 搜了一圈代码,没发现适合的,要么只能在相同类型对象间复制,要 ...

  9. Dozer 实现对象间属性复制

    使用场景:两个领域之间对象转换. 比如:在系统分层解耦过程中, 对外facade接口,一般使用VO对象,而内core业务逻辑层或者数据层通常使用Entity实体. VO对象 package com.m ...

随机推荐

  1. kworkerds挖矿木马

    昨天一朋友的公司服务器中了挖矿病毒,一起帮忙查看并做下记录.   病毒信息 名称:kworkerds 目录:/tmp/ 关键点:文件 -i 属性   i :这个i可就很厉害了.它可以让一个文件“不能被 ...

  2. 深度学习在高德ETA应用的探索与实践

    1.导读 驾车导航是数字地图的核心用户场景,用户在进行导航规划时,高德地图会提供给用户3条路线选择,由用户根据自身情况来决定按照哪条路线行驶. 同时各路线的ETA(estimated time of ...

  3. MATLAB作图之二

    "平滑"二维图像可以通过对图像进行插值实现.那么对于一条有大量"毛刺"的曲线,是不是也可以通过插值来平滑呢?答案是肯定的. "平滑"前 x ...

  4. [CF163E]e-Government

    题目   点这里看题目. 分析   首先,我们不需要真的从 AC 自动机中把串删掉.由于我们计算贡献和,我们只需要在 AC 自动机上,把已经删除的串的贡献抹掉就可以了.   接着考虑询问.这是一个很基 ...

  5. @atcoder - CODE FESTIVAL 2017 Elimination Tournament Round 3 F@ Unicyclic Graph Counting

    目录 @description@ @solution@ @accpeted code@ @details@ @description@ 求有多少 n 点 n 边的无向连通图,满足第 i 个点的度数为 ...

  6. postman发送json数据

    原文链接:https://blog.csdn.net/weixin_33387378/article/details/90721599 1.设置header  Content-Type   appli ...

  7. mingw32 exception在sjlj与dwarf差别-反汇编分析

    sjlj (setjump/longjump)与dwarf-2为mingw32两种异常处理模型的实现.sjlj有着开销,而随linux发行的mingw32开发库包都是用sjlj版编译的,而Qt却采用d ...

  8. 【String注解驱动开发】面试官让我说说:如何使用FactoryBean向Spring容器中注册bean?

    写在前面 在前面的文章中,我们知道可以通过多种方式向Spring容器中注册bean.可以使用@Configuration结合@Bean向Spring容器中注册bean:可以按照条件向Spring容器中 ...

  9. 客户端软件GUI开发技术漫谈:原生与跨平台解决方案分析

    原生开发应用开发 Microsoft阵营的 Winform WinForm是·Net开发平台中对Windows Form的一种称谓. 如果你想深入的美化UI,需要耗费很大的力气,对于目前主流的CSS样 ...

  10. Spring声明周期的学习心得

    我们首先来看下面的一个案例: 这里是 HelloWorld.java 文件的内容: package com.yiibai;    public class HelloWorld {   private ...