屬性復制神器-mapstruct


我們之前說到項目中會用到各種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的原理是基於第二種方法,但是它只用寫一個接口和方法,會自動生成實現類,工作量和第一種相當,效率和第二種方法一樣。
 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、其它

還有其它的高級功能,自行到官網探索

 豐極
推薦關注此文作者公眾號:豐極,關注后回復“面試資料”即可獲取百度阿里美團等大廠面試資料。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM