MapStruct的简单使用笔记
前言
我们在开发中,经常会遇到实体之间的转换问题。今天给大家带来的是如何优雅的使用mapstruct来完成实体之间的转换。
实体转换方法
手动转换
对实体的数据逐个设置,工作量比较大。
BeanUtils
直接使用spring自带的BeanUtils的copyProperties方法。会有一些性能问题
MapStruct
最近项目在使用Mapstruct,简单记录一下。
作用
主要用于 Java 中实体对象之间的转换,如(VO、DTO、PO…)
VO:用于接收前端请求参数的实体,可以扩展继承DTO或者直接使用DTO。
DTO:用于后端传输数据的实体。
PO:用于orm映射处理的实体,与表结构对应。
只需要编写一个接口,在接口上增加注解,就能够在编译期自动生成接口的实现类,实现类帮我们进行值的set操作。
官网介绍
MapStruct 是一个 Java注释处理器,用于生成类型安全的 bean 映射类。您所要做的就是定义一个映射器接口,它声明任何所需的映射方法。在编译期间,MapStruct 将生成该接口的实现。此实现使用普通 Java 方法调用来在源对象和目标对象之间进行映射,即没有反射或类似的情况。
优点
通过使用普通方法调用而不是反射来快速执行 编译时类型安全:只能映射相互映射的对象和属性,不会意外地将订单实体映射到客户 DTO 等。
在构建时清除错误报告,如果 映射不完整(并非所有目标属性都已映射) 映射不正确(找不到正确的映射方法或类型转换)
如何使用Mapstruct
官方地址
依赖引入
<properties>
<org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
</properties>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<!-- 添加mapstruct插件-->
<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>
编写接口
当两个转换实体字段和类型一直时
当你要转换的两个对象实体字段名称和类型都一样时,只需要加一个@Mapper注解即可
// 此Mapper注解为mapstruct包下的,不是ibatis中,请注意区分。
@Mapper
public interface DishConvertMapper {
DishConvertMapper INSTANCE = Mappers.getMapper(DishConvertMapper.class);
/***
* 将entity转换为Dto
* @param dish
* @return
*/
DishDto convert(Dish dish);
/***
* 将dto转换为entity
* @param dishDto
* @return
*/
Dish convert(DishDto dishDto);
}
当两个转换实体字段不同时
假设我的实体A的字段为name,实体B的字段为userName,实际上存储的数据是一样的,这时,我们需要做一个映射。
@Mappings(
{@Mapping(source = "name", target = "userName")}
)
DishDto convert(Dish dish);
当有多个字段需要做映射时,只需要再添加一个@Mapping注解即可。
数据类型转换
当两个字段的数据类型不一样时,Mapstruct支持source和target属性的类型转换。提供最基本的数据类型和包装类之间的转换。
- 基本类型及对应的包装类之间的转换:int 和Integer、long和Long等。
- 所有基本类型及包装类与String之间都可以自动转换
- 枚举和String之间
- 更多类型转换详见官方文档
如何使用
直接使用
原来的写法
// DishDto dishDto = new DishDto();
// BeanUtils.copyProperties(dish, dishDto);
//使用mapstruct后的写法
DishDto dishDto = DishConvertMapper.INSTANCE.convert(dish);
依赖注入
@Mapper(componentModel = "spring")
public interface DishConvertMapper {
/***
* 将entity转换为Dto
* @param dish
* @return
*/
@Mappings(
{@Mapping(source = "name", target = "userName")}
)
DishDto convert(Dish dish);
/***
* 将dto转换为entity
* @param dishDto
* @return
*/
Dish convert(DishDto dishDto);
}
通过@Mapper指定componentModel 为"spring",就会被spring管理,就不需要Mappers.getMapper()的方式,直接通过@Autoware的方式注入。
实现原理
在程序编译时,会自动生成实体转换接口的实现类,实现类在classes路径下。以下是自动生成的实现类:
@Component
public class DishConvertMapperImpl implements DishConvertMapper {
public DishConvertMapperImpl() {
}
public DishDto convert(Dish dish) {
if (dish == null) {
return null;
} else {
DishDto dishDto = new DishDto();
dishDto.setId(dish.getId());
dishDto.setName(dish.getName());
dishDto.setCategoryId(dish.getCategoryId());
dishDto.setPrice(dish.getPrice());
dishDto.setCode(dish.getCode());
dishDto.setImage(dish.getImage());
dishDto.setDescription(dish.getDescription());
dishDto.setStatus(dish.getStatus());
dishDto.setSort(dish.getSort());
dishDto.setCreateTime(dish.getCreateTime());
dishDto.setUpdateTime(dish.getUpdateTime());
dishDto.setCreateUser(dish.getCreateUser());
dishDto.setUpdateUser(dish.getUpdateUser());
return dishDto;
}
}
public Dish convert(DishDto dishDto) {
if (dishDto == null) {
return null;
} else {
Dish dish = new Dish();
dish.setId(dishDto.getId());
dish.setName(dishDto.getName());
dish.setCategoryId(dishDto.getCategoryId());
dish.setPrice(dishDto.getPrice());
dish.setCode(dishDto.getCode());
dish.setImage(dishDto.getImage());
dish.setDescription(dishDto.getDescription());
dish.setStatus(dishDto.getStatus());
dish.setSort(dishDto.getSort());
dish.setCreateTime(dishDto.getCreateTime());
dish.setUpdateTime(dishDto.getUpdateTime());
dish.setCreateUser(dishDto.getCreateUser());
dish.setUpdateUser(dishDto.getUpdateUser());
return dish;
}
}
}
可以看到,实现类帮我们做了数据源类的get和目标类的set操作。
遇到问题
java: 找不到符号 符号: 变量 log
这个报错位置是:lombok的@Slf4j注解的log变量
引入MapStruct和Lombok后,构建过程中发生冲突。
解决办法:在pom文件中增加lombok注解支持
<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>
<!--增加lombok注解支持 解决找不到log 符号问题-->
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
总结
本文只是一个简单的Mapstruct入门使用,如果您使用的场景更复杂,建议您通过官方文档来实现您的需求。