Java 实体映射工具 MapStruct

createh51周前 (03-27)技术教程3

简介: 让你的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包引入即可。


    0.2.0
    1.3.0.Final
    1.3.0.Final



    
        org.mapstruct
        mapstruct-jdk8
        ${org.mapstruct.version}
    
    
        org.mapstruct
        mapstruct-processor
        ${org.mapstruct.processor.version}
        provided
    



    ${java.version}
    ${java.version}
    
        
            org.mapstruct
            mapstruct-processor
            ${org.mapstruct.processor.version}
        
        
            org.projectlombok
            lombok
            ${lombok.version}
        
        
            org.projectlombok
            lombok-mapstruct-binding
            ${lombok-mapstruct-binding.version}
        
    


2.原理

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


3.使用方法

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


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

@Mapper(componentModel = "spring")




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

MapStructReq1

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

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

}

MapStructResp1:

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

    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 MapStructReq1 {

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

}

MapStructResp2

@Data
public class MapStructResp2 {

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

}

converter

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


controller:

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")
    MapStructResp1 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 MapStructReq3 {

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

}

resp1:

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

    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

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

    private Integer id;
    private MapStructReq1 target;
    private List list;

}

resp5

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

    private Integer id;
    private MapStructResp1 target;
    private List list;

}

converter:

List req1ListToResp1List(List req1List);

controller:


3.6 嵌套对象的拷贝


converter:

MapStructResp5 req5ToResp5(MapStructReq5 req);


controller:

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

3.7 使用java表达式进行映射

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

注意要导入使用到的类。


req6

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

    private Integer id;
    private int price1;
    private int price2;

}

resp6

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

    private Integer id;
    private int price1;
    private int price2;

}

DemoUtils

public class DemoUtils {

    public static int add(int val1, int val2) {
        return val1 + val2;
    }
}

converter:

@Mapper(componentModel = "spring", imports = {DemoUtils.class})//导入java表达式使用的类,导入多个类在{}中用逗号分隔
public interface MapStructConverterDemo1 {

    /**
     * 使用java表达式进行映射
     * @param req
     * @return
     */
    @Mapping(target = "price1", expression = "java(req.getPrice1() + req.getPrice2())")//直接相加
    @Mapping(target = "price2", expression = "java(DemoUtils.add(req.getPrice1(), req.getPrice2()))")//使用工具类处理
    MapStructResp6 req6ToResp6(MapStructReq6 req);
}

controller:

参考链接

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

相关文章

100个Java工具类之69:提供HTTP实体处理功能的EntityUtils

在Java开发中,org.apache.http.util.EntityUtils是一个非常实用的工具类,尤其在进行HTTP请求和响应处理时。它是Apache HttpClient库的一部分,提供了一...

java编程语言中实体类属性自动生成lombok插件_v1

大家好,欢迎来到人工智复,我们的使命是互相勉励,坚定信念,认准自己的方向,坚持到底。//1. 依赖 org.projectlombok lombok 1.14.8 //2....

JPA实体类注解,看这篇就全会了

基本注解@Entity标注于实体类声明语句之前,指出该 Java 类为实体类,将映射到指定的数据库表。name(可选):实体名称。 缺省为实体类的非限定名称。该名称用于引用查询中的实体。不与 @Tab...

mybatis根据表逆向自动化生成代码:自动生成实体类、mapper文件

若采用mybatis框架,数据库新建表,手动编写的话,需要编写大量的实体类、mapper文件、mapper.xml文件,都是一些重复且有规律的工作。我们可以引用插件,然后做配置,自动生成这些文件,提供...

Java的抽象类与举例说明

#暑期创作大赛#1.抽象类我们知道类是产生对象的模板;那么我们可以将抽象类理解为是产生 实体类的模板。在 Java 中可以专门创建一种父类,它的子类必须遵循父类设定的规则,但父类又不能 直接创建对象,...