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. oeasy教您玩转vim - 39 - # 剪切粘贴

    ​ 剪切粘贴 回忆上节课内容 我们大幅度地复习了整个 motion: 直接运动 h j k l 行运动 首行g g 末行G 第n行n G 单词运动 wbe w 是到下一个 word 的开头 b 是到当 ...

  2. SSH指定用户登录与限制

    环境准备 :::info 实验目标:ServerA通过用户ServerB(已发送密钥和指定端口) ::: 主机 IP 身份 ServerA 192.168.10.201 SSH客户端 ServerB ...

  3. [翻译]欢迎使用C#9.0

    本文由公众号[开发者精选资讯](微信号:yuantoutiao)翻译首发,转载请注明来源 C# 9.0 is taking shape, and I'd like to share our think ...

  4. Visual Studio 必备插件集合:AI 助力开发

     一.前言 2024年AI浪潮席卷全球,编程界迎来全新的挑战与机遇.智能编程.自动化测试.代码审查,这一切都得益于AI技术的迅猛发展,它正在重塑开发者的日常,让编写代码变得更加高效.智能. 精选出最受 ...

  5. ThinkPHP一对一关联模型的运用(ORM)

    一.序言 最近在写ThinkPHP关联模型的时候一些用法总忘,我就想通过写博客的方式复习和整理下一些用法. 具体版本: topthink/framework:6.1.4 topthink/think- ...

  6. 最好用的截图工具,提取自QQ(带以截图搜图、ocr文字识别,截长图,贴图,色号等功能)

    背景 现在登录QQ比较少,手机的QQ已经具备ocr识别功能,但是电脑上不登陆QQ,微信的简单截图功能又不能进行ocr识别,对于想提取的文字特别麻烦,需要找别的工具去提取.机缘发现网络上这款提取自QQ的 ...

  7. Miniconda 切换python版本

    要在 Miniconda 中切换 Python 版本,可以按照以下步骤进行操作: 打开命令提示符或者 Anaconda Prompt(如果已经安装了). 输入 conda info --envs 查看 ...

  8. Jmeter JDBC连接配置

    JDBC连接配置(JDBC Connection Configuration),用于创建数据库连接,后续可对数据库进行增删查等操作.和组件[JDBC请求(JDBC Request)]搭配使用 组件路径 ...

  9. 低代码如何借助 K8s 实现高并发支持?

    引言 在当今这个数字化时代,互联网的普及和技术的飞速发展使得应用程序面临着前所未有的挑战,其中最为显著的就是高并发访问的需求.随着用户数量的激增和业务规模的扩大,如何确保应用在高并发场景下依然能够稳定 ...

  10. matplotlib中渐变颜色条转CSS样式(hex格式)——同mapbox中cog的颜色条拉伸显示

    matplotlib中渐变颜色条转CSS样式(hex格式)--同mapbox中cog的颜色条拉伸显示 应用场景: 1.适用于mapbox中显示cog影像时,colormap_name拉伸颜色条转换 2 ...