Mapstruct怎么使用【学习总结】

什么是Mapstruct?

Mapstruct是一个将Entity向Vo互相转换的工具,各实体间互相转换

为什么要用Mapstruct?

容易,方便,易理解,快捷高效

怎么用?

  1. 首先需要和lombok一起使用,因为这样很方便,当然也可以不用
    因为使用lombok需要一些规范,后面会说
    什么?lombok怎么用?
    很容易!
    lombok提供了很多注解,方便实体类的编写
    如@Data,@Getter,@Setter等
    (这里直接偷张图来)
    在这里插入图片描述
    下面例子用的lombok
  2. maven导入这些包
 	<dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.12</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.mapstruct</groupId>
      <artifactId>mapstruct</artifactId>
      <version>1.5.0.Final</version>
    </dependency>
    <dependency>
      <groupId>org.mapstruct</groupId>
      <artifactId>mapstruct-processor</artifactId>
      <version>1.5.0.Final</version>
    </dependency>
  1. 现在有参数相同的User 和 UserVo,注意参数完全相同

User是Entity面向数据库

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String name;
    private String pass;
}

UserVo(View Object)面向前端

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserVo {
    private String name;
    private String pass;
}

ok,资源都准备好了

正题来了

  1. 首先写个接口类,名字自己随便取
  2. 写上mapstruct的注解@Mapper,注意不是ibatis的
  3. 然后照着写就是了
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface converter {
    converter INSTANCE = Mappers.getMapper(converter.class);
}

现在要将User转换成UserVo

  1. 当参数都相同时
@Mapper
public interface converter {
    converter INSTANCE = Mappers.getMapper(converter.class);
    /**
     * 
     * @param user 被复制的对象
     * @return 转换的对象
     */
    UserVo ConverToUserVo(User user);
}

没错写完了,就这么容易

测试:

public class Test {
    public static void main(String[] args) {
        User user = new User("haha","123");
        UserVo userVo = null;//并没有new
        userVo = converter.INSTANCE.ConverToUserVo(user);//直接用接口的方法
        System.out.println(userVo);//输出
}

输出:
在这里插入图片描述

我们看看Mapstruct干了什么:
很清楚的看到Mapstruct实现了我们写的接口
注意我之前并没有new UserVo,是因为我接口里的写法,Mapstruct会帮我们new
在这里插入图片描述

  1. 那么我们要求参数不同时怎么写呢?
    我们将UserVo改成
public class UserVo {
    private String nameVo;//name
    private String passVo;//pass
}
  • 一般情况推荐使用
    这里使用@Mapping,用来指定谁是源谁是目标
    很明显
    source 代表 被复制的值
    target 代表 被转换的值
@Mapper
public interface converter {
   converter INSTANCE = Mappers.getMapper(converter.class);
   /**
    *
    * @param user 被复制的对象
    * @return 转换的对象
    */
   @Mappings({
           @Mapping(source = "name",target = "nameVo"),
           @Mapping(source = "pass",target = "passVo")
   })
   UserVo ConverToUserVo(User user);
}

这里测试用例还是一样
在这里插入图片描述
实现类的get和set也相应的改了
在这里插入图片描述

  1. 当参数来自不同的source时,这时就需要我们指定source
    写法如下:
    注意观察写法不一样了
    这里我们用对象来指定source
@Mapper
public interface converter {
   converter INSTANCE = Mappers.getMapper(converter.class);
   /**
    *
    * @param user 被复制的对象
    * @return 转换的对象
    */
   @Mappings({
           @Mapping(source = "user.name",target = "nameVo"),
           @Mapping(source = "userVo.passVo",target = "passVo")
   })
   UserVo ConverToUserVo(UserVo userVo, User user);
}

测试用例换成:

        User user = new User("haha","123");
        UserVo userVo = new UserVo("jj","456");//这里new了,不new不行
        userVo = converter.INSTANCE.ConverToUserVo(userVo,user);
        System.out.println(userVo);

结果:

UserVo(nameVo=haha, passVo=456)

实现类:
在这里插入图片描述
ok,这里有个bug,UserVo重复new了一次

  • 那么当我们想要修改现有的对象的某个值,但不想重新创个对象的时候,怎么办呢?
    这时@MappingTarget注解就有用了.

我们现在将接口方法改成:

@Mapper
public interface converter {
    converter INSTANCE = Mappers.getMapper(converter.class);
    /**
     *
     * @param user 被复制的对象
     * @return 转换的对象
     */
    @Mappings({
            @Mapping(source = "name",target = "nameVo"),
            @Mapping(source = "pass",target = "passVo")
    })
    //对转换对象加上@MappingTarget注解,表示这是我要转换的对象
    UserVo ConverToUserVo(@MappingTarget UserVo userVo, User user);
}

@MappingTarget指定一个是转换的对象,没有注解的就是被复制的对象
缺点是,target的源固定,没法改,就是复制源不能再取自己了,改了会报错
优点是,对象用户自己定义,不会出现空指针

  1. 还有一种情况,当出现多层嵌套对象时
    如User中还有一个对象Order,我们将orderName复制给UserVo.name
    代码如下:
    在这里插入图片描述

在这里插入图片描述
怎么办呢?
其实写法和上一个一样,我们指定源就是了

@Mapper
public interface converter {
    converter INSTANCE = Mappers.getMapper(converter.class);
    /**
     *
     * @param user 被复制的对象
     * @return 转换的对象
     */
    @Mappings({
    		//多重嵌套
            @Mapping(source = "user.order.orderName",target = "nameVo"),
            @Mapping(source = "pass",target = "passVo")//这里pass就源的pass
    })
    UserVo ConverToUserVo(@MappingTarget UserVo userVo, User user);
}

测试:
在这里插入图片描述
结果:

UserVo(nameVo=kaka, passVo=123)

实现类:
这里多了一块
在这里插入图片描述

最后说说一些注意事项

  • Mapstruct和lombok一起用的参数命名
    命名要求首字母不能大写,命名要规范,否则会出问题
    类似userName,username,usernAme都可以
    不能写成 UserName,Username…
  • 接口方法参数顺序无所谓

总结

本文章为了记录本人对Mapstruct学习经验,以免日后忘记.
还有很多不足的地方。望各位网友指教。

参考文章:https://blog.csdn.net/qq_40194399/article/details/110162124,感谢此文作者

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值