Java 实体映射工具 MapStruct

Java
280
0
0
2023-09-12

简介: 让你的 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的代码量)

Java 实体映射工具 MapStruct

再到现在的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包

Java 实体映射工具 MapStruct

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

@Mapper (componentModel = “spring” )

Java 实体映射工具 MapStruct

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:

Java 实体映射工具 MapStruct

serviceImpl:

Java 实体映射工具 MapStruct

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

 @Data
public class MapStructResp {

    private Integer id;
    private String productName;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date updateTime;

} 

converter

 @Mapping(source = "name", target = "productName")
MapStructResp req1ToResp2(MapStructReq1 req); 

controller:

Java 实体映射工具 MapStruct

Java 实体映射工具 MapStruct

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:

Java 实体映射工具 MapStruct

Java 实体映射工具 MapStruct

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

Java 实体映射工具 MapStruct

controller:

Java 实体映射工具 MapStruct

Java 实体映射工具 MapStruct

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

3.5 集合的拷贝

req5

 @Data
@Accessors(chain = true)
public class MapStructReq {

    private Integer id;
    private MapStructReq target;
    private List<MapStructReq> list;

} 

resp5

 @Data
@Accessors(chain = true)
public class MapStructResp {

    private Integer id;
    private MapStructResp target;
    private List<MapStructResp> list;

} 

converter:

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

controller:

Java 实体映射工具 MapStruct

3.6 嵌套对象的拷贝

converter:

 MapStructResp req5ToResp5(MapStructReq5 req); 

controller:

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

Java 实体映射工具 MapStruct

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);
}