Java项目整合MapStruct

Java项目整合MapStruct

作为一个Java开发程序员,在编写代码的过程中,几乎不能避免不同对象之间的映射和转换,无论是一对一还是一对多的映射,一般都是DO/DTO/VO/ENTITY之间的映射。

市面上也有很多这样的工具,如BeanUtils、Hutool、Dozer工具包等,但是各个工具的效率和性能也是良莠不齐,大家可以参考如下这篇文章。

从上文的真实测试中,我们可以知道,性能最好的就是MapStruct。

简而言之, MapStruct 是一个生成类型安全,高性能且无依赖的,基于约定优于配置的JavaBean映射代码的注解处理器。

下面我们就介绍一下 MapStruct 的常用操作。

POM配置

POM配置如下。

JDK版本号是11.0.17。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ylz</groupId>
    <artifactId>mapstruct-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mapstruct-demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <jdk11.version>11</jdk11.version>
        <mapstruct-version>1.5.3.Final</mapstruct-version>
        <lombok>1.18.24</lombok>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${mapstruct-version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${jdk11.version}</source>
                    <target>${jdk11.version}</target>
                    <annotationProcessorPaths>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>${lombok}</version>
                        </path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${mapstruct-version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

代码结构

代码结果如下图。

我们首先创建Student实体类以及对应的StudentDTO类。

Student.java代码如下。

package com.ylz.mapstruct.domain.entity;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
public class Student {
    private Long id;
    private String name;
    private String idCard;
    private LocalDate birthday;

StudentDTO.java代码如下。

package com.ylz.mapstruct.domain.dto;
import lombok.Data;
import java.time.LocalDate;
@Data
public class StudentDTO {
    private Long userId;
    private String userName;
    private String idNumber;
    private LocalDate dateOfBirth;
}

示例代码

IStudentConvert.java代码如下。

package com.ylz.mapstruct.domain.convert;
import com.ylz.mapstruct.domain.dto.StudentDTO;
import com.ylz.mapstruct.domain.entity.Student;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
public interface IStudentConvert {
    IStudentConvert INSTANCE = Mappers.getMapper(IStudentConvert.class);
    @Mapping(source = "id", target = "userId")
    @Mapping(source = "name", target = "userName")
    @Mapping(source = "idCard", target = "idNumber")
    @Mapping(source = "birthday", target = "dateOfBirth")
    StudentDTO student2StudentDTO(Student student);
    @Mapping(source = "userId", target = "id")
    @Mapping(source = "userName", target = "name")
    @Mapping(source = "idNumber", target = "idCard")
    @Mapping(source = "dateOfBirth", target = "birthday")
    Student studentDTO2Student(StudentDTO studentDTO);

单元测试代码如下。

package com.ylz.mapstruct;
import com.ylz.mapstruct.domain.convert.IStudentConvert;
import com.ylz.mapstruct.domain.dto.StudentDTO;
import com.ylz.mapstruct.domain.entity.Student;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDate;
@SpringBootTest
class MapstructDemoApplicationTests {
    @Test
    void test() {
        StudentDTO studentDTO = new StudentDTO();
        studentDTO.setUserId(0L);
        studentDTO.setUserName("jack");
        studentDTO.setIdNumber("1111");
        studentDTO.setDateOfBirth(LocalDate.now());
        System.out.println(IStudentConvert.INSTANCE.studentDTO2Student(studentDTO));
        Student student = new Student();
        student.setId(1L);
        student.setName("michael");
        student.setIdCard("22222");
        student.setBirthday(LocalDate.now());
        System.out.println(IStudentConvert.INSTANCE.student2StudentDTO(student));

在执行单元测试仿方法之前,还有关键一步要操作—— 编译

我们可以通过命令行方式编译,也可以通过上图双击compile按钮编译。

编译完成后,在上图中的指定目录会生成一个IStudentConvertImpl.class类,其代码如下所示。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
package com.ylz.mapstruct.domain.convert;
import com.ylz.mapstruct.domain.dto.StudentDTO;
import com.ylz.mapstruct.domain.entity.Student;
public class IStudentConvertImpl implements IStudentConvert {
    public IStudentConvertImpl() {
    public StudentDTO student2StudentDTO(Student student) {
        if (student == null) {
            return null;
        } else {
            StudentDTO studentDTO = new StudentDTO();
            studentDTO.setUserId(student.getId());
            studentDTO.setUserName(student.getName());
            studentDTO.setIdNumber(student.getIdCard());
            studentDTO.setDateOfBirth(student.getBirthday());
            return studentDTO;
    public Student studentDTO2Student(StudentDTO studentDTO) {
        if (studentDTO == null) {
            return null;
        } else {
            Student student = new Student();
            student.setId(studentDTO.getUserId());
            student.setName(studentDTO.getUserName());