MapStruct
作者:互联网
MapStruct
一.MapStruct是什么
MapStruct 是一个 Java注释处理器,用于生成类型安全的 bean 映射类。
MapStruct 的一般理念是生成的代码看起来尽可能像您自己亲手编写的代码。特别是这意味着通过简单的 getter/setter 调用而不是反射或类似方法将值从源复制到目标。
二.为什么要用MapStruct
类型安全、高性能和无依赖的 bean 映射代码
与动态映射框架相比,MapStruct 具有以下优势:
- 通过使用普通方法调用而不是反射来快速执行
- 编译时类型安全:只能映射相互映射的对象和属性,不能将订单实体意外映射到客户 DTO 等。
- 在构建时清除错误报告,如果
- 映射不完整(并非所有目标属性都被映射)
- 映射不正确(找不到合适的映射方法或类型转换)
三.MapStruct怎么用
所以要做的就是定义一个映射器接口,该接口声明任何所需的映射方法。在编译期间,MapStruct 将生成此接口的实现。此实现使用纯 Java 方法调用来映射源对象和目标对象,即没有反射或类似的。
它包括以下工件:
- org.mapstruct:mapstruct:包含所需的注释,例如
@Mapping
- org.mapstruct:mapstruct-processor:包含生成映射器实现的注释处理器
3.1 maven配置
对于基于 Maven 的项目,将以下内容添加到您的 POM 文件中以使用 MapStruct:(特别注明:lombok请使用1.16.16及以上版本)
<properties>
<org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
</properties>
...
<dependencies>
<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>
</dependencies>
...
3.2 关键注解
@Mapper
@Mappings
@Mapping
@MappingTarget
@InheritInverseConfiguration
@IterableMapping
Mapping注解解析
public @interface Mapping {
java.lang.String target(); // 目标
java.lang.String source() default ""; //源
java.lang.String dateFormat() default ""; //时间类型的日期格式
java.lang.String numberFormat() default ""; //数字格式
java.lang.String constant() default ""; //常量 源目标也必须要有对应字段,与defaultValue只能存一
java.lang.String expression() default ""; //表达式
java.lang.String defaultExpression() default "";
boolean ignore() default false; //忽略
java.lang.Class<? extends java.lang.annotation.Annotation>[] qualifiedBy() default {};
java.lang.String[] qualifiedByName() default {};
java.lang.Class<?> resultType() default void.class;
java.lang.String[] dependsOn() default {};
java.lang.String defaultValue() default ""; // 来源的默认值,与constant只能存一,
org.mapstruct.NullValueCheckStrategy nullValueCheckStrategy() default org.mapstruct.NullValueCheckStrategy.ON_IMPLICIT_CONVERSION;
org.mapstruct.NullValuePropertyMappingStrategy nullValuePropertyMappingStrategy() default org.mapstruct.NullValuePropertyMappingStrategy.SET_TO_NULL;
java.lang.Class<? extends java.lang.annotation.Annotation> mappingControl() default org.mapstruct.control.MappingControl.class;
}
3.3配置映射器
@Mapper
public interface WmsMapper {
/**
* 获取该类自动生成的实现类的实例
* 接口中的属性都是 public static final 的 方法都是public abstract的
*/
WmsMapper INSTANCES = Mappers.getMapper(WmsMapper.class);
}
3.4开始使用MapStruct
1.定义相互转化的实体
wms
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Wms {
private int id;
private String name;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class WmsDto {
private int id;
private String name;
}
2.简单映射方法
第一种:
在WmsMapper映射器里新增方法:
/**
* 对象映射
* @param wms
* @return
*/
WmsDto wmsToWmsDto(Wms wms);
/**
* 批量映射
* @param list
* @return
*/
List<WmsDto> wmsToWmsDto(List<Wms> list);
/**
* 对象映射反转 (当对象存在多个映射方法时,逆转方法需在注解中声明逆转的哪个方法,所以为了防止编译不通过,最好写的时候就在注解的name属性里声明好)
* @param wmsDto
* @return
*/
@InheritInverseConfiguration(name = "wmsToWmsDto")
Wms wmsDtoToWms(WmsDto wmsDto);
/**
* 批量映射 (当对象存在多个映射方法时,逆转方法需在注解中声明逆转的哪个方法,所以为了防止编译不通过,最好写的时候就在注解的name属性里声明好)
* @param list
* @return
*/
@InheritInverseConfiguration(name = "wmsToWmsDto")
List<Wms> wmsDtoToWms(List<WmsDto> list);
测试代码:
public static void main(String[] args) {
System.out.println("MapStruct简单映射方法1------------start");
Wms wms = Wms.builder().id(1).name("wms").build();
WmsDto wmsToWmsDto = WmsMapper.INSTANCES.wmsToWmsDto(wms);
System.out.println("对象映射结果"+wmsToWmsDto);
System.out.println("批量对象映射结果---");
WmsMapper.INSTANCES.wmsToWmsDto(Arrays.asList(wms,wms,wms)).forEach(System.out::println);
System.out.println("映射反转---");
Wms wmsDtoToWms = WmsMapper.INSTANCES.wmsDtoToWms(wmsToWmsDto);
System.out.println("映射反转结果"+wmsDtoToWms);
System.out.println("批量映射反转结果---");
WmsMapper.INSTANCES.wmsDtoToWms(Arrays.asList(wmsToWmsDto,wmsToWmsDto,wmsToWmsDto)).forEach(System.out::println);
System.out.println("MapStruct简单映射方法1------------end");
}
运行结果:
MapStruct简单映射方法1------------start
对象映射结果WmsDto(id=1, name=wms)
批量对象映射结果---
WmsDto(id=1, name=wms)
WmsDto(id=1, name=wms)
WmsDto(id=1, name=wms)
映射反转---
映射反转结果Wms(id=1, name=wms)
批量映射反转结果---
Wms(id=1, name=wms)
Wms(id=1, name=wms)
Wms(id=1, name=wms)
MapStruct简单映射方法1------------end
第二种:
在WmsMapper映射器里新增方法:
/**
* 对象映射
* @param wms
* @param wmsDto
*/
void wmsToWmsDtoMothod(Wms wms, @MappingTarget WmsDto wmsDto);
/**
* 批量对象映射
* @param wms
* @param wmsDto
*/
void wmsToWmsDtoMothod(List<Wms> wms, @MappingTarget List<WmsDto> wmsDto);
测试代码:
public static void main(String[] args) {
System.out.println("MapStruct简单映射方法2***************start");
Wms wms2 = Wms.builder().id(2).name("wms2").build();
WmsDto wmsDto2 = WmsDto.builder().build();
System.out.println("第二种映射前"+wmsDto2);
WmsMapper.INSTANCES.wmsToWmsDtoMothod(wms2,wmsDto2);
System.out.println("第二种映射后"+wmsDto2);
List<Wms> WmsList = Arrays.asList(Wms.builder().id(1).name("wms1").build()
,Wms.builder().id(2).name("wms2").build()
,Wms.builder().id(3).name("wms3").build()
);
List<WmsDto> wmsDtoList = new ArrayList<>();
WmsMapper.INSTANCES.wmsToWmsDtoMothod(WmsList,wmsDtoList);
System.out.println("批量映射结果***************end");
wmsDtoList.forEach(System.out::println);
System.out.println("MapStruct简单映射方法2***************end");
}
运行结果:
MapStruct简单映射方法2***************start
第二种映射前WmsDto(id=0, name=null)
第二种映射后WmsDto(id=2, name=wms2)
批量映射结果***************end
WmsDto(id=1, name=wms1)
WmsDto(id=2, name=wms2)
WmsDto(id=3, name=wms3)
MapStruct简单映射方法2***************end
3.不规则命名映射
在Wms实体新增age属性
private int age;
在WmsDto新增ageNumber属性
private int ageNumber;
在WmsMapper映射器里方法上加上映射规则:
/**
* 对象映射
* @param wms
* @return
*/
@Mapping(source = "age" , target = "ageNumber")
WmsDto wmsToWmsDto(Wms wms);
/**
* 对象映射
* @param wms
* @param wmsDto
*/
@Mapping(source = "age" , target = "ageNumber")
void wmsToWmsDtoMothod(Wms wms, @MappingTarget WmsDto wmsDto);
测试代码:
public static void main(String[] args) {
System.out.println("MapStruct简单映射方法1------------start");
Wms wms = Wms.builder().id(1).name("wms").age(24).build();
WmsDto wmsToWmsDto = WmsMapper.INSTANCES.wmsToWmsDto(wms);
System.out.println("对象映射结果"+wmsToWmsDto);
System.out.println("批量对象映射结果---");
WmsMapper.INSTANCES.wmsToWmsDto(Arrays.asList(wms,wms,wms)).forEach(System.out::println);
System.out.println("映射反转---");
Wms wmsDtoToWms = WmsMapper.INSTANCES.wmsDtoToWms(wmsToWmsDto);
System.out.println("映射反转结果"+wmsDtoToWms);
System.out.println("批量映射反转结果---");
WmsMapper.INSTANCES.wmsDtoToWms(Arrays.asList(wmsToWmsDto,wmsToWmsDto,wmsToWmsDto)).forEach(System.out::println);
System.out.println("MapStruct简单映射方法1------------end");
System.out.println("MapStruct简单映射方法2***************start");
Wms wms2 = Wms.builder().id(2).name("wms2").age(10).build();
WmsDto wmsDto2 = WmsDto.builder().build();
System.out.println("第二种映射前"+wmsDto2);
WmsMapper.INSTANCES.wmsToWmsDtoMothod(wms2,wmsDto2);
System.out.println("第二种映射后"+wmsDto2);
List<Wms> WmsList = Arrays.asList(Wms.builder().id(1).age(12).name("wms1").build()
,Wms.builder().id(2).name("wms2").age(12).build()
,Wms.builder().id(3).name("wms3").age(12).build()
);
List<WmsDto> wmsDtoList = new ArrayList<>();
WmsMapper.INSTANCES.wmsToWmsDtoMothod(WmsList,wmsDtoList);
System.out.println("批量映射结果***************");
wmsDtoList.forEach(System.out::println);
System.out.println("MapStruct简单映射方法2***************end");
}
运行结果:
MapStruct简单映射方法1------------start
对象映射结果WmsDto(id=1, name=wms, ageNumber=24)
批量对象映射结果---
WmsDto(id=1, name=wms, ageNumber=24)
WmsDto(id=1, name=wms, ageNumber=24)
WmsDto(id=1, name=wms, ageNumber=24)
映射反转---
映射反转结果Wms(id=1, name=wms, age=24)
批量映射反转结果---
Wms(id=1, name=wms, age=24)
Wms(id=1, name=wms, age=24)
Wms(id=1, name=wms, age=24)
MapStruct简单映射方法1------------end
MapStruct简单映射方法2***************start
第二种映射前WmsDto(id=0, name=null, ageNumber=0)
第二种映射后WmsDto(id=2, name=wms2, ageNumber=10)
批量映射结果***************
WmsDto(id=1, name=wms1, ageNumber=12)
WmsDto(id=2, name=wms2, ageNumber=12)
WmsDto(id=3, name=wms3, ageNumber=12)
MapStruct简单映射方法2***************end
Process finished with exit code 0
注:只用在上述映射方法上声明即可,批量映射及映射反转不用声明
4.多对一映射
第一种多对象映射:
WmsDto对象新增属性
private String memberName;
private int myAge;
新增对象
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Member {
private String myName;
private int myAge;
}
新增映射方法
@Mapping(source = "member.myAge" ,target = "myAge")
@Mapping(source = "member.myName" ,target = "memberName")
@Mapping(source = "wms.age" , target = "ageNumber")
WmsDto wmsAndMemberToWmsDto(Wms wms,Member member);
注:多对一映射时,与映射对象名一样的不用再次声明,源对象唯一命名不用加声明前缀,但是为了可读性,最好是加上声明前缀
测试代码
public static void main(String[] args) {
Wms wms = Wms.builder().id(1).name("wms").age(2).build();
Member member = Member.builder().myName("ssk").myAge(24).build();
WmsDto wmsDto = WmsMapper.INSTANCES.wmsAndMemberToWmsDto(wms, member);
System.out.println(wmsDto);
}
运行结果
WmsDto(id=1, name=wms, ageNumber=2, memberName=ssk, myAge=24)
特殊:在多对一映射时,可以选择性忽略某些属性的映射
映射方法修改:
@Mapping(source = "member.myAge" ,target = "myAge")
@Mapping(source = "member.myName" ,target = "memberName")
@Mapping(source = "wms.age" , target = "ageNumber")
@Mapping(target = "id" ,ignore = true)
WmsDto wmsAndMemberToWmsDto(Wms wms,Member member);
运行结果
WmsDto(id=0, name=wms, ageNumber=2, memberName=师宋奎, myAge=24)
第二种常量映射:
新增映射方法
@Mapping(source = "id",target = "id" )
@Mapping(source = "name",target = "name" )
WmsDto wmsAndMemberToWmsDto(Wms wms,String name,int id);
测试代码:
public static void main(String[] args) {
Wms wms = Wms.builder().id(1).build();
WmsDto wmsDto = WmsMapper.INSTANCES.wmsAndMemberToWmsDto(wms, "wms", 11);
System.out.println(wmsDto);
}
运行结果
WmsDto(id=11, name=wms, ageNumber=0, memberName=null, myAge=0)
5.@Mapping(defaultValue = “wd” )
注:
声明 ignore = true 不生效
源属性有值 不生效
映射方法修改:
@Mapping(source = "member.myAge" ,target = "myAge")
@Mapping(source = "member.myName" ,target = "memberName")
@Mapping(source = "wms.age" , target = "ageNumber")
@Mapping(target = "id" ,ignore = true)
@Mapping(target = "name" ,defaultValue = "wms" )
WmsDto wmsAndMemberToWmsDto(Wms wms,Member member);
测试代码
public static void main(String[] args) {
Wms wms = Wms.builder().id(1).build();
WmsDto wmsDto = WmsMapper.INSTANCES.wmsAndMemberToWmsDto(wms, null);
System.out.println(wmsDto);
}
运行结果
WmsDto(id=0, name=wms, ageNumber=0, memberName=null, myAge=0)
6.@Mapping(constant= “11” )
注:
声明 ignore = true 不生效
源属性有值 替换
修改映射方法
@Mapping(target = “id” ,constant = “11”)
@Mapping(source = "member.myAge" ,target = "myAge")
@Mapping(source = "member.myName" ,target = "memberName")
@Mapping(source = "wms.age" , target = "ageNumber")
@Mapping(target = "id" ,constant = "11")
@Mapping(target = "name" ,defaultValue = "wms" )
WmsDto wmsAndMemberToWmsDto(Wms wms,Member member);
7.@Mapping(expression = “java(new Date())” )
WmsDto新增属性
private Date time;
修改映射方法
@Mapping(source = "id",target = "id" )
@Mapping(source = "name",target = "name" )
@Mapping(target = "time" ,expression = "java(new java.util.Date())")
WmsDto wmsAndMemberToWmsDto(Wms wms,String name,int id);
测试代码
public static void main(String[] args) {
Wms wms = Wms.builder().id(1).build();
WmsDto wmsDto1 = WmsMapper.INSTANCES.wmsAndMemberToWmsDto(wms, "wms", 11);
System.out.println(wmsDto1);
}
运行结果:
WmsDto(id=11, name=wms, ageNumber=0, memberName=null, myAge=0, time=Wed Sep 15 15:13:20 CST 2021)
其他
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WkOUDBXJ-1631951526475)(C:\Users\edy\AppData\Roaming\Typora\typora-user-images\image-20210915172448682.png)]
修改方式
在映射器@Mapper注解里新增属性
@Mapper(imports = {Date.class})
方法上声明变为
@Mapping(source = "id",target = "id" )
@Mapping(source = "name",target = "name" )
@Mapping(target = "time" ,expression = "java(new Date())")
WmsDto wmsAndMemberToWmsDto(Wms wms,String name,int id);
8.从int到String的转换 numberFormat
新增对象
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Base {
private int price;
private BigDecimal power;
private Date time;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BaseDto {
private String price;
private String power;
private String time;
}
在映射器里新增方法
/**
*从int到String的转换
* @param
* @return
*/
@Mapping(target = "price", source = "price", numberFormat = "$#.00")
BaseDto baseToBaseDTOShowInt(Base base);
@IterableMapping(numberFormat = "$#.00")
List<String> intToString(List<Integer> list);
@InheritInverseConfiguration(name = "intToString")
List<Integer> StringToInt(List<String> list);
测试代码
public static void main(String[] args) {
Base base = Base.builder().price(100).build();
BaseDto baseDto = WmsMapper.INSTANCES.baseToBaseDTOShowInt(base);
System.out.println(baseDto);
System.out.println("-------------分割线------------");
List<String> strings = WmsMapper.INSTANCES.intToString(Arrays.asList(1, 2, 30, 40));
strings.forEach(System.out::println);
System.out.println("-------------分割线------------");
WmsMapper.INSTANCES.StringToInt(strings).forEach(System.out::println);
}
运行结果
BaseDto(price=$100.00, power=null, time=null)
-------------分割线------------
$1.00
$2.00
$30.00
$40.00
-------------分割线------------
1
2
30
40
9.从BigDecimal到String的转换 numberFormat
在映射器里新增方法
/**
*从BigDecimal到String的转换
* @param
* @return
*/
@Mapping(target = "power", source = "power", numberFormat = "#.##E0")
BaseDto baseToBaseDTOShowBigDecimal(Base base);
测试代码
public static void main(String[] args) {
Base base = Base.builder().power(new BigDecimal(10.112)).build();
BaseDto baseDto = WmsMapper.INSTANCES.baseToBaseDTOShowBigDecimal(base);
System.out.println(baseDto);
}
运行结果
BaseDto(price=0, power=1.01E1, time=null)
10.从日期到字符串的转换 dateFormat
在映射器里新增方法
/**
*从日期到字符串的转换
* @param
* @return
*/
@Mapping(target = "time", source = "time", dateFormat = "yyyy.MM.dd HH:mm:ss")
BaseDto baseToBaseDTOShowDate(Base base);
@IterableMapping(dateFormat = "dd.MM.yyyy")
List<String> DateToString(List<Date> list);
/**
* 从字符串到日期的转换 逆转
* @param list
* @return
*/
@InheritInverseConfiguration(name = "DateToString")
List<Date> StringToDate(List<String> list);
测试代码
public static void main(String[] args) {
System.out.println("------------baseToBaseDTOShowDate");
Base base = Base.builder().time(new Date()).build();
BaseDto baseDto = WmsMapper.INSTANCES.baseToBaseDTOShowDate(base);
System.out.println(baseDto);
System.out.println("------------DateToString");
List<String> strings = WmsMapper.INSTANCES.DateToString(Arrays.asList(new Date(), new Date(), new Date(), new Date()));
strings.forEach(System.out::println);
System.out.println("------------StringToDate");
WmsMapper.INSTANCES.StringToDate(strings).forEach(System.out::println);
}
运行结果
------------baseToBaseDTOShowDate
BaseDto(price=0, power=null, time=2021.09.15 18:05:43)
------------DateToString
15.09.2021
15.09.2021
15.09.2021
15.09.2021
------------StringToDate
Wed Sep 15 00:00:00 CST 2021
Wed Sep 15 00:00:00 CST 2021
Wed Sep 15 00:00:00 CST 2021
Wed Sep 15 00:00:00 CST 2021
11.Map转换成对象
在映射器里新增方法
@Mappings({
@Mapping(expression = "java(Integer.valueOf(map.get(\"id\")))" ,target = "id",resultType = Integer.class),
@Mapping(expression = "java(map.get(\"name\"))" ,target = "name",resultType = String.class),
@Mapping(expression = "java(WmsMapMapper.stringToInteger((map.get(\"age\"))))" ,target = "age",resultType = Integer.class)
})
Wms mapToWms(Map<String,String> map);
static Integer stringToInteger(String s){
return Integer.valueOf(s);
}
测试代码
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("id","1");
map.put("name","ZSHMWMS组");
map.put("age","2");
Wms wms = WmsMapMapper.INSTANCES.mapToWms(map);
System.out.println(wms);
}
运行结果
Wms(id=1, name=ZSHMWMS组, age=2)
r.valueOf(map.get(“id”)))" ,target = “id”,resultType = Integer.class),
@Mapping(expression = “java(map.get(“name”))” ,target = “name”,resultType = String.class),
@Mapping(expression = “java(WmsMapMapper.stringToInteger((map.get(“age”))))” ,target = “age”,resultType = Integer.class)
})
Wms mapToWms(Map<String,String> map);
static Integer stringToInteger(String s){
return Integer.valueOf(s);
}
测试代码
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("id","1");
map.put("name","ZSHMWMS组");
map.put("age","2");
Wms wms = WmsMapMapper.INSTANCES.mapToWms(map);
System.out.println(wms);
}
运行结果
Wms(id=1, name=ZSHMWMS组, age=2)
@MapperConfig
public interface BaseMapping<S, T> {
/**
* 映射同名属性
*
* @param source
* @return
*/
T sourceToTarget(S source);
/**
* 批量映射同名属性
*
* @param source
* @return
*/
@InheritConfiguration(name = "sourceToTarget")
List<T> sourceToTarget(List<S> source);
/**
* 反向映射同名属性
*
* @param target
* @return
*/
@InheritInverseConfiguration(name = "sourceToTarget")
S targetToSource(T target);
/**
* 批量反向映射同名属性
*
* @param target
* @return
*/
@InheritConfiguration(name = "targetToSource")
List<S> targetToSource(List<T> target);
/**
* 流式批量映射同名属性
*
* @param source
* @return
*/
List<T> sourceToTarget(Stream<S> source);
/**
* 流式批量反向映射同名属性
*
* @param target
* @return
*/
@InheritConfiguration(name = "targetToSource")
List<S> targetToSource(Stream<T> target);
}
标签:name,Wms,MapStruct,映射,wms,WmsDto,id 来源: https://blog.csdn.net/SSKDCT/article/details/120368906