MapStruct 使用总结

前置条件

maven 引入依赖

 <properties>
        <java.version>11</java.version>
        <java.version>1.8</java.version>
        <org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.2</version>
        </dependency>

        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-jdk8</artifactId>
            <version>${org.mapstruct.version}</version>
        </dependency>

        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>${org.mapstruct.version}</version>
        </dependency>

        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>1.4.2.Final</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
       
    </dependencies>

1-lombok(若是使用lombok,不仅仅是@Data,还需要别的注解,具体google),2-mapstruct ,3-hutool-all


public class Student {

    private String name;
    private String sex;
    private Integer age;
    // 对应person -> tall
    private Long height;
    private Integer rank;
    /** long 形式的时间格式 */
   private Long time;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Long getHeight() {
        return height;
    }

    public void setHeight(Long height) {
        this.height = height;
    }

    public Integer getRank() {
        return rank;
    }

    public void setRank(Integer rank) {
        this.rank = rank;
    }

    public Long getTime() {
        return time;
    }

    public void setTime(Long time) {
        this.time = time;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                ", height=" + height +
                ", rank=" + rank +
                ", time=" + time +
                '}';
    }
}


public class Person {
    private String name;
    private String sex;
    private Integer age;
    private String tall;
    private String time;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getTall() {
        return tall;
    }

    public void setTall(String tall) {
        this.tall = tall;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }
}

写MapStruct 接口

注意点
1- student - height 与 person-tall 要相互复制的。类型和名字都不同
2-student-time 与 person-time 名字相同,类型不同
结论
1-对于 string 类型与 基本类型之间,若名字相同,类型不同,可直接转化(不要手动干预)
2-如时间,string与long的转化需要定义方法


import cn.hutool.core.date.DateUtil;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;

import java.sql.Time;

/*    @Mapping(source = "time",target = "time",expression = "java(StructHelper.DateTimeStrToTimeMillis(person.getTime()))"*/
@Mapper(componentModel = "spring", uses = StructHelper.class)
public interface MapStructTest {
    //    MapStructTest INSTANCE = Mappers.getMapper(MapStructTest.class);
    @Mappings({
            @Mapping(source = "tall", target = "height"),
            @Mapping(source = "time", target = "time", qualifiedByName = StructConstant.DATE_TIME_STR_TO_TIME_MILLIS)
    })
    Student personToStudent(Person person);


//    @Named(value = "dateTimeStrToTimeMillis")
//    default  Long DateTimeStrToTimeMillis(String dataTimeStr) {
//
//        return DateUtil.parseDateTime(dataTimeStr).getTime();
//    }
}

方式一:expression
缺点:需要写 全限定类型。不好维护

@Mapping(source = "time",target = "time",expression = "java(StructHelper.DateTimeStrToTimeMillis(person.getTime()))

**方式二:qualifiedByName **
优点:维护性比较高。
我这里定义了常量。方便 Ctrl+鼠标左键,进行点击。

若定义转换方法不多的话,可以直接写在这个接口里。然后常量类也省去了。

自定义方法


@Component
@Named(value = "StructHelper")
public class StructHelper {

    /**
     * 时间搓转换程日期格式
     * @param timeMillis
     * @return
     */
    @Named(value = StructConstant.TIME_MILLIS_TO_DATE_STR)
    public static String timeMillisToDateStr(Long timeMillis) {

        return DateUtil.formatDate(DateUtil.date(timeMillis));
    }

    /**
     * 时间搓转换程日期时间格式
     * @param timeMillis
     * @return
     */
    @Named(value = StructConstant.TIME_MILLIS_TO_DATE_TIME_STR)
    public static String timeMillisToDateTimeStr(Long timeMillis) {

        return DateUtil.formatDateTime(DateUtil.date(timeMillis));
    }

    /**
     * 日期时间格式转换程时间搓
     * @param dataStr
     * @return
     */
    @Named(value = StructConstant.DATE_STR_TO_TIME_MILLIS)
    public static Long DateStrToTimeMillis(String dataStr) {

        return DateUtil.parseDateTime(dataStr).getTime();
    }

    /**
     * 日期时间格式转换程时间搓
     * @param dataTimeStr
     * @return
     */
    @Named(value = StructConstant.DATE_TIME_STR_TO_TIME_MILLIS)
//    @Named(value = "dateTimeStrToTimeMillis")
    public static Long DateTimeStrToTimeMillis(String dataTimeStr) {

        return DateUtil.parseDateTime(dataTimeStr).getTime();
    }
}

注意点
在这里插入图片描述

使用

方式一:apStructTest INSTANCE = Mappers.getMapper(MapStructTest.class);
方式二:直接注入,写的接口,MapStructTest
实际两者一样,获得一个对象,然后调用方法

原理

第一步:执行下
在这里插入图片描述
第二步:
在这里插入图片描述
第三步:

  @Override
    public InvoiceApplyVo entityToInvoiceApplyVo(InvoiceApply invoiceApply) {
        if ( invoiceApply == null ) {
            return null;
        }

        InvoiceApplyVo invoiceApplyVo = new InvoiceApplyVo();

        invoiceApplyVo.setAuditTime( structHelper.timeMillisToDateTimeStr( invoiceApply.getAuditTime() ) );
        invoiceApplyVo.setId( invoiceApply.getId() );
        invoiceApplyVo.setInvoiceContent( invoiceApply.getInvoiceContent() );
        invoiceApplyVo.setInvoiceRiseName( invoiceApply.getInvoiceRiseName() );
        invoiceApplyVo.setAdminName( invoiceApply.getAdminName() );
        invoiceApplyVo.setStatus( invoiceApply.getStatus() );

        return invoiceApplyVo;
    }

上面对类型的转换,使用的自定义的函数调用

复杂类型

list --> list

    /**
     * List<InvoiceApply>--> List<InvoiceApplyVo>
     *
     * @param invoiceApplies
     * @return
     */
    List<InvoiceApplyVo> toInvoiceApplyVo(List<InvoiceApply> invoiceApplies);

看自动生成的接口实现


    @Override
    public List<InvoiceApplyVo> toInvoiceApplyVo(List<InvoiceApply> invoiceApplies) {
        if ( invoiceApplies == null ) {
            return null;
        }

        List<InvoiceApplyVo> list = new ArrayList<InvoiceApplyVo>( invoiceApplies.size() );
        for ( InvoiceApply invoiceApply : invoiceApplies ) {
            list.add( entityToInvoiceApplyVo( invoiceApply ) );
        }

        return list;
    }

这里,会自动调用单个的,然后for循环。

总结

mapStruct 实际上是比较好用的,可能前期写的时候,可能比较繁琐。
但是在 Dto、entity,vo,转换的时候,可以省事一些。

lombok+MapStruct兼容使用

若版本不对应的话,会导致这两个玩意不能兼容
出现这样

    public XXXVO toXXXVO(XXXModel model) {
        if ( model == null ) {
            return null;
        }
 
        XXXVO xxxVO = new XXXVO();
 
        return xxxVO;
    }

答案是:mapstruct-1.3.0.Final,对应lombok-1.18.10 就可以正常使用了!done.

常见错误

Error:(38, 13) java: Can’t map property “Integer autoTakeTime” to “Integer autoTakeTime”. Consider to declare/implement a mapping method: “Integer map(Integer value)”.
检查你 自定义转换方法
比如

    @Named(value = StructConstant.TIME_MILLIS_TO_DATE_TIME_STR)
    public String timeMillisToDateTimeStr(Long timeMillis) {
        if (ValidateUtil.isEmpty(timeMillis)){
            return "";
        }
        return DateUtil.formatDateTime(DateUtil.date(timeMillis));
    }

实际上。自定义方法是将long 转为 String。但是 target对象使用Interger接的。所有抛出了异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值