数据模型转换MybatisPlus DO BO DTO VO

1,480 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 26 天,点击查看活动详情

代码链接:github.com/Wild-dog-is…

github.com/Wild-dog-is…

一、什么是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表示过滤。