屬性映射工具——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的印象更深了。好了,今天就到這里了。下期我們繼續!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM