DTO转VO工具
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工具的更多相关文章
- DO、DTO和VO分层设计的好处
2016年10月23日 20:11:03 阅读数:10646 在Java中 VO. PO.DO.DTO. BO. QO.DAO.POJO的概念中介绍过Java中的各种模型概念.在这里简单再总结一下 ...
- Java中PO、DO、TO、DTO、 VO、 BO、POJO 、DAO的概念
本文系转载-原创@HollisChuang :http://www.hollischuang.com/archives/553 1.PO(persistant object) 持久对象 在 o/r ...
- 什么是JavaBean、bean? 什么是POJO、PO、DTO、VO、BO ? 什么是EJB、EntityBean?
什么是JavaBean.bean? 什么是POJO.PO.DTO.VO.BO ? 什么是EJB.EntityBean? 前言: 在Java开发中经常遇到这些概念问题,有的可能理解混淆,有的 ...
- Java中PO、DO、DTO、 VO、 BO、POJO 、DAO、TO的概念
1. PO(persistant object) 持久对象 在 O/R 映射的时候出现的概念,如果没有 O/R 映射,没有这个概念存在了. 通常对应数据模型 ( 数据库 ), 本身还有部分业务逻辑的 ...
- PO、POJO、BO、DTO、VO之间的区别(转)
PO:persistent object持久对象 1 .有时也被称为Data对象,对应数据库中的entity,可以简单认为一个PO对应数据库中的一条记录. 2 .在hibernate持久化框架中与in ...
- DO,DTO和VO的使用
DO,DTO和VO的使用 DO:对应数据库表结构 VO:一般用于前端展示使用 DTO:用于数据传递.(接口入参和接口返回值都可以) 以ssm框架为例: controller层: public List ...
- 转载--Java中的PO、DO、DTO、 VO的概念
Java中的PO.DO.DTO. VO的概念 写的很清晰,学习了.
- 什么是DO / DTO / BO / VO /AO ?
转载:https://blog.csdn.net/ouzhuangzhuang/article/details/86644476 POJO 是 DO / DTO / BO / VO 的统称. DO(D ...
- javabean、DTO、VO
一.javabean 一. javabean 是什么? Bean的中文含义是“豆子”,顾名思义,JavaBean是指一段特殊的Java类, 就是有默然构造方法,只有get,set的方法的java类的对 ...
- Java中DAO/DTO/PO/VO/BO/QO/POJO
ORM:是Object Relational Mapping(对象关系映射)的缩写. 通俗点讲,就是将对象与关系数据库绑定,用对象来表示关系数据.在O/R/M的世界里,有两个基本的也是重要的东东需要了 ...
随机推荐
- WSS SSL HTTPS之间的关系
ssl: secure socket layer 安全套接层,简单来说是一种加密技术,通过它可以在通信的双方上建立一个安全的通信链路,因此数据交互的双方可以安全地通信,而不用担心数据被窃取:wss: ...
- MySQL之DCL
DCL * 一个项目创建一个用户!一个项目对应的数据库只有一个! * 这个用户只能对这个数据库有权限,其他数据库你就操作不了了! 1. 创建用户 * CREATE USER 用户名@IP地址 ID ...
- OpenGL 4.0中数据缓冲VBO,VAO,EBO的使用总结
Opengl是大家常用的一个API,我们用它绘制数据的时候需要使用vao,vbo,ebo等对象,绘制方式分为 vao绘制,ebo绘制等.使用不同api还能分为普通调用以及Instance绘制. 首先申 ...
- 面试题-python 什么是装饰器(decorator )?
前言 python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象.很多python初学者学到面向对象类和方法是一道大坎,那么py ...
- 解决Sqoop导入导出MySQL数据错位问题
添加--columns "columns,columns,columns" \可以在hive导入mysql时防止数据错位:
- linux常用命令(每日积累)
linux查看应用程序的进程号和端口号 lsof -i :port,查看指定端口运行的程序,同时还有当前连接. netstat -nupl (UDP类型的端口)netstat -ntpl (TCP ...
- 【Java】java.util.ConcurrentModificationException
异常提示信息: java.util.ConcurrentModificationException at java.util.LinkedHashMap$LinkedHashIterator.next ...
- 【MySQL】01 概念与介绍
视频节选自 :P1 - P7 https://www.bilibili.com/video/BV1xW411u7ax 用户浏览的页面 - 服务器 - 数据库 所有访问的本质的东西,就是访问数据,数据 ...
- 【Scala】07 集合
分三大类: 序列 Seq 集 Set 映射 Map 所有集合类型都扩展自Iterable特质(可迭代的) 所有集合类型都提供[可变]和[不可变]的版本 归纳在下面两个包中 scala.collecti ...
- 前端RSA密钥生成和加解密——window.crypto使用相关
转自简书,原文地址,本文介绍window.crypto关于RSA方面的API. crypto API支持常用的rsa.aes加解密,这边介绍rsa的应用. 浏览器兼容性 window.crypto需要 ...