MapStruct

MapStruct的介绍:

       MapStruct是一个属性映射工具,只需要定义一个 Mapper 接口,MapStruct 就会自动实现这个映射接口,避免了复杂繁琐的映射实现。 

        在一个JavaWeb工程中会涉及到多种对象,po、vo、dto、entity、do、domain这些定义的对象运用在不同的场景模块中,这种对象与对象之间的互相转换,就需要有一个专门用来解决转换问题的工具。以前是通过反射的方法实现,但是现在无论是 BeanUtils, BeanCopier 等在使用反射的时候都会影响到性能,再后来自己写装换器但是会很浪费时间, 而且在添加新的字段的时候也要进行方法的修改。

        MapSturct 是一个生成类型安全, 高性能且无依赖的 JavaBean 映射代码的注解处理器。作为一个工具类,相比于手写, 其具有便捷, 不容易出错的特点。

MapStruct的使用

引入pom依赖和配置编译时指定注解处理器

...
<properties>
    <org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
</properties>
...
<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
</dependencies>
...
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
              <compilerArgs>
            <compilerArg>
                -Amapstruct.suppressGeneratorTimestamp=true
            </compilerArg>
            <compilerArg>
                -Amapstruct.suppressGeneratorVersionInfoComment=true
            </compilerArg>
        </compilerArgs>
            </configuration>
        </plugin>
    </plugins>
</build>
 
 

        在使用过程中需要只需要配置完成后运行 mvn compile就会发现 target文件夹中生成了一个mapper接口的实现类。打开实现类会发现实体类中自动生成了字段一一对应的get、set方法的文件。 比如我定义一个MapStruct接口

@Mapper
public interface BoMapper {
    BoMapper INSTANCE = Mappers.getMapper(BoMapper.class);

    /**
     * AdvertInfoResult -> AdvertResponseDTO
     * @param advertInfoResult
     * @return
     */
    AdvertResponseDTO advertToDTO(AdvertInfoResult advertInfoResult);

}

编译之后你会发现target多了一个实现类,类似于我们手写

 功能强大的MapStruct框架,它的好处呢,就是既生成了代码,比较直观方便debug。又支持非常多且强大的注解,可以轻松做到多层级之间字段映射、字段ignore、日期格式化、金额格式化等。还有mapping模版继承复用、组合等功能。还有就是天然支持Spring注入,SpringBoot集成等,在这一点上,相比较Dozer式的xml映射,注解是更符合现代编程方式的。

MapStruct 中注解的关键词

@Mapper 只有在接口加上这个注解, MapStruct 才会去实现该接口
    @Mapper 里有个 componentModel 属性,主要是指定实现类的类型,有如下4种方式
    default: 这是默认的情况,MapStruct不使用任何组件类型, 可以通过Mappers.getMapper(Class)方式获取自动生成的实例对象。
    cdi: the generated mapper is an application-scoped CDI bean and can be retrieved via @Inject。
    spring: 生成的实现类上面会自动添加一个@Component注解,可以通过Spring的 @Autowired方式进行注入。
    jsr330: 生成的实现类上会添加@javax.inject.Named 和@Singleton注解,可以通过 @Inject注解获取。

@Mapping:属性映射,若源对象属性与目标对象名字一致,会自动映射对应属性
    source:源属性
    target:目标属性
    dateFormat:String 到 Date 日期之间相互转换,通过 SimpleDateFormat,该值为 SimpleDateFormat 的日期格式
    numberFormat:数值格式化, 例:"0.00"
    expression: 自定义java代码实现属性映射
    ignore: 忽略这个字段
@Mappings:配置多个@Mapping
@MappingTarget 用于更新已有对象
@InheritConfiguration 用于继承配置
@IterableMapping 用于迭代映射
@MapMapping 支持map转map

MapStruct 转换方式

1.属性名称相同,则进行转化。

这种类似于BeanUtils转换的方式。

2.属性名不相同, 可通过 @Mapping 注解进行指定转化。

例 @Mapping(source = “numberOfSeats”, target = “seatCount”)

3.Mapper 中使用自定义的转换

对于某些类型, 无法通过代码生成器的形式来进行处理,就需要自定义的方法来进行转换。利用java8新特性,在接口中定义一个默认方法。

 default CarDto carToCarDto2(Car car) {
    if (car == null) {
        return null;
    }
    CarDto carDto = new CarDto();
    carDto.setMake("China:" + car.getMake());
    carDto.setSeatCount(car.getNumberOfSeats());
    return carDto;
}

4.多个对象装换成一个对象

Car car1 = new Car( "测试", 10 );
Brand brand = new Brand( "bwm", "宝马" );

CarDto toCarDto = CarMapper.INSTANCE.carToCarDto(car, brand);

5. 隐式类型转换

@Mapper
public interface CarMapper {

    @Mapping(source = "price", numberFormat = "$#.00")
    CarDto carToCarDto(Car car);

    @IterableMapping(numberFormat = "$#.00")
    List<String> prices(List<Integer> prices);
}

6. MapStruct 支持来自Java Collection Framework 的各种可迭代类型

@Mapper
public interface CarMapper {

    Set<String> integerSetToStringSet(Set<Integer> integers);

    List<CarDto> carsToCarDtos(List<Car> cars);

    CarDto carToCarDto(Car car);
}

7. 支持map转map

public interface SourceTargetMapper {

    @MapMapping(valueDateFormat = "dd.MM.yyyy")
    Map<String, String> longDateMapToStringStringMap(Map<Long, Date> source);
}
@Mapper
public interface VoMapper {
    VoMapper INSTANCE = Mappers.getMapper(VoMapper.class);

    @MapMapping(valueTargetType = ImageInfo.class)
    Map<String, List<ImageInfo>> mapToMap(Map<String, List<ImageInfoDTO>> map);
}
@Mapper
public interface VoMapper {
    VoMapper INSTANCE = Mappers.getMapper(VoMapper.class);

    ImageInfo imageToVo(ImageInfoDTO imageInfoDTO);

    @MapMapping(valueTargetType = ImageInfo.class)
    Map<String, ImageInfo> mapToMap(Map<String, ImageInfoDTO> map);

    @Named("imageListToVoLst")
    default List<ImageInfo> imageListToVoList(List<ImageInfoDTO> list){
        return list.stream().map(it -> imageToVo(it)).collect(Collectors.toList());
    }

    @MapMapping(valueQualifiedByName = "imageListToVoLst")
    Map<String, List<ImageInfo>> mapToMapList(Map<String, List<ImageInfoDTO>> map);
}

注意:

  • 当多个对象中, 有其中一个为 null, 则会直接返回 null
  • 当多个原对象中,有相同名字的属性时,需要通过 @Mapping 注解来具体的指定, 以免出现歧义
  • 我个人感觉目前对于Map类型的数据转换不是很方便,感觉可读性和易用性会差一些

更多用法等你挖掘

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值