简单尝试了下发现比Dozer还有BeanUtil还方便小巧

注解的作用是在生成字节码文件时实现具体GetterSetter方法,实际转换时就是赋值操作,嘎嘎快

参考文章:

https://juejin.cn/post/7140149801991012365

  

引入必须的依赖:

lombok一般项目都会添加,这里我就只放这两个

<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>

 

一、入门案例:

两个需要相互转换的实体类,演示用:

DTO

package cn.cloud9.server.test.mapstruct;

import lombok.*;
import lombok.experimental.Accessors; @Data
@Builder
@ToString
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class DemoDTO {
private Integer fieldA;
private Boolean fieldB;
private String fieldC;
}

Entity

package cn.cloud9.server.test.mapstruct;

import lombok.*;
import lombok.experimental.Accessors; @Data
@Builder
@ToString
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class DemoEntity {
private Integer fieldD;
private Boolean fieldE;
private String fieldF;
}

  

转换器接口编写:

如果需要转换更多的实体类,都可以在接口声明方法,然后声明映射的字段

package cn.cloud9.server.test.mapstruct;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers; /**
* 转换器接口
*/
@Mapper
public interface DemoConverter {
DemoConverter INSTANCE = Mappers.getMapper(DemoConverter.class); /* DTO -> ENTITY */
@Mappings(value = {
@Mapping(source = "fieldA", target = "fieldD"),
@Mapping(source = "fieldB", target = "fieldE"),
@Mapping(source = "fieldC", target = "fieldF"),
})
DemoEntity dto2entity(DemoDTO demoDTO); /* ENTITY -> DTO */
@Mappings(value = {
@Mapping(source = "fieldD", target = "fieldA"),
@Mapping(source = "fieldE", target = "fieldB"),
@Mapping(source = "fieldF", target = "fieldC"),
})
DemoDTO entity2dto(DemoEntity demoEntity);
}

  

测试方法:

    @Test
public void converterTest() {
DemoDTO build = DemoDTO.builder()
.fieldA(1001)
.fieldB(Boolean.TRUE)
.fieldC("TEST")
.build(); DemoEntity demoEntity = DemoConverter.INSTANCE.dto2entity(build);
DemoDTO demoDTO = DemoConverter.INSTANCE.entity2dto(demoEntity);
log.info("demoEntity -> {}", demoEntity);
log.info("demoDTO -> {}", demoDTO);
}

  

执行结果:

22:52:20.079 [main] INFO cn.cloud9.spring.BeanFactoryTest - demoEntity -> DemoEntity(fieldD=1001, fieldE=true, fieldF=TEST)
22:52:20.083 [main] INFO cn.cloud9.spring.BeanFactoryTest - demoDTO -> DemoDTO(fieldA=1001, fieldB=true, fieldC=TEST) Process finished with exit code 0

 

二、集合转换支持

也是根据参数类型推断,自动生成了迭代集合

    /* List<ENTITY -> DTO>  */
@Mappings(value = {
@Mapping(source = "fieldD", target = "fieldA"),
@Mapping(source = "fieldE", target = "fieldB"),
@Mapping(source = "fieldF", target = "fieldC"),
})
List<DemoDTO> entity2dto(List<DemoEntity> demoEntity); /* List<DTO -> ENTITY> */
@Mappings(value = {
@Mapping(source = "fieldA", target = "fieldD"),
@Mapping(source = "fieldB", target = "fieldE"),
@Mapping(source = "fieldC", target = "fieldF"),
})
List<DemoEntity> dto2entity(List<DemoDTO> demoDTO);

测试方法:

ArrayList<DemoDTO> objects = new ArrayList<>();
for (int i = 0; i < 10; i++) {
objects.add(DemoDTO.builder()
.fieldA(1001)
.fieldB(Boolean.TRUE)
.fieldC("TEST")
.build());
}
List<DemoEntity> demoEntityList = DemoConverter.INSTANCE.dto2entity(objects);
demoEntityList.forEach(d -> log.info("de {}", d));

执行结果:

23:16:13.845 [main] INFO cn.cloud9.spring.BeanFactoryTest - de DemoEntity(fieldD=1001, fieldE=true, fieldF=TEST)
23:16:13.845 [main] INFO cn.cloud9.spring.BeanFactoryTest - de DemoEntity(fieldD=1001, fieldE=true, fieldF=TEST)
23:16:13.845 [main] INFO cn.cloud9.spring.BeanFactoryTest - de DemoEntity(fieldD=1001, fieldE=true, fieldF=TEST)
23:16:13.845 [main] INFO cn.cloud9.spring.BeanFactoryTest - de DemoEntity(fieldD=1001, fieldE=true, fieldF=TEST)
23:16:13.845 [main] INFO cn.cloud9.spring.BeanFactoryTest - de DemoEntity(fieldD=1001, fieldE=true, fieldF=TEST)
23:16:13.845 [main] INFO cn.cloud9.spring.BeanFactoryTest - de DemoEntity(fieldD=1001, fieldE=true, fieldF=TEST)
23:16:13.845 [main] INFO cn.cloud9.spring.BeanFactoryTest - de DemoEntity(fieldD=1001, fieldE=true, fieldF=TEST)
23:16:13.845 [main] INFO cn.cloud9.spring.BeanFactoryTest - de DemoEntity(fieldD=1001, fieldE=true, fieldF=TEST)
23:16:13.845 [main] INFO cn.cloud9.spring.BeanFactoryTest - de DemoEntity(fieldD=1001, fieldE=true, fieldF=TEST)
23:16:13.845 [main] INFO cn.cloud9.spring.BeanFactoryTest - de DemoEntity(fieldD=1001, fieldE=true, fieldF=TEST)

  

三、映射配置继承与反向继承

只需要提供一份映射注解信息即可,其他方法通过继承注解获取映射信息

同理,要反向转换时,提供了一个反向注解:

两个注解都需要你提供方法名来查找映射配置

package cn.cloud9.server.test.mapstruct;

import org.mapstruct.*;
import org.mapstruct.factory.Mappers; import java.util.List; /**
* 转换器接口
*/
@Mapper
public interface DemoConverter {
DemoConverter INSTANCE = Mappers.getMapper(DemoConverter.class); /* DTO -> ENTITY */
@Mappings(value = {
@Mapping(source = "fieldA", target = "fieldD"),
@Mapping(source = "fieldB", target = "fieldE"),
@Mapping(source = "fieldC", target = "fieldF"),
})
DemoEntity dto2entity(DemoDTO demoDTO); /* ENTITY -> DTO */
// @Mappings(value = {
// @Mapping(source = "fieldD", target = "fieldA"),
// @Mapping(source = "fieldE", target = "fieldB"),
// @Mapping(source = "fieldF", target = "fieldC"),
// })
// DemoDTO entity2dto(DemoEntity demoEntity);
@InheritInverseConfiguration(name = "dto2entity")
DemoDTO entity2dto(DemoEntity demoEntity); /* List<ENTITY -> DTO> */
// @Mappings(value = {
// @Mapping(source = "fieldD", target = "fieldA"),
// @Mapping(source = "fieldE", target = "fieldB"),
// @Mapping(source = "fieldF", target = "fieldC"),
// })
@InheritConfiguration(name = "entity2dto")
List<DemoDTO> entity2dto(List<DemoEntity> demoEntity); /* List<DTO -> ENTITY> */
// @Mappings(value = {
// @Mapping(source = "fieldA", target = "fieldD"),
// @Mapping(source = "fieldB", target = "fieldE"),
// @Mapping(source = "fieldC", target = "fieldF"),
// })
@InheritInverseConfiguration(name = "entity2dto")
List<DemoEntity> dto2entity(List<DemoDTO> demoDTO);
}

  

四、是否阻止默认映射

默认同名同类型字段直接映射

这里对两个实体类新加了同一个字段:

private Long filedG;

 

测试时添加该属性:

@Test
public void converterTest() {
DemoDTO build = DemoDTO.builder()
.fieldA(1001)
.fieldB(Boolean.TRUE)
.fieldC("TEST")
.filedG(3003L)
.build();
DemoEntity demoEntity = DemoConverter.INSTANCE.dto2entity(build);
DemoDTO demoDTO = DemoConverter.INSTANCE.entity2dto(demoEntity);
log.info("demoEntity -> {}", demoEntity);
log.info("demoDTO -> {}", demoDTO);
}

执行结果可以发现,默认赋值上去了

23:34:51.780 [main] INFO cn.cloud9.spring.BeanFactoryTest - demoEntity -> DemoEntity(fieldD=1001, fieldE=true, fieldF=TEST, filedG=3003)
23:34:51.787 [main] INFO cn.cloud9.spring.BeanFactoryTest - demoDTO -> DemoDTO(fieldA=1001, fieldB=true, fieldC=TEST, filedG=3003) Process finished with exit code 0

  

使用@BeanMapping注解可以阻止这种赋值行为:

/**
* 转换器接口
*/
@Mapper
public interface DemoConverter {
DemoConverter INSTANCE = Mappers.getMapper(DemoConverter.class); /* @BeanMapping(ignoreByDefault = true) 阻止MapStruct默认同名字段赋值行为 */
@BeanMapping(ignoreByDefault = true)
/* DTO -> ENTITY */
@Mappings(value = {
@Mapping(source = "fieldA", target = "fieldD"),
@Mapping(source = "fieldB", target = "fieldE"),
@Mapping(source = "fieldC", target = "fieldF"),
})
DemoEntity dto2entity(DemoDTO demoDTO); /* ENTITY -> DTO */
@InheritInverseConfiguration(name = "dto2entity")
DemoDTO entity2dto(DemoEntity demoEntity); /* List<ENTITY -> DTO> */
@InheritConfiguration(name = "entity2dto")
List<DemoDTO> entity2dto(List<DemoEntity> demoEntity); /* List<DTO -> ENTITY> */
@InheritInverseConfiguration(name = "entity2dto")
List<DemoEntity> dto2entity(List<DemoDTO> demoDTO);
}

  

再次执行发现不再能够进行赋值处理了:

23:38:03.011 [main] INFO cn.cloud9.spring.BeanFactoryTest - demoEntity -> DemoEntity(fieldD=1001, fieldE=true, fieldF=TEST, filedG=null)
23:38:03.015 [main] INFO cn.cloud9.spring.BeanFactoryTest - demoDTO -> DemoDTO(fieldA=1001, fieldB=true, fieldC=TEST, filedG=null)

  

是否不继承@BeanMapping忽略默认映射的配置?

https://www.bilibili.com/video/BV1E5411n7HR?p=9

在视频中提到是不继承的,这里我加上了字段的赋值,并且调用反向转换的方法:

DemoDTO build = DemoDTO.builder()
.fieldA(1001)
.fieldB(Boolean.TRUE)
.fieldC("TEST")
.fieldG(3003L)
.build();
DemoEntity demoEntity = DemoConverter.INSTANCE.dto2entity(build);
demoEntity.setFieldG(3003L);
DemoDTO demoDTO = DemoConverter.INSTANCE.entity2dto(demoEntity);
log.info("demoEntity -> {}", demoEntity);
log.info("demoDTO -> {}", demoDTO);

可以从执行结果发现,实际上是没有赋值的,说明是继承了@BeanMapping的效果了

23:41:02.989 [main] INFO cn.cloud9.spring.BeanFactoryTest - demoEntity -> DemoEntity(fieldD=1001, fieldE=true, fieldF=TEST, fieldG=3003)
23:41:02.994 [main] INFO cn.cloud9.spring.BeanFactoryTest - demoDTO -> DemoDTO(fieldA=1001, fieldB=true, fieldC=TEST, fieldG=null) Process finished with exit code 0

  

五、注册成SpringBean

在前面的用法中都是直接声明一个单例使用,这里可以交给Spring处理:

@Mapper(componentModel = "spring")

package cn.cloud9.server.test.mapstruct;

import org.mapstruct.*;
import org.mapstruct.factory.Mappers; import java.util.List; /**
* 转换器接口
*/
@Mapper(componentModel = "spring")
public interface DemoConverter {
DemoConverter INSTANCE = Mappers.getMapper(DemoConverter.class); /* @BeanMapping(ignoreByDefault = true) 阻止MapStruct默认同名字段赋值行为 */
// @BeanMapping(ignoreByDefault = true)
/* DTO -> ENTITY */
@Mappings(value = {
@Mapping(source = "fieldA", target = "fieldD"),
@Mapping(source = "fieldB", target = "fieldE"),
@Mapping(source = "fieldC", target = "fieldF"),
})
DemoEntity dto2entity(DemoDTO demoDTO); /* ENTITY -> DTO */
@InheritInverseConfiguration(name = "dto2entity")
DemoDTO entity2dto(DemoEntity demoEntity); /* List<ENTITY -> DTO> */
@InheritConfiguration(name = "entity2dto")
List<DemoDTO> entity2dto(List<DemoEntity> demoEntity); /* List<DTO -> ENTITY> */
@InheritInverseConfiguration(name = "entity2dto")
List<DemoEntity> dto2entity(List<DemoDTO> demoDTO);
}

  

在需要调用的地方声明即可:

package cn.cloud9.server.test.controller;

import cn.cloud9.server.test.mapstruct.DemoConverter;
import cn.cloud9.server.test.mapstruct.DemoDTO;
import cn.cloud9.server.test.mapstruct.DemoEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController
@RequestMapping("/test/map-struct")
public class MapStructController { @Resource
private DemoConverter demoConverter; @GetMapping("/get")
public DemoEntity converterTest() {
DemoDTO build = DemoDTO.builder()
.fieldA(1001)
.fieldB(Boolean.TRUE)
.fieldC("TEST")
.fieldG(3003L)
.build();
return demoConverter.dto2entity(build);
}
}

测试结果:

  

【Java】实体类转换框架 MapStruct的更多相关文章

  1. Java实体映射工具MapStruct的使用

    官网地址:http://mapstruct.org/ MapStruct 是一个代码生成器,简化了不同的 Java Bean 之间映射的处理,所谓的映射指的就是从一个实体变化成一个实体.例如我们在实际 ...

  2. 利用在线工具根据JSon数据自动生成对应的Java实体类

    如果你希望根据JSon数据自动生成对应的Java实体类,并且希望能进行变量的重命名,那么“JSON To Java”一定适合你.(下面的地址需要FQ) https://jsontojava.appsp ...

  3. 我写了一个java实体类,implements了Serializable接口,然后我如何让serialversionUID自动生成

    写了一个java实体类,implements了Serializable接口,让serialversionUID自动生成方法: 1.点击类旁边的警告符号: 2.选择Add generated seria ...

  4. 利用JAXB实现java实体类和xml互相转换

    1.应用场景 在使用WebService实现数据上传下载,数据查询时,可以利用JAXB实现java实体类和xml互相转换 2.Demo 2.1 student.java 实体类,包含list(set同 ...

  5. MyEclipse 利用反向功能生成Java 实体类

    1.Window -> Open Perspective -> MyEclipse Database Explorer 到DB Broswer界面 2.右键 -> New,新建一个数 ...

  6. 在线数据库表(sql语句)生成java实体类工具

    相信每个做java开发的读者,都接触过SQL建表语句,尤其是在项目开发初期,因为数据库是项目的基石. 在现代项目开发中,出现了许多ORM框架,通过简单的实体映射,即可实现与数据库的交互,然而我们最初设 ...

  7. Mysql逆向工程效率神器之使用IDE自动生成Java实体类

    Mysql逆向工程效率神器之使用IDE自动生成Java实体类 简介:实战使用IDE根据Mysql自动生成java pojo实体类 1.IDEA连接数据库 菜单View→Tool Windows→Dat ...

  8. JAVA实体类不要使用基本类型,基本类型包含byte、int、short、long、float、double、char、boolean

    由于JAVA的基本类型会有默认值,例如当某个类中存在private  int age;字段时,创建这个类时,age会有默认值0.当使用age属性时,它总会有值.因此在某些情况下,便无法实现age为nu ...

  9. xml文档的解析并通过工具类实现java实体类的映射:XML工具-XmlUtil

    若有疑问,可以联系我本人微信:Y1141100952 声明:本文章为原稿,转载必须说明 本文章地址,否则一旦发现,必追究法律责任 1:本文章显示通过 XML工具-XmlUtil工具实现解析soap报文 ...

  10. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_2-6.Mysql逆向工程效率神器之使用IDE自动生成Java实体类

    笔记 6.Mysql逆向工程效率神器之使用IDE自动生成Java实体类     简介:实战使用IDE根据Mysql自动生成java pojo实体类                  1.IDEA连接数 ...

随机推荐

  1. 使用python获取房价信息

    从贝壳网获取房价信息. 基本的步骤和我的这篇博文一样:https://www.cnblogs.com/mrlayfolk/p/12319414.html.不熟悉的可参考一下. 下面的代码是获取3000 ...

  2. 前端使用 Konva 实现可视化设计器(13)- 折线 - 最优路径应用【思路篇】

    这一章把直线连接改为折线连接,沿用原来连接点的关系信息.关于折线的计算,使用的是开源的 AStar 算法进行路径规划,启发方式为 曼哈顿距离,且不允许对角线移动. 请大家动动小手,给我一个免费的 St ...

  3. C# JAVA UrlEncode

    C#  JAVA urlencode 默认是不兼容的.C# 需要encode的部分是小写.JAVA 需要encode的部分是大写. /// <summary> /// java UrlEn ...

  4. redis高可用哨兵篇

    https://redis.io/docs/manual/sentinel/#sentinels-and-replicas-auto-discovery 官网资料 在上文主从复制的基础上,如果注节点出 ...

  5. redis安全篇

    redis被攻击,作为突破口,服务器惨遭毒手的事太常见了. 大多数云服务器被攻击,都是redis,mongodb等数据库被入侵. 因此修改端口,密码,以及注意bind运行地址,是必须. 思考是否要暴露 ...

  6. Jenkins技术概述与开发实战

    本文详细讲解了Jenkins的安装与配置.构建作业.流水线.构建.测试和部署的具体方法,涵盖关键概念.详细步骤及代码示例,旨在帮助专业从业者实现高效的CI/CD自动化流程. 关注作者,复旦博士,分享云 ...

  7. babel 基础概念 & 从零到一写一个 babel 插件

    babel 基础概念 简单来说,做语法转换兼容的, 复杂一点的说,babel可以将我们写的 ES6+ 的Javascript语法转换为向后兼容的语法,以便能够在旧版本的浏览器或者其他环境运行. bab ...

  8. leetcode_2-两数相加_javascript

    题目 2.两数相加 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新 ...

  9. 在线Bcrypt加密、验证工具

    在线bcrypt加密,bcrypt算法是一种密码哈希算法,它是基于Blowfish加密算法改进的,能够生成安全性很高的哈希值,并且可以通过调整计算时间来提高安全性.本工具支持在线Bcrypt加密及验证 ...

  10. 如果redis没有设置expire,他是否默认永不过期

    如果redis没有设置expire,他是否默认永不过期?默认是的 通过EXPIRE key seconds 命令来设置数据的过期时间.返回1表明设置成功,返回0表明key不存在或者不能成功设置过期时间 ...