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的世界里,有两个基本的也是重要的东东需要了 ...
随机推荐
- [oeasy]python0136_接收输入_input函数_字符串_str
输入变量 回忆上次内容 上次研究了 一行赋值多个变量 a = b = 5 a, b = 7, 8 还研究了 标识符的惯用法 python使用的是 snake_case蛇形命名法 用下划线 分隔开小 ...
- oeasy教您玩转vim - 64- # 参数argument
参数argument 回忆上次 上次了解了 窗口 window 窗口是用来装缓冲buffer的 buffer是在内存里面加载的硬盘文件 窗口的切分 :sp[lit] 水平切分 :vsp[lit] ...
- 一张图看懂 SQL 的各种 JOIN 用法(含数据集和韦恩图)
- 很好用的python游戏环境(续):强化学习算法走迷宫游戏环境(导航问题 navigation):分享一个python语言的迷宫游戏环境
相关: 很好用的python游戏环境:强化学习算法走迷宫游戏环境(导航问题 navigation):分享一个python语言的迷宫游戏环境 前文分享了一个python下的maze游戏环境,本文再给出一 ...
- AI领域的国产显卡如何在现有技术下吸引用户 —— 廉价增加显存 —— 大显存
先给出一个不大准确的但相差不差的背景介绍: 同样性能级别的显卡,NVIDA的24G的要3W,32G的要5W,48G的要7W, 80G的要10W. 国产同同性能的显卡32G的要10W,48G的要15W, ...
- 【转载】 vim中常用折叠命令
原文地址: https://www.cnblogs.com/litifeng/p/11675547.html 个人推荐的一个视频教程地址: 上古神器Vim:从恶言相向到爱不释手 - 终极Vim教程01 ...
- .gitignore文件的使用方法(学习总结版)
平时总是喜欢把日常学习的代码以代码库的形式上传到Gitee或Github上(Github上的代码正逐渐迁移至Gitee上),但是有时候总有一些中间编译的文件不行要一起上传,原有有两个: 1.是不行Gi ...
- dubbo服务治理(一)降级
在线网站一般都会有服务器压力剧增的时候,比如说网上商城的促销,这个时候常用的手段就是服务降级,根据当前业务情况及流量对一些服务和页面有策略的降级,以此缓解了服务器资源压力,以保证核心任务的正常运行,同 ...
- Diskpart 操作
DiskPart 是 Windows 操作系统中的一个命令行工具,用于管理磁盘分区.它可以创建.删除.格式化和调整分区大小,还可以设置活动分区等.以下是一些常用的 DiskPart 命令和操作步骤. ...
- Snap 使用
Snap 是一个或多个应用程序的捆绑包,可在许多不同的 Linux 发行版中使用,无需依赖或修改.Snap 可从 Snap Store(一个拥有数百万用户的公共应用程序商店)中发现和安装.很多常用的软 ...