- DTO (Data Transfer Object):
DTO is a design pattern used to transfer data between different layers or components of an application. It is a simple object that carries data and has no behavior logic. DTOs are often used in distributed systems or when data needs to be transferred between remote services. They serve as a container for data that needs to be exchanged between different parts of the system and are commonly used to encapsulate data fetched from a database or received from external services.
DTOs typically have properties that represent the data being transferred, and they may also provide methods for accessing and manipulating the data. They are usually designed to be serializable so that they can be easily transmitted over a network or stored in a persistent storage system.
- VO (Value Object):
VO, also known as a value object, is a design pattern used to represent an immutable object that holds values and is primarily used for modeling concepts or entities within a domain. Value objects are characterized by their immutability, meaning their state cannot be modified once created. They are usually used to encapsulate a set of related attributes or properties that form a coherent value.
Value objects are often used to represent concepts like dates, coordinates, addresses, or any other concept that can be defined by its values rather than its identity. They are typically used to enforce business rules and ensure that the values they hold remain consistent and unchanged.
通常需要将DTO中的属性搬运到VO中,再发送给前端进行页面展示:
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
User user=(User)authentication.getPrincipal();
AuthorizeVO vo =new AuthorizeVO();
Account account=service.findAccountByNameOrEmail(user.getUsername());
String token =utils.createJwt(user,account.getId(),account.getUsername());
vo.setExpire(utils.expireTime());
vo.setRole(account.getRole());
vo.setToken(token);
vo.setUsername(account.getUsername());
response.getWriter().write(RestBean.success(vo).asJsonString());
System.out.println(RestBean.success(token).asJsonString());
}
可以看到这样的搬运不太方便
spring提供了一个方便的办法,beanutils中的copyproperties方法能够将前一个对象中的属性拷贝到后一个对象中:
BeanUtils.copyProperties(account,vo);
vo.setExpire(utils.expireTime());
// vo.setRole(account.getRole());
vo.setToken(token);
// vo.setUsername(account.getUsername());
我们尝试手动显现这个功能
在entity包下编写basedata接口,account继承basedata接口中的方法,快速的将dto转换成vo对象:
package com.example.entity;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public interface BaseData {
default <V> V asViewObject(Class<V> clazz) {
try {
//获取vo中的fields并创建新的vo实例
Field[] declaredFields = clazz.getDeclaredFields();
Constructor<V> constructor = clazz.getConstructor();
V v = constructor.newInstance();
//对于vo中的每一个属性,在当前dto如果存在则赋值给vo
for (Field declaredField : declaredFields) {
convert(declaredField,v);
}
return v;
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
private void convert(Field field, Object vo) {
try {
// 获取当前DTO类中与VO中存在的属性同名的字段
Field source = this.getClass().getDeclaredField(field.getName());
// 设置字段可访问(即使是私有字段)
field.setAccessible(true);
source.setAccessible(true);
// 从当前DTO对象中获取对应字段的值,并将其设置到VO对象中的相应字段中
field.set(vo, source.get(this));
} catch (NoSuchFieldException e) {
// 如果字段不存在,则抛出运行时异常
System.out.println(e);
// throw new RuntimeException(e);
} catch (IllegalAccessException e) {
// 如果访问字段时发生非法访问异常,则抛出运行时异常
// throw new RuntimeException(e);
System.out.println(e);
}
}
}
In a broader context, the Consumer<V>
functional interface’s effect is to enable you to define a piece of behavior or an action that operates on an object of type V
(the input argument) without returning any result. The Consumer<V>
interface represents a function that accepts an object and performs some operation on it.
但有额外的信息需要传入viewobject,通过consumer接口构造匿名函数使得整体更简约:
AuthorizeVO vo=account.asViewObject(AuthorizeVO.class,viewobject->{
viewobject.setExpire(utils.expireTime());
viewobject.setToken(token);
});
default <V> V asViewObject(Class<V> clazz, Consumer <V> consumer) {
V v=this.asViewObject(clazz);
consumer.accept(v);
return v;
}