前言
在软件架构中,分层式结构是最常见,各层之间有其独立且隔离的业务逻辑,也因而各层有自己的输入输出对象,也就是代码中见到各种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的代码量)
再到现在的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:
chain=true) (publicclassMapStructReq1 { privateIntegerid; privateStringname; pattern="yyyy-MM-dd") (privateDateupdateTime; }
MapStructResp1:
chain=true) (publicclassMapStructResp1 { privateIntegerid; privateStringname; pattern="yyyy-MM-dd") (privateDateupdateTime; }
converter:
@apper(componentModel
spring
publicinterfaceMaptrucconeeDemo
8
9
水*
*对于同名同属性的字段,无需特别声明指定,自动转换.
*Cparamreg
Sreturn
MapStructResp1regIToResp(MatructReqlreq;
serviceImpl:
@Service
implementsMapStructDemoService
publicclassMapStructDemoServiceImp
@Autowired
MapStructConverterDemomaptructconverterDemo
Qoverride
publicMapstructReplgToRepiMaucRqlr
returnmapstructconverterDemoITRep
controller:
**
*对于同名同属性的字段,无需特别声明指定,自动转换.
@return
GGetMapping(/demo12)
publicMapStructResplreqIToResp10
NEwMapstructReqlO.setd1.setam(nmeetUterime(eDate;
MapStructReqlreql
returnmapStrucDemoService.reaiToRespreq)
调用demo1接口后,可以看到我们给MapStructReq1赋值后,成功拷贝到了MapStructResp1中返回
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:
chain=true) (publicclassMapStructReq1 { privateIntegerid; privateStringname; pattern="yyyy-MM-dd") (privateDateupdateTime; }
MapStructResp2
publicclassMapStructResp2 { privateIntegerid; privateStringproductName; pattern="yyyy-MM-dd") (privateDateupdateTime; }
converter
source="name", target="productName") (MapStructResp2req1ToResp2(MapStructReq1req);
controller:
@GetMapping(/demo2)
publicMapStructResp2reqIToResp20
MaStructkqleqlneMstucRq..
mapStructDemoService.reqlToResp2(reql)
return
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:
source="req1.id", target="id") (source="req2.productName", target="name") (source="req1.updateTime", target="updateTime") (MapStructResp1req1And2ToResp1(MapStructReq1req1, MapStructReq2req2);
controller:
GGetMapping(/demo3")
publicMapStructResplreqlAnd2ToResp1O
MSTNetRnMstrucRqo
MPSTHUCRTPHSTUGRQOLAOOUTOInDTEO
etURNMAPStructDemSviceqApq
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:
chain=true) (publicclassMapStructReq3 { privateStringid; privateintname; pattern="yyyy-MM-dd") (privateDateupdateTime; }
resp1:
chain=true) (publicclassMapStructResp1 { privateIntegerid; privateStringname; pattern="yyyy-MM-dd") (privateDateupdateTime; }
converter:
**
*对于基础数据类型会进行自动隐式的转换
如intlong,StringIntegerLong等
*@paramreg
*
preturn
*/
eg3ToResp1(MapStructReq3reg
MapStructResp1
controller:
对于基础数据类型会进行自动隐式的转换
@return
*
GGetMapping(/demo5)
publicMapStructResplreqToResp1
MPSTNUCRSTESWMSTUCRESOetT)eLm2SUATeTIEEWDATEO)
returnmapStructDemoServicergToRespq)
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
chain=true) (publicclassMapStructReq5 { privateIntegerid; privateMapStructReq1target; privateList<MapStructReq1>list; }
resp5
chain=true) (publicclassMapStructResp5 { privateIntegerid; privateMapStructResp1target; privateList<MapStructResp1>list; }
converter:
List<MapStructResp1>req1ListToResp1List(List<MapStructReq1>req1List);
controller:
属性为集合的拷贝
Greturn
QGetMapping(/demo6')
publicListMapStructRepeqLiToRepLis
L:nWMastructeql.setam
MapStructRealreg1
MEPStrUCRqLFCMSTRLO
MaStHcReqLteshoqlStukqo
MDSTHUGRL
List:MapstructReglrqListAi
etURnMaStructDeSViceqLisoRepLiLi
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:
嵌套对象的拷贝
*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
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
chain=true) (publicclassMapStructReq6 { privateIntegerid; privateintprice1; privateintprice2; }
resp6
chain=true) (publicclassMapStructResp6 { privateIntegerid; privateintprice1; privateintprice2; }
DemoUtils
publicclassDemoUtils { publicstaticintadd(intval1, intval2) { returnval1+val2; } }
converter:
componentModel="spring", imports= {DemoUtils.class})//导入java表达式使用的类,导入多个类在{}中用逗号分隔 (publicinterfaceMapStructConverterDemo1 { /*** 使用java表达式进行映射* @param req* @return*/target="price1", expression="java(req.getPrice1() + req.getPrice2())")//直接相加 (target="price2", expression="java(DemoUtils.add(req.getPrice1(), req.getPrice2()))")//使用工具类处理 (MapStructResp6req6ToResp6(MapStructReq6req); }
controller:
**
使用java表达式拷贝
areturn
*
GGetMapping(/demo8)
publicMapStructResp6reg6ToResp60
MapStructReg6reg6newMapStructReg6
setId(1)
setPrice1(10)
setPrice2(100)
eturnmapStructDemoServicereg6ToResp6reg6);
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