MapStruct入门
介绍
MapStruct是一个开源的java对象映射框架,它用于简化不同类型对象之间的转换过程。提供了一种自动生成对象映射代码的机制,可以大大减少手动编写转换代码的工作量,提高开发效率
MapStruct 的优点包括:
- 类型安全:MapStruct 在编译时会检查类型,并提供编译期错误提示,避免运行时错误。
- 高性能:MapStruct 生成的转换代码经过优化,执行效率较高。
- 可配置性强:可以通过注解和自定义映射器来处理复杂的转换逻辑。
- 易于集成:MapStruct 可与常见的构建工具和框架(如 Maven、Gradle、Spring)无缝集成。
原理
MapStruct 是一个 Java 注解处理器,它基于注解和代码生成技术来实现对象之间的映射。其原理可以分为以下几个步骤:
- 定义映射接口:创建一个使用
@Mapper注解标记的接口,该接口定义了源对象到目标对象的映射方法。- 编译时代码生成:在编译时,MapStruct 注解处理器会扫描项目中的映射接口,并根据接口的定义信息进行代码生成。生成的代码包括具体的映射方法的实现,以及必要的辅助类和方法。
- 映射方法实现:生成的映射方法会根据源对象和目标对象的属性名称和类型,自动进行属性值的拷贝。在映射过程中,MapStruct 会根据类型转换规则进行类型的自动转换,例如基本类型到包装类型的转换、日期类型到字符串的转换等。
- 自定义映射配置:如果需要进行更复杂的转换逻辑,可以在映射接口中定义自定义的映射方法,并在方法中编写转换逻辑。这些自定义方法可以通过
@Mapping注解来指定源属性和目标属性之间的映射关系。- 使用映射接口:在应用程序中,可以通过获取映射接口的实例,然后调用其中的映射方法来完成对象之间的转换操作。
通过以上的步骤,MapStruct 实现了简化对象之间映射的过程。它可以帮助开发人员自动生成类型安全的映射代码,减少手动编写转换逻辑的工作量,并提高代码的可维护性和可读性。
如何使用MapStruct
1、引入依赖
maven:
<!-- MapStruct核心包 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>
<!-- 作用是编译时根据MapStruct的注解生成实现类-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
<scope>provided</scope>
</dependency>
2、具体使用
属性一致类相互转换
创建转换接口,定义转换方法
package com.yxx.mapstruct.mapstruct;
import com.yxx.mapstruct.dto.UserDto;
import com.yxx.mapstruct.entity.User;
import org.mapstruct.Mapper;
import java.util.List;
@Mapper(componentModel = "spring")
public interface UserMapStruct{
// 可以不使用componentModel = "spring"
UserMapStruct INSTANCE = Mappers.getMapper(UserMapStruct.class);
UserDto toUserDto(User user);
List<UserDto> toUserDtoList(List<User> userList);
}
此接口在项目编译后,会生成一个实现类,见下发
componentModel = "spring",编译后会自动变成@Component注解,方便其他类注入
编译后生成的接口实现类:UserMapStructImpl
package com.yxx.mapstruct.mapstruct;
import com.yxx.mapstruct.dto.UserDto;
import com.yxx.mapstruct.entity.User;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;
@Component
public class UserMapStructImpl
implements UserMapStruct
{
public UserDto toUserDto(User user) {
if (user == null) {
return null;
}
UserDto userDto = new UserDto();
userDto.setName(user.getName());
userDto.setSex(user.getSex());
userDto.setRemark(user.getRemark());
userDto.setPassword(user.getPassword());
return userDto;
}
public List<UserDto> toUserDtoList(List<User> userList) {
if (userList == null) {
return null;
}
List<UserDto> list = new ArrayList<>(userList.size());
for (User user : userList) {
list.add(toUserDto(user));
}
return list;
}
}
需要忽略属性转换
方法1,目标对象userDto删除相关属性,重新编译
方法2:使用@Mapping(target = "password", ignore = true)忽略目标对象属性
@Mapping(target = "password", ignore = true) // 忽略password转换
UserDto toUserDto(User user);
不同属性名称转换
@Mapping(source = "userName",target = "name") // 名称不同转换
转换的类包含引用类不同转换
//1.指定来源属性和目标属性
@Mapping(target = "schoolDto", source = "school") // 引用类型属性转换
UserDto toUserDto(User user);
//2.添加引用类型的转换方法
SchoolDto toSchoolDto(School school);
日期类型转换
@Mapping(target = "updateTime", source = "updateTime", dateFormat = "yyyy-MM-dd") //日期格式转换
// Date -> String,生成的实现类
if (user.getUpdateTime() != null) {
userDto.setUpdateTime((new SimpleDateFormat("yyyy-MM-dd")).format(user.getUpdateTime()));
}
// String -> Date,生成的实现类
try {
if (user.getUpdateTime() != null) {
userDto.setUpdateTime((new SimpleDateFormat("yyyy-MM-dd")).parse(user.getUpdateTime()));
}
}
catch (ParseException e) {
throw new RuntimeException(e);
}
固定值转换
// 无论源属性值是什么,目标属性值都是固定的
@Mapping(target = "name", constant = "liudehua")
自定义表达式转换
// 1.增加expression="java(方法名(方法参数))"格式的表达式,注意source和expression不能同时使用,编译会报错
@Mapping(target = "gender",expression = "java(sexToGender(user))")
UserDto toUserDto(User user);
// 2.增加对应名称参数的转换方法
default String sexToGender(User user) {
if (user.getSex() == 1) {
return "男";
}
return "女";
}
其他转换
基本类型和对应的包装类型中间是自动转换的,原理通过Integer.valueOf 或者 intValue()转换
基本类型都能转换为String,原理通过String.valueOf转换