⚡效率工具⚡ - 推荐一款对象映射神器「MapStruct」,后端值得拥有!!!

⚡前言

工作中常常出现的一种情况是,我们需要把 Entity/PO/DTO/VO/QueryParam 之间做转换,解决这类问题的工具有很多,如 OrikaBeanUtilsHutool工具包,为何对 MapStruct 情有独钟,用来单独推荐呢?

⚡简介

MapStruct是一个生成类型安全,高性能且无依赖的JavaBean映射代码的注解处理器

怎么理解呢,对于BeanUtil来说,映射主要是靠反射来实现,当有大量的拷贝时,意味着大量的使用了反射,效率相对低下,就连《阿里巴巴开发手册》中也明确提到,不准使用BeanUtils

 众所周知,效率最快的当然是手写的get(),set(),当然开发效率也是最慢的,而MapStruct通过编译器编译生成常规的方法,我们通过写接口和注解就可以手动帮我们生成get()、set()代码,效率不知提高了多少倍。MapStruct映射效率本人已经体会,再项目种也运用到了,确实很好用,所以很推荐。

具体性能测试已经有人做过实验了,可以参考这篇文章:《5种常见Bean映射工具的性能对比》

⚡示例

首先引入MapStruct的依赖

Maven:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.4.2.Final</version>
</dependency>

在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>
            <path>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct-processor</artifactId>
                <version>1.4.2.Final</version>
            </path>
            <path>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.12</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

现有两个实体类

@Data
public class Student {
    String name;
    Integer age;
    String idCard;
    Date birthDay;
}
@Data
public class StudentVO {
    String name;
    Integer studentAge;
    String idCard;
    String birthDay;
}

 场景1:单个对象之间的映射 / 批量映射

按照需求,我们要把Studen对象转换为StudentVo对象,其中student.age要映射到studenVo.studentAge中,而student.idCard在这次查询中无需显示,student.birthDay格式成字符串再传入studentVo.birthDay中

我们只需要创建一个接口:

@Component
@Mapper(componentModel = "spring")
public interface StudentConverter {
    
    @Mapping(target = "studentAge", source = "age")
    @Mapping(target = "idCard", ignore = true)
    StudentVO studentToStudentVO(Student student);
    
    List<StudentVO> studentToStudentVO(List<Student> students);
}

使用:

@RestController
public class TestController {

    @Autowired
    private StudentConverter studentConvert ;

    @GetMapping("/test")
    public void beanConvertTest() {
        Student student = new Student();
        student.setName("张三");
        student.setAge(18);
        student.setIdCard("123456");
        student.setBirthDay(new Date());

        StudentVO studentVO = studentConvert.studentToStudentVO(student);
        System.out.println(studentVO);
        
        List<Student> students = Collections.singletonList(student);
        List<StudentVO> studentVOS = studentConvert.studentToStudentVO(students);
        System.out.println(studentVOS);
    }
}

输出结果:

 场景2:多个对象映射为一个

有时候会出现要将多个对象映射为一个对象的情况,而多个对象之间可能有重复的字段,这个根据@Mapping注解就能灵活解决

现有新增一个类Address.class,其中name字段和student.name是重复字段

@Data
public class Address {
    String name;
    String address;
}

需求是在场景1的基础上,将address字段加到VO对象中,但是name字段得用Student.class的。

我们可以通过source参数来设置需要映射的字段来自于哪个实例,接口方法如下:

@Mapping(target = "studentAge", source = "student.age")
@Mapping(target = "idCard", ignore = true)
@Mapping(target = "birthDay", source = "student.birthDay", dateFormat = "yyyy-MM-dd HH:mm:ss")
@Mapping(target = "name", source = "student.name")
StudentVO studentAndAddressToVO(Student student, Address address);

注意:对于上面的例子,多个对象映射为一个对象时,只有student 和address中重复的字段,或者字段名不一样的映射,才需要用注解告诉MapStruct,到底要使用哪个来源的字段。

GitHub上的实例

  • mapstruct-lombok:展示了如何将 MapStruct 与 Lombok 一起使用(使用 Mavenpom.xml和 Gradlebuild.gradle);要构建示例项目,请运行mvn clean install./gradlew clean build在命令行上运行
  • mapstruct-clone:展示了如何通过定义所有映射方法来深度克隆对象。

还有更多示例,可以参看官方实例仓库,https://github.com/mapstruct/mapstruct-examples

⚡其他注意事项

  • 如果项目中也同时使用到了Lombok,一定要注意Lombok的版本要等于或者高于1.18.10,否则会有编译不通过的情况发生
  • 如果接口的存放包为mapper,可能与Mybatis冲突会导致项目跑不起来
  • 当两个对象属性不一致时,比如Student对象中某个字段不存在于StudentVO当中时,在编译时会有警告提示,可以在@Mapping中配置 ignore = true,当字段较多时,可以直接在@Mapper中设置unmappedTargetPolicy属性或者unmappedSourcePolicy属性为 ReportingPolicy.IGNORE即可

⚡总结

  • 若是字段少,写起来也不麻烦,就没必要用框架了,手写get()/set() 就好了,技术不应该为用而用,应该为了解决对应的问题而用
  • 若是字段多,转换不频繁,为省事就用BeanUtils吧,稍微复杂点的场景也可以使用 Hutool工具包BeanUtils,提供的拷贝选项要多一些
  • 字段多又转换频繁,从性能方面考虑,还是从高性能的工具中选一个用吧,比如本文推荐的MapStruct

⚡参考文献

        -- 常用开发库-MapStruct工具详解

希望本文章能帮助那些为此发愁不知用什么映射工具的朋友们提供帮助,如果觉得不错,给作者留下关注,用小手点点赞吧!!   你的点赞动力,就是作者出更多好的作品的动力!!!!

作者:筱白爱学习!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

筱白爱学习

你的鼓励将是我写作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值