小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
上文我们已经从官方文档处了解了 MapStruct 的简单介绍,本文我们将从实例出发,动手带大家了解它的使用情况。
简单实现
我们注意到官网中有涉及到简单样例的实现,我们用2分钟来分析一波:
1. 引入依赖
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.3.0.Final</version>
</dependency>
//注解处理器,根据注解自动生成mapper的实现
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.2.0.Final</version>
</dependency>
我们在编译时会报
java: No property named "numberOfSeats" exists in source parameter(s). Did you mean "null"?
错误,经过查阅资料发现mapstruct-processor
和Lombok
的版本需要统一一下:mapstruct-processor
:1.2.0.Final
,Lombok
:1.16.14
。
2. 准备实体类 Car.java
和 数据传输类 CarDto.java
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Car {
private String make;
private int numberOfSeats;
private CarType type;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CarDto {
private String make;
private int seatCount;
private String type;
}
3. 创建映射器接口,里边定义映射方法
@Mapper
public interface CarMapper {
CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
@Mapping(source = "numberOfSeats", target = "seatCount")
CarDto carToCarDto(Car car);
}
解析分析:
@Mapper
将接口标记为映射接口,并允许MapStruct
处理器在编译期间启动。这里的@Mapper
注解不是mybatis
的注解,而是org.mapstruct.Mapper
的;- 实际映射方法
carToCarDto()
期望源对象Car
作为参数,并返回目标对象CarDto
,方法名可以自由选择; - 对于源对象和目标对象中具有不同名称的属性,可以使用
@Mapping
注释来配置名称; - 对于源对象和目标对象中具有不同类型的属性,也可以使用
@Mapping
注释来进行转换,比如:类型属性将从枚举类型转换为字符串; - 一个接口中可以有多个映射方法,对于所有的这些方法,
MapStruct
将生成一个实现; - 该接口的实现实例可以从
Mappers
中获得,接口声明一个INSTANCE
,为客户端提供对映射器实现的访问。
4. 实现类
我们可以将代码进行编译,然后会发现在 target
文件中生成了 CarMapperImpl.class
文件:
从代码中可以看出 MapStruct
为我们自动生成了 set/get
代码,并且对枚举类进行了特殊处理。
5. 客户端
@Test
public void shouldMapCarToDto() {
Car car = new Car( "Morris", 5, CarType.SEDAN );
CarDto carDto = CarMapper.INSTANCE.carToCarDto( car );
System.out.println(carDto);
}
执行结果:
小结:
MapStruct
基于mapper
接口,在编译期动态生成set/get
代码的class
文件 ,在运行时直接调用该class
文件。
这个简单的案例你掌握了吗?下文我们将抽丝剥茧,深入研究他的使用情况!如果你有不同的意见或者更好的idea
,欢迎联系阿Q,添加阿Q可以加入技术交流群参与讨论呦!