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.
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 asViewObject(Class clazz) {
try {
//获取vo中的fields并创建新的vo实例
Field[] declaredFields = clazz.getDeclaredFields();
Constructor 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
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
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 asViewObject(Class clazz, Consumer consumer) {
V v=this.asViewObject(clazz);
consumer.accept(v);
return v;
}