title: MapStruct 总结
date: 2022-03-22 13:51:27
tags:

  • Java
    categories:
  • 开发技术及框架
    cover: https://cover.png
    feature: false

1. 概念

在系统工程开发过程中,会有各个层之间的对象转换,比如 VO、DTO、PO、DO 等,如果都是手动 setter、getter 特别浪费时间,还可能操作错误,所以选择一个自动化工具会更加方便。常见的有 json2Json、Apache 和 Spring 的 BeanUtils.copyProperties()、BeanCopier、JMapper 等

对象属性转换的操作无非是基于反射、AOP、CGlib、ASM、Javassist 在编译时和运行期进行处理,再有好的思路就是在编译前生成出对应的 setter、getter,就像手写出来的一样。MapStruct 就是直接在编译期生成对应的 setter、getter,性能更好、使用方便

2. POM

导入依赖

<dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifactId><version>1.5.0.RC1</version>
</dependency>
<dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>1.5.0.RC1</version>
</dependency>
<dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-jdk8</artifactId><version>1.5.0.RC1</version>
</dependency>

可以选择在 IDEA 中下载其插件

3. 实体类

定义几个 DO 和 DTO

// UserDO
@Data
@Builder
public class UserDO {private Integer id;private String name;private Integer age;private String address;private String birthday;private String phone;private String userDOGender;private Date createTime;private Map<String, String> map;private List<PersonDO> personList;
}
// UserDTO
@Data
@Builder
public class UserDTO {private Integer id;private String name;private Integer age;private String address;private String userDTOGender;private Date createTime;private Map<String, String> map;private List<PersonDO> personList;
}
// PersonDO
@Data
@Builder
public class PersonDO {private Integer id;private String name;private String job;private String remark;private Date createTime;
}
// PersonDTO
@Data
@Builder
public class PersonDTO {private Integer id;private String name;private String job;
}

3. 映射器

  • 如果 DTO 和实体类中的字段名称是一致的,只需要写方法签名即可
  • 如果参数名称有变化,需要使用 @Maping 注解,source 为原参数名称,target 为转换后的类的参数名称
  • 隐式类型转换
    在许多情况下,MapStruct 会自动处理类型转换。如在 source 中是 int 类型但在 target 中是 String 类型,会自动进行转换。以及所有 Java 基本数据类型及其相应的包装类型,如 int 和 Integer,boolean 和 Boolean 等。还有所有 Java Number类型和包装器类型之间,如 int 和 long 或 byte 和 Integer
@Mapper // 直接使用
@Mapper(componentModel = "spring") // 整合 Spring,设置 componentModel = "spring",需要使用的地方直接通过 @Resource 注入即可
public interface MapStruct {MapStruct INSTANCE = Mappers.getMapper(MapStruct.class);@Mapping(source = "userDOGender", target = "userDTOGender")UserDTO userDOToUserDTO(UserDO userDO);@Mapping(source = "userDTOGender", target = "userDOGender")UserDO UserDTOToUserDO(UserDTO userDTO);PersonDTO personDOToPersonDTO(PersonDO personDO);PersonDO PersonDTOToPersonDO(PersonDTO personDTO);
}

编译后,会在同级目录生成实现类:

@Generated(value = "org.mapstruct.ap.MappingProcessor",date = "2022-03-22T12:16:06+0800",comments = "version: 1.5.0.RC1, compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)"
)
public class MapStructImpl implements MapStruct {@Overridepublic UserDTO userDOToUserDTO(UserDO userDO) {if ( userDO == null ) {return null;}UserDTO.UserDTOBuilder userDTO = UserDTO.builder();userDTO.userDTOGender( userDO.getUserDOGender() );userDTO.id( userDO.getId() );userDTO.name( userDO.getName() );userDTO.age( userDO.getAge() );userDTO.address( userDO.getAddress() );userDTO.createTime( userDO.getCreateTime() );Map<String, String> map = userDO.getMap();if ( map != null ) {userDTO.map( new LinkedHashMap<String, String>( map ) );}List<PersonDO> list = userDO.getPersonList();if ( list != null ) {userDTO.personList( new ArrayList<PersonDO>( list ) );}return userDTO.build();}@Overridepublic UserDO UserDTOToUserDO(UserDTO userDTO) {if ( userDTO == null ) {return null;}UserDO.UserDOBuilder userDO = UserDO.builder();userDO.userDOGender( userDTO.getUserDTOGender() );userDO.id( userDTO.getId() );userDO.name( userDTO.getName() );userDO.age( userDTO.getAge() );userDO.address( userDTO.getAddress() );userDO.createTime( userDTO.getCreateTime() );Map<String, String> map = userDTO.getMap();if ( map != null ) {userDO.map( new LinkedHashMap<String, String>( map ) );}List<PersonDO> list = userDTO.getPersonList();if ( list != null ) {userDO.personList( new ArrayList<PersonDO>( list ) );}return userDO.build();}@Overridepublic PersonDTO personDOToPersonDTO(PersonDO personDO) {if ( personDO == null ) {return null;}PersonDTO.PersonDTOBuilder personDTO = PersonDTO.builder();personDTO.id( personDO.getId() );personDTO.name( personDO.getName() );personDTO.job( personDO.getJob() );return personDTO.build();}@Overridepublic PersonDO PersonDTOToPersonDO(PersonDTO personDTO) {if ( personDTO == null ) {return null;}PersonDO.PersonDOBuilder personDO = PersonDO.builder();personDO.id( personDTO.getId() );personDO.name( personDTO.getName() );personDO.job( personDTO.getJob() );return personDO.build();}
}

4. 测试

public class Test {public static void main(String[] args) {UserDO userDO = UserDO.builder().id(1).name("张三").age(18).birthday("2003-01-04").phone("12343").userDOGender("男").createTime(new Date(System.currentTimeMillis())).map(new HashMap<String, String>(){{this.put("key", "value");}}).personList(new ArrayList<PersonDO>(){{this.add(PersonDO.builder().id(11).build());}}).build();UserDTO userDTO = Mappers.getMapper(MapStruct.class).userDOToUserDTO(userDO);System.out.println(userDTO);PersonDTO personDTO = PersonDTO.builder().id(11).name("李四").job("开发").build();PersonDO personDO = MapStruct.INSTANCE.PersonDTOToPersonDO(personDTO);System.out.println(personDO);}
}

5. 自定义转换规则

MapStruct 只提供了隐式类型转换和默认的一些转换,假如需要特定的类型转换,如将 java.sql.Timestamp 日期转换为只保留年月日的字符串等,可以自定义转换规则

5.1 使用 expression 表达式

1、创建一个转换规则类

public class MapStructRule {public static String toDate(Timestamp date) {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");return simpleDateFormat.format(date);}
}

2、在映射器对应的转换方法上使用 @Mapping 注解的 expression 属性标识转换规则,这里的属性值为需要写 全类名.方法名(参数),使用了 expression 就不需要 source 属性

@Mapper(componentModel = "spring") // 整合 Spring,设置 componentModel = "spring",需要使用的地方直接通过 @Resource 注入即可
public interface MapStruct {MapStruct INSTANCE = Mappers.getMapper(MapStruct.class);@Mapping(target = "createTime", expression = "java(fan.fanblog.utils.MapStructRule.toDate(menuDO.getCreateTime()))")@Mapping(target = "updateTime", expression = "java(fan.fanblog.utils.MapStructRule.toDate(menuDO.getUpdateTime()))")MenuVO MenuDOToMenuVO(MenuDO menuDO);
}

3、测试类

public class Demo {public static void main(String[] args) {MenuDO menuDO = new MenuDO();menuDO.setCreateTime(new Timestamp(System.currentTimeMillis()));menuDO.setUpdateTime(new Timestamp(System.currentTimeMillis()));System.out.println(menuDO);MenuVO menuVO = MapStruct.INSTANCE.MenuDOToMenuVO(menuDO);System.out.println(menuVO);}
}

5.2 使用 @Named 注解

1、创建一个转换规则类,在对应的转换方法上标注 @Named 注解表示转换方法名

public class MapStructRule {@Named("toDate")public static String toDate(Timestamp date) {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return simpleDateFormat.format(date);}
}

2、在映射器上使用 @Mapperuses 属性,属性值为转换规则类的 Class 对象,然后再映射器对应的方法上使用 @Mapping 注解的 qualifiedByName 属性,属性值为转换规则类 @Named 定义的方法名

@Mapper(componentModel = "spring", uses = MapStructRule.class) // 整合 Spring,设置 componentModel = "spring",需要使用的地方直接通过 @Resource 注入即可
public interface MapStruct {MapStruct INSTANCE = Mappers.getMapper(MapStruct.class);@Mapping(target = "createTime", source = "createTime", qualifiedByName = "toDate")@Mapping(target = "updateTime", source = "updateTime", qualifiedByName = "toDate")MenuVO MenuDOToMenuVO(MenuDO menuDO);
}

3、测试类

public class Demo {public static void main(String[] args) {MenuDO menuDO = new MenuDO();menuDO.setCreateTime(new Timestamp(System.currentTimeMillis()));menuDO.setUpdateTime(new Timestamp(System.currentTimeMillis()));System.out.println(menuDO);MenuVO menuVO = MapStruct.INSTANCE.MenuDOToMenuVO(menuDO);System.out.println(menuVO);}
}

6. 忽略属性不转换

@Mapper(componentModel = "spring", uses = MapStructRule.class) // 整合 Spring,设置 componentModel = "spring",需要使用的地方直接通过 @Resource 注入即可
public interface MapStruct {MapStruct INSTANCE = Mappers.getMapper(MapStruct.class);@Mapping(target = "createTime", ignore = true)@Mapping(target = "updateTime", ignore = true)MenuDO MenuVOToMenuDO(MenuVO menuVO);
}

MapStruct 总结相关推荐

  1. 还在用 BeanUtils来做对象转换吗?快试试 MapStruct吧

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 作者:阿进的写字台 https://www.cnblogs ...

  2. 丢弃掉那些BeanUtils工具类吧,MapStruct真香!!!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 在前几天的文章<为什么阿里巴巴禁止使用Apache Bean ...

  3. 业务代码的救星——Java对象转换框架MapStruct

    介绍 在业务项目的开发中,我们经常需要将Java对象进行转换,比如从外部HSF服务得到的对象转换为本域的业务对象domain object,将domain object转为数据持久层的data obj ...

  4. 推荐一个 Java 实体映射工具 MapStruct

    声明: 1.DO(业务实体对象),DTO(数据传输对象). 2.我的代码中用到了 Lombok ,不了解的可以自行了解一下,了解的忽略这条就好. 在一个成熟的工程中,尤其是现在的分布式系统中,应用与应 ...

  5. java map 结构体_业务代码的救星——Java 对象转换框架 MapStruct 妙用

    简介 在业务项目的开发中,我们经常需要将 Java 对象进行转换,比如从将外部微服务得到的对象转换为本域的业务对象 domain object,将 domain object 转为数据持久层的 dat ...

  6. 【迁移2018-04-12 10:46:11】BeanCopier之MapStruct(一)

    为什么80%的码农都做不了架构师?>>>    无意中见同事在比较BeanCopier的效率,MapStruct的使用者很牛皮的说我的效率是你的XX倍,今天认识了一下MapStrut ...

  7. MapStruct在Eclipse中的使用

    在Eclipse中使用MapStruct时,会报找不到实现类.需要添加m2e-apt插件 同时在preferences->maven中设置Automatically configure JDT ...

  8. 遇到MapStruct后,再也不手写PO,DTO,VO对象之间的转换了

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:腾讯推出高性能 RPC 开发框架 个人原创100W+访问量博客:点击前往,查看更多 介绍 在工作中,我们经常要进 ...

  9. 如何解决mapstruct和lombok冲突问题

    一.冲突如何产生 在按照官网配置mapstruct,使用lombok.当我们在maven install时候会出现属性找不到错误. 二.解决配置如下 确保 Lombok 最低版本为 1.18.16 a ...

  10. mapstruct 1.4.2 和 lombok 1.18.16 及以上版本结合使用

    在使用 mapstruct 时发现其不生效,检查生成的转换器实现类,发现全部没有调用 setter 方法进行对象数据转移. 后来考虑到类 setter 方法是使用 lombok 插件生成的,所以应该控 ...

最新文章

  1. 重磅!新一轮“双一流”,有重大变化!
  2. 线程:Timer定时器
  3. 我感觉这是目前讲得最明白的线性回归的文章了
  4. c语言程序设计和数据结构,C语言程序设计与数据结构实践 闵光太主编.pdf
  5. 构造器和析构器 - C++快速入门15
  6. 关于ios手机上传图片旋转问题的解决
  7. Azure开发者任务之一:解决Azure Storage Emulator初始化失败
  8. 还要我带一个六级辅导班--痛苦!
  9. (转)软件开发和团队”最小模式”初探2-6人模型(下)
  10. 实时获取浏览器滚动条高度(兼容写法)
  11. ant 时 --java.lang.NoSuchMethodError: org.apache.tools.ant.util.FileUtils.getFileUtils 解决方法
  12. 如何手动添加或者修改海威康视摄像头IP地址的方法
  13. bci测试如何整改_电源动态响应测试,什么样的波形算合格?
  14. 依赖注入应该慎用,测试可用测试框架帮忙
  15. STM32CubeIDE HAL库微秒us的延时Delay实现
  16. java 图片背景色_java处理图片背景颜色的方法
  17. Balsamiq mockups
  18. Android开发模式万佛朝中MVX(MVC、MVP、MVVM)
  19. linux系统locale的设定
  20. 基于kinect的人体动作识别系统(算法和代码都放出)

热门文章

  1. NSTimer解决循环引用常见方法
  2. NSTimer (IOS开发)
  3. 瑞吉外卖-新增菜品-异常处理
  4. Apple IAP官方文档
  5. 老罗的“子弹短信”登顶社交软件榜首!超过了微信!
  6. Android 1.5 -10.0 都有哪些新特性?
  7. vue本地项目配置图片加载失败_vue图片加载失败时用默认图片替换的方法
  8. CAD版本转换怎么操作?这些方法了解了吗
  9. Pycharm安装配置详细教程
  10. mysql保存emoji表情(比如微信开发用户昵称)