开始前必读:基于grpc从零开始搭建一个准生产分布式应用(0) - quickStart
从本章开始,大概会分5个章节来讲述mapStruct的使用。
一、Maven配置
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.2.Final</version>
</dependency>
二、Maven-Plug配置
<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>
<!-- 使用lombok注意冲突,maven-compiler-plugin要3.6以上,lombok使用1.16.16版本以上,需要配置lombok的path -->
<!-- 注意下面的声明顺序,否则lombok会不起作用 -->
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.4.1.Final</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.1.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
2.1、打印编译日志
<!--配置showWarning和mapstruct.verbose=true会在编译时打印相关转换信息-->
<showWarnings>true</showWarnings>
<compilerArgs>
<compilerArg>-Amapstruct.verbose=true </compilerArg>
</compilerArgs>
效果如下
[INFO] -- MapStruct: selecting element mapping: com.mapstruct.bo.TestBO #testToBO(testPO).
[INFO] - MapStruct: creating bean mapping method implementation for com.mapstruct.bo.TestBO testToBO(com.mapstruct.bo.TestPO testPO).
[INFO] -- MapStruct: mapping property: testPO.getId() to: setId(java.lang.Long).
[INFO] -- MapStruct: selecting property mapping: testPO.getId().
[INFO] -- MapStruct: mapping property: testPO.getName() to: setName(java.lang.String).
2.2、Spring声明方式
//需再增加以下参数在Maven配置上,
<compilerArgs>
<compilerArg>-Amapstruct.defaultComponentModel=spring</compilerArg> <!-- 以spring注入的方式访问mapper-->
</compilerArgs>
-------------------------------------------------------------------------------------
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-01-31T00:38:47+0800",
comments = "version: 1.4.1.Final, compiler: javac, environment: Java 1.8.0_144 (Oracle Corporation)"
)
/**这个东西是设置<compilerArg>-Amapstruct.defaultComponentModel=spring</compilerArg>后生成的,
* 这个默认属性优先级低于Mapper注解上的componentModel属性值
* */
@Component
public class ManyToOneImpl implements ManyToOne {
}
2.3、Spring注入方式
//需再增加以下两个参数在Maven配置上,这个默认属性优先级低于Mapper注解上的injectionStrategy属性值
<compilerArgs>
<!-- 注入方式 默认是字段注入 设置为constructor是构造器注入-->
<compilerArg> -Amapstruct.defaultInjectionStrategy=field </compilerArg>
</compilerArgs>
@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = {OneToOne.class})
public interface ManyToOne {
List<TestBO> testToBOS(List<TestPO> testPOS);
}
@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
public interface OneToOne {
TestBO testToBO(TestPO testPO);
}
//=================以下是注入实现=================
public class ManyToOneImpl implements ManyToOne {
@Autowired
private OneToOne oneToOne;
}
//=================以下是构造函数方式,实现方式,但需要设置 injectionStrategy=================
@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = {OneToOne.class},
injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public class ManyToOneImpl implements ManyToOne {
private final OneToOne oneToOne;
@Autowired
public ManyToOneImpl(OneToOne oneToOne) {
this.oneToOne = oneToOne;
}
}
三、实现方式
3.1、通用复制
//这里假设BO和PO的类属性完全一样,
@Data
@ToString
public class TestPO {
private Long id;
private String name;
private BigDecimal price;
private Date creteTime;
}
//接口方式定义,如果用List时也必须定义单个属性的转换,在下例中testToBOS会用到testToBO方法,它们的方法名没有必然的联系,可随意定义,程序会自动组装;
@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS) 或 @Mapper
public interface TestMapper {
TestBO testToBO(TestPO testPO);
List<TestBO> testToBOS(List<TestPO> testPOS);
}
//测试
@Test
public void baseTest() {
List<TestPO> list = new ArrayList<>();
for (int i = 0; i < 2; i++) {
TestPO testPO = new TestPO();
testPO.setId(1L);
testPO.setName("haru");
testPO.setPrice(new BigDecimal("12.02"));
testPO.setCreteTime(new Date(System.currentTimeMillis()));
list.add(testPO);
}
TestMapper mapper = Mappers.getMapper(TestMapper.class); // 获取mapper
List<TestBO> testBOS = mapper.testToBOS(list); // 转换
System.out.println(testBOS);
}
3.2、自定义映射(推荐)
3.2.1、接口实现
//在自动生成的类中会实现 此抽象类
@Mapper
public interface TestMapper {
TestBO testToBO(TestPO testPO);
List<TestBO> testToBOS(List<TestPO> testPOS);
}
TestMapper mapper = Mappers.getMapper(TestMapper.class); // 获取mapper
List<TestBO> testBOS = mapper.testToBOS(list); // 转换
3.2.2、抽象类-实现自定义方法
//作用同上面接口实现一样,在自动生成的类中会实现 此抽象类
@Mapper
public abstract class AbstractTestMapper {
public TestBO testToBO(TestPO testPO) {
TestBO testBO = new TestBO();
testBO.setName(testPO.getName() + "BO");
return testBO;
}
public abstract List<TestBO> testToBOS(List<TestPO> testPOS);
}
AbstractTestMapper mapper = Mappers.getMapper(AbstractTestMapper.class); // 获取mapper
List<TestBO> testBOS = mapper.testToBOS(list); // 转换
3.2.3、默认方法-(需jdk1.8)实现自定义方法
//适用1.8以上的JDK
@Mapper
public interface DefaultMappler {
default TestBO testToBO(TestPO testPO) {
TestBO testBO = new TestBO();
testBO.setName(testPO.getName() + "BEEEO");
return testBO;
}
List<TestBO> testToBOS(List<TestPO> testPOS);
}
四、复杂使用
下面也是常用的使用方式,非高级用法。
4.1、多个对象映射成一个对象
public class TestPO {
private Long id;
private String name;
private BigDecimal price;
private Date creteTime;
}
public class TestTwoPO {
private Long id;
private String title;
private Float totalPrice;
}
public class TestMixBO {
private Long id;
private String name;
private BigDecimal price;
private Date creteTime;
private String title;
}
//这里需要注意的是,在上面的类都有一个ID属性,所以必须用Mapping指定一个soure,如source = "testPO.id",否则会报错
@Mapper
public interface ManyToOne {
@Mapping(source = "testPO.id", target = "id")
TestMixBO testToBO(TestPO testPO, TestTwoPO testTwoPO);
}
//void toTarget( MammalDto source, Long numberOfStomachs, @MappingTarget MammalEntity target );
4.2、嵌套对象映射
可以将target设为".",source所对应的属性对象字段会全部映射到target中同名字段上。
@Data
@ToString
@Builder
public class TestMixBO {
private Long id;
private String name;
private BigDecimal price;
private Date creteTime;
private String title;
private float price1;
}
@Data
@ToString
public class TestThreePO {
private TestPO test;
}
@Data
@ToString
public class TestPO {
private Long id;
private String name;
private BigDecimal price;
private Date creteTime;
}
@Mapper
public interface TestMapper {
@Mapping(source = "test", target = ".")
TestMixBO testToBO(TestThreePO testPO);
}
4.3、非对象属性映射到目标上
@Mapper
public interface TestMapper {
@Mapping(target = "discount", source = "totalPrice")
TestMixBO testToBO(TestPO testPO, Float totalPrice);
}
//discount是TestMixBO新加的一个属性,这里的totalPrice就是一个自定义的参数,用于写死某个值时非常有用;
4.4、更新数据
@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
public interface ManyToOne {
//同样也可以使用@Mapping在方法上
//@Mapping(target = "id", ignore = true)
void updateBO(TestPO var1, @MappingTarget TestBO var2);
}
//生成的代码如下
public void updateBO(TestPO testPO, TestBO testBO) {
if (testPO != null) {
if (testPO.getId() != null) {
testBO.setId(testPO.getId());
} else {
testBO.setId((Long)null);
}