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

相关文章
|
1月前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
69 9
|
23天前
|
SQL Java 索引
java小工具util系列2:字符串工具
java小工具util系列2:字符串工具
137 83
|
20天前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
38 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
23天前
|
Java 数据库
java小工具util系列1:日期和字符串转换工具
java小工具util系列1:日期和字符串转换工具
53 26
|
24天前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
48 24
|
23天前
|
数据采集 存储 监控
Java爬虫:数据采集的强大工具
在数据驱动的时代,Java爬虫技术凭借其强大的功能和灵活性,成为企业获取市场信息、用户行为及竞争情报的关键工具。本文详细介绍了Java爬虫的工作原理、应用场景、构建方法及其重要性,强调了在合法合规的前提下,如何有效利用Java爬虫技术为企业决策提供支持。
|
1月前
|
Java 数据格式 索引
使用 Java 字节码工具检查类文件完整性的原理是什么
Java字节码工具通过解析和分析类文件的字节码,检查其结构和内容是否符合Java虚拟机规范,确保类文件的完整性和合法性,防止恶意代码或损坏的类文件影响程序运行。
44 5
|
7天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
37 6
|
22天前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
20天前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
下一篇
DataWorks