Java实体对象转换利器MapStruct详解

news2024/11/24 18:25:58

概述

现在的JAVA项目多数采用分层结构,参考《阿里巴巴JAVA开发手册》。

分层之后,每一层都有自己的领域模型,即不同类型的 Bean:

DO Data Object :与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
DTO Data Transfer Object :数据传输对象, Service Manager 向外传输的对象。
BO Business Object :业务对象。由 Service 层输出的封装业务逻辑的对象。
AO Application Object :应用对象。在 Web 层与 Service 层之间抽象的复用对象模型,
极为贴近展示层,复用度不高。
VO View Object :显示层对象,通常是 Web 向模板渲染引擎层传输的对象。
Query :数据查询对象,各层接收上层的查询请求。注意超过 2 个参数的查询封装,禁止
使用 Map 类来传输。
那么,进行就需要这些 对象的转换

例如将UserDo转换为UserVo就很普遍,如下所示:

public class UserDo{
    private String name;
    private Integer age;
}

转换为:

public class UserVo {
    private String name;
    private Integer age;
}

手动进行对象的转换,虽然执行性能很高,但是开发效率非常低下,且可能会存在错漏的情况。因此,我们会选择借助框架或是工具来实现对象的转换,之前常用BeanUtils(有多种可选,性能对比网上找找),现在多了一个选择就是MapStruct。

MapStruct

简介

MapStruct 是一个JSR 269 的 Java 注解处理器,是它是基于注解的,而且是编译时APT(annotation processor tool)。不像其他APT是运行时,例如Spring里面的注解处理方式,是在运行时通过反射的方式处理的。

使用

maven配置

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <mapstruct.version>1.5.3.Final</mapstruct.version>
        <lombok.version>1.18.20</lombok.version>
        <lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${mapstruct.version}</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                ...
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                    <configuration>
                        <source>${maven.compiler.source}</source>
                        <target>${maven.compiler.target}</target>
                        <annotationProcessorPaths>
                            <path>
                                <groupId>org.mapstruct</groupId>
                                <artifactId>mapstruct-processor</artifactId>
                                <version>${mapstruct.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>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

应用

假设我们有如下两个需要转换的类:

@Data
public class UserDo {
    private String name;
    private String gender;
    private Double height;
    private Date birthday;
    private Address address;
    private String girlName;
    private String girlDes;
}

@Data
public class UserVo {
    private String name;
    private String gender;
    private String height;
    private String bornDay;
    private AddressDto address;
    private GirlFriendDto girlFriend;
}

第一步: 定义一个interface,使用 @Mapper 标记。

第二步:构建一个实例属性用于访问里面的方法。

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

 第三步:提供转换方法申明,必要时使用@Mapping注解

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

    @Mapping(target = "bornDay", source = "birthday")
    UserVo toUserVo(UserDo userDo);
}

自定义映射

MapStruc默认会将两个bean的名称相同的属性进行映射,如果source与target的属性名称不一致则需要借助@Mapping注解。编译程序后就会在\target\generated-sources\annotations下产生UserConvetorImpl实现类了。

 第四步:代码中使用UserConvetor转换类

public void runConvetor(){
    UserDo userDo = new UserDo();
    userDo.setName("张三");
    ...

    UserVo userVo= UserConvetor.INSTANCE.toUserVo(userDo);
    log.info("vo: {}", userVo);
}

忽略映射

如果不想给UserDobirthday赋值可以忽略它。

@Mapping(target = "bornDay", ignore = true)
UserVo toUserVo(UserDo userDo);

设置默认值

如果想实现在source值为null时给一个默认值也是可以了。

@Mapping(target = "gender", defaultValue = "man")
UserVo toUserVo(UserDo userDo);

设置常量

@Mapping(target = "height", constant = "175")

数据类型转换

日期类型转换

@Mapping(target = "bornDay", source = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss")
UserVo toUserVo(UserDo userDo);

小数点位数转换 

@Mapping(target = "height", source = "height" ,numberFormat = "#.00")

表达式 

大写转换

@Mapping(target = "name", expression = "java(programer.getName().toUpperCase())")

 方法调用

@Mapping(target = "name", expression = "java(nameToUp(userDo))")
UserVo toUserVo(UserDo userDo);

default String nameToUp(UserDo userDo){
    return Optional.ofNullable(userDo)
            .filter(Objects::nonNull)
            .map(u->u.getName())
            .orElse(null)
            .toUpperCase();
}

 

嵌套映射

我们经常会遇到bean里面套着bean的映射。

{
    "name":"shusheng007",
    "address":{
        "country":"China",
        "city":"TianJin"
    }
}

对于这样的映射,我们只需要在mapper中提供一个嵌套bean的转换关系即可。

@Mapping(target = "address", source = "address")
UserVo toUserVo(UserDo userDo);
//嵌套bean的转换关系
AddressDto toAddressDto(Address addr);

集合映射

只需要提供集合元素类型的映射即可。

AddressDto toAddressDto(Address addr);

List<AddressDto> toAddressList(List<Address> addrList);

多个数据对象

@Mapping(target = "name", source = "programer.name")
@Mapping(target = "girlFriendName", source = "girl.name")
UserVo toUserVo(UserDo userDo, Gir girl);

 其他还有外部引用、切面操作在此就不一一列举。

IDE 插件

MapStruct 提供了 IDEA MapStruct Support 插件,让我们在 IDEA 中,可以更愉快的使用 MapStruct!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2196438.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蓝牙资讯|AirPods Pro 2推送新固件,或新增听力健康相关功能

苹果公司面向 USB-C 和 Lightning 两种型号的 AirPods Pro 2 耳机&#xff0c;推送了新的固件版本7A305&#xff0c;高于 9 月早些时候发布的 7A302 固件。 相关更新包含默认启用的听力保护模式&#xff08;在嘈杂环境下提供被动降噪&#xff09;&#xff0c;以及一种“临床级…

大模型面试八股+答案,LLM-offer手到擒来!

你是否也曾为面试大模型八股文而苦恼&#xff1f;别担心&#xff01;今天我就来给你分享一些绝妙的面试技巧&#xff0c;让你轻松应对&#xff01; &#x1f50d; 第一关&#xff1a;了解题目 首先&#xff0c;一定要仔细阅读题目&#xff0c;理解清楚每个要求。明确问题的关键…

windows C++-创建数据流代理(二)

完整的数据流演示 下图显示了 dataflow_agent 类的完整数据流网络&#xff1a; 由于 run 方法是在一个单独的线程上调用的&#xff0c;因此在完全连接网络之前&#xff0c;其他线程可以将消息发送到网络。 _source 数据成员是一个 unbounded_buffer 对象&#xff0c;用于缓冲…

git clone 私有仓库时出现错误 Authentication failed for :xxxxxx

错误信息 remote: Support for password authentication was removed on August 13, 2021. remote: Please see https://docs.github.com/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended…

【算法】博弈论(C/C++)

个人主页&#xff1a;摆烂小白敲代码 创作领域&#xff1a;算法、C/C 持续更新算法领域的文章&#xff0c;让博主在您的算法之路上祝您一臂之力 欢迎各位大佬莅临我的博客&#xff0c;您的关注、点赞、收藏、评论是我持续创作最大的动力 目录 博弈论&#xff1a; 1. Grundy数…

手机商城系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;用户管理&#xff0c;订单管理&#xff0c;商品信息管理&#xff0c;基础数据管理&#xff0c;地址管理&#xff0c;轮播图管理 微信端账号功能包括&#xff1a;系统首页&#…

Java数据结构栈和队列(Stack和Queue详解)

前言&#xff1a; 栈和队列是数据结构中重要的存储方式&#xff0c;也是建立在Arrarylist和LinkedList之上的数据结构。 本猿在C语言阶段就已经详细剖析过栈和队列&#xff0c;不熟悉的小伙伴可以翻看之前的博客内容&#xff01; Java阶段一方面剖析Java中自带的Stack和Queue中…

宠物咖啡馆平台开发:SpringBoot框架的高效应用

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

【Spring】“请求“ 之传递 JSON 数据

文章目录 JSON 概念JSON 语法JSON 的语法JSON 的两种结构 JSON 字符串和 Java 对象互转JSON 优点传递 JSON 对象 JSON 概念 JSON&#xff1a;JavaScript Object Notation【JavaScript 对象表示法】 JSON 就是一种数据格式&#xff0c;有自己的格式和语法&#xff0c;使用文本…

什么是PLM系统?PLM系统对制造业起到哪些作用?三品PLM系统对汽车制造业意义

在当今竞争激烈的制造业环境中&#xff0c;企业面临着来自市场、技术、客户需求等多方面的挑战。为了应对这些挑战&#xff0c;许多制造企业纷纷引入产品生命周期管理PLM系统&#xff0c;以实现更高效、更灵活的产品全生命周期管理。PLM系统以其独特的优势&#xff0c;在优化产…

社区圈子系统 圈子社区系统 兴趣社区圈子论坛系统 圈子系统源码圈子系统的适用领域有哪些?如何打造自己的圈子圈子系统有哪些常见问题

社区圈子系统 圈子社区系统 兴趣社区圈子论坛系统 圈子系统源码圈子系统的适用领域有哪些&#xff1f;如何打造自己的圈子圈子系统有哪些常见问题 圈子系统的适用领域 圈子系统的适用领域广泛&#xff0c;涵盖了多个行业和场景&#xff0c;包括但不限于以下几个方面&#xff1…

计算机毕业设计 自习室座位预约系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

火语言发布暨火车采集器VIP用户回馈活动

火车头软件系列产品从最初的火车采集器、火车浏览器到触控精灵一直致力于数据采集领域的深耕与拓展&#xff0c;不断优化用户体验&#xff0c;力求为用户提供更加高效、便捷的数据处理工具。 火语言也属于同创始团队的旗下产品&#xff0c;历经三年每周版本更新&#xff0c;迭…

电感七大关键参数

大家好,这里是大话硬件。 今天这篇文章介绍电感的七大关键参数。 1、电感值 电感值就是电感做好以后的固有特性,比如1uH, 10mH,1H,这样不同类型的感值。在学习电感值之前,我们先看一下电阻公式: 其中p是导体的电阻率(Ω*m),S是导体的横截面积(m2),l是导体的长度…

Linux驱动学习——Linux启动流程

什么是驱动 驱动&#xff0c;即设备驱动程序&#xff0c;是一种可以使计算机和设备通信的特殊程序。 从作用角度来看&#xff0c;驱动的主要功能是将硬件设备的功能与操作系统进行连接&#xff0c;让操作系统能够识别并正确使用硬件设备。例如&#xff0c;显卡驱动能让操作系…

Java SE-object类和里面的3个主要方法解读

文章目录 1.object类2.toString方法调用过程2.1具体案例2.2源代码查看2.3方法的重写2.4重写效果 3.equals方法调用过程3.1现象的描述3.2方法的重写3.3IDEA自动填充 4.hashcode方法 1.object类 java里面除了object类&#xff0c;所有的类都是存在继承关系的&#xff0c;object类…

【Docker】03-自制镜像

1. 自制镜像 2. Dockerfile # 基础镜像 FROM openjdk:11.0-jre-buster # 设定时区 ENV TZAsia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # 拷贝jar包 COPY docker-demo.jar /app.jar # 入口 ENTRYPOINT ["ja…

javaweb-请求和响应

1.http协议 1.1请求 1.2.响应 常见响应状态码&#xff1a; 状态码大全&#xff1a;https://cloud.tencent.com/developer/chapter/13553 常见的响应头&#xff1a; 2.请求和响应 2.1.请求 2.1.1postman 作用&#xff1a;常用于接口测试 使用&#xff1a;官网安装-->注册…

电脑手机下载小米xiaomi redmi刷机包太慢 解决办法

文章目录 修改前下载速度修改后下载速度修改方法&#xff08;修改host&#xff09; 修改前下载速度 一开始笔者以为是迅雷没开会员的问题&#xff0c;在淘宝上买了一个临时会员后下载速度依然最高才100KB/s 修改后下载速度 修改方法&#xff08;修改host&#xff09; host文…

【星汇极客】STM32 HAL库各种模块开发之DHT11模块

前言 本人是一名嵌入式学习者&#xff0c;在大学期间也参加了不少的竞赛并获奖&#xff0c;包括&#xff1a;江苏省电子设计竞赛省一、睿抗机器人国二、中国高校智能机器人国二、嵌入式设计竞赛国三、光电设计竞赛国三、节能减排竞赛国三等。 暑假的时候参加了太多的比赛&#…