MapStruct入门笔记,取代BeanUtils.copy(source,target)
官网地址:
https://mapstruct.org/
官网文档:
https://mapstruct.org/documentation/reference-guide/
选择相应版本 HTML 或 PDF 形式文档查看即可。
V1.2.0 HTML地址:
https://mapstruct.org/documentation/1.2/reference/html/
我第一次用的是1.3.1版本,但是插件不可用,降级尝试1.2.0,完美。
...
<properties>
<org.mapstruct.version>1.2.0.Final</org.mapstruct.version>
</properties>
...
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
</dependencies>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.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>
...
官网上是:
To create a mapper simply define a Java interface with the required
mapping method(s) and annotate it with the org.mapstruct.Mapper annotation
在这里引用官网的栗子
@Mapper
public interface CarMapper {
@Mappings({
@Mapping(source = "make", target = "manufacturer"),
@Mapping(source = "numberOfSeats", target = "seatCount")
@Mapping(target = "name", ignore = true)
})
CarDto carToCarDto(Car car);
@Mapping(source = "name", target = "fullName")
PersonDto personToPersonDto(Person person);
}
1,@Mapper 注解,表示MapStruct要会去实现该接口
1,@Mapping 有多个时,需要使用@Mappings(),否则会报错,如下
2,如果source对象中属性与target对象中属性字段名一致,会自动映射对应属性,而不需要@Mapping指定。如果不一致则需要指定。
3,如果有某个属性不想映射,可以加 ignore=true
4,类型转换
4.1 int 转 String
@Mapper
public interface CarMapper {
@Mapping(source = "price", numberFormat = "$#.00")
CarDto carToCarDto(Car car);
@IterableMapping(numberFormat = "$#.00")
List<String> prices(List<Integer> prices);
}
4.2 BigDecimal 转 String
@Mapper
public interface CarMapper {
@Mapping(source = "power", numberFormat = "#.##E0")
CarDto carToCarDto(Car car);
}
4.3 date 转 String 指定格式
@Mapper
public interface CarMapper {
@Mapping(source = "manufacturingDate", dateFormat = "dd.MM.yyyy")
CarDto carToCarDto(Car car);
@IterableMapping(dateFormat = "dd.MM.yyyy")
List<String> stringListToDateList(List<Date> dates);
}
在执行程序或插件compiler后,检查是否有自动生成的一个implement实现接口CarMapper,这个文件在target目录下,最快的方式是全局搜索CarMapper,定位CarMapperImpl。如果此文件存在,表示映射可用。
如果在执行程序或compiler插件的过程中build failure,需要先解决问题啦。我遇到的问题以及解决方法将在下一篇笔记汇总。
官网上是:
The @Mapper annotation causes the MapStruct code generator to create
an implementation of the CarMapper interface during build-time.
自动生成的代码如下:
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( engineTtoEngineDto( 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;
}
}
映射添加好了,接下来怎么用呢?
继续看文档,文档中提到两种方式,一种是使用Mappers Factory(默认),一种是使用依赖注入
1,声明一个映射接口
@Mapper
public interface CarMapper {
CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
CarDto carToCarDto(Car car);
}
Or
声明一个抽象的映射接口 (1.3.1版本支持)
@Mapper
public abstract class CarMapper {
public static final CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
CarDto carToCarDto(Car car);
}
然后在service层就可以调用了
Car car = ...;
CarDto dto = CarMapper.INSTANCE.carToCarDto( car );
在映射接口上注解@Mapper后添加属性componentModel,与Spring框架结合,所以我在代码中添加@Mapper(componentModel=“spring”),下面是官网中的栗子
@Mapper(componentModel = "cdi")
public interface CarMapper {
CarDto carToCarDto(Car car);
}
在service层,使用@Autowired就可以注入,
@Autowired
private CarMapper mapper;
在官网中,给出的栗子是这样的:
@Inject
private CarMapper mapper;
并且启动程序会发现,在自动生成的代码中,也就是在接口的实现类上会自动生成注解 @Component
@Component
public class ThirlDtoMapperImpl implements ThirlDtoMapper {
... ...
}
end