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这两种类型非常相似
不同点:
- 只是座位数属性的名称不同
- 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);
}
使用映射器
基于映射器接口,客户端可以以非常简单且类型安全的方式执行对象映射:
/**
* @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);
}
}
结果:
查看编译自动生成的接口实现类
可以看到编译之后自动生成了个实现类
字节码文件反编译:
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的性能会比动态框架更加优秀