天天看點

MapStruct使用指北mapstruct是什麼?為什麼要使用mapstruct?如何使用?

mapstruct官方文檔連結,點選跳轉

mapstruct是什麼?

MapStruct 是一個代碼生成器,它基于約定優于配置方法極大地簡化了 Java bean 類型之間映射的實作。

生成的映射代碼使用簡單的方法調用,是以速度快、類型安全且易于了解。

為什麼要使用mapstruct?

多層應用程式通常需要在不同的對象模型(例如實體和 DTO)之間進行映射。編寫這樣的映射代碼是一項繁瑣且容易出錯的任務。MapStruct 旨在通過盡可能自動化來簡化這項工作。

與其他映射架構相比,MapStruct 在編譯時生成 bean 映射,這確定了高性能,允許快速的開發人員回報和徹底的錯誤檢查。

如何使用?

MapStruct 是一個注釋處理器,它被插入到 Java 編譯器中,可以在指令行建構(Maven、Gradle 等)中使用,也可以在 IDE 中使用。MapStruct 使用合理的預設值,但在配置或實作特殊行為時會避開您的方式。

入門案例

引入maven依賴

...
<properties>
    <org.mapstruct.version>1.5.3.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.8.1</version>
            <configuration>
                <source>1.8</source> <!-- depending on your project -->
                <target>1.8</target> <!-- depending on your project -->
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                    <!-- other annotation processors -->
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>
           

實體類

/**
 * @author 雲川
 * @description: 車 實體類
 * @date 2023/2/14 22:51
 */
public class Car {

    private String make;
    private int numberOfSeats;
    private CarType type;

    public Car() {
    }

    public Car(String make, int numberOfSeats, CarType type) {
        this.make = make;
        this.numberOfSeats = numberOfSeats;
        this.type = type;
    }

    public String getMake() {
        return make;
    }

    public void setMake(String make) {
        this.make = make;
    }

    public int getNumberOfSeats() {
        return numberOfSeats;
    }

    public void setNumberOfSeats(int numberOfSeats) {
        this.numberOfSeats = numberOfSeats;
    }

    public CarType getType() {
        return type;
    }

    public void setType(CarType type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "Car{" +
                "make='" + make + '\'' +
                ", numberOfSeats=" + numberOfSeats +
                ", type=" + type +
                '}';
    }
}
           

CartType枚舉類

/**
 * @author 雲川
 * @description: 車的類型枚舉值
 * @date 2023/2/14 22:52
 */
public enum CarType {
    TYPE_A, TYPE_B, TYPE_C;
}

           

DTO類

/**
 * @author 雲川
 * @description: 車 dto類
 * @date 2023/2/14 23:01
 */
public class CarDto {

    private String make;
    private int seatCount;
    private String type;

    public CarDto() {
    }

    public CarDto(String make, int seatCount, String type) {
        this.make = make;
        this.seatCount = seatCount;
        this.type = type;
    }

    public String getMake() {
        return make;
    }

    public void setMake(String make) {
        this.make = make;
    }

    public int getSeatCount() {
        return seatCount;
    }

    public void setSeatCount(int seatCount) {
        this.seatCount = seatCount;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "CarDto{" +
                "make='" + make + '\'' +
                ", seatCount=" + seatCount +
                ", type='" + type + '\'' +
                '}';
    }
}

           

建立映射器接口

上面的Car類和CarDTO這兩種類型非常相似

不同點:

  1. 隻是座位數屬性的名稱不同
  2. type 屬性在Car類中是一個引用類型,Car但在 DTO 中是一個普通字元串。

現在想要把Car對象轉換成CarDto對象,通過mapstruct實作,首先需要定義一個Mapper轉換器

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

/**
 * @author 雲川
 * @description: 轉換器
 * @date 2023/2/14 23:07
 */
@Mapper
public interface CarMapper {

    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );

    @Mapping(source = "numberOfSeats", target = "seatCount")
    CarDto carToCarDto(Car car);
}
           
MapStruct使用指北mapstruct是什麼?為什麼要使用mapstruct?如何使用?

使用映射器

基于映射器接口,用戶端可以以非常簡單且類型安全的方式執行對象映射:

/**
 * @author 雲川
 * @description: 測試類
 * @date 2023/2/14 23:22
 */
public class MapStructTest {
    @Test
    public void shouldMapCarToDto() {
        //given
        Car car = new Car( "Morris", 5, CarType.TYPEA );

        //when
        CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );

        //then
        System.out.println(carDto);
    }
}
           

結果:

MapStruct使用指北mapstruct是什麼?為什麼要使用mapstruct?如何使用?

檢視編譯自動生成的接口實作類

可以看到編譯之後自動生成了個實作類

MapStruct使用指北mapstruct是什麼?為什麼要使用mapstruct?如何使用?

位元組碼檔案反編譯:

public class CarMapperImpl implements CarMapper {
    public CarMapperImpl() {
    }

    public CarDto carToCarDto(Car car) {
        if (car == null) {
            return null;
        } else {
            CarDto carDto = new CarDto();
            carDto.setSeatCount(car.getNumberOfSeats());
            carDto.setMake(car.getMake());
            if (car.getType() != null) {
                carDto.setType(car.getType().name());
            }

            return carDto;
        }
    }
}

           

MapStruct的原理是生成和我們自己寫的代碼一樣的代碼,這意味着這些值是通過簡單的

getter/setter

調用而不是反射或類似的方法從

source

類複制到

target

類的。使得MapStruct的性能會比動态架構更加優秀