开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 26 天,点击查看活动详情
一、什么是DO PO DTO VO BO
1、PO/DO
PO/DO: Persistent Object / Data Object,持久对象 / 数据对象。
- 跟数据库表是一一对应的,一个PO/DO 数据是表的一条记录。
- PO / DO 只是数据的对象,不包含任何的操作。举个例子,学生表是StudentDO,对学生表的增删改查等操作就是StudentDAO。
- DO(Data Object) ,持久化对象,它跟持久层(Dao)的数据结构形成一一对应的映射关系。如果持久层是关系型数据库,那么数据库表中的每个字段就对应PO的一个属性,常是entity实体类。
2、VO
VO (View Object),用于表示一个与前端进行交互的视图对象,它的作用是把某个指定页面(或组件)的所有数据封装起来。实际上,这里的 VO 只包含前端需要展示的数据,对于前端不需要的数据,比如数据创建和修改的时间等字段,出于减少传输数据量大小和保护数据库结构不外泄的目的,不应该在 VO 中体现出来。
3、DTO
DTO(Data Transfer Object),用于表示一个数据传输对象,DTO 通常用于展示层(Controller)和服务层(Service)之间的数据传输对象。DTO 与 VO 概念相似,并且通常情况下字段也基本一致。但 DTO 与 VO 又有一些不同,这个不同主要是设计理念上的,比如 API 服务需要使用的 DTO 就可能与 VO 存在差异。
4、Bo
POJO在业务层的体现,对于业务操作来说,更多的是从业务上来包装对象,如一个User的BO,可能包括name, age, sex, privilege, group等,这些属性在数据库中可能会在多张表中,因为每一张表对应一个PO,而我们的BO需要这些PO组合起来(或说重新拼装)才能成为业务上的一个完整对象。
二、DO PO DTO VO 数据流转关系
1、DO -> 控制器返回
2、DO -> PO -> 控制器返回
3、DO -> PO -> VO -> 控制器返回
4、DO -> DTO -> 控制器返回
5、DO -> PO -> VO -> 控制器返回
6、DO -> PO -> DTO -> 控制器返回
三、实战
PO需要继承DO,VO需要实现相应的构造方法以供转换使用。
使用的工具类为:
<dependency>
<groupId>xin.altitude.cms</groupId>
<artifactId>ucode-cms-common</artifactId>
<version>1.5.8</version>
</dependency>
3.1 DO转PO返回
/**
* DO转PO返回
*/
public List<UserPo> selectUser1() {
List<User> userList = this.list();
return EntityUtils.toList(userList, UserPo::new);
}
3.2 DO转VO返回
/**
* DO转VO返回
*/
public List<UserVO> selectUser2() {
List<User> userList = this.list();
return EntityUtils.toList(userList, UserVO::new);
}
3.3 DO转PO转VO返回
/**
* DO转PO转VO返回
*/
public List<UserVO> selectUser3() {
List<User> userList = this.list();
List<UserVO> userVOList = EntityUtils.toList(userList, UserVO::new);
if (userVOList.size() > 0) {
Set<Long> deptIds = EntityUtils.toSet(userVOList, UserVO::getDeptId);
System.out.println(deptIds);
List<Dept> deptList = deptMapper.selectList(Wrappers.lambdaQuery(Dept.class).in(Dept::getDeptId, deptIds));
Map<Long, String> map = EntityUtils.toMap(deptList, Dept::getDeptId, Dept::getDeptName);
for (UserVO userVO : userVOList) {
userVO.setDeptName(map.get(userVO.getDeptId()));
}
}
return userVOList;
}
public List<NewUserVo> selectUserList4() {
// DO
List<User> userList = this.list();
// PO
List<NewUserPo> newUserPoList = EntityUtils.toList(userList, NewUserPo::new);
// VO
List<NewUserVo> newUserVoList = EntityUtils.toList(newUserPoList, NewUserVo::new);
if (newUserVoList.size() > 0) {
Set<Long> deptIds = EntityUtils.toSet(newUserVoList, NewUserVo::getDeptId);
List<Dept> deptList = deptMapper.selectList(Wrappers.lambdaQuery(Dept.class).in(Dept::getDeptId, deptIds));
Map<Long, String> map = EntityUtils.toMap(deptList, Dept::getDeptId, Dept::getDeptName);
for (NewUserVo newUserVo : newUserVoList) {
newUserVo.setDeptName(map.get(newUserVo.getDeptId()));
}
}
return newUserVoList;
}
四、实战进阶
如果一个DO,因为业务需要多个PO或者VO,那么需要创建多个类,而在工具包中提供了对应的过滤筛选方法,大大提高了效率,减少了创建多个类的操作。
首先实现方法。
/**
* DO 返回到控制器
*/
public List<User> selectUserList1() {
return this.list();
}
/**
* DO转化为VO
*/
public List<UserVo> selectUserList2() {
List<User> userList = this.list();
List<UserVo> userVoList = EntityUtils.toList(userList, UserVo::new);
// 新型的属性注入过程
FieldInjectUtils.injectField(userVoList,
UserVo::getDeptId,
DeptServiceImpl.class,
Dept::getDeptId,
UserVo::getTel,
UserVo::getDeptName);
return userVoList;
}
上面使用到的方法是工具包的一大特色,大大简化了属性注入的操作。
下面演示如何在数据返回时,进行过滤的操作。
@RestController
@RequestMapping("/front")
public class IndexController {
@Resource
private UserService userService;
@GetMapping("/list1")
public AjaxResult list1() {
return AjaxResult.success(userService.selectUserList1());
}
/**
* 在DO模型的基础上 过滤字段:deptId
*/
@GetMapping("/list2")
public AjaxResult list2() {
return AjaxResult.success(userService.selectUserList1(), false, User::getDeptId);
}
/**
* 在DO模型的基础上 过滤字段:userId,age
*/
@GetMapping("/list3")
public AjaxResult list3() {
return AjaxResult.success(userService.selectUserList1(), false, User::getUserId, User::getAge);
}
/**
* 在DO模型的基础上 提取字段:userName
*/
@GetMapping("/list4")
public AjaxResult list4() {
return AjaxResult.success(userService.selectUserList1(), true, User::getUserName);
}
/**
* 在DO模型的基础上 提取字段:userName,age
*/
@GetMapping("/list5")
public AjaxResult list5() {
return AjaxResult.success(userService.selectUserList1(), true, User::getUserName, User::getAge);
}
@GetMapping("/list6")
public AjaxResult list6() {
return AjaxResult.success(userService.selectUserList2());
}
/**
* 在VO模型的基础上 过滤字段
*/
@GetMapping("/list7")
public AjaxResult list7() {
return AjaxResult.success(userService.selectUserList2(), false, User::getDeptId);
}
/**
* 在VO模型的基础上 保留字段
*/
@GetMapping("/list8")
public AjaxResult list8() {
return AjaxResult.success(userService.selectUserList2(), true, User::getUserId, User::getUserName, UserVo::getDeptName);
}
}
返回值中true表示保留,false表示过滤。