属性映射工具——MapStruct(二)

目录:

属性映射工具——MapStruct(一)

属性映射工具——MapStruct(二)

属性映射工具——MapStruct(三)

属性映射工具——MapStruct(四)

属性映射工具——MapStruct(五)


   写完第一篇,好长时间没写了。趁着今天有时间,继续总结一下吧。来吧,我们继续。今天我们看一个转化的例子,例子几乎涉及到了大部分情况。

 

一、目标及要求

  先定义两个互相赋值的类People1,People2。我们的目的是把People1的属性赋值给People2。当然了在赋值的过程中有一些修改。先看看两个People的区别以及赋值的要求吧。

1) id——主键——属性相同,直接赋值;

2) name——名称——需要将name1赋值给name2;

3) no——编号——需要将no1赋值给no2;

4) age——年龄——不需要赋值,即people2不能有这个值;

5) height——身高——需要将“cm”为单位的height1转化为以“m”单位的height2;

6) weight——体重——需要将“kg”为单位的weight转化为以“斤”为单位的weight2,并且加上单位;

7) sex——性别——需要将枚举转化为对应的code;

8) createTime——创建时间——需要将Date类型的创建时间转化为字符串形式,并且是"yyyy-MM-dd HH:mm:ss:SSS"的形式;

9) bloodType——血型——不管任何人,血型都是“A型血”;

10) salary——工资——工资是Double类型的,需要转化为String类型,并且保留三位小数;

11) saseDough——私房钱(小金库)—私房钱市String类型的,需要转化为Integer类型的;

12) address——地址——people1里面的地址是一个对象(省+市+县+街道),但是people2里面只有省,所以需要将people1里面的对应的省给people2里面。

@Data
@NoArgsConstructor
@AllArgsConstructor
public class People1 {
    //主键
    private String id;
    //名称
    private String name1;
    //编号
    private String no1;
    //年龄
    private String age1;
    //身高(cm)
    private Long height1;
    //体重(kg)
    private Integer weight1;
    //性别
    private SexEnum sex1;
    //创建时间
    private Date createTime1;
    //血型
    private Character bloodType1;
    //工资卡
    private Double salary1;
    //小金库
    private String caseDough1;
    //地址
    private Address address;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class People2 {
    //主键
    private String id;
    //名称
    private String name2;
    //编号
    private String no2;
    //年龄
    private Integer age2;
    //身高(m)
    private Double height2;
    //体重(斤)
    private String weight2;
    //性别(1:男,0:女)
    private Integer sex2;
    //创建时间
    private String createTime2;
    //血型
    private String bloodType2;
    //工资卡
    private String salary2;
    //小金库
    private Integer caseDough2;
    //地址(所在省)
    private String province;
}

 

  辅助类:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Address {
    //
    private String province;
    //
    private String city;
    //
    private String county;
    //街道
    private String street;
}
public enum SexEnum {
    MAN(1, "男"),
    WOMAN(0, "女");

    private Integer code;
    private String desc;

    SexEnum(Integer code, String desc) {
        this.code = code;
        this.desc = desc;
    }
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
}

 

二、实现

以下是我们根据要求写的PeopleMapper转化接口。总之一句话,学习MapStruct就是看文档,然后看它生成的转化实体类,你就大彻大悟了。

1) id——主键——属性相同,直接赋值

  属性名称、类型均相同,所以不需要特别指定。  

2) name——名称——需要将name1赋值给name2;

  属性类型相同。名称不同,需要指定——@Mapping(source = "name1", target = "name2")

3) no——编号——需要将no1赋值给no2;

  类似name。属性类型相同。名称不同,需要指定——@Mapping(source = "no1", target = "no2")

4) age——年龄——不需要赋值;

  增加了ignore参数,该参数默认是false,这里设置为true。所以忽略该参数的赋值——@Mapping(source = "age1", target = "age2", ignore = true)

5) height——身高——需要将“cm”为单位的height1转化为以“m”单位的height2;

a) 这是一个比较复杂的转化。我们使用了qualifiedByName。qualifiedByName的意思就是使用这个Mapper接口中的指定的默认方法去处理这个属性的转换,而不是简单的get set。可用于格式化小数位等,在po转换为vo时就已格式化小数位完成,所以不必单独再写代码处理小数位。  

b) 我们在PeopleMapper接口里面定义了一个接口的默认方法heightConvert(default关键字开头的,只有java8及以上的版本支持,java8以下的版本,请参考weight的转化)。方法的名字是啥不重要,重要的是方法上面@Named()中的值。必须确保qualifiedByName的值和方法上加的@Named的值是一样的,这样才可以进行匹配。这里qualifiedByName的值是字符串。

6) weight——体重——需要将“kg”为单位的weight转化为以“斤”为单位的weight2;

  这个转化类似与height的转化,但是我们采用了不同的方式

  a) 我们没有在PeopleMapper中定义接口的默认方法。而是单独的创建了一个转化的类WeightMapper,并且定义了转化的方法weightConvert。同理,类的名称、方法的名称是啥不重要,重要的是@Named里面的值。

  b) 我们的qualifiedByName的值不再是字符串,而是一个数组,数组中两个元素,第一个是类的Named值,第二个是方法的Named值。

  c) 如果不采用单独写转化类。那么PeopleMapper上注解@Mapper就可以了。但是如果是单独写转化类的这种形式,必须在PeopleMapper的@Mapper中指定uses的值,uses的值是一个数组,里面是转化类的class对象,转化接口中你引用了几个,你就写几个,否则取不到值。

  结果:@Mapping(source = "weight1", target = "weight2", qualifiedByName = {"WeightMapper", "WeightConvert"})

7) sex——性别——需要将枚举转化为对应的code;

  这里我们直接用链式法则写了——@Mapping(source = "sex1.code",target = "sex2")

8) createTime——创建时间——需要将Date类型的创建时间转化为字符串形式,并且是"yyyy-MM-dd HH:mm:ss:SSS"的形式;

    这里我们采用了@Mapping的新的属性dateFormat,值为SimpleDateFormat的值,看了它生成的源码,你就会有所发现了。但是dateFormat属性只能用于 Date 转 String 类型。

9) bloodType——血型——不管任何人,血型都是“A型血”;

  同样的我们使用了@Mapping的新属性constant。但是这里需要注意的是,与其他属性不同,其他属性搭配的往往必须有source、target。但是constant搭配的属性只有target,意思是不管你原属性是啥样的,我最终的值是constant的值,和你无关。如果你搭配了source属性,会编译异常——Source and constant are both defined in @Mapping, either define a source or a constant。

10) salary——工资——工资是Double类型的,需要转化为String类型,并且保留三位小数;

  使用了@Mapping的新属性numberFormat。number是使用DecimalFormat将一个Number(java里面所有的数值类都继承了这个抽象类)转化为String,或者将String转化为Number,其他的转化是不生效的。比如Double转Double,String转String等。所以你就知道了DecimalFormat怎么玩,你这里就怎么用。不清楚的看这里  java.text.DecimalFormat实战

11) saseDough——私房钱(小金库)—私房钱市String类型的,需要转化为Integer类型的;

    原理同salary。只不过是Double类型转化为Integer类型。

12) address——地址——people1里面的地址是一个对象(省+市+县+街道),但是people2里面只有省,所以需要将people1里面的对应的省给people2里面。

    这里是使用了多参数转化,类似与sex的转换,但是稍微有所不同。大家可以类似的对照理解。

@Mapper(uses={WeightMapper.class})
public interface PeopleMapper {
    PeopleMapper INSTANCE = Mappers.getMapper(PeopleMapper.class);
    
    @Mappings({
            @Mapping(source = "name1", target = "name2"),
            @Mapping(source = "no1", target = "no2"),
            @Mapping(source = "age1", target = "age2", ignore = true),
            @Mapping(source = "height1", target = "height2", qualifiedByName = "heightConvert"),
            @Mapping(source = "weight1", target = "weight2", qualifiedByName = {"WeightMapper", "WeightConvert"}),
            @Mapping(source = "sex1.code",target = "sex2")
    })
    People2 toPeople2(People1 people1);
    
    @Named("heightConvert")
    default Double heightConvert(Long height) {
        return height * 1.0 / 100;
    }
}
@Component
@Named("WeightMapper")
public class WeightMapper {
    @Named("WeightConvert")
    public String weightConvert(Integer weight){
        //kg —— 斤
        return (weight*2)+"斤";
    }
}

 

三、结果

  编译后自动生成的PeopleMapper对应实现类PeopleMapperImpl。

import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import javax.annotation.Generated;

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2020-07-23T11:04:13+0800",
    comments = "version: 1.2.0.Final, compiler: javac, environment: Java 1.8.0_201 (Oracle Corporation)"
)
public class PeopleMapperImpl implements PeopleMapper {
    private final WeightMapper weightMapper = new WeightMapper();

    @Override
    public People2 toPeople2(People1 people1) {
        if ( people1 == null ) {
            return null;
        }

        People2 people2 = new People2();

        people2.setNo2( people1.getNo1() );
        people2.setHeight2( heightConvert( people1.getHeight1() ) );
        String province = people1AddressProvince( people1 );
        if ( province != null ) {
            people2.setProvince( province );
        }
        Integer code = people1Sex1Code( people1 );
        if ( code != null ) {
            people2.setSex2( code );
        }
        if ( people1.getSalary1() != null ) {
            people2.setSalary2( new DecimalFormat( "0.000" ).format( people1.getSalary1() ) );
        }
        try {
            if ( people1.getCaseDough1() != null ) {
                people2.setCaseDough2( new DecimalFormat( "0." ).parse( people1.getCaseDough1() ).intValue() );
            }
        }
        catch ( ParseException e ) {
            throw new RuntimeException( e );
        }
        people2.setName2( people1.getName1() );
        people2.setWeight2( weightMapper.weightConvert( people1.getWeight1() ) );
        if ( people1.getCreateTime1() != null ) {
            people2.setCreateTime2( new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss:SSS" ).format( people1.getCreateTime1() ) );
        }
        people2.setId( people1.getId() );

        people2.setBloodType2( "A型血" );

        return people2;
    }

    private String people1AddressProvince(People1 people1) {
        if ( people1 == null ) {
            return null;
        }
        Address address = people1.getAddress();
        if ( address == null ) {
            return null;
        }
        String province = address.getProvince();
        if ( province == null ) {
            return null;
        }
        return province;
    }

    private Integer people1Sex1Code(People1 people1) {
        if ( people1 == null ) {
            return null;
        }
        SexEnum sex1 = people1.getSex1();
        if ( sex1 == null ) {
            return null;
        }
        Integer code = sex1.getCode();
        if ( code == null ) {
            return null;
        }
        return code;
    }
}

 

测试结果:

public class PeopleTest {
    /**
     * 输出结果:
     * People1(id=0001, name1=张三, no1=001, age1=18, height1=183, weight1=70, sex1=MAN, createTime1=Thu Jul 22 10:19:36 CST 2010, bloodType1=A, salary1=28.09888888888, caseDough1=1.08888888888, address=Address(province=安徽省, city=安庆市, county=太湖县, street=123街道))
     * People2(id=0001, name2=张三, no2=001, age2=null, height2=1.83, weight2=140斤, sex2=1, createTime2=2010-07-22 10:19:36:000, bloodType2=A型血, salary2=28.099, caseDough2=1, province=安徽省)
     */
    @Test
    public void test1() {
        People2 people2 = PeopleMapper.INSTANCE.toPeople2(setPeople1());
        System.out.println(people2);
    }
    
    private People1 setPeople1() {
        People1 people1 = new People1();
        people1.setId("0001");
        people1.setName1("张三");
        people1.setNo1("001");
        people1.setAge1("18");
        people1.setHeight1(183L);
        people1.setWeight1(70);
        people1.setSex1(SexEnum.MAN);
        people1.setCreateTime1(new Date(1279765176000L));
        people1.setBloodType1('A');
        people1.setSalary1(28.09888888888);
        people1.setCaseDough1("1.08888888888");
        people1.setAddress(new Address("安徽省", "安庆市", "太湖县", "123街道"));
        System.out.println(people1);
        return people1;
    }
}

 

如果你是从头至尾的看完这篇博文的话,相信你对mapStruct的印象更深了。好了,今天就到这里了。下期我们继续!!!

 

posted @ 2020-07-22 19:53  Erneste  阅读(3617)  评论(0编辑  收藏  举报