👋 前言
MapStruct
是一个代码生成器,它基于约定优于配置方法极大地简化了 Java bean
类型之间映射的实现。自动生成的映射转换代码只使用简单的方法调用,因此速度快、类型安全而且易于理解阅读。总的来说,有如下三个特点:
- 基于注解
- 在编译期自动生成映射转换代码
- 类型安全、高性能、无依赖性
💡 正文
1 Maven依赖
<properties>
<lombok.version>1.18.28</lombok.version>
<mapstruct.version>1.3.0.Final</mapstruct.version>
</properties>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<!-- mapstruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
<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.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
2 Mapstruct常用转换方式
基础数据类:
@Data
@AllArgsConstructor
public class StudentVO {
// 学号
private Integer sid;
// 姓名
private String name;
// 性别
private String sex;
// 电话号码
private String phone;
// 邮箱
private String email;
// 班级
private String classes;
// 考试成绩
private Map<String, Integer> score;
// 爱好特长
private List<String> hobby;
// 入学日期
private LocalDate schoolDate;
}
@Data
@AllArgsConstructor
@Builder
public class StudentDO {
// 学号
private Integer sid;
// 姓名
private String name;
// 年龄
private Integer age;
// 性别
private String sex;
// 地址
private String address;
// 电话号码
private String phone;
// 邮箱
private String email;
// 创建时间
private LocalDateTime createTime;
// 更新时间
private LocalDateTime updateTime;
}
@Data
@AllArgsConstructor
@Builder
public class Score {
// 考试成绩
private Map<String,Integer> score;
}
2.1 单DO转VO(不同属性值)
假设vo中姓名的属性值是sname,其他都一样的情况,那么do转vo的时候,只需要对属性进行映射即可
@Mapper
public interface StudentConvert {
/**
* 初始化 convert 实例
*/
StudentConvert INSTANCE = Mappers.getMapper(StudentConvert.class);
/**
* 在vo和do属性相同,属性名不同的情况下,将DO转为VO
*
* @param studentDO
* @return
*/
@Mapping(target = "sname", source = "name")
StudentVO convertDO2VO(StudentDO studentDO);
}
备注:如果存在多个属性值不同,可以使用@Mappings({}),包裹起来
@Mappings({
@Mapping(target = "sname", source = "name"),
@Mapping(target = "xxx", source = "yyy")
})
StudentVO convertDO2VO(StudentDO studentDO);
2.2 单DO转VO(自定义属性值)
当do转换vo时,其中vo中schooleDate为自定义属性值,使用do的createTime来表示,并且手动模拟根据sid在数据库中查询出的其他信息,如考试成绩,爱好,班级。
@Mapper
public interface StudentConvert {
/**
* 初始化 convert 实例
*/
StudentConvert INSTANCE = Mappers.getMapper(StudentConvert.class);
/**
* 将DO转为VO
*
* @param studentDO
* @return
*/
@Mapping(target = "schoolDate", expression = "java(java.time.LocalDate.from(studentDO.getCreateTime()))")
StudentVO convertDO2VO(StudentDO studentDO);
}
备注:接口方法的注解@Mapping中,将DO类中createTime的值转换成LocalDate类型,当作目标类中的schoolDate的属性值
public class Test {
public static void main(String[] args) {
// 模拟数据库获取的学生信息
StudentDO studentDO = StudentDO.builder()
.sid(10001)
.name("张三")
.age(18)
.sex("男")
.address("四川省成都市")
.phone("13988888888")
.email("123456789@qq.com")
.createTime(LocalDateTime.now())
.updateTime(LocalDateTime.now())
.build();
System.out.println(studentDO);
StudentVO studentVO = StudentConvert.INSTANCE.convertDO2VO(studentDO);
// 模拟从数据库根据学号查询关联的班级,学生成绩和爱好
String classes = "高三1班";
studentVO.setClasses(classes);
List<String> hobby = new ArrayList<>();
hobby.add("吉他");
hobby.add("足球");
studentVO.setHobby(hobby);
Map<String, Integer> map = new HashMap<>();
map.put("语文", 125);
map.put("数学", 131);
map.put("英语", 120);
studentVO.setHobby(map);
System.out.println(studentVO);
}
}
2.3 多DO转VO
将Score,StudentDO转换成StudentVO
@Mapper
public interface StudentConvert {
/**
* 初始化 convert 实例
*/
StudentConvert INSTANCE = Mappers.getMapper(StudentConvert.class);
/**
* 将DO转为VO
*
* @param studentDO
* @return
*/
@Mapping(target = "schoolDate", expression = "java(java.time.LocalDate.from(studentDO.getCreateTime()))")
@Mapping(source = "s.score", target = "score")
StudentVO convertDO2VO(StudentDO studentDO, Score s);
}
备注:将源Score类的scroe属性,赋值给目标的score属性
public class Test {
public static void main(String[] args) {
// 模拟数据库获取的学生信息
StudentDO studentDO = StudentDO.builder()
.sid(10001)
.name("张三")
.age(18)
.sex("男")
.address("四川省成都市")
.phone("13988888888")
.email("123456789@qq.com")
.createTime(LocalDateTime.now())
.updateTime(LocalDateTime.now())
.build();
System.out.println(studentDO);
// 模拟从数据库根据学号查询关联的班级,学生成绩和爱好
String classes = "高三1班";
List<String> hobby = new ArrayList<>();
hobby.add("吉他");
hobby.add("足球");
Map<String, Integer> map = new HashMap<>();
map.put("语文", 125);
map.put("数学", 131);
map.put("英语", 120);
// 模拟数据库获取的成绩信息
Score score = Score.builder()
.score(map)
.build();
StudentVO studentVO = StudentConvert.INSTANCE.convertDO2VO(studentDO, score);
studentVO.setHobby(hobby);
studentVO.setClasses(classes);
System.out.println(studentVO);
}
}