当我们定义多层架构时,我们往往会针对不同层级定义不同的实体对象。如DTO、Entity(DO)以及VO。从而不同对象之间的转换就成为了头等大事。
在充血模型中,我们一般会把转换方法放入具体对象中。
classDiagram
class Dto {
Vo toVo()
Entity toEntity()
}
class Vo {
Dto toDto()
}
class Entity {
Dto toDto()
}
然而也有部分情况下我们会专门引入转换类来负责对象之间的转换。
classDiagram
class Dto
class Vo
class Entity
class Converter {
Vo toVo(Dto dto)
Dto toDto(Entity entity)
Entity toEntity(Dto dto)
}
针对每一个实体模型,我们都要单独形成Convertor类来负责对象之间的转换关系(数据映射)。所以一个好用的动态映射框架对我们提高代码效率有很大的益处。
MapStruct
根据我的Java开发经验,我非常喜欢 MapStruct ,它不仅仅可以帮我快速做好对象之间的映射关系、还可以把一些过程数据构造、格式转换等操作一并处理,让我更关注于业务代码本身。
MapStruct 是用于生成类型安全的映射Bean类的Java注释处理器。
与动态映射框架对比,MapStruct 能够带来以下优势:
- 通过使用普通方法调用而不是反射所以执行速度更快
- 编译时类型的安全性:只能映射限定的属性,不会超边界映射对象
- 如果映射有问题会在在构建阶段指出明确的错误
就如我所说,这个 MapStruct 能做到的事情非常多,对我来说目前为止我只用到了它的皮毛。所以我想通过一个系列,从头开始学习整理 MapStruct 的官方文档。
安装
凡事从安装开始!
MapStruct是基于JSR 269的Java注释处理器,因此可以在命令行构建(Javac,Ant,Maven等)以及IDE内部使用。
Maven
如果你的构建工具是Maven,你需要在你的pom.xml文件使用MapStruct依赖,如下:
...
<properties>
<org.mapstruct.version>1.4.2.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>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
...
Grandle
将以下内容添加到你的gradle构建文件中:
...
plugins {
...
id "com.diffplug.eclipse.apt" version "3.26.0" // Only for Eclipse
}
dependencies {
...
implementation "org.mapstruct:mapstruct:${mapstructVersion}"
annotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"
// If you are using mapstruct in test code
testAnnotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"
}
...
定义 Mapper
我们来定义一个最基础的Mapper吧。
@Mapper
public ixnterface CarMapper {
@Mapping(source = "make", target = "manufacturer")
@Mapping(source = "numberOfSeats", target = "seatCount")
CarDto carToCarDto(Car car);
@Mapping(source = "name", target = "fullName")
PersonDto personToPersonDto(Person person);
}
构建后,MapStruct自动给我们生成映射的实现类
// GENERATED CODE
public class CarMapperImpl implements CarMapper {
@Override
public CarDto carToCarDto(Car car) {
if ( car == null ) {
return null;
}
CarDto carDto = new CarDto();
if ( car.getFeatures() != null ) {
carDto.setFeatures( new ArrayList<String>( car.getFeatures() ) );
}
carDto.setManufacturer( car.getMake() );
carDto.setSeatCount( car.getNumberOfSeats() );
carDto.setDriver( personToPersonDto( car.getDriver() ) );
carDto.setPrice( String.valueOf( car.getPrice() ) );
if ( car.getCategory() != null ) {
carDto.setCategory( car.getCategory().toString() );
}
carDto.setEngine( engineToEngineDto( car.getEngine() ) );
return carDto;
}
@Override
public PersonDto personToPersonDto(Person person) {
//...
}
private EngineDto engineToEngineDto(Engine engine) {
if ( engine == null ) {
return null;
}
EngineDto engineDto = new EngineDto();
engineDto.setHorsePower(engine.getHorsePower());
engineDto.setFuel(engine.getFuel());
return engineDto;
}
}
是不是很神奇?这是官方最快捷的案例。其实要弄懂MapStruct的映射规则以及编写机制,我们可以大大提高日常开发过程中的对象转换效率。让我们的代码更加简洁更关注于业务模型的设计工作当中,告别这些繁琐的转换类的编写。
今天就带大家看到这里。咱们下期继续深入学习MapStruct。