MapStruct是用来做什么的

首先来了解一下dto,dto简单的理解就是做数据传输对象的,类似于vo,但是vo用于传输到前端。
1.mapstruct是用来做什么的? 现在有这么个场景,从数据库查询出来了一个user对象(包含id,用户名,密码,手机号,邮箱,角色这些字段)和一个对应的角色对象role(包含id,角色名,角色描述这些字段),现在在controller需要用到user对象的id,用户名,和角色对象的角色名三个属性。
一种方式是直接把两个对象传递到controller层,但是这样会多出很多没用的属性。更通用的方式是需要用到的属性封装成一个类(dto),通过传输这个类的实例来完成数据传输。
user.java
@allargsconstructor  @data  public class user {      private long id;      private string username;      private string password;      private string phonenum;      private string email;      private role role;  }   role.java
@allargsconstructor  @data  public class role {      private long id;      private string rolename;      private string description;  }   userroledto.java,这个类就是封装的类
@data  public class userroledto {      /**       * 用户id       */      private long userid;      /**       * 用户名       */      private string name;      /**       * 角色名       */      private string rolename;  }   测试类,模拟将user对象转换成userroledto对象
public class maintest {      user user = null;        /**       * 模拟从数据库中查出user对象       */      @before      public void before() {         role role  = new role(2l, administrator, 超级管理员);         user  = new user(1l, zhangsan, 12345, 17677778888, 123@qq.com, role);      }        /**       * 模拟把user对象转换成userroledto对象       */      @test      public void test1() {          userroledto userroledto = new userroledto();          userroledto.setuserid(user.getid());          userroledto.setname(user.getusername());          userroledto.setrolename(user.getrole().getrolename());          system.out.println(userroledto);      }  }   从上面代码可以看出,通过getter、setter的方式把一个对象属性值复制到另一个对象中去还是很麻烦的,尤其是当属性过多的时候。而mapstruct就是用于解决这种问题的。
2.使用mapstruct解决上述问题 这里我们沿用user.java、role.java、userroledto.java。
新建一个userrolemapper.java,这个来用来定义user.java、role.java和userroledto.java之间属性对应规则:
userrolemapper.java
import org.mapstruct.mapper;  import org.mapstruct.mapping;  import org.mapstruct.mappings;  import org.mapstruct.factory.mappers;    /**   * @mapper 定义这是一个mapstruct对象属性转换接口,在这个类里面规定转换规则   *          在项目构建时,会自动生成改接口的实现类,这个实现类将实现对象属性值复制   */  @mapper  public interface userrolemapper {        /**       * 获取该类自动生成的实现类的实例       * 接口中的属性都是 public static final 的 方法都是public abstract的       */      userrolemapper instances = mappers.getmapper(userrolemapper.class);        /**       * 这个方法就是用于实现对象属性复制的方法       *       * @mapping 用来定义属性复制规则 source 指定源对象属性 target指定目标对象属性       *       * @param user 这个参数就是源对象,也就是需要被复制的对象       * @return 返回的是目标对象,就是最终的结果对象       */      @mappings({              @mapping(source = id, target = userid),              @mapping(source = username, target = name),              @mapping(source = role.rolename, target = rolename)      })      userroledto touserroledto(user user);    }   在测试类中测试:
通过上面的例子可以看出,使用mapstruct方便许多。
3.添加默认方法 添加默认方法是为了这个类(接口)不只是为了做数据转换用的,也可以做一些其他的事。
import org.mapstruct.mapper;  import org.mapstruct.mapping;  import org.mapstruct.mappings;  import org.mapstruct.factory.mappers;    /**   * @mapper 定义这是一个mapstruct对象属性转换接口,在这个类里面规定转换规则   *          在项目构建时,会自动生成改接口的实现类,这个实现类将实现对象属性值复制   */  @mapper  public interface userrolemapper {        /**       * 获取该类自动生成的实现类的实例       * 接口中的属性都是 public static final 的 方法都是public abstract的       */      userrolemapper instances = mappers.getmapper(userrolemapper.class);        /**       * 这个方法就是用于实现对象属性复制的方法       *       * @mapping 用来定义属性复制规则 source 指定源对象属性 target指定目标对象属性       *       * @param user 这个参数就是源对象,也就是需要被复制的对象       * @return 返回的是目标对象,就是最终的结果对象       */      @mappings({              @mapping(source = id, target = userid),              @mapping(source = username, target = name),              @mapping(source = role.rolename, target = rolename)      })      userroledto touserroledto(user user);        /**       * 提供默认方法,方法自己定义,这个方法是我随便写的,不是要按照这个格式来的       * @return       */      default userroledto defaultconvert() {          userroledto userroledto = new userroledto();          userroledto.setuserid(0l);          userroledto.setname(none);          userroledto.setrolename(none);          return userroledto;      }    }   测试代码:
@test  public void test3() {      userrolemapper userrolemapperinstances = userrolemapper.instances;      userroledto userroledto = userrolemapperinstances.defaultconvert();      system.out.println(userroledto);  }   4. 可以使用abstract class来代替接口 mapper可以用接口来实现,也可以完全由抽象来完全代替
import org.mapstruct.mapper;  import org.mapstruct.mapping;  import org.mapstruct.mappings;  import org.mapstruct.factory.mappers;    /**   * @mapper 定义这是一个mapstruct对象属性转换接口,在这个类里面规定转换规则   *          在项目构建时,会自动生成改接口的实现类,这个实现类将实现对象属性值复制   */  @mapper  public abstract class userrolemapper {        /**       * 获取该类自动生成的实现类的实例       * 接口中的属性都是 public static final 的 方法都是public abstract的       */      public static final userrolemapper instances = mappers.getmapper(userrolemapper.class);        /**       * 这个方法就是用于实现对象属性复制的方法       *       * @mapping 用来定义属性复制规则 source 指定源对象属性 target指定目标对象属性       *       * @param user 这个参数就是源对象,也就是需要被复制的对象       * @return 返回的是目标对象,就是最终的结果对象       */      @mappings({              @mapping(source = id, target = userid),              @mapping(source = username, target = name),              @mapping(source = role.rolename, target = rolename)      })      public abstract userroledto touserroledto(user user);        /**       * 提供默认方法,方法自己定义,这个方法是我随便写的,不是要按照这个格式来的       * @return       */      userroledto defaultconvert() {          userroledto userroledto = new userroledto();          userroledto.setuserid(0l);          userroledto.setname(none);          userroledto.setrolename(none);          return userroledto;      }    }   5.可以使用多个参数 可以绑定多个对象的属性值到目标对象中:
package com.mapstruct.demo;    import org.mapstruct.mapper;  import org.mapstruct.mapping;  import org.mapstruct.mappings;  import org.mapstruct.factory.mappers;    /**   * @mapper 定义这是一个mapstruct对象属性转换接口,在这个类里面规定转换规则   *          在项目构建时,会自动生成改接口的实现类,这个实现类将实现对象属性值复制   */  @mapper  public interface userrolemapper {        /**       * 获取该类自动生成的实现类的实例       * 接口中的属性都是 public static final 的 方法都是public abstract的       */      userrolemapper instances = mappers.getmapper(userrolemapper.class);        /**       * 这个方法就是用于实现对象属性复制的方法       *       * @mapping 用来定义属性复制规则 source 指定源对象属性 target指定目标对象属性       *       * @param user 这个参数就是源对象,也就是需要被复制的对象       * @return 返回的是目标对象,就是最终的结果对象       */      @mappings({              @mapping(source = id, target = userid),              @mapping(source = username, target = name),              @mapping(source = role.rolename, target = rolename)      })      userroledto touserroledto(user user);        /**       * 多个参数中的值绑定        * @param user 源1       * @param role 源2       * @return 从源1、2中提取出的结果       */      @mappings({              @mapping(source = user.id, target = userid), // 把user中的id绑定到目标对象的userid属性中              @mapping(source = user.username, target = name), // 把user中的username绑定到目标对象的name属性中              @mapping(source = role.rolename, target = rolename) // 把role对象的rolename属性值绑定到目标对象的rolename中      })      userroledto touserroledto(user user, role role);   对比两个方法~
5.直接使用参数作为属性值 package com.mapstruct.demo;    import org.mapstruct.mapper;  import org.mapstruct.mapping;  import org.mapstruct.mappings;  import org.mapstruct.factory.mappers;    /**   * @mapper 定义这是一个mapstruct对象属性转换接口,在这个类里面规定转换规则   *          在项目构建时,会自动生成改接口的实现类,这个实现类将实现对象属性值复制   */  @mapper  public interface userrolemapper {        /**       * 获取该类自动生成的实现类的实例       * 接口中的属性都是 public static final 的 方法都是public abstract的       */      userrolemapper instances = mappers.getmapper(userrolemapper.class);        /**       * 直接使用参数作为值       * @param user       * @param myrolename       * @return       */      @mappings({              @mapping(source = user.id, target = userid), // 把user中的id绑定到目标对象的userid属性中              @mapping(source = user.username, target = name), // 把user中的username绑定到目标对象的name属性中              @mapping(source = myrolename, target = rolename) // 把role对象的rolename属性值绑定到目标对象的rolename中      })      userroledto useparameter(user user, string myrolename);    }   测试类:
public class test1 {      role role = null;      user user = null;        @before      public void before() {          role = new role(2l, administrator, 超级管理员);          user = new user(1l, zhangsan, 12345, 17677778888, 123@qq.com, role);      }      @test      public void test1() {          userrolemapper instances = userrolemapper.instances;          userroledto userroledto = instances.useparameter(user, myuserrole);          system.out.println(userroledto);      }  }   6.更新对象属性 在之前的例子中userroledto useparameter(user user, string myrolename);都是通过类似上面的方法来生成一个对象。而mapstruct提供了另外一种方式来更新一个对象中的属性。@mappingtarget
public interface userrolemapper1 {        userrolemapper1 instances = mappers.getmapper(userrolemapper1.class);        @mappings({              @mapping(source = userid, target = id),              @mapping(source = name, target = username),              @mapping(source = rolename, target = role.rolename)      })      void updatedto(userroledto userroledto, @mappingtarget user user);          @mappings({              @mapping(source = id, target = userid),              @mapping(source = username, target = name),              @mapping(source = role.rolename, target = rolename)      })      void update(user user, @mappingtarget userroledto userroledto);    }   通过@mappingtarget来指定目标类是谁(谁的属性需要被更新)。@mapping还是用来定义属性对应规则。
以此为例说明:
@mappings({              @mapping(source = id, target = userid),              @mapping(source = username, target = name),              @mapping(source = role.rolename, target = rolename)      })      void update(user user, @mappingtarget userroledto userroledto);   @mappingtarget标注的类userroledto 为目标类,user类为源类,调用此方法,会把源类中的属性更新到目标类中。更新规则还是由@mapping指定。
7.没有getter/setter也能赋值 对于没有getter/setter的属性也能实现赋值操作
public class customer {        private long id;      private string name;        //getters and setter omitted for brevity  }    public class customerdto {        public long id;      public string customername;  }    @mapper  public interface customermapper {        customermapper instance = mappers.getmapper( customermapper.class );        @mapping(source = customername, target = name)      customer tocustomer(customerdto customerdto);        @inheritinverseconfiguration      customerdto fromcustomer(customer customer);  }   @mapping(source = “customername”, target = “name”)不是用来指定属性映射的,如果两个对象的属性名相同是可以省略@mapping的。
mapstruct生成的实现类:
@generated(      value = org.mapstruct.ap.mappingprocessor,      date = 2019-02-14t1521+0800,      comments = version: 1.3.0.final, compiler: javac, environment: java 1.8.0_181 (oracle corporation)  )  public class customermapperimpl implements customermapper {        @override      public customer tocustomer(customerdto customerdto) {          if ( customerdto == null ) {              return null;          }            customer customer = new customer();            customer.setname( customerdto.customername );          customer.setid( customerdto.id );            return customer;      }        @override      public customerdto tocustomerdto(customer customer) {          if ( customer == null ) {              return null;          }            customerdto customerdto = new customerdto();            customerdto.customername = customer.getname();          customerdto.id = customer.getid();            return customerdto;      }  }   @inheritinverseconfiguration在这里的作用就是实现customerdto.customername = customer.getname();功能的。如果没有这个注解,tocustomerdto这个方法则不会有customername 和name两个属性的对应关系的。
8.使用spring依赖注入 @data  @noargsconstructor  @allargsconstructor  public class customer {      private long id;      private string name;  }    @data  public class customerdto {      private long id;      private string customername;  }    // 这里主要是这个componentmodel 属性,它的值就是当前要使用的依赖注入的环境  @mapper(componentmodel = spring)  public interface customermapper {        @mapping(source = name, target = customername)      customerdto tocustomerdto(customer customer);  }   @mapper(componentmodel = “spring”),表示把当前mapper类纳入spring容器。可以在其它类中直接注入了:
@springbootapplication  @restcontroller  public class demomapstructapplication {     // 注入mapper      @autowired      private customermapper mapper;        public static void main(string[] args) {          springapplication.run(demomapstructapplication.class, args);      }        @getmapping(/test)      public string test() {          customer customer = new customer(1l, zhangsan);          customerdto customerdto = mapper.tocustomerdto(customer);          return customerdto.tostring();      }    }   看一下由mapstruct自动生成的类文件,会发现标记了@component注解。
@generated(      value = org.mapstruct.ap.mappingprocessor,      date = 2019-02-14t1517+0800,      comments = version: 1.3.0.final, compiler: javac, environment: java 1.8.0_181 (oracle corporation)  )  @component  public class customermapperimpl implements customermapper {        @override      public customerdto tocustomerdto(customer customer) {          if ( customer == null ) {              return null;          }            customerdto customerdto = new customerdto();            customerdto.setcustomername( customer.getname() );          customerdto.setid( customer.getid() );            return customerdto;      }  }   9.自定义类型转换 有时候,在对象转换的时候可能会出现这样一个问题,就是源对象中的类型是boolean类型,而目标对象类型是string类型,这种情况可以通过@mapper的uses属性来实现:
@data  @noargsconstructor  @allargsconstructor  public class customer {      private long id;      private string name;      private boolean isdisable;  }    @data  public class customerdto {      private long id;      private string customername;      private string disable;  }   定义转换规则的类:
public class booleanstrformat {      public string tostr(boolean isdisable) {          if (isdisable) {              return y;          } else {              return n;          }      }      public boolean toboolean(string str) {          if (str.equals(y)) {              return true;          } else {              return false;          }      }  }   定义mapper,@mapper( uses = { booleanstrformat.class}),注意,这里的users属性用于引用之前定义的转换规则的类:
@mapper( uses = { booleanstrformat.class})  public interface customermapper {        customermapper instances = mappers.getmapper(customermapper.class);        @mappings({              @mapping(source = name, target = customername),              @mapping(source = isdisable, target = disable)      })      customerdto tocustomerdto(customer customer);  }   这样子,customer类中的isdisable属性的true就会转变成customerdto中的disable属性的yes。
mapstruct自动生成的类中的代码:
@generated(      value = org.mapstruct.ap.mappingprocessor,      date = 2019-02-14t1618+0800,      comments = version: 1.3.0.final, compiler: javac, environment: java 1.8.0_181 (oracle corporation)  )  public class customermapperimpl implements customermapper {     // 引用 uses 中指定的类      private final booleanstrformat booleanstrformat = new booleanstrformat();        @override      public customerdto tocustomerdto(customer customer) {          if ( customer == null ) {              return null;          }            customerdto customerdto = new customerdto();    // 转换方式的使用          customerdto.setdisable( booleanstrformat.tostr( customer.getisdisable() ) );          customerdto.setcustomername( customer.getname() );          customerdto.setid( customer.getid() );            return customerdto;      }  }   要注意的是,如果使用了例如像spring这样的环境,mapper引入uses类实例的方式将是自动注入,那么这个类也应该纳入spring容器:
customermapper.java指定使用spring
@mapper(componentmodel = spring, uses = { booleanstrformat.class})  public interface customermapper {        customermapper instances = mappers.getmapper(customermapper.class);        @mappings({              @mapping(source = name, target = customername),              @mapping(source = isdisable, target = disable)      })      customerdto tocustomerdto(customer customer);  }   转换类要加入spring容器:
@component  public class booleanstrformat {      public string tostr(boolean isdisable) {          if (isdisable) {              return y;          } else {              return n;          }      }      public boolean toboolean(string str) {          if (str.equals(y)) {              return true;          } else {              return false;          }      }  }   mapstruct自动生成的类:
@generated(      value = org.mapstruct.ap.mappingprocessor,      date = 2019-02-14t1635+0800,      comments = version: 1.3.0.final, compiler: javac, environment: java 1.8.0_181 (oracle corporation)  )  @component  public class customermapperimpl implements customermapper {     // 使用自动注入的方式引入      @autowired      private booleanstrformat booleanstrformat;        @override      public customerdto tocustomerdto(customer customer) {          if ( customer == null ) {              return null;          }            customerdto customerdto = new customerdto();            customerdto.setdisable( booleanstrformat.tostr( customer.getisdisable() ) );          customerdto.setcustomername( customer.getname() );          customerdto.setid( customer.getid() );            return customerdto;      }  } 原文标题:实体映射最强工具类:mapstruct 真香!
文章出处:【微信公众号:android编程精选】欢迎添加关注!文章转载请注明出处。


视频硬核解读安森美图像传感器各项关键成像技术
AI及物联网企业佳华科技发布2022第一季度报告
PCB设计后期检查的六个重点
国产CPU大腾飞前夜:从一场参加人员严重爆仓的大会说起
教你怎么选择智能汽车域控制器芯片?
MapStruct是用来做什么的
全球最快记忆卡32秒就能塞满一个iPhone7 Plus
高速数字电路中电子隔离应用
浅谈碳化硅流程的核心技术
M5256-000002-350BG压力传感器的坚固设计
如何使用4017 IC和RGB LED制作LED追光器
海康威视人工智能(AI)平台正式对外开放
TMS320C5402芯片在复用器中有哪些应用
OrCAD FPGA系统规划
python环境变量的配置pip
英睿达新款P2固态硬盘,250GB读取速度可达2100M/s
联通将推自有品牌手机“沃Phone”
三星/SK海力士/美光纷纷减产 存储器行业或将面临相当大的挑战
浅谈KUKA机器人CWRITE编程用法
采用FPGA技术芯片模块实现运动估计的设计方案并进行仿真研究