其他分享
首页 > 其他分享> > MapStruct

MapStruct

作者:互联网

MapStruct

一.MapStruct是什么

MapStruct 是一个 Java注释处理器,用于生成类型安全的 bean 映射类。

MapStruct 的一般理念是生成的代码看起来尽可能像您自己亲手编写的代码。特别是这意味着通过简单的 getter/setter 调用而不是反射或类似方法将值从源复制到目标。

二.为什么要用MapStruct

类型安全、高性能和无依赖的 bean 映射代码

与动态映射框架相比,MapStruct 具有以下优势:

三.MapStruct怎么用

所以要做的就是定义一个映射器接口,该接口声明任何所需的映射方法。在编译期间,MapStruct 将生成此接口的实现。此实现使用纯 Java 方法调用来映射源对象和目标对象,即没有反射或类似的。

它包括以下工件:

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