一文带你掌握Mapstruct用法_mapstruct单位转换-程序员宅基地

技术标签: Java  用法  配置  Mapstruct  # Java核心  

MapStruct用途

在我们项目中,我们经常要处理将DTO转换成VO,DTO转成Entity等各类对象相互转换,如果我们采用BeanUtils工具类的copyProperty进行转换,很容易出现转换性能低,类型转换错误等问题。
与其他转换工具相对,MapStruct具有以下优点:
通过使用普通方法调用而不是反射来快速执行
编译时类型安全性:只能映射相互映射的对象和属性,不能将订单实体意外映射到客户DTO等。

Maven配置

...
<properties>
    <org.mapstruct.version>1.3.1.Final</org.mapstruct.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</artifactId>
        <version>${
    org.mapstruct.version}</version>
    </dependency>
</dependencies>
...
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${
    org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>
...

基本映射

场景:将一个对象映射成另外一种类型的对象,如将DTO映射成VO
定义一个映射接口类CarMapper

@Mapper
public interface CarMapper {
    
    CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);

    @Mapping(source = "make", target = "manufacturer")
    @Mapping(source = "numberOfSeats", target = "seatCount")
    CarDto carToCarDto(Car car);
	
    @Mapping(source = "name", target = "fullName")
    PersonDto personToPersonDto(Person person);
}

代码中使用CarDTO carDTO = CarMapper.INSTANCE.carToCarDto(car)进行类型抓换(下同)。
在生成的方法实现中,源类型(例如Car)的所有可读属性都将被复制到目标类型(例如CarDto)的相应属性中:
当一个属性与其目标实体对应的名称相同时,它将被隐式映射。
当属性在目标实体中具有不同的名称时,可以通过@Mapping注释指定其名称。

多个属性的映射

场景:为了将多个实体组合到一个数据传输对象中。

@Mapper
public interface AddressMapper {
    
	AddressMapper INSTANCE = Mappers.getMapper(AddressMapper.class);
	
    @Mapping(source = "person.description", target = "description")
    @Mapping(source = "address.houseNo", target = "houseNumber")
    DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address);
}

直接引用源参数的映射方法

@Mapper
public interface AddressMapper {
    
	AddressMapper INSTANCE = Mappers.getMapper(AddressMapper.class);
	
    @Mapping(source = "person.description", target = "description")
    @Mapping(source = "address.houseNo", target = "houseNumber")
    DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address);
}

更新现有的Bean实例

场景:将一个Bean的属性更新到另外一个bean的同名属性

@Mapper
public interface CarMapper {
    
	CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);
	
    void updateCarFromDto(CarDto carDto, @MappingTarget Car car);
}

继承反转配置

场景:已经存在一个Car映射成CarDTO的方法,现在需要将CarDTO映射成Car。

@Mapper
public interface CarMapper {
    
	CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);
	   
    @Mapping(source = "make", target = "manufacturer")
    @Mapping(source = "numberOfSeats", target = "seatCount")
    CarDto carToCarDto(Car car);

	@InheritInverseConfiguration(name = "carToCarDto")
	Car carDTOTocar(CarDto carDto);
}

隐式类型转换

在许多情况下,MapStruct会自动处理类型转换。例如,如果一个属性int在源Bean中是类型但String在目标Bean中是类型,则生成的代码将分别通过分别调用String#valueOf(int)和来透明地执行转换Integer#parseInt(String)。
当前,以下转换将自动应用:
之间的所有Java基本数据类型及其相应的包装类型,例如之间int和Integer,boolean和Boolean等。之间的所有Java基本类型和包装类之间,例如int和long或byte和Integer。
从较大的数据类型转换为较小的数据类型(例如从long到int)可能会导致值或精度损失。在Mapper和MapperConfig注释有一个方法typeConversionPolicy来控制警告/错误。由于向后兼容的原因,默认值为“ ReportingPolicy.IGNORE”。
所有Java基本类型之间(包括其包装)和String之间,例如int和String或Boolean和String。java.text.DecimalFormat可以指定理解的格式字符串。
从int到String的转换

@Mapper
public interface CarMapper {
    

    @Mapping(source = "price", numberFormat = "$#.00")
    CarDto carToCarDto(Car car);

    @IterableMapping(numberFormat = "$#.00")
    List<String> prices(List<Integer> prices);
}

从BigDecimal到String的转换

@Mapper
public interface CarMapper {
    

    @Mapping(source = "power", numberFormat = "#.##E0")
    CarDto carToCarDto(Car car);

}

从日期到字符串的转换

@Mapper
public interface CarMapper {
    

    @Mapping(source = "manufacturingDate", dateFormat = "dd.MM.yyyy")
    CarDto carToCarDto(Car car);

    @IterableMapping(dateFormat = "dd.MM.yyyy")
    List<String> stringListToDateList(List<Date> dates);
}

更多映射见@Mapping注解

控制嵌套bean映射

场景:对象内部存在多重嵌套。

@Mapper
public interface FishTankMapper {
    

    @Mapping(target = "fish.kind", source = "fish.type")
    @Mapping(target = "fish.name", ignore = true)
    @Mapping(target = "ornament", source = "interior.ornament")
    @Mapping(target = "material.materialType", source = "material")
    @Mapping(target = "quality.report.organisation.name", source = "quality.report.organisationName")
    FishTankDto map( FishTank source );
}

映射表达式

场景:target属性需要通过计算得到。这个功能很强大,可以适用很多场景,比如将Integer类转换成枚举类,单位换算等等。

@Mappings({
    
            @Mapping(target = "extensionInsuranceAmount", expression = "java(com.souche.connector.common.util.AmountConvertUtil.convertToFen(vo.getExtensionInsuranceAmount()))"),
            @Mapping(target = "insuranceAmount", expression = "java(com.souche.connector.common.util.AmountConvertUtil.convertToFen(vo.getInsuranceAmount()))"),
            @Mapping(target = "purchaseTax", expression = "java(com.souche.connector.common.util.AmountConvertUtil.convertToFen(vo.getPurchaseTax()))"),
            @Mapping(target = "decorationAmount", expression = "java(com.souche.connector.common.util.AmountConvertUtil.convertToFen(vo.getDecorationAmount()))"),
            @Mapping(target = "boutiqueAmount", expression = "java(com.souche.connector.common.util.AmountConvertUtil.convertToFen(vo.getBoutiqueAmount()))"),
            @Mapping(target = "maintainPackageAmount", expression = "java(com.souche.connector.common.util.AmountConvertUtil.convertToFen(vo.getMaintainPackageAmount()))"),
            @Mapping(target = "repairAmount", expression = "java(com.souche.connector.common.util.AmountConvertUtil.convertToFen(vo.getRepairAmount()))"),
            @Mapping(target = "renewalFundAmount", expression = "java(com.souche.connector.common.util.AmountConvertUtil.convertToFen(vo.getRenewalFundAmount()))")
    })
    AdditionalDetailDTO map(AdditionalDetailVO vo);

映射集合

场景:将一个集合映射成另外一个集合。

@Mapper
public interface CarMapper {
    

    Set<String> integerSetToStringSet(Set<Integer> integers);

    List<CarDto> carsToCarDtos(List<Car> cars);

    CarDto carToCarDto(Car car);
}

映射map

场景:将一个Map对象映射成另外一个Map对象

public interface SourceTargetMapper {
    

    @MapMapping(valueDateFormat = "dd.MM.yyyy")
    Map<String, String> longDateMapToStringStringMap(Map<Long, Date> source);
}

映射枚举类型

可以在@ValueMapping注释的帮助下将源枚举中的常量映射到具有其他名称的常量。来自源枚举的多个常量可以映射到目标类型中的相同常量。

@Mapper
public interface OrderMapper {
    

    OrderMapper INSTANCE = Mappers.getMapper( OrderMapper.class );

    @ValueMappings({
    
        @ValueMapping(source = "EXTRA", target = "SPECIAL"),
        @ValueMapping(source = "STANDARD", target = "DEFAULT"),
        @ValueMapping(source = "NORMAL", target = "DEFAULT")
    })
    ExternalOrderType orderTypeToExternalOrderType(OrderType orderType);
}

默认值和常量

分别可以通过@Mapping的defaultValue和constant属性指定,当source对象的属性值为null时,如果有指定defaultValue将注入defaultValue的设定的值。constant属性通用用于给target属性注入常量值。

@Mapper(uses = StringListMapper.class)
public interface SourceTargetMapper {
    

    SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );

    @Mapping(target = "stringProperty", source = "stringProp", defaultValue = "undefined")
    @Mapping(target = "longProperty", source = "longProp", defaultValue = "-1")
    @Mapping(target = "stringConstant", constant = "Constant Value")
    @Mapping(target = "integerConstant", constant = "14")
    @Mapping(target = "longWrapperConstant", constant = "3001")
    @Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014")
    @Mapping(target = "stringListConstants", constant = "jack-jill-tom")
    Target sourceToTarget(Source s);
}

如果为s.getStringProp() == null,则将target属性stringProperty设置为"undefined"而不是应用来自s.getStringProp()的值。如果为s.getLongProperty() == null,则目标属性longProperty将设置为-1。将String "Constant Value"设置为目标属性stringConstant。该值"3001"被类型转换为 targe类的longWrapperConstant属性。该常量"jack-jill-tom"将破折号分隔的列表映射到List。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_35211818/article/details/104714363

智能推荐

linux gcc-c++等依赖安装以及防火墙基础命令_gcc-c++安装包-程序员宅基地

文章浏览阅读3.5k次,点赞2次,收藏7次。linux gcc-c++等依赖安装以及防火墙基础命令_gcc-c++安装包

sybase安装字符集_sybase12.5添加字符集-程序员宅基地

文章浏览阅读1.6k次。我是在windows环境下安装了一个sybase数据库。1、找到要安装的字符集目录D:\ProgramFiles\sybase12.5\charsets\cp850 ,这个目录是在sybaes的安装目录;sybae默认不会安装所有的字符集,如果你需要的字符集数据库没有安装的话;可以自行进行安装。在cp850同级目录还有许多的其他字符集。2_sybase12.5添加字符集

一文了解路由平台的 Cisco IOS 和 IOS XE 命名约定,看这篇就够了_ios xe system 在哪些设备-程序员宅基地

文章浏览阅读4.9k次。文章目录概述命名约定一致性IOSCisco IOS XE 软件版本 16 和 17IOS XE 软件版本 3SIOS XE Train 标识符物理平台虚拟平台IOS经典Cisco IOS 软件版本 15IOS 经典列车标识符物理平台概述命名约定一致性对某事物进行任何命名约定的全部意义在于使事物保持一致和统一。遵守约定可为专业人员提供基本规则,让他们坚持已知的内容,为现在和未来的员工以及使用思科产品的人员提供清晰简洁的信息。本文概述了Cisco 路由平台的 Cisco IOS 命名约定,包括 IOS _ios xe system 在哪些设备

Nginx反向代理L4后进行keepalived检测_l4的代理-程序员宅基地

文章浏览阅读442次。1、10和11上安装nginx代理12和13和keepalived并配置yum install nginx keepalived -yvim /etc/nginx/nginx.conf末尾添加stream { upstream kube-apiserver { server 10.4.7.12:6443 max_fails=3 fail_timeout=30..._l4的代理

Java后台获取小程序用户信息和登录_java 小程序 后端获得userinfo 2024-程序员宅基地

文章浏览阅读2.1k次。登录请求体public class MiniProgramLoginCommand { private String jsCode; private String encryptedData; private String iv;}核心代码private static final Logger logger = LoggerFactory.getLogger(XX..._java 小程序 后端获得userinfo 2024

HDFS(12)--HDFS的javaAPI操作_java hdfs api filesystem exists-程序员宅基地

文章浏览阅读1.9k次。创建maven工程并导入jar包<repositories><repository><id>cloudera</id><url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>&..._java hdfs api filesystem exists

随便推点

【转载】WPF自定义控件与样式(1)-矢量字体图标(iconfont)_/k.framework.controls;component/resources/#sf2015-程序员宅基地

文章浏览阅读1.4k次。原文地址:http://www.cnblogs.com/anding/p/4961215.html一.图标字体  图标字体在网页开发上运用非常广泛,具体可以网络搜索了解,网页上的运用有很多例子,如Bootstrap。但在C/S程序中使用还不多,字体图标其实就是把矢量图形打包到字体文件里,就像使用一般外置字体一样的使用,因此Winform、WPF中都是可以用的。  在我们多个_/k.framework.controls;component/resources/#sf2015

k8s gcr.io/google-samples/hello-frontend:1.0 镜像无法下载_docker pull gcr.io/google-samples/node-hello:1.0-程序员宅基地

文章浏览阅读2.5k次。Failed to pull image "gcr.io/google-samples/hello-frontend:1.0": rpc error: code = Unknown desc = Error response from daemon: Get https://gcr.io/v2/: net/http: request canceled while waiting for conne..._docker pull gcr.io/google-samples/node-hello:1.0

vector数组的初始化_vector数组初始化-程序员宅基地

文章浏览阅读2.2k次。1.已知元素的初始化vector a={1,2,3,4,5};2.需要输入元素的初始化(1)先将vector中所有元素初始化为0vector a(n)或vector a(n,0)#include<iostream>#include<vector>using namespace std;int main(){ int n; cin >&..._vector数组初始化

二级c语言105道上机题库,微机原理及应用习题105道-程序员宅基地

文章浏览阅读5.3k次。《微机原理与应用》习题1. 求ADDRI开始单元中连续存放的两个双字数据之和,将结果存放在ADDR2开始的单元,并将结果在显示器上显示出来。(假定和不超过双字) 2. 在一个首地址为STR、长度为N的字符串中查找“空格”,找到则向DL中送1,否则向DL中送-1。 3. 将两位十六进制数转换成ASCII码,并送屏幕显示,要求使用顺序结构实现。 4. 使用分支结构实现将1位十六进制数转换成ASCII码..._自1000h单元开始有1000个单字节带符号数

python fabric2.X版本-程序员宅基地

文章浏览阅读998次。2019独角兽企业重金招聘Python工程师标准>>> ..._python通过fabric2可以用rsync吗

DAO设计模式_dao设计模式最广泛-程序员宅基地

文章浏览阅读278次。DAO (Data Access Object,数据访问对象)的主要功能是数据操作,提供多个原子性的DAO操作,如增加、修改、删除等,都于原子性的操作。DAO主要由以下几个部分组成:1.DatabaseConnection:专门负责数据库的打开与关闭操作的类。2.VO:主要由属性、setter、getter方法组成3.DAO:主要定义操作的接口,定义一系列数据库的原子性操_dao设计模式最广泛