公众号:飞翔的代码
MapStruct这个库是用来做两个对象之间转换拷贝的,之前大家都使用BeanUtils工具类,在Spring和Apache common包里都有这个工具类,但是BeanUtils利用反射机制,在运行时反射再设置属性值效率很低,同时还不能够对类型不同的数据进行转换,所以我们采用MapStruct来实现
配置pom.xml
<properties>
<mapstruct.version>1.4.1.Final</mapstruct.version>
</properties>
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</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>
<encoding>utf-8</encoding>
<annotationProcessorPaths>
<!-- 如果使用lombok
<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>
简单的一对一对应
先定义两个要转换的类
@Data
public class Data1 {
private Long id;
private String name;
private Integer createTime;
}
@Data
public class Data2 {
private String name;
private Integer createTime;
}
创建一个转换接口
@Mapper
public interface TestConverter {
TestConverter INSTANCE = Mappers.getMapper(TestConverter.class);
/**
* data1转data2
* @param data1
* @return
*/
Data2 data1ToData2(Data1 data1);
/**
* data2转data1
* @param data2
* @return
*/
Data1 data2ToData1(Data2 data2);
}
测试转换
Data1 data1 = new Data1();
data1.setId(1L);
data1.setName("hello world");
data1.setCreateTime(123);
System.out.println(TestConverter.INSTANCE.data1ToData2(data1));
注意:如果在idea中启动报没有实现类,或者修改了Data1和Data2但是转换后没有生效,需要重新build项目
自动类型映射
当Data1和Data2的属性类型不一致时,会自动进行类型转换,如下:
@Data
public class Data1 {
private String createTime;
}
@Data
public class Data2 {
private Integer createTime;
}
字段映射
需要手动指定映射时可以通过添加注解来实现,先将Data1稍做调整,使其和Data2属性名不一致
@Data
public class Data1 {
private Long id;
private String title;
private String time;
}
在接口中添加注解,指明来源属性名和目标属性名
@Mapping(source = "title", target = "name")
@Mapping(source = "time", target = "createTime")
Data2 data1ToData2(Data1 data1);
自定义转换
再对Data1进行调整,添加prefix属性,期望转换时将prefix和title拼接起来赋值给Data2的name属性
@Data
public class Data1 {
private Long id;
private String prefix;
private String title;
private String time;
}
在接口中添加注解,将两个属性拼接起来
@Mapping(target = "name", expression = "java(data1.getPrefix() + data1.getTitle())")
Data2 data1ToData2(Data1 data1);
注意:使用expression就不能再指定target,另外对于复杂的转换,或者需要调用其他工具类,可以在接口中定义default方法来实现
@Mapping(target = "name", expression = "java(join(data1.getPrefix(), data1.getTitle()))")
Data2 data1ToData2(Data1 data1);
default String join(String str1, String str2) {
return str1 + str2;
}
在上面的join方法内就可以写很多复杂的转换逻辑了
集合转换
只需要在接口中添加一个方法即可
List<Data2> data1ToData2List(List<Data1> data1List);
前提是接口中已经存在Data2 data1ToData2(Data1 data1);这个方法,原理是遇到集合转换时遍历集合调用data1ToData2方法,因此data1ToData2方法上添加的映射注解都有效
自定义抽象实现类
定义接口的抽象实现类来处理复杂的转换
在接口上添加@DecoratedWith注解指定抽象实现类
@Mapper
@DecoratedWith(AbstractTestConverter.class)
public interface TestConverter {
TestConverter INSTANCE = Mappers.getMapper(TestConverter.class);
/**
* data1转data2
* @param data1
* @return
*/
@Mapping(source = "time", target = "createTime")
Data2 data1ToData2(Data1 data1);
}
定义抽象类
public abstract class AbstractTestConverter implements TestConverter {
private final TestConverter delegate;
public AbstractTestConverter(TestConverter delegate) {
this.delegate = delegate;
}
@Override
public Data2 data1ToData2(Data1 data1) {
// 这里调用data1ToData2方法时接口中添加的@Mapping注解仍然有效
Data2 data2 = delegate.data1ToData2(data1);
data2.setName(data1.getPrefix() + data1.getTitle());
return data2;
}
}
公众号:飞翔的代码