MapStruct
1. 官网
https://mapstruct.org/documentation/stable/reference/html/#_apache_maven
2. Github项目地址
3. 引入Maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
</properties>
<groupId>org.example</groupId>
<artifactId>learning_MapStruct</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- 官网说明引入此maven,但此依赖与lombok依赖冲突,所以还要继续多引用下面的两个依赖-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</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>
</configuration>
</plugin>
</plugins>
</build>
</project>
4. 编写实体类
4.1 Do
@Data
@AllArgsConstructor
public class User {
private Integer id;
private Integer addressId;
/**
* vo 中没有 password 字段
*/
private String password;
private String name;
/**
* vo 中 phone => 130****000
*/
private String phone;
/**
* birthday 在 vo 中将转换为 birthday(String) 和 age(Integer)
*/
private Date birthday;
/**
* createTime => createTime(String)
*/
private Date createTime;
}
@Data
@AllArgsConstructor
public class Address {
private Integer id;
private String fullAddress;
}
4.2 Vo
@Data
public class UserVo {
private Integer id;
private String username;
private String phone;
private String address;
private String birthday;
private Integer age;
private String createTime;
}
5. 定义映射器
5.1 基本映射
此种方式会自动拷贝变量名相同的字段
编写mapper
package top.ptcc9.mapstruct;
import org.mapstruct.Mapper;
import top.ptcc9.entity.Do.User;
import top.ptcc9.entity.Vo.UserVo;
/**
* @Author: HE LONG CAN
* @Description:
* @Date: 2021-03-31 12:50
*/
@Mapper
public interface User2Mapper {
/**
* user => userVo
* @param user
* @return
*/
UserVo user2Vo(User user);
}
测试:
package top.ptcc9;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import top.ptcc9.entity.Do.Address;
import top.ptcc9.entity.Do.User;
/**
* @Author HE LONG CAN
* @Description TODO
* @Date 2021-03-31 18:47:23
*/
@SpringBootTest
public class Tester {
private static final User user = new User(
1,
2,
"123456",
"HE LONG CAN",
"13800000000",
DateUtil.parse("1996-02-14 23:59:59","yyyy-MM-dd HH:mm:ss"),
DateTime.now()
);
private static final Address address = new Address(
2,
"M78星云24号星区"
);
@Test
void test01() {
User2Mapper mapper = Mappers.getMapper(User2Mapper.class);
UserVo userVo = mapper.user2Vo(user);
System.out.println("userVo = " + userVo);
}
}
运行结果:
可见在mapStruct
会拷名称相同的变量到Vo
中。
5.2 匹配名称不同的变量
@Mapping
可以用来配置对应规则。
@Mapper
public interface User2Mapper {
@Mapping(source = "name",target = "username")
UserVo user2Vo(User user);
}
source
表示user
target
表示 userVo
测试结果:
可以看到username
也被拷贝了过来。
5.3 多对一
当出现多个 Do
转换为一个 Vo
时:
@Mapping(source = "user.name",target = "username")
@Mapping(source = "address.fullAddress",target = "address")
@Mapping(source = "user.id",target = "id") //多数据源会使mapStruct不知道使用谁的id,所以要重新指定
UserVo userAddress2Vo(User user, Address address);
测试:
@Test
void test02() {
User2Mapper mapper = Mappers.getMapper(User2Mapper.class);
UserVo userVo = mapper.userAddress2Vo(user, address);
System.out.println("userVo = " + userVo);
}
测试结果:
5.4 仅更新现有Bean
示例
@Mapping(source = "user.name",target = "username")
@Mapping(source = "address.fullAddress",target = "address")
@Mapping(source = "user.id",target = "id")
void updateUserVoFromUser(UserVo userVo,User user);
6. 检索映射器
6.1 无依赖注入
使用:
@Test
void test03() {
UserVo userVo = User2Mapper.INSTANCE.userAddress2Vo(user, address);
}
7. 数据类型转换
7.1 调用映射器
编写映射器:
public class DateRule {
public String asString(Date date) {
return date != null ? DateUtil.format(date,"yyyy-MM-dd HH:mm:ss") : null;
}
}
引用映射器:
@Mapper(uses = DateRule.class) //引用
public interface User2Mapper {
User2Mapper INSTANCE = Mappers.getMapper(User2Mapper.class);
@Mapping(source = "name",target = "username")
UserVo user2Vo(User user);
@Mapping(source = "user.name",target = "username")
@Mapping(source = "address.fullAddress",target = "address")
@Mapping(source = "user.id",target = "id")
UserVo userAddress2Vo(User user, Address address);
}
至此,程序会自动在给定class
中寻找可用的转换方法,达到日期格式化的目的。
7.2 自定义映射
@Mapping(source = "user.name",target = "username")
@Mapping(source = "address.fullAddress",target = "address")
@Mapping(source = "user.id",target = "id")
@Mapping(source = "user.birthday",target = "age",qualifiedByName = "calculateAge") //调用自定义映射方法
UserVo userAddress2Vo(User user, Address address);
@Named("calculateAge")
default Integer calculateAge(Date birthday) {
return birthday != null ?
(int) DateTime.of(birthday).between(DateTime.now(), DateUnit.DAY) / 365 :
0;
}
由此,可以根据生日计算出年龄。
8. 逆映射
@Mapper
public interface CarMapper {
@Mapping(source = "numberOfSeats", target = "seatCount")
CarDto carToDto(Car car);
@InheritInverseConfiguration
@Mapping(target = "numberOfSeats", ignore = true)
Car carDtoToCar(CarDto carDto);
}
**总结:**以上只是MapStruct
的基本用法,能够满足日常开发。完整功能介绍建议阅读官方文档。