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

一、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);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZuuuuYao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值