MapStruct 的使用
DO
DTO
VO
DO:即 Data Object,是和数据库一一对应的 Java 实体,在 mapper 层传递
DTO:即 Data Transfer Object,删掉了 DO 中一些不需要的字段,在 service 层或 manager 层传输。比如在 service 层中,接收来自 mapper 层的 DO 数据,返回给别的 service 层 DTO 数据,返回给 controller 层 VO 数据。
VO:即 View Object,专门展示给前端的数据对象,是 service 层传给 controller 层的数据,controller 层再给前端的数据。
使用这三种类型的而不是简单得只用 DO ,可以有效得隔离字段,解耦清晰,和友好展示。在学习阶段或小项目中,一般不引入 DTO,在 service 层中,也可只使用 DO ,返回给别的 service 层以 DO ,但依旧返回给 controller 层 VO。
使用这几个数据,势必需要进行转换,通常情况下,有三种常见的转换方式:
手动转换
使用 BeanUtils 转换
使用 MapStruct 转换
第一种,手动转换,类似于:
public UserVO convertToVO(UserDO userDO) {
UserVO vo = new UserVO();
vo.setId(userDO.getId());
vo.setUsername(userDO.getUsername());
vo.setEmail(userDO.getEmail());
return vo;
}优先就是字段可以灵活按照自己的想法去处理,缺点也很明显,就是代码繁杂,容易出错、难维护,所以平时也不太会用这种。
第二种,使用 BeanUtils ,这是 Spring 自带的对象转换的工具,样例代码如:
import org.springframework.beans.BeanUtils;
UserVO vo = new UserVO();
BeanUtils.copyProperties(userDO, vo);优点是快速、简单,代码量少,也不用创建新的转换类。缺点是这种方法只能自动拷贝同名且同数据类型的字段,要想有特殊的处理,只能手动去处理。
第三种,使用 MapStruct 转换,是目前在 Java 微服务中最主流的转换方式之一,优点是支持不同字段、不同类型的复杂映射,性能高、易维护,在编译期生成代码,运行时不会反射影响性能。
下面就来详细介绍这个 MapStruct 的使用。
引入依赖
这里的依赖可不少,主要是因为不能单独引入 MapStruct ,还要引入 Lombok 依赖,并且把他们两个绑定,不然 MapStruct 识别不了 Lombok 自动生成的 set/get 方法。
<dependency>
<groupId>org.mapstructgroupId>
<artifactId>mapstructartifactId>
<version>1.5.5.Finalversion>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombok-mapstruct-bindingartifactId>
<version>0.2.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.mapstructgroupId>
<artifactId>mapstruct-processorartifactId>
<version>1.5.5.Finalversion>
<scope>providedscope>
dependency>除了依赖以外,还要在 pom 文件的依赖后面,加入 maven-compiler-plugin ,直接赋值下面的代码就好,注意
标签是和 标签同级的,而且要在它的下面。 <build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.11.0version>
<configuration>
<source>21source>
<target>21target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>${lombok.version}version>
path>
<path>
<groupId>org.mapstructgroupId>
<artifactId>mapstruct-processorartifactId>
<version>1.5.5.Finalversion>
path>
<path>
<groupId>org.projectlombokgroupId>
<artifactId>lombok-mapstruct-bindingartifactId>
<version>0.2.0version>
path>
annotationProcessorPaths>
configuration>
plugin>
plugins>
build>创建转换器接口
// 我们目前是 SpringBoot 项目,交由 spring 管理,这样才能在后面注入
(componentModel = "spring")
public interface CategoryConverter {
/**
* DO → VO
*/
CategoryVo doToVo(CategoryDo categoryDo);
}使用
public class ConverterTest {
private CategoryConverter categoryConverter;
public void testDoToVo(){
CategoryDo categoryDo = new CategoryDo();
categoryDo.setCatId(1L);
// 调用方法转化
CategoryVo categoryVo = categoryConverter.doToVo(categoryDo);
// 打印
System.out.println(categoryVo);
}
}小技巧1:忽略字段映射
某些字段,并不希望给他赋值,那么在转换器对应的方法上,加入如下代码:
(componentModel = "spring")
public interface CategoryConverter {
// 加入 Mapping 注解,忽略字段,这里是:忽略 CategoryVo 对象的 id 字段,不赋值。
(target = "id", ignore = true)
CategoryVo doToVo(CategoryDo categoryDo);
}target 表示目标对象,ignore 表示忽略赋值。
小技巧2:字段名不同的赋值映射
这个技巧,可以在两个要转换的对象之间,即使名字不一样,也可以转换。
(componentModel = "spring")
public interface CategoryConverter {
// 加入 Mapping 注解,这里是:将 source(CategoryDo)中的 catId,映射到 target(CategoryVo)中的 id。
(target = "id",source = "catId")
CategoryVo doToVo(CategoryDo categoryDo);
}小技巧3:直接设置特定值
若源属性值为null,设立一个默认值
对应方法上加入如下注解:
// 意思是,source(CategoryDo)中的 catId 若为空,则将 target(CategoryVo)中的 id 设置为 10086
(target = "id", source = "catId", defaultValue = "10086")若源属性值不为null,永远等于一个值
对应方法上加入如下注解:
// 意思是,将 target(CategoryVo)中的 id 设置为固定值:96211
(target = "id", constant = "96211")
至此,这些小技巧足以应对大部分的情况了,还有 表达式映射、自定义映射等,可查阅 查看。
- 微信
- 赶快加我聊天吧

- 赶快加我聊天吧
