data工具,实现了对象拷贝 DTO -> VO 只需要实现一个类即可

data-utils

data工具,实现了对象拷贝DTO —> VO

解决的问题

Mapstruct需要安插件!!!!很多云桌面等会很不方便
org.springframework.beans.BeanUtils有一个 copyProperties的方法

@Data
@AllArgsConstructor
@NoArgsConstructor
public class AccountDTO { private Long id;
private String username;
private String password;
private String gender;
private String email;
private String role;
private Date registerTime;
private Integer isDelete;
}
@Data
public class AccountVO {
private String username;
private String gender;
private String role;
//男 1 女 0
private String genderNum; private Integer isDelete;
}

比如我们有两个类 DTO 和 VO 在给前端VO的时候,需要把DTO 转换成VO 我们需要这样写 遇到genderNumDTO类里没有的这种情况,我们需要手动set的时候,是下面这种写法

import com.example.entity.AccountVO;

@Data
public class DataTest {
@Test
void contextLoads1() {
AccountDTO accountDTO = new AccountDTO(1L, "test", "123456", "男", "112@qq.com", "user", new Date(), 1);
AccountVO accountVO = new AccountVO();
BeanUtils.copyProperties(accountDTO, accountVO);
accountVO.setGender(Objects.equals(accountDTO.getGender(), "男") ? "1" : "0");
System.out.println(accountVO);
}
}

有两个缺点:
1.VO需要手动new一个出来
2.如果VO里面有很多字段需要手动set的时候,会把代码写的很长
3.如果遇到集合里面想要转换, sonar还会报不让在循环中创建对象的问题

BaseData的作用

BaseData代码(项目里只要有这个就可以)

import com.example.common.Constants;
import com.example.common.ErrorCode;
import com.example.exception.BusinessException;
import org.springframework.util.ReflectionUtils; import java.lang.reflect.*;
import java.util.Arrays;
import java.util.function.Consumer; public interface BaseData { /**
* 默认方法,根据传入的Class3类型将当前对象转换为目标对象并执行操作
*
* @param clazz 目标类
* @param consumer 可以写lambda表达式比如
* accountDTO.asTargetObject(AccountVO.class,v->{
* v.setGenderNum(Objects.equals(accountDT0.getGender(),"男")?"1":"0");
* });
* consumer是这段
* v->{
* v.setGenderNum(Objects.equals(accountDT0.getGender(),"男")?"1":"0");
* }
*/
default <V> V asTargetObject(Class<V> clazz, Consumer<V> consumer) {
// 调用 asTargetObject 方法将当前对象转换为目标对象
V v = this.asTargetObject(clazz);
// 执行传入的Consumer操作
consumer.accept(v);
return v;
} /**
* 默认方法 将当前对象转换为目标对象
*
* @param clazz 目标类
* @param <V> 目标类类型 如AccountVO
* @return 转换完的目标类
*/
default <V> V asTargetObject(Class<V> clazz) {
try {
// 获取目标类的所有字段
Field[] declaredFields = clazz.getDeclaredFields();
// 获取目标类的构造函数
Constructor<V> constructor = clazz.getConstructor();
// 根据构造函数实例化目标对象
V v = constructor.newInstance();
// 遍历目标类的每个字段,并进行转换试值
Arrays.stream(declaredFields).forEach(declaredField -> convert(declaredField, v));
return v;
} catch (ReflectiveOperationException e) {
// //捕获ReflectiveOperationException异常,抛出自定义的BusinessException
throw new BusinessException(ErrorCode.CAST_OBJECT_ERROR);
} } /**
* 默认方法,将字段转换并赋值给目标对象
* @param field VO剩余的字段,自定义
* @param vo 要转换的VO
*/
default void convert(Field field, Object vo) { try {
// 获取当前对象中与目标字段同名的字段
Field source = this.getClass().getDeclaredField(field.getName());
// 设置字段可访问
ReflectionUtils.makeAccessible(field);
ReflectionUtils.makeAccessible(source);
// 获取当前对象中获取字段值的方法和目标对象中设置字段值的方法,并进行转换赋值
Method sourceGetter = this.getClass().getMethod(Constants.GET + capitalize(field.getName()));
Method targetSetter = vo.getClass().getMethod(Constants.SET + capitalize(field.getName()), field.getType());
Object value = sourceGetter.invoke(this);
targetSetter.invoke(vo, value);
} catch (NoSuchFieldException | InvocationTargetException | IllegalAccessException |
NoSuchMethodException ignored) {
// 这里ignored 原因是
// 两个类的字段数量不一样的时候,会报 java.lang.NoSuchFieldException
// 但是多出来的字段我们是可以处理的
}
} /**
* 默认方法,将字符串首字母大写
* @param str 比如字段名 name
* @return 返回 Name
*/
default String capitalize(String str) {
if (str == null || str.isEmpty()) {
return str;
}
return Character.toUpperCase(str.charAt(0)) + str.substring(1);
}
}

1.实现对象深拷贝

@Data
public class DataTest {
@Test
void contextLoads1() {
AccountDTO accountDTO = new AccountDTO(1L,"test","123456","男","112@qq.com","user",new Date(),1);
AccountVO accountVO = accountDTO.asTargetObject(AccountVO.class,v->{
v.setGenderNum(Objects.equals(accountDTO.getGender(), "男") ? "1" : "0");
});
System.out.println(accountVO);
}
}

1.实现对象Collection深拷贝(List Set...)

@Data
public class DataTest {
@Test
void contextLoads2() {
AccountDTO accountDTO = new AccountDTO(1L,"test","123456","男","112@qq.com","user",new Date(),0);
AccountDTO accountDTO2 = new AccountDTO(2L,"test2","123456","女","112@qq.com","admin",new Date(),1);
List<AccountDTO> accountDTOList = new ArrayList<>();
accountDTOList.add(accountDTO);
accountDTOList.add(accountDTO2);
List<AccountVO> list = accountDTOList.stream().map(source -> source.asTargetObject(AccountVO.class, v-> {
v.setGenderNum(Objects.equals(source.getGender(), "男") ? "1" : "0");
})).collect(Collectors.toList());
list.forEach(System.out::println);
} @Test
void contextLoads3() {
AccountDTO accountDTO = new AccountDTO(1L,"test","123456","男","112@qq.com","user",new Date(),1);
AccountDTO accountDTO2 = new AccountDTO(2L,"test2","123456","女","112@qq.com","admin",new Date(),0);
Set<AccountDTO> accountDTOSet = new HashSet<>();
accountDTOSet.add(accountDTO);
accountDTOSet.add(accountDTO2);
Set<AccountVO> set = accountDTOSet.stream().map(source -> source.asTargetObject(AccountVO.class, v-> {
v.setGenderNum(Objects.equals(source.getGender(), "男") ? "1" : "0");
})).collect(Collectors.toSet());
set.forEach(System.out::println);
}
}

实现步骤

1. dto 实现 BaseData接口
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AccountDTO implements BaseData { private Long id;
private String username;
private String password;
private String gender;
private String email;
private String role;
private Date registerTime;
private Integer isDelete;
}
2. dto.asViewObject(Target.class);
3. 如果 Target 还有其他字段 也可以自定义,例如测试用例中的genderNum(只是简单举的例子,按照项目实际来)
4. `isDelete` 这种is开头的也支持
1. 如果有问题,看下lombok版本是否有问题 此项目用的版本是 1.18.28 没问题
2. 如果没用lombok 手动加上getIsDelete() 用这个格式就可以了

注意

两个类 相同的字段名的字段类型 必须完全一样!!!

DTO转VO工具的更多相关文章

  1. DO、DTO和VO分层设计的好处

      2016年10月23日 20:11:03 阅读数:10646 在Java中 VO. PO.DO.DTO. BO. QO.DAO.POJO的概念中介绍过Java中的各种模型概念.在这里简单再总结一下 ...

  2. Java中PO、DO、TO、DTO、 VO、 BO、POJO 、DAO的概念

    本文系转载-原创@HollisChuang :http://www.hollischuang.com/archives/553 1.PO(persistant object) 持久对象   在 o/r ...

  3. 什么是JavaBean、bean? 什么是POJO、PO、DTO、VO、BO ? 什么是EJB、EntityBean?

    什么是JavaBean.bean?  什么是POJO.PO.DTO.VO.BO ?  什么是EJB.EntityBean?   前言:   在Java开发中经常遇到这些概念问题,有的可能理解混淆,有的 ...

  4. Java中PO、DO、DTO、 VO、 BO、POJO 、DAO、TO的概念

    1.  PO(persistant object) 持久对象 在 O/R 映射的时候出现的概念,如果没有 O/R 映射,没有这个概念存在了. 通常对应数据模型 ( 数据库 ), 本身还有部分业务逻辑的 ...

  5. PO、POJO、BO、DTO、VO之间的区别(转)

    PO:persistent object持久对象 1 .有时也被称为Data对象,对应数据库中的entity,可以简单认为一个PO对应数据库中的一条记录. 2 .在hibernate持久化框架中与in ...

  6. DO,DTO和VO的使用

    DO,DTO和VO的使用 DO:对应数据库表结构 VO:一般用于前端展示使用 DTO:用于数据传递.(接口入参和接口返回值都可以) 以ssm框架为例: controller层: public List ...

  7. 转载--Java中的PO、DO、DTO、 VO的概念

    Java中的PO.DO.DTO. VO的概念 写的很清晰,学习了.

  8. 什么是DO / DTO / BO / VO /AO ?

    转载:https://blog.csdn.net/ouzhuangzhuang/article/details/86644476 POJO 是 DO / DTO / BO / VO 的统称. DO(D ...

  9. javabean、DTO、VO

    一.javabean 一. javabean 是什么? Bean的中文含义是“豆子”,顾名思义,JavaBean是指一段特殊的Java类, 就是有默然构造方法,只有get,set的方法的java类的对 ...

  10. Java中DAO/DTO/PO/VO/BO/QO/POJO

    ORM:是Object Relational Mapping(对象关系映射)的缩写. 通俗点讲,就是将对象与关系数据库绑定,用对象来表示关系数据.在O/R/M的世界里,有两个基本的也是重要的东东需要了 ...

随机推荐

  1. JavaScript处理后端返回PDF文件流,在线预览下载PDF文件

    在实际开发业务中,遇到这一需求,即后端返回的pdf文件,是以base64文件流的方式,在此不便操作接口响应等操作,便以上传一个文件转化为文件流的形式模拟 实际应用时,base64Img = res.d ...

  2. C#:进程之间传递数据

    一.思路 在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯.常用的方法有 使用内存映射文件 通过共享内存DLL共享内存 使用SendMessage向另一进程发送WM_COPYDATA ...

  3. vue项目使用elementUI的el-upload组件实现图片上传和文件上传的公共组件封装

    图片上传: <template> <div class="upload-pic"> <el-upload class="upload-dem ...

  4. Goutte爬虫

    安装 composer require fabpot/goutte:4.0

  5. top的wa,mpstat的%iowait以及pidstat的%wait

    top的wa,mpstat的%iowait以及pidstat的%wait pidstat 中, %wait 表示进程等待 CPU 的时间百分比.等待 CPU 的进程已经在 CPU 的就绪队列中,处于运 ...

  6. .NET8 Blazor 从入门到精通:(一)关键概念

    目录 Blazor 的关键概念 项目模板 Razor 语法 依赖注入 注入配置 HeadOutlet 组件 @code 分离 Blazor 调试 CSS 隔离 调用JavaScript 最近在学习 B ...

  7. 银河麒麟V10高级服务器编译安装pg13.4

    安装postgres依赖 yum install -y openssl openssl-devel pam pam-devel libxml2 libxml2-devel libxslt libxsl ...

  8. 算法·理论:KMP 学习笔记

    \(\text{KMP}\) 笔记! 上次比赛,出题人出了一个 \(\text{KMP}\) 模板,我敲了个 \(\text{SAM}\) 跑了,但是学长给的好题中又有很多 \(\text{KMP}\ ...

  9. 【Ubuntu】下载安装 20.04.版本 桌面端

    下载 Download 这次的是直接在界面上下载的,我都不知道为什么怎么点到之前的版本去了 12.04.5远古版本界面怪难看的... [下载地址:点我访问] https://cn.ubuntu.com ...

  10. 代码随想录Day3

    203.移除链表元素 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 . 示例 1: 输入:head = [1 ...