java中do、dto、vo、po的区别?

从另外一个回答复制过来:

就比如说我用一个实际场景举例子吧,你更好懂,假如有一张user表,里面有几个字段:

50c288a6f9f7478bb2cf7c8ac6f4e0d5.png
user_id    user_name    pass_word    create_time    dept_id 

假设就这么多吧,一张很基础的表,那么对应Java的写法就是一个类:

class User{
private Long userId;
private String userName;
private String passWord;
private LocalDateTime createTime;
private Long deptId;
//getter setter constrcutor.....【可以用lombok,随意,我这里就省略了】
}

那么我现在需要对于User这张表进行增删改查,那么如果我假设你学过Mybatis?还是JPA这种持久层框架的话,或者你只要学过JDBC的话,你就应该知道,Java中肯定需要一个对象来映射数据库的这张表。User类的每个属性就是数据库表的每一个字段,该类的每一个对象就代表数据库中的每一行,List<User>就代表该表的所有记录。

这个User类就被称为PO,一般也不会加PO的说法,这个类一般就是User。

下面来说说DTO和VO。Data Transfer Object和View Object(不知道拼错没有?大概就这个意思)下面用一个实际场景解释一下:

比如,User这张表,一般在前端我们会进行分页+条件查询,然后在前端用一个列表组件,对于后端请求过来的数据做渲染。对于CRUD来说,这也是一个基本的需求。

那么假设现在有这样一个情况:假设我们再简化一下情况,我们只做条件查询,我需要按照用户名userName模糊匹配,用户创建时间createTime区间匹配的时候,我后端应该如何写?

或者换言之,我后端应该用一个什么对象来接收前端传过来的请求参数?

这时候我们来想想,User类对象,他还能胜任吗?userName还好说,那create Time的区间怎么表示呢?

显然这时候我们就不能在后端这样写了:

public XXX【返回值】 selectUserByCondidition(@RequestBody @Validated User user);
光靠一个User对象我们是不足以接收前端传过来的请求参数的,那你说我可以这样啊:

public XXX【返回值】 selectUserByCondidition(String userName,
LocalDateTime startTime,
LocalDateTime endTime)

这还只是两个字段的条件,如果字段一但多起来了,你确定这样写?你确定老板看了以后不会让你当场毕业?

所以这时候我们就要用到DTO了,数据传输对象,用于在网络中涉及到数据传输的封装对象。那么此时我们就可以在后端定义这样一个DTO:UserQueryConditionDTO【用户条件查询DTO】

public class UserQueryConditionDTO{
private String userName;
private LocalDateTime startTime;
private LocalDateTime endTime;
//getter setter validation_annotation constrcutor【这些答主就不写了】
}
然后我们后端接口就可以这样写:

public XXX【返回值】 selectUserByCondidition(@RequestBody @Validated UserQueryConditionDTO dto);
简单明了,别人一看代码,点进去一看,你再给字段打上备注,一下就清晰了。这就是DTO的用处。

下面来说VO的用处:VO意思就是View Object,View这个单词学过MVC思想的都知道,【都能看到这个问题了,不会还有人MVC都不知道吧】,叫视图层,那么View Object呢?顾名思义,那就是返回给视图层【前端】需要用到的对象。

这时候又有人不懂了,返回给前端我需要啥VO啊,什么意思?还是用这个User举例子。

我通过刚才的DTO,然后通过一系列JDBC操作,我查询到了List<User>列表,里面就包含每一个用户的完整信息【用户Id,用户名,密码,部门Id,创建时间】,也就是上面表的五个字段。

但是你准备就把这个List<User>返给前端吗??前端展示的用户所属部门,至少是展示部门名吧?怎么可能直接在前端列表去展示每个用户的所属部门Id呢?

不会吧,不会真有兄弟给前端说,你获取到List<User>这个数组以后,你对于每一个dept_Id再分别发请求,我给一个接口,你给我dept_Id,我给你返回dept_Name,不就完了吗。你确定前端兄弟不想打屎你?这样的网络IO有考虑过吗,数据量多了一个页面都是几十个请求到时候,这样是肯定不行的。

那部门名去哪里找呢?那肯定有一张部门表咯,这不就是表的关联关系吗,一般来说,最简单的情况下,都是通过Id关联,假设有一张部门表dept:

a72e53e5122c43ad8a5965f5dac2047c.png 

Id就是部门的Id,和User表的dept_id有映射关系,deleted就是逻辑删除,create_time和dept_name就不多说了。逻辑删除不懂的请自行百度或谷歌。

大概提一下,逻辑删除就是当前端删除该数据的时候,用这个标识字段来表示该数据的删除情况,假设0就是未删除,1就是已删除。在任意查询的时候我们也会避开逻辑删除字段为1的数据。

那么此时我们就应该用关联来查询出用户的所属部门名了:SQL伪代码,看懂意思就行

select 
  u表的所有数据,d.dept_name
from user u 
left join dept d 
on u.dept_id = d.Id

//后面你排不排序啥的我也不管了,这里自行按照业务逻辑添加
那么此时,我们通过该SQL返回的数据还能用User对象接收吗?

当然就不行了,因为User对象没有DeptName这个属性,但现在我们需要一个对象封装带有deptName属性的user。

那么我们考虑该对象是需要发送给前端来展示的,也就是视图层,所以我们就需要一个对象,来传输给视图层,那么,就是我们的VO了。UserVO来返回给前端。

class UserVO{
   Long userId;
   String userName;
   String deptName;
   String password;
   Long deptId;
   LocalDateTime createTime;
//Getter  Setter etc ...
}
这就是VO的用处

下面来说一下DAO,DAO一般在刚学MVC的时候会涉及到,Data Access Object,数据访问对象,他就是用来访问数据库的对象,我们一般就会在这里面写上很多查询数据库的方法。

比如UserDAO【User的CRUD操作】,一般增删改查会有五个方法:

条件分页查询
按照批量Id【也可以传单个】删除
新增
按照Id查询某一条的数据【修改时候数据前端回显】
修改接口
interface/class UserDAO {

public List<UserVO> queryUserByCondition(UserDTO dto,PageCondition page);

public User getUserById(Long userId);

public int deletedUserByBatchIds(List<Long> userIds);

public int editUser(UserEditDTO dto);

public int addUser(UserAddDTO dto);

}
如果看到这里都没问题,那么有些靓仔可能又有问题了,你这UserDAO为啥类型又写interface又写class啊?

这个其实是接口的一种思想,如果你把查询数据库的代码【假如是JDBC逻辑,不用持久层框架哈】,那么这个UserDAO会变得很大,如果别人想来看一下你这个UserDAO里面到底有什么方法的时候,别人就会看着很头疼。

所以我们一般把UserDAO写成一个接口,里面定义UserDAO操作数据库的方法的规范,然后会有一个类UserDAOImpl去实现UserDAO接口,然后在Impl类中写上真正操作数据库的代码。

这样别人想了解UserDAO到底提供了哪些功能的时候,可以,看接口即可。想看功能到底怎么实现的时候,也可以,看Impl实现类的业务逻辑即可。

DAO其实就是用来操作数据库的,封装所有对于数据库的数据CRUD操作,然后让业务层直接注入DAO对象,然后使用该方法即可。

不过在后面,我们更倾向于把DAO对象叫做Mapper【Map不是地图的意思,在后面开发中他更多的意思在于映射】,以后就不叫UserDAO了,我们一般叫UserMapper【mapper的意思和dao一样】,UserMapper就是表示用于封装数据库操作的一个映射对象,可以这样理解吧,不过mapper的意思和DAO八九不离十,后面开发中就是一个概念了。【下文中就把DAO称为Mapper了】

那么这时候又有靓仔想问了,假如我有很多表,User,Dept,SysJob【系统任务表】,SysLog【系统日志表】,SysDict【系统字典表】等等很多表,每一张表我都想提供基本的CRUD功能。

那么我难道要把上面五个逻辑几乎一样的CRUD方法还要在每一个XXXMapper中写一次吗?

比如UserMapper,DeptMapper,SysJobMapper,SysLogMapper,SysDictMapper,我每一个Mapper都要去写通用的五个CRUD逻辑吗?显然是太冗余了,那我能不能抽出一个公用的BaseMapper,来封装单表的CRUD操作呢?

如果上面思路能懂,那你学MybatisPlus也就不难了,MybatisPlus【简称MP】,就是提供了一个Base Mapper接口,这个接口里面封装了大量的单表CRUD便利操作,相当于以后,我们只需要这样写:

public interface UserMapper extends BaseMapper<User>
我们就可以在Mapper层写0代码,直接快速完成对于user单表的CRUD了,包括单表的各种复杂查询,直接0SQL开发【就是不用写一句SQL】,快不快?

BO就是Business Object了,业务对象,这个就不用怎么解释了,就是封装了业务逻辑的对象,一般开发中,BO估计就是代指Service层吧?

业务层对象,MVC的设计模式一般是前端请求,来到后端的Controller【Provider】控制器层,控制器做一些最基本的校验【比如身份校验,入参校验,日志AOP等等】,然后分发请求到相应的业务层【也就是Service组件】来做处理。

业务层对于请求进行业务处理,如果要涉及到和数据库交互的,就是用Mapper【也就是DAO】层对象和数据库交互即可,大概就是这样一个逻辑。按照这样来说,Service层对象,比如User Service,应该算BO对象吧,这一点答主不是特别清楚,参见评论区坐等大神解惑。

POJO就是Plain And Ordinary Java Object,简单Java对象,这就没啥 好讲的。

DO,Data Object,数据对象,这概念吧,其实有是有,但是用的,我个人感觉不多,有一种情况就是微服务之间互相传输对象数据的时候,我们就会将该数据抽取出来。

比如商品下单以后,大量的JSON数据会传输到后台,我们会在后台调用很多模块,比如OMS/订单管理模块,又或是ERP模块,又或是WMS/库存物流模块,等等等等,会调用很多其他微服务模块。

不同服务之间传输对象,要不然就将对象定义为DO【或者TO,不同叫法而已,Transfer Object或者Data Object】,然后两个模块之间RPC调用,传输的对象要被两个模块共享,要不然就将每一个模块涉及的各种实体对象单独抽出来放在一个entities模块下啊,要不然就是将这些微服务模块之间的交互传输对象定义在Common模块中,作为DO或者TO,来进行微服务之间的数据传输所用。

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜀州凯哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值