Java 实体映射工具 MapStruct

简介: 让你的DO(业务实体对象),DTO(数据传输对象)数据转换更简单强大

前言

  在软件架构中,分层式结构是最常见,各层之间有其独立且隔离的业务逻辑,也因而各层有自己的输入输出对象,也就是代码中见到各种O,如DO、DTO、VO,这些数据对象之间通常都有很多相同或相近的属性对象,数据在传输的过程中从一个O到另一个O,就通常需要赋值,从最初的的get/set    


personDTO.setName(personDO.getName());
personDTO.setAge(personDO.getAge());
personDTO.setSex(personDO.getSex());
personDTO.setBirthday(personDO.getBirthday());

到后来的BeanUtils(减少了set的代码量)

image.png

再到现在的MapStruct


1.MapStruct配置

         MapStuct的使用非常简单,把对应的jar包引入即可。

<properties><lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version><org.mapstruct.version>1.3.0.Final</org.mapstruct.version><org.mapstruct.processor.version>1.3.0.Final</org.mapstruct.processor.version></properties><dependencies><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.processor.version}</version><scope>provided</scope></dependency></dependencies><configuration><source>${java.version}</source><target>${java.version}</target><annotationProcessorPaths><path><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>${org.mapstruct.processor.version}</version></path><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></path><path><groupId>org.projectlombok</groupId><artifactId>lombok-mapstruct-binding</artifactId><version>${lombok-mapstruct-binding.version}</version></path></annotationProcessorPaths></configuration>


2.原理

     MapStruct属于在编译期,生成调用get/set方法进行赋值的代码,生成对应的java文件。在编译期间消耗少许的时间,换取运行时的高性能。


3.使用方法

先定义一个接口,按照规范我们在service或domainService下建一个converter包


通过依赖注入的方式获取Mapper实例

@Mapper(componentModel = "spring")




3.1 对于同名同属性的字段,无需特别声明指定,自动转换。

MapStructReq1

@Data@Accessors(chain=true)
publicclassMapStructReq1 {
privateIntegerid;
privateStringname;
@JsonFormat(pattern="yyyy-MM-dd")
privateDateupdateTime;
}

MapStructResp1:

@Data@Accessors(chain=true)
publicclassMapStructResp1 {
privateIntegerid;
privateStringname;
@JsonFormat(pattern="yyyy-MM-dd")
privateDateupdateTime;
}


converter:

image.png

@apper(componentModel

spring

publicinterfaceMaptrucconeeDemo

8

9

水*

*对于同名同属性的字段,无需特别声明指定,自动转换.

*Cparamreg

Sreturn

MapStructResp1regIToResp(MatructReqlreq;



serviceImpl:

image.png

@Service

implementsMapStructDemoService

publicclassMapStructDemoServiceImp

@Autowired

MapStructConverterDemomaptructconverterDemo

Qoverride

publicMapstructReplgToRepiMaucRqlr

returnmapstructconverterDemoITRep



controller:

image.png

**

*对于同名同属性的字段,无需特别声明指定,自动转换.

@return

GGetMapping(/demo12)

publicMapStructResplreqIToResp10

NEwMapstructReqlO.setd1.setam(nmeetUterime(eDate;

MapStructReqlreql

returnmapStrucDemoService.reaiToRespreq)

调用demo1接口后,可以看到我们给MapStructReq1赋值后,成功拷贝到了MapStructResp1中返回

image.png

fhosty/apil2/demo/mapstruct/demo1

GET

Te

Pre-requestScript

Body

Headers(8)

Params

Authorization

Body

Headers(3)

Cookies

TestResults

Pretty

Preview

Visualize

Raw

JSON

4

"traceId:"e873370e527449dbb8628c3da11b3b42"

"success":true,

"errCode":0,

"errMsg":'"success",

datas":f

"id":1,

7

8

"name":'"name",

"updateTime":"2021-02-08"

9

10

11


3.2 对于不同名相同属性的字段,可以使用Mapping注解指定。

MapStructReq1

@Data@Accessors(chain=true)
publicclassMapStructReq1 {
privateIntegerid;
privateStringname;
@JsonFormat(pattern="yyyy-MM-dd")
privateDateupdateTime;
}

MapStructResp2

@DatapublicclassMapStructResp2 {
privateIntegerid;
privateStringproductName;
@JsonFormat(pattern="yyyy-MM-dd")
privateDateupdateTime;
}

converter

@Mapping(source="name", target="productName")
MapStructResp2req1ToResp2(MapStructReq1req);


controller:

image.png

@GetMapping(/demo2)

publicMapStructResp2reqIToResp20

MaStructkqleqlneMstucRq..

mapStructDemoService.reqlToResp2(reql)

return

image.png

tthosty/apin2/demo/mapstruct/demo2

GET

Headers(8)

Body

Pre-requestScript

Params

Authorization

CookiesHeaders(3)

Body

TestResults

Pretty

Preview

Raw

JSON

Visualize

"traceId:"d888fe7a643848f5856c557c8981be8a"

"success":true,

"errCode":0,

"'errmsg":

success",

"datas":f

7

"id":1,

"productName":"name",

"updateTime":"2021-02-08"

10

11

req1中的name字段拷贝到了resp2中的productName中



3.3 支持把多个参数映射成一个类型,使用@Mapping指定即可。

converter:

@Mapping(source="req1.id", target="id")
@Mapping(source="req2.productName", target="name")
@Mapping(source="req1.updateTime", target="updateTime")
MapStructResp1req1And2ToResp1(MapStructReq1req1, MapStructReq2req2);

controller:

image.png

GGetMapping(/demo3")

publicMapStructResplreqlAnd2ToResp1O

MSTNetRnMstrucRqo

MPSTHUCRTPHSTUGRQOLAOOUTOInDTEO

etURNMAPStructDemSviceqApq

image.png

fhosty/apil2/demo/mapstruct/demo3

GET

Params

Body

Headers(8)

Pre-requestScript

Authorization

Cookies

Headers(3)

Body

TestResults

Preview

Pretty

Visualize

JSON

Raw

"traceId:"928a04ff46c84e9ad3e6686eae6bbda"

2

3

"success":true,

"errCode":0,

5

"errMsg":"'success",

6

"datas":

7

"id":1,

8

"name2",

name"

9

"updateTime":"2021-02-08"

10

t

11

将req1中的id,req2中的name拷贝到了resp1中


3.4 对于基础数据类型会进行自动隐式的转换

如int、long、String,Integer、Long等。

req3

@Data@Accessors(chain=true)
publicclassMapStructReq3 {
privateStringid;
privateintname;
@JsonFormat(pattern="yyyy-MM-dd")
privateDateupdateTime;
}

resp1:

@Data@Accessors(chain=true)
publicclassMapStructResp1 {
privateIntegerid;
privateStringname;
@JsonFormat(pattern="yyyy-MM-dd")
privateDateupdateTime;
}

converter:

image.png

**

*对于基础数据类型会进行自动隐式的转换

如intlong,StringIntegerLong等

*@paramreg

*

preturn

*/

eg3ToResp1(MapStructReq3reg

MapStructResp1

controller:

image.png

对于基础数据类型会进行自动隐式的转换

@return

*

GGetMapping(/demo5)

publicMapStructResplreqToResp1

MPSTNUCRSTESWMSTUCRESOetT)eLm2SUATeTIEEWDATEO)

returnmapStructDemoServicergToRespq)



image.png

GET

fhost/apiw2/demo/mapstruct/demo5

Params

Headers(8)

Authorization

Pre-requestScript

Body

CookiesHeaders(3)TestResults

Body

Pretty

Visualize

Raw

Preview

JSON

2

"traceId:"d6702d2od9a34a2db73a50c18abb74fc"

"success":true,

4

"errCode":0,

5

"errMsg":"'success",

"datas":1

"id":1,

8

"name":"2",

9

"updateTime":"2021-02-08"

10

11

String 类型的id转为了int型,int型的name转为了String型


3.5 集合的拷贝

req5

@Data@Accessors(chain=true)
publicclassMapStructReq5 {
privateIntegerid;
privateMapStructReq1target;
privateList<MapStructReq1>list;
}

resp5

@Data@Accessors(chain=true)
publicclassMapStructResp5 {
privateIntegerid;
privateMapStructResp1target;
privateList<MapStructResp1>list;
}

converter:

List<MapStructResp1>req1ListToResp1List(List<MapStructReq1>req1List);

controller:

image.png

属性为集合的拷贝

Greturn

QGetMapping(/demo6')

publicListMapStructRepeqLiToRepLis

L:nWMastructeql.setam

MapStructRealreg1

MEPStrUCRqLFCMSTRLO

MaStHcReqLteshoqlStukqo

MDSTHUGRL

List:MapstructReglrqListAi

etURnMaStructDeSViceqLisoRepLiLi

image.png

Headers(3)

Cookies

TestResults

Body

JSON

Pretty

Preview

Visualize

Raw

true

success

errCode":0,

5

success"

6

datas"

7

8

"id:1,

9

"name":"namel",

10

"updateTime:*2021-02-08

11

12

13

"id:2

14

"name":"name2",

"updateTime:*2021-02-08"

15

16

17

id:3,

18

19

"name":"name3",

20

"updateTime:*2021-02-08*

21

22

23

id:

24

"name":"name4",

第20210200群


3.6 嵌套对象的拷贝


converter:

MapStructResp5req5ToResp5(MapStructReq5req);


controller:

image.png

嵌套对象的拷贝

*Creturn

*/

@CetMapping(/demo7?)

publicMapStructRespreg5ToResp5

MPStHctRLet

MapStructReqlreg2neMa

WMapstructRealo.setd.setmmm

wDateQ):

MAStHuctReLe

newMapstructReqlo.setdtm

MapStructReqlreq4ne

MapStuctReg5req5-newMapstuct.eaerq)

setList(Arrays.asList(reqlqq)

returnmapStructDemoService.reg5ToResp5rea5)

target赋值为req1,给list赋值为4个不同名字的req1

image.png

CookiesHeaders(3)TestResults

ody

Status

Pretty

JSON

Visualize

Preview

Raw

errloue

"errMsg":"success"

datas*:f

1

id:5,

target"

"id:1,

10

"name":"namel",

11

"updateTime:"2021-02-08"

12

"1ist":

13

14

"id:1,

15

16

"name":"namel",

17

"updateTime:"2021-02-08"

18

19

20

"id:2,

21

"name":"name2",

22

"updateTime:2021-02-08

23

24

"iD:3,

25

26

name*:"name3",

3.7 使用java表达式进行映射

对于复杂的映射,允许使用java表达式实现字段的映射。

注意要导入使用到的类。


req6

@Data@Accessors(chain=true)
publicclassMapStructReq6 {
privateIntegerid;
privateintprice1;
privateintprice2;
}

resp6

@Data@Accessors(chain=true)
publicclassMapStructResp6 {
privateIntegerid;
privateintprice1;
privateintprice2;
}

DemoUtils

publicclassDemoUtils {
publicstaticintadd(intval1, intval2) {
returnval1+val2;
    }
}

converter:

@Mapper(componentModel="spring", imports= {DemoUtils.class})//导入java表达式使用的类,导入多个类在{}中用逗号分隔publicinterfaceMapStructConverterDemo1 {
/*** 使用java表达式进行映射* @param req* @return*/@Mapping(target="price1", expression="java(req.getPrice1() + req.getPrice2())")//直接相加@Mapping(target="price2", expression="java(DemoUtils.add(req.getPrice1(), req.getPrice2()))")//使用工具类处理MapStructResp6req6ToResp6(MapStructReq6req);
}

controller:

image.png

**

使用java表达式拷贝

areturn

*

GGetMapping(/demo8)

publicMapStructResp6reg6ToResp60

MapStructReg6reg6newMapStructReg6

setId(1)

setPrice1(10)

setPrice2(100)

eturnmapStructDemoServicereg6ToResp6reg6);

image.png

fhosty/apilya/demo/mapstruct/demo8

GET

Pre-requestScript

Body

Headers

Authorization

Params

CookiesHeaders(3)

Body

TestResults

Pretty

Visualize

Preview

Raw

JSON

"traceId:"f4e3687f845044f48a15d257b8a925b1"

3

'suCceSS":

true,

"errCode":0,

4

5

"errMsg':'success",

6

"datas":1

7

"id":1,

8

"price1":110,

9

"price2":110

10

11

参考链接

https://www.cnblogs.com/gotten/p/13052911.html

相关文章
|
16天前
|
算法 Java 程序员
在Java的编程世界里,多态不仅仅是一种代码层面的技术,它是思想的碰撞,是程序员对现实世界复杂性的抽象映射,是对软件设计哲学的深刻领悟。
在Java的编程世界里,多态不仅仅是一种代码层面的技术,它是思想的碰撞,是程序员对现实世界复杂性的抽象映射,是对软件设计哲学的深刻领悟。
47 9
|
4天前
|
Arthas Java 测试技术
Java字节码文件、组成,jclasslib插件、阿里arthas工具,Java注解
Java字节码文件、组成、详解、分析;常用工具,jclasslib插件、阿里arthas工具;如何定位线上问题;Java注解
Java字节码文件、组成,jclasslib插件、阿里arthas工具,Java注解
|
18天前
|
XML 存储 JSON
【IO面试题 六】、 除了Java自带的序列化之外,你还了解哪些序列化工具?
除了Java自带的序列化,常见的序列化工具还包括JSON(如jackson、gson、fastjson)、Protobuf、Thrift和Avro,各具特点,适用于不同的应用场景和性能需求。
|
19天前
|
Java 持续交付 项目管理
Maven是一款基于Apache许可的项目管理和构建自动化工具,在Java开发中极为流行。
Maven是一款基于Apache许可的项目管理和构建自动化工具,在Java开发中极为流行。它采用项目对象模型(POM)来描述项目,简化构建流程。Maven提供依赖管理、标准构建生命周期、插件扩展等功能,支持多模块项目及版本控制。在Java Web开发中,Maven能够自动生成项目结构、管理依赖、自动化构建流程并运行多种插件任务,如代码质量检查和单元测试。遵循Maven的最佳实践,结合持续集成工具,可以显著提升开发效率和项目质量。
35 1
|
21天前
|
Java
在Java编程的广阔天地中,条件语句是控制程序流程、实现逻辑判断的重要工具。
在Java编程中,if-else与switch作为核心条件语句,各具特色。if-else以其高度灵活性,适用于复杂逻辑判断,支持多种条件组合;而switch在多分支选择上表现优异,尤其适合处理枚举类型或固定选项集,通过内部跳转表提高执行效率。两者各有千秋:if-else擅长复杂逻辑,switch则在多分支选择中更胜一筹。理解它们的特点并在合适场景下使用,能够编写出更高效、易读的Java代码。
22 1
|
27天前
|
Java
Java——编码GBK的不可映射字符
Java——编码GBK的不可映射字符
25 1
|
1月前
|
并行计算 Java API
Java中的Lambda表达式:简化代码的现代工具
在Java 8中引入的Lambda表达式,为函数式编程范式铺平了道路,提供了一种更简洁、更灵活的编写匿名方法的方式。本文将深入探讨Lambda表达式如何优化代码结构,提高开发效率,并通过具体示例展示其在实际应用中的魔力。
35 3
|
28天前
|
监控 Java
JAVA性能优化- IntelliJ插件:java内存分析工具(JProfiler)
JAVA性能优化- IntelliJ插件:java内存分析工具(JProfiler)
54 0
|
5天前
|
监控 Java 调度
【Java学习】多线程&JUC万字超详解
本文详细介绍了多线程的概念和三种实现方式,还有一些常见的成员方法,CPU的调动方式,多线程的生命周期,还有线程安全问题,锁和死锁的概念,以及等待唤醒机制,阻塞队列,多线程的六种状态,线程池等
30 6
【Java学习】多线程&JUC万字超详解
|
4天前
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。