首页 > 编程语言 >【Java DTO、VO类型转换工具类,对象与对象之间赋值】全部一行代码搞定!爽

【Java DTO、VO类型转换工具类,对象与对象之间赋值】全部一行代码搞定!爽

时间:2024-09-20 11:24:32浏览次数:3  
标签:类型转换 转换 target 对象 param VO private import DTO

对象转换工具

一、modelmapper 介绍

  1. 简化对象转换操作
    在Java 应用开发中,经常需要在不同层次(如持久层、业务逻辑层、表示层)之间转换对象。例如,将数据库查询得到的实体对象(Entity)转换为适合在网络上传输的数据传输对象(DTO),或者将用户输入的表单对象转换为业务逻辑处理的领域对象(Domain Object)。ModelMapper 能够自动完成大部分属性的映射,减少了手动编写大量属性赋值语句的工作量。
    假设存在一个UserEntity类,包含id、username、password、createdAt等属性,以及一个UserDTO类,包含id、username和isAdmin属性。使用 ModelMapper 可以轻松地将UserEntity转换为UserDTO,而不需要为每个属性手动编写转换代码。
  2. 支持复杂对象结构的转换
    当处理具有嵌套结构的对象时,ModelMapper 能够递归地进行映射。例如,在一个电商系统中,有Order类包含Customer对象和List,对应的OrderDTO也有类似的嵌套结构。ModelMapper 可以自动处理这种嵌套对象的映射,将Order对象中的Customer和Product相关属性正确地映射到OrderDTO中的相应部分。

二、安装

(一)引入依赖

        <!-- 对象转换工具-->
        <dependency>
            <groupId>org.modelmapper</groupId>
            <artifactId>modelmapper</artifactId>
            <version>3.2.0</version>
        </dependency>

(二)添加工具类

需要修改一下包名

package org.github.zuuuyao.common.util;

import org.modelmapper.ModelMapper;
import org.modelmapper.convention.MatchingStrategies;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * 对象映射转换工具类,转换逻辑属性名完全匹配进行转换
 *
 * @Description:
 * @Time: 2019-11-28 20:18
 * @Author: HuangZhangYao
 */
public final class ModelMapperUtil {

    public static final ModelMapper MODEL_MAPPER;

    static {

        MODEL_MAPPER = new ModelMapper();
        // 完全类型匹配
        //MODEL_MAPPER.getConfiguration().setFullTypeMatchingRequired(true);
        // 设置属性匹配规则,设置为最严格匹配,必须属性名相同
        MODEL_MAPPER.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
    }

    /**
     * 禁止实列化该类
     * @throws InstantiationException 不能实列化
     */
    private ModelMapperUtil() throws InstantiationException {
        throw new InstantiationException("Tool Class Cannot Be Created Instantiation !");
    }

    /**
     * 将对象转换为指定class类型对象。
     * @param source 源对象
     * @param targetClass 转换目标类型
     * @return 转换后对象
     * @param <Target> 目标类型
     */
    public static <Target> Target map(Object source, Class<Target> targetClass) {
        return source == null ? null : MODEL_MAPPER.map(source, targetClass);
    }


    /**
     * 将源对象中的属性转换到目标对象中,源对象与目标对象属性名相同的则转换
     * @param source 源对象
     * @param target 目标对象
     */
    public static void map(Object source, Object target) {
        if (source == null || target == null) {
            return;
        } else {
            MODEL_MAPPER.map(source, target);
        }
    }

    /**
     * 将对象转换为指定class类型对象,并对转换后对象进行处理
     * @param source 源对象
     * @param targetClass 转换目标类型
     * @param consumer 对转换后对象进行消费处理
     * @return 转换后对象
     * @param <Target> 目标类型
     */
    public static <Target> Target map(Object source, Class<Target> targetClass, Consumer<Target> consumer) {
        Target target = source == null ? null : MODEL_MAPPER.map(source, targetClass);
        if (consumer != null) {
            consumer.accept(target);
        }
        return target;
    }

    /**
     * 将对象转换为指定class类型对象,并对转换后对象进行处理
     * @param source 源对象
     * @param targetClass 转换目标类型
     * @param consumer 对转换后对象进行消费处理
     * @return 转换后对象
     * @param <Source> 源对象类型
     * @param <Target> 目标类型
     */
    public static <Source, Target> Target map(Source source, Class<Target> targetClass, BiConsumer<Source, Target> consumer) {
        Target target = source == null ? null : MODEL_MAPPER.map(source, targetClass);
        if (consumer != null) {
            consumer.accept(source, target);
        }
        return target;
    }

    /**
     * 将集合中的元素抓换为指定类型
     * @param sourceList 源集合
     * @param targetClass 转换目标类型
     * @return 转换后的目标类型集合
     * @param <TSource> 源类型
     * @param <Target> 目标类型
     */
    public static <TSource, Target> List<Target> mapList(Collection<TSource> sourceList, Class<Target> targetClass) {

        if (sourceList == null) {
            return new ArrayList<Target>();
        }

        ArrayList<Target> targets = new ArrayList<>(sourceList.size());

        sourceList.forEach(p -> {
            Target item = map(p, targetClass);
            targets.add(item);
        });

        return targets;
    }

    /**
     * 将集合中的元素抓换为指定类型,并对转换后的元素处理
     * @param sourceList 源集合
     * @param targetClass 转换目标类型
     * @param consumer 对转换后元素处理
     * @return 转换后的集合
     * @param <TSource> 源类型
     * @param <Target> 目标类型
     */
    public static <TSource, Target> List<Target> mapList(Collection<TSource> sourceList, Class<Target> targetClass, Consumer<Target> consumer) {

        if (sourceList == null) {
            return new ArrayList<Target>();
        }

        ArrayList<Target> targets = new ArrayList<>(sourceList.size());

        sourceList.forEach(p -> {
            Target item = map(p, targetClass);

            if (consumer != null) {
                consumer.accept(item);
            }
            targets.add(item);
        });

        return targets;
    }

    /**
     * 将集合中的元素抓换为指定类型,并对转换后的元素处理
     * @param sourceList 源集合
     * @param targetClass 转换目标类型
     * @param consumer 对转换后元素处理
     * @return 转换后的集合
     * @param <TSource> 源类型
     * @param <Target> 目标类型
     */
    public static <TSource, Target> List<Target> mapList(Collection<TSource> sourceList, Class<Target> targetClass, BiConsumer<TSource, Target> consumer) {

        if (sourceList == null) {
            return new ArrayList<Target>();
        }

        ArrayList<Target> targets = new ArrayList<>(sourceList.size());

        sourceList.forEach(p -> {
            Target map = ModelMapperUtil.map(p, targetClass);
            if (consumer != null) {
                consumer.accept(p, map);
            }
            targets.add(map);
        });
        return targets;
    }

}

三、使用示例

  • 准备 UserEntity 实体
package org.github.zuuuyao.entity.system;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import org.github.zuuuyao.common.base.entity.AbstractBaseEntity;
import org.github.zuuuyao.entity.enums.GenderEnum;

import java.io.Serial;
import java.time.LocalDateTime;

/**
 * @Desc 系统用户表
 * @Time 2024-07-11 16:31
 * @Author HuangZhongYao
 */
@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
@TableName("sys_user")
public class UserEntity extends AbstractBaseEntity {

    @Serial
    private static final long serialVersionUID = -4075127738715995785L;

    /**
     * 用户名
     */
    private String username;

    /**
     * 账号
     */
    private String account;

    /**
     * 密码
     */
    private String password;

    /**
     * 密码盐
     */
    private String salt;

    /**
     * 性别
     */
    private GenderEnum gender = GenderEnum.UNKNOWN;

    /**
     * 手机号
     */
    private String phone;

    /**
     * 头像url
     */
    private String avatarUrl;

    /**
     * 备注
     */
    private String remark;

    /**
     * 最后登录时间
     */
    private LocalDateTime lastLoginTime;

    /**
     * 启用状态
     */
    private Boolean enable;

}

  • 准备 UserVo 实体
package org.github.zuuuyao.service.user.dto.output;

import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serial;
import java.time.LocalDateTime;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
import org.github.zuuuyao.common.base.dto.output.BaseOutputIdAndTimeAndOperationDTO;
import org.github.zuuuyao.entity.enums.GenderEnum;
import org.github.zuuuyao.service.role.dto.output.RoleVo;
import org.github.zuuuyao.service.user.model.UserRoleModel;

/**
 * @Desc
 * @Time 2024-07-16 16:29
 * @Author HuangZhongYao
 */
@Getter
@Setter
public class UserVo extends BaseOutputIdAndTimeAndOperationDTO {

    @Serial
    private static final long serialVersionUID = -7091624991626890336L;

    /**
     * 用户名
     */
    @Schema(description = "用户名")
    private String username;

    /**
     * 账号
     */
    @Schema(description = "账号")
    private String account;

    /**
     * 性别枚举
     */
    @Schema(description = "性别")
    private GenderEnum gender;

    /**
     * 性别枚举表示值
     */
    @Schema(description = "性别枚举表示值")
    private int genderEnumValue;

    /**
     * 性别枚举描述
     */
    @Schema(description = "性别枚举描述")
    private String genderEnumDesc;
    
    /**
     * 手机号
     */
    @Schema(description = "手机号")
    private String phone;

    /**
     * 头像url
     */
    @Schema(description = "头像url")
    private String avatarUrl;

    /**
     * 备注
     */
    @Schema(description = "备注")
    private String remark;

    /**
     * 最后登录时间
     */
    @Schema(description = "最后登录时间")
    private LocalDateTime lastLoginTime;

    /**
     * 启用状态
     */
    @Schema(description = "启用状态")
    private Boolean enable;

    /**
     * 用户角色列表
     */
    @Schema(description = "用户角色列表")
    private List<UserRoleModel> roles;
}

(一)单个对象转换

(一)简单转换

    public static void main(String[] args) {

        // 创建一个用户实体对象
        UserEntity admin = UserEntity.builder()
                .username("ZuuuYao")
                .phone("1888888888")
                .account("zy9527")
                .avatarUrl("http://xxx.com/avatar.png")
                .gender(GenderEnum.MALE)
                .remark("管理员")
                .enable(Boolean.TRUE)
                .build();

        // 方式1: 转换为指定类型
        UserVo adminDetailsVo = ModelMapperUtil.map(admin, UserVo.class);

        // 方式2: 转换到指定对象上
        UserVo userVo = new UserVo();
        // 将admin中的同名的数据映射到userVo中
        ModelMapperUtil.map(admin, userVo);

    } 

(二)转换时对转换后的对象处理

    public static void main(String[] args) {

        // 创建一个用户实体对象
        UserEntity admin = UserEntity.builder()
                .username("ZuuuYao")
                .phone("1888888888")
                .account("zy9527")
                .avatarUrl("http://xxx.com/avatar.png")
                .gender(GenderEnum.MALE)
                .remark("管理员")
                .enable(Boolean.TRUE)
                .build();

        // 转换为指定类型, 并使用Consumer设置自定义属性
        UserVo adminDetailsVo = ModelMapperUtil.map(admin, UserVo.class, target -> {
            // 模拟执行逻辑
            target.setGenderEnumDesc(target.getGender().getDesc());
            target.setGenderEnumValue(target.getGenderEnumValue());
        });


    }

(二)转换时对转换后的对象、源对象处理

    public static void main(String[] args) {

        // 创建一个用户实体对象
        UserEntity admin = UserEntity.builder()
                .username("ZuuuYao")
                .phone("1888888888")
                .account("zy9527")
                .avatarUrl("http://xxx.com/avatar.png")
                .gender(GenderEnum.MALE)
                .remark("管理员")
                .enable(Boolean.TRUE)
                .build();

        // 转换为指定类型, 并使用Consumer设置自定义属性
        UserVo adminDetailsVo = ModelMapperUtil.map(admin, UserVo.class, (source, target) -> {

            // source 是 admin
            // target 是 转换后的adminDetailsVo

            // 模拟执行逻辑
            target.setRemark("用户:" + source.getUsername() + ",描述:" + source.getRemark());
        });

    }

(一)批量转换

(一)简单转换

    public static void main(String[] args) {

        // stream 生成100个对象
        List<UserEntity> userEntityList = Stream.generate(() -> UserEntity.builder()
                        .username("ZuuuYao")
                        .phone("1888888888")
                        .account("zy9527")
                        .avatarUrl("http://xxx.com/avatar.png")
                        .gender(GenderEnum.MALE)
                        .remark("管理员")
                        .enable(Boolean.TRUE)
                        .build())
                .limit(100)
                .toList();

        // 转换为指定类型
        List<UserVo> userVos = ModelMapperUtil.mapList(userEntityList, UserVo.class);

    }

(二)转换时对转换后的对象处理

    public static void main(String[] args) {

        // stream 生成100个对象
        List<UserEntity> userEntityList = Stream.generate(() -> UserEntity.builder()
                        .username("ZuuuYao")
                        .phone("18888889898")
                        .account("zy9527")
                        .avatarUrl("http://xxx.com/avatar.png")
                        .gender(GenderEnum.MALE)
                        .remark("管理员")
                        .enable(Boolean.TRUE)
                        .build())
                .limit(100)
                .toList();

        // 转换为指定类型
        List<UserVo> userVos = ModelMapperUtil.mapList(userEntityList, UserVo.class, target -> {
            // 将手机号脱敏
            String phone = target.getPhone();
            String desensitizationPhone = phone.substring(0, 3) + "*****" + phone.substring(8);
            target.setPhone(desensitizationPhone);
        });

    }

(二)转换时对转换后的对象、源对象处理

    public static void main(String[] args) {

        // stream 生成100个对象
        List<UserEntity> userEntityList = Stream.generate(() -> UserEntity.builder()
                        .username("ZuuuYao")
                        .phone("18888889898")
                        .account("zy9527")
                        .avatarUrl("http://xxx.com/avatar.png")
                        .gender(GenderEnum.MALE)
                        .remark("管理员")
                        .enable(Boolean.TRUE)
                        .build())
                .limit(100)
                .toList();

        // 转换为指定类型
        List<UserVo> userVos = ModelMapperUtil.mapList(userEntityList, UserVo.class, (source, target) -> {
            // 可以获取到源对象和转换后对象

            // 假如源对象中有的属性,目标对象没有可以手动赋值
            // target.setA(source.getB());

        });

    }

四、扩展

可以结合mybatis、JPA做一些封装
如下:

// 查询结果就转换为UserVo了就不用再转换了,写起来也比较舒服
Page<UserVo> page = userRepository.selectPage(inputDTO.toMybatisPageObject(), queryWrapper, UserVo.class);

标签:类型转换,转换,target,对象,param,VO,private,import,DTO
From: https://blog.csdn.net/weixin_42703501/article/details/142377665

相关文章

  • WPF behavior InvokeCommndAction PassEventArgsToCommand
    //xaml<ListBoxx:Name="lbx"SelectedIndex="0"ItemsSource="{BindingBooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"VirtualizingPanel.IsContainerVirtualizable="Tru......
  • 新版本QT的QMetaObject::invokeMethod实现
    corelib\kernel\qobjectdefs.htemplate<typenameT>inlineQTemplatedMetaMethodReturnArgument<T>returnArgument(constchar*name,T&t){return{qMetaTypeInterfaceForType<T>(),name,std::addressof(t)};}template<ty......
  • 【目标检测数据集】小车表面缺陷破损检测数据集3135张8类标签VOC+YOLO格式(裂纹掉漆划
    数据集格式:PascalVOC格式+YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件)图片数量(jpg文件个数):3135标注数量(xml文件个数):3135标注数量(txt文件个数):3135标注类别数:8标注类别名称:["crack","dent1","dent2","dislocation"......
  • C语言类型与强制类型转换
    目录类型关键字sizeof如何理解强制类型转化不同类型的0null字符设备(补充)char有有符号和无符号两种类型,字符是无符号类型.(补充)getchar的返回值为什么是int键盘输入的内容,以及往显示器中打印的内容,都是字符-->键盘/显示器称为字符设备类型C语言为何有类型?让我们能够......
  • 华为云DevSecOps和DevOps
    目录1.华为云DevSecOps和DevOps1.1DevSecOps1.1.1核心功能1.1.2 优势1.2 DevOps1.2.1 核心功能1.2.2 优势1.3 DevOps和DevSecOps的区别1.3.1 安全性集成1.3.2 自动化的安全工具1.3.3 团队协作1.3.4 质量与合规性1.3.5 成本与风险管理1.3.5总结2.De......
  • volatile 实现原理了解吗?
    volatile实现原理了解吗?volatile有两个作用,保证可见性和有序性。volatile怎么保证可见性的呢?简单来说:读取和写入变量从原本的本地内存变成主内存中相比synchronized的加锁方式来解决共享变量的内存可见性问题,volatile就是更轻量的选择,它没有上下文切换的额外开销......
  • DS2000 Every Vote Counts
    DS2000Fall2024Homework 1Assigned: September 13,2024Deadline: September20, 2024at9pmeasternSubmiteachprogramasa .pyfileingradescope (filenames are specifiedbelow).You may submit multiple timesrightupuntilthedeadline.Y......
  • 论文阅读:Unsupervised Representation Learning with Deep Convolutional Generative
    Abstract背景:希望能缩小CNN在监督学习和无监督学习之间成功应用的差距。贡献:引入了一类称为深度卷积生成对抗网络(DCGAN)的CNN。结果:DCGAN在生成器和判别器中都能从对象到场景学习表示层次结构。1.Introduction贡献:提出DCGAN用于图像分类任务,展示其性能对滤波器......
  • 杂题总结 Vol.3
    杂题总结Vol.3\(\def\EZ{\textcolor{#51af44}{\text{EZ}}}\EZ\)表示简单,10分钟内就能想到。\(\def\HD{\textcolor{#3173b3}{\text{HD}}}\HD\)表示中等,能独立想出\(\def\IN{\textcolor{#be2d23}{\text{IN}}}\IN\)表示困难,独立思考能想到\(50\%\)以上\(\def\AT{\textcolor......
  • Java 数据类型转换详解:隐式转换(自动转换)与强制转换(手动转换)
    目录前言取值范围从小到大的关系:隐式转换(自动转换)......