ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

MapStruct

2021-09-18 15:58:51  阅读:583  来源: 互联网

标签:name Wms MapStruct 映射 wms WmsDto id


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有