MapStruct使用
在一个项目的不同模块或不同需求中,经常需要一个数据模型的一部分,需要进行对象与对象之间的互相转换。
最为简单直接的就是使用getter
,setter
方法进行转换,或者使用自定义Beans.copyProperties
等实现。
前者编写麻烦,后者使用反射的方式导致性能消耗较大
MapStruct是一个属性映射工具、框架。通过生成这些繁琐的代码来节省时间。
- GitHub: mapstruct/mapstruct
依赖
以SpringBoot+Lombok+MapStruct为例,其余场景见 GitHub示例代码
...
<properties>
<org.mapstruct.version>1.5.2.Final</org.mapstruct.version>
<org.projectlombok.version>1.18.20</org.projectlombok.version>
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
</properties>
...
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<!-- lombok dependencies should not end up on classpath -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.version}</version>
<scope>provided</scope>
</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>
<!-- MapStruct 注解处理器 -->
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<!-- Lombok 注解处理器 -->
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.version}</version>
</path>
<!-- MapStruct 和 Lombok 注解绑定处理器 -->
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok-mapstruct-binding.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
...
使用
创建pojo
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Boy {
private String name;
private Integer age;
private String school;
private String blog;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Man {
private String name;
private Integer age;
private String work;
private String blogName;
private String blogUrl;
}
- 公共属性:name,age
- Boy独有属性:school
- Man独有属性:work
- 不同名属性:blog / blogName
- 自定义转换:blogUrl
创建映射器
配置
属性
-
mapstruct.suppressGeneratorTimestamp
- 禁止在生成的映射器中创建时间戳
- 默认
false
-
mapstruct.supppressGeneratorVersionInfoComment
- 禁止在生成的映射器中创建属性
- 默认为
false
-
mapstruct.defaultComponentModel
- 基于生成映射器的组件模型的名称,支持
default
,cdi
,spring
,jsr30
- 默认
default
,使用spring
可以使用@Autowired
方式注入
- 基于生成映射器的组件模型的名称,支持
-
mapstruct.unmappedTargetPolicy
- 在未使用source值填充映射方法的target属性的情况下要应用的默认报告策略,支持
ERROR
(映射代码生成失败)、WARN
(构建时引起警告)、IGNORE
(忽略)- 默认为
WARN
,如Warning:(36, 24) java: Unmapped target property: .....
- 默认为
- 在未使用source值填充映射方法的target属性的情况下要应用的默认报告策略,支持
配置方式一:注解配置
@Mapper(componentModel="spring", ....)
配置方式二:pom配置
<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>
<compilerArgs>
<compilerArg>
-Amapstruct.suppressGeneratorTimestamp=true
</compilerArg>
<compilerArg>
-Amapstruct.suppressGeneratorVersionInfoComment=true
</compilerArg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
映射器实现
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper
public Interface ObjectConvertor(){
@Mapping(source = "blogName", target = "blog")
@Mapping(source = "blogName", target = "blogUrl", qualifiedByName = "blogUrl")
Man boy2Man(Boy boy);
@Named("blogUrl")
default String blogUrl(String blog){
return "https://"+blog;
}
}
属性的默认转换是按照属性名进行转换
List等对象需要先有其中元素对象的转换方法。
自定义的转换方式采用
qualifiedName
和@Named()
实现
@Mapping
的source
可以是传入的参数,如@Mapping(source=“boy”, ...)
对于多个不同名属性,可以在
@Mapping
外包一层@Mappings
,或多个@Mapping
叠加
@Mappings({ @Mapping(source = "blogName", target = "blog"), ... })
由于生成的代码直接为
.class
文件,如果是对pojo的属性做出调整,重新运行时不会再重新生成,导致类型转换出错,需要ReBuild。
使用
@Autowired
ObjectConvertor objectConvertor;
public void objConvert() {
Boy boy = new Boy("zang", 18, "zjut", "zang.gold");
System.out.println(boy);
Man man = objectConvertor.boy2Student(boy);
System.out.println("After convert: ");
System.out.println(man);
}
~$: Boy(name=zang, age=18, school=zjut, blog=zang.gold)
~$: After convert:
~$: Man(name=zang, age=18, work=null, blogName=zang.gold)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现