我们之前说到项目中会用到各种object,vo,bo,dto等等。我们需要在不同的对象上复制属性。
我们最常用的就是Common包里面的BeanUtils,或者Spring里面的BeanUtils.
BeanUtils.copyProperties(dest, orig);
还有一个PropertyUtils
PropertyUtils.copyProperties(dest, orig);
它俩区别:
BeanUtils和PropertyUtils复制对象时,根据属性名进行复制。
如果属性名相同,但类型不同,BeanUtils会直接转换; 而PropertyUtils会直接抛出异常。
上面的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的原理是基于第二种方法,但是它只用写一个接口和方法,会自动生成实现类,工作量和第一种相当,效率和第二种方法一样。
引入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" ); }
mapStruct还可以更新已有的bean
@Mapper public interface CarMapper { void updateCarFromDto(CarDto carDto, @MappingTarget Car car); }
比如int转String
@Mapper public interface CarMapper { @Mapping(source = "price", numberFormat = "$#.00") CarDto carToCarDto(Car car); @IterableMapping(numberFormat = "$#.00") List<String> prices(List<Integer> prices); }
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); }
@Mapper public interface CarMapper { Set<String> integerStreamToStringSet(Stream<Integer> integers); List<CarDto> carsToCarDtos(Stream<Car> cars); CarDto carToCarDto(Car car); }
@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); }
用这种方式就不会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); }
还有其它的高级功能,自行到官网探索
推荐关注此文作者公众号:丰极,关注后回复“面试资料”即可获取百度阿里美团等大厂面试资料。