简介: 让你的 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的代码量)
再到现在的MapStruct
1.MapStruct配置
MapStuct的使用非常简单,把对应的jar包引入即可。
<properties> | |
<lombok-mapstruct-binding.version>.2.0</lombok-mapstruct-binding.version> | |
< org .mapstruct.version>1.3.0.Final</org.mapstruct.version> | |
<org.mapstruct.processor.version>.3.0.Final</org.mapstruct.processor.version> | |
</properties> | |
<dependencies> | |
<dependency> | |
<groupId>org.mapstruct</groupId> | |
<artifactId>mapstruct-jdk</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) | |
public class MapStructReq { | |
private Integer id; | |
private String name; | |
@JsonFormat(pattern = "yyyy-MM-dd") | |
private Date updateTime; | |
} |
MapStructResp1:
@Data | |
@Accessors(chain = true) | |
public class MapStructResp { | |
private Integer id; | |
private String name; | |
@JsonFormat(pattern = "yyyy-MM-dd") | |
private Date updateTime; | |
} |
converter:
serviceImpl:
controller:
调用demo1接口后,可以看到我们给MapStructReq1赋值后,成功拷贝到了MapStructResp1中返回
3.2 对于不同名相同属性的字段,可以使用Mapping注解指定。
MapStructReq1 :
@Data | |
@Accessors(chain = true) | |
public class MapStructReq { | |
private Integer id; | |
private String name; | |
@JsonFormat(pattern = "yyyy-MM-dd") | |
private Date updateTime; | |
} |
MapStructResp2
public class MapStructResp { | |
private Integer id; | |
private String productName; | |
"yyyy-MM-dd") | (pattern =|
private Date updateTime; | |
} |
converter
MapStructResp req1ToResp2(MapStructReq1 req); |
controller:
req1中的name字段拷贝到了resp2中的productName中
3.3 支持把多个参数映射成一个类型,使用@Mapping指定即可。
converter:
@Mapping(source = "req.id", target = "id") | |
@Mapping(source = "req.productName", target = "name") | |
@Mapping(source = "req.updateTime", target = "updateTime") | |
MapStructResp req1And2ToResp1(MapStructReq1 req1, MapStructReq2 req2); |
controller:
将req1中的id,req2中的name拷贝到了resp1中
3.4 对于基础数据类型会进行自动隐式的转换
如int、long、String,Integer、Long等。
req3 :
@Data | |
@Accessors(chain = true) | |
public class MapStructReq { | |
private String id; | |
private int name; | |
@JsonFormat(pattern = "yyyy-MM-dd") | |
private Date updateTime; | |
} |
resp1:
@Data | |
@Accessors(chain = true) | |
public class MapStructResp { | |
private Integer id; | |
private String name; | |
@JsonFormat(pattern = "yyyy-MM-dd") | |
private Date updateTime; | |
} |
converter:
controller:
String 类型的id转为了int型,int型的name转为了String型
3.5 集合的拷贝
req5
= true) | (chain|
public class MapStructReq { | |
private Integer id; | |
private MapStructReq target; | |
private List<MapStructReq> list; | |
} |
resp5
= true) | (chain|
public class MapStructResp { | |
private Integer id; | |
private MapStructResp target; | |
private List<MapStructResp> list; | |
} |
converter:
List<MapStructResp> req1ListToResp1List(List<MapStructReq1> req1List);
controller:
3.6 嵌套对象的拷贝
converter:
MapStructResp req5ToResp5(MapStructReq5 req);
controller:
给target赋值为req1,给list赋值为4个不同名字的req1
3.7 使用java表达式进行映射
对于复杂的映射,允许使用java表达式实现字段的映射。
注意要导入使用到的类。
req6
@Data | |
@Accessors(chain = true) | |
public class MapStructReq { | |
private Integer id; | |
private int price; | |
private int price; | |
} |
resp6
@Data | |
@Accessors(chain = true) | |
public class MapStructResp { | |
private Integer id; | |
private int price; | |
private int price; | |
} |
DemoUtils
public class DemoUtils { | |
public static int add(int val, int val2) { | |
return val + val2; | |
} | |
} |
converter:
@Mapper(componentModel = "spring", imports = {DemoUtils.class})//导入java表达式使用的类,导入多个类在{}中用逗号分隔 | |
public interface MapStructConverterDemo { | |
/** | |
* 使用java表达式进行映射 | |
* @param req | |
* @return | |
*/ @Mapping(target = "price", expression = "java(req.getPrice1() + req.getPrice2())")//直接相加 | |
@Mapping(target = "price", expression = "java(DemoUtils.add(req.getPrice1(), req.getPrice2()))")//使用工具类处理 | |
MapStructResp req6ToResp6(MapStructReq6 req); | |
} |