欢迎光临
我们一直在努力

性能爆棚的实体转换复制工具MapStruct如何使用

这篇“性能爆棚的实体转换复制工具MapStruct如何使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“性能爆棚的实体转换复制工具MapStruct如何使用”文章吧。

    引言

    Java项目中实体转换无处不在,当实体字段较多或者大批量的进行复制时,通过手工setter/getter显得太LOW,同时兼备高性能要求情况下,MapStruct完全完全能够胜任。官方解释,MapStruct是一个代码生成器,它基于约定优于配置的方法,极大地简化了Java bean类型之间映射的实现。生成的映射代码使用普通方法调用,因此快速、类型安全且易于理解。因为MapStruct是在编译期间生成setter/getter方法,实际运行时就是直接调用setter/getter,效率会非常高。

    优点

    • MapStruct编译期生成映射代码,所以可以在编译时暴露映射错误的代码,让错误提前暴露;

    • 因为使用setter/getter方式,而非反射方式,所以可以更快的执行效率;

    • 可以实现深拷贝,自动类型转换,如枚举转换;

    • 进行自定义的映射,多种映射方式,下边具体说明;

    性能对比

    对比对象 10个对象复制1次 1万个对象复制1次 100万个对象复制1次 100万个对象复制5次
    MapStruct 0ms 3ms 96ms 281ms
    Hutools的BeanUtil 23ms 102ms 1734ms 8316ms
    Spring的BeanUtils 2ms 47ms 726ms 3676ms
    Apache的BeanUtils 20ms 156ms 10658ms 52355ms
    Apache的PropertyUtils 5ms 68ms 6767ms 30694ms

    使用

    依赖

    <!-- MapStruct核心,包含了一些必要的注解-->
    <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.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <annotationProcessorPaths>
                        <!-- MapStruct编译,注解处理器,根据注解自动生成Mapper的实现 -->
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${org.mapstruct.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>

    定义转换接口

    /**
     * 测试接口
     *
     * @author reboot
     */
    @Mapper
    public interface OrderConvertor {
        /**
         * 实例
         */
        OrderConvertor INSTANCE = Mappers.getMapper(OrderConvertor.class);
        /**
         * OrderDo -> OrderModel
         *
         * @param orderDo 订单实体
         * @return {@link OrderModel}
         */
        OrderModel toModel(OrderDo orderDo);
        /**
         * OrderDo -> OrderModel
         *
         * @param orderDos 订单实体
         * @return {@link OrderModel}
         */
        List<OrderModel> toModel(List<OrderDo> orderDos);
        /**
         * OrderModel -> OrderDo
         *
         * @param orderModel 订单模型
         * @return {@link OrderDo}
         */
        OrderDo toDo(OrderModel orderModel);
        /**
         * OrderModel -> OrderDo
         *
         * @param orderModels 订单模型
         * @return {@link OrderDo}
         */
        List<OrderDo> toDo(List<OrderModel> orderModels);
    }

    编译结果

    MapStruct会自动生成对应接口的实现,并自动完成属性映射关系,List会自动进行批量处理。

    调用

    /**
     * 订单服务
     *
     * @author reboot
     */
    @Service
    public class OrderService {
        /**
         * 获取订单列表
         *
         * @return {@link List}<{@link OrderModel}>
         */
        public List<OrderModel> getOrderList() {
            // 获取数据库数据DO
            List<OrderDo> result = selectOrderList();
            // 参数转换
            return OrderConvertor.INSTANCE.toModel(result);
        }
    }

    插件

    上边的使用方式虽然能够正常使用,但是在一些属性配置映射上和提示上,如果使用插件能够提升使用体验,IDEA中可以直接安装Mapstruct Support插件,当然Eclipse也有对应的插件。

    特性

    • 突出显示目标属性和源属性。将目标属性和源属性转到声明的setter / getter中;

    • 错误和快速修复:

      • 缺少@Mapper或@MapperConfig注解检查;

      • 快速修复未映射的目标属性,添加未映射目标属性和忽略未映射目标属性;

    其他用法

    更加详细的内容可以查看官方文档,发布文章时最新版本是 MapStruct 1.5.3.Final.html。

    基础映射

    @Mapper
    public interface CarMapper {
        @Mapping(target = "manufacturer", source = "make")
        @Mapping(target = "seatCount", source = "numberOfSeats")
        CarDto carToCarDto(Car car);
        @Mapping(target = "fullName", source = "name")
        PersonDto personToPersonDto(Person person);
    }

    target表示目标属性名,source表示源属性名,一般在目标属性和源属性不同时使用,相同的属性名会自动进行映射。

    映射器添加自定义方法

    @Mapper
    public interface CarMapper {
        @Mapping(...)
        ...
        CarDto carToCarDto(Car car);
        default PersonDto personToPersonDto(Person person) {
            //hand-written mapping logic
        }
    }

    自定义方法personToPersonDto并实现,在生成的实现类中会进行覆盖使用。

    多个源参数映射

    @Mapper
    public interface AddressMapper {
        @Mapping(target = "description", source = "person.description")
        @Mapping(target = "houseNumber", source = "address.houseNo")
        DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address);
        @Mapping(target = "description", source = "person.description")
        @Mapping(target = "houseNumber", source = "hn")
        DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Integer hn);
    }

    存在多个源参数,使用参数名.属性名的方式进行表示,也可以直接使用基础类型的属性名称。

    嵌套属性映射到当前目标

    @Mapper
     public interface CustomerMapper {
         @Mapping( target = "name", source = "record.name" )
         @Mapping( target = ".", source = "record" )
         @Mapping( target = ".", source = "account" )
         Customer customerDtoToCustomer(CustomerDto customerDto);
     }

    当源参数中存在对象属性,可以手动进行映射,或者直接使用"."的方式将对象中的属性全部映射到当前目标对象。

    表达式方式

    @Mapper
    public interface SourceTargetMapper {
        SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );
        @Mapping(
            target = "timeAndFormat",
            expression = "java( new org.sample.TimeAndFormat( s.getTime(), s.getFormat() ) )"
        )
        Target sourceToTarget(Source s);
    }

    支持使用java代码块进行转换,一般可以将静态方法处理的字段放到这里。

    更新现有实例

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

    @MappingTarget源参数,编译时会将carDto参数中的属性映射到car参数中。

    Map映射

    @Mapper
    public interface CustomerMapper {
        @Mapping(target = "name", source = "customerName")
        Customer toCustomer(Map<String, String> map);
    }

    直接将map中的key进行映射。

    更多用法

    还有更多其他用法,比如:

    • 支持映射定义的public属性;

    • 支持映射参数Builder模式;

    • 使用注入方式引入转换器;

    • 数据类型字段转换,如枚举、日期,支持日期格式化,支持数字类型格式化,具体可以看 Implicit type conversions;

    • 集合类型自动转换;

    • 转换Stream。

    以上就是关于“性能爆棚的实体转换复制工具MapStruct如何使用”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注云搜网行业资讯频道。

    赞(0)
    【声明】:本博客不参与任何交易,也非中介,仅记录个人感兴趣的主机测评结果和优惠活动,内容均不作直接、间接、法定、约定的保证。访问本博客请务必遵守有关互联网的相关法律、规定与规则。一旦您访问本博客,即表示您已经知晓并接受了此声明通告。