当前位置: 首页 > news >正文

详解MVC架构与三层架构以及DO、VO、DTO、BO、PO | SpringBoot基础概念

🙋大家好!我是毛毛张!
🌈个人首页: 神马都会亿点点的毛毛张

今天毛毛张分享的是SpeingBoot框架学习中的一些基础概念性的东西:MVC结构、三层架构、POJO、Entity、PO、VO、DO、BO、DTO、DAO

文章目录

  • 1.架构
    • 1.1 基本概述
      • 1.1.1 什么是架构?
      • 1.1.2 为什么需要架构?
    • 1.2 MVC架构
      • 1.2.1 什么是MVC架构
      • 1.2.2 MVC架构工作流程
    • 1.3 三层架构
      • 1.3.1 什么是三层架构?
      • 1.3.2 为什么需要三层架构?
      • 1.3.3 三层架构之间如何联系?
    • 1.4 三层架构与MVC的区别
  • 2.实体类对象
    • 2.1 基本概念
      • 2.1.1 **POJO**(Plain Old Java Object)
      • 2.1.2 **Entity**
      • 2.1.3 PO(Persistent Object)
      • 2.1.4 DAO(Data Access Object)
      • 2.1.5 **DO(Domain Object)**
      • 2.1.6 **BO(Business Object)**
      • 2.1.7 **DTO(Data Transfer Object)**
      • 2.1.8 **VO(View Object)**
      • 2.1.9 **req(Request)** 和 **rsp(Response)**
    • 2.2 区别与联系
    • 2.3 阿里巴巴技术规范
  • 参考文献

1.架构

1.1 基本概述

1.1.1 什么是架构?

  • 架构可以分为两种类型:系统架构和应用架构
    • 系统架构(通常称为网络架构)主要关注硬件、网络和通信的设计与组织。
    • 应用架构(通常指代码架构)则侧重于软件系统内部结构、模块划分、接口设计等方面。

1.1.2 为什么需要架构?

  • 在早期,系统较为简单,通常一个应用只部署在一台服务器上,且开发主要集中在基础的CRUD操作,应用结构也相对简单,维护较为容易。然而,随着业务复杂度的增加,功能模块的扩展,系统的耦合度逐渐增高,导致整体复杂度难以管理。
  • 为了应对这种复杂性,出现了多种架构设计:
    • 网络架构(如分布式架构、微服务架构)旨在降低系统间的耦合度,提升系统的可扩展性和容错性。
    • 应用架构(如三层架构、MVC架构)旨在优化代码的组织结构,增强可维护性。在这些架构的基础上,又发展出了如SSM框架、SSH框架等具体技术框架。使用框架的好处在于能够提供清晰的结构,便于管理和维护。

1.2 MVC架构

1.2.1 什么是MVC架构

  • MVC(Model-View-Controller)是模型-视图-控制器的缩写,是一种软件设计模式。它将软件系统划分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。通过这种方式,业务逻辑、数据和界面显示相互分离,使得系统的维护和扩展更加灵活。在这种结构下,业务逻辑集中在模型层,界面和用户交互则由视图层负责,控制器则负责协调模型和视图的交互。

  • 视图层(View)

    • 视图层负责提供用户交互界面,显示数据并接收用户输入。在传统的应用程序中,视图层会包含与界面显示相关的文件,如 HTML、CSS、JavaScript 等。
    • 在前后端分离的项目中,视图层已转化为独立的前端项目,后端不再直接包含视图文件。此时,后端仅负责提供数据和业务逻辑,前端则负责界面展示。
  • 模型层(Model)

    • 模型层代表存取数据的对象,通常为 Java POJO(Plain Old Java Object,简单Java对象)。模型层不仅仅是数据的承载者,它还可能包含与数据相关的业务逻辑。模型层可以分为两类:
      • 数据承载 Bean:例如实体类(如 User 类),专门用于承载数据。
      • 业务处理 Bean:如 ServiceDao 类,专门用于处理用户请求并进行业务逻辑操作。
    • 模型层的结构
      • 实体类包(如 pojoentitybean):存放与数据库表对应的实体类以及一些非数据库表相关的 VO(Value Object)对象。
      • 数据库访问包(如 daomapper):封装对数据库表格的 CRUD 操作。
      • 服务包(如 service):包含处理业务逻辑的类。

    注: Java Bean 是一种可重用的组件,可以在构建工具中可视化操作

  • 控制层(Controller)

    • 控制层负责接收用户的请求并将其转发给相应的模型进行处理。它还会根据模型的计算结果,将响应数据返回给用户。控制层将视图层和模型层分离,使得系统的各个部分解耦,易于维护和扩展。控制层的职责包括:接收客户端请求、处理请求数据,并调用模型层进行数据处理或计算,最后将处理结果反馈给客户端。
    • 控制层的结构
      • 控制器通常包含在一个专门的控制层包中(如 controller

1.2.2 MVC架构工作流程

流程步骤:

  1. 用户请求:用户通过 View 页面向服务端提出请求,这个请求可以是表单提交、超链接点击、AJAX请求等。
  2. 控制器处理请求:服务端的 Controller 接收到请求后,解析请求内容,确定需要处理的 Model。Controller 根据请求的类型和参数,调用相应的模型进行处理。
  3. 模型处理Model 根据 Controller 传递的数据执行相应的业务逻辑处理。这可以涉及数据的计算、存储操作、验证等。
  4. 渲染响应页面:处理完成后,ControllerModel 处理结果返回,并选择合适的 View 页面进行渲染。视图会根据传递的数据生成 HTML 内容,并将页面返回给客户端,作为用户的最终响应。
    在这里插入图片描述
  • MVC模式的最大优势在于 将视图和模型分离,这种分离带来了多个显著的好处,尤其是提高了代码的 可重用性
    • 可重用性:多个视图可以共享一个模型。由于 Model 负责处理数据和业务逻辑,而 View 仅负责展示数据,二者的分离使得同一份业务逻辑(模型)可以在多个不同的视图中复用,而不需要重复编写代码。这种设计不仅减少了代码的冗余,也提升了系统的扩展性和维护性。
    • 灵活性:视图和模型的分离使得开发者可以独立地修改或替换视图(界面)或模型(业务逻辑),而不会影响到其他层次。这种松耦合的设计大大提升了系统的灵活性和可维护性。

1.3 三层架构

1.3.1 什么是三层架构?

  • 三层架构(3-Tier Architecture)是一种将系统划分为三个独立层次的设计模式,以实现“高内聚、低耦合”的目标。这种架构将系统功能模块分为:表示层(UI)、业务逻辑层(BLL)和数据访问层(DAL),每一层独立负责不同的职责,有效降低了系统各个层次之间的耦合度,提升了系统的可维护性和扩展性。
  • 表示层(UI)
    • 表示层是架构的最上层,直接与用户交互,负责显示界面并接收用户输入。它作为系统与用户之间的桥梁,将用户的请求传递给业务逻辑层,同时将处理结果返回给用户。
    • 表示层的主要功能是:提供用户界面、展示数据、接收用户输入,并反馈操作结果。通常,表示层由 Web 应用程序或桌面应用程序构成。
  • 业务逻辑层(BLL)
    • 业务逻辑层位于架构的核心,负责处理具体的业务规则和逻辑。它充当表示层与数据访问层之间的桥梁,主要负责接收表示层的请求,进行数据处理或计算,并协调调用数据访问层执行必要的数据操作。
    • 业务逻辑层的职责包括:处理业务逻辑、验证数据一致性、管理事务、确保业务规则得到正确执行。
  • 数据访问层(DAL)
    • 数据访问层,也称为持久层,负责与数据存储进行交互(如数据库、文件系统等)。它主要处理数据的增删改查(CRUD)操作,将数据从存储介质中读取并返回给业务逻辑层,或将数据保存回数据库。
    • 数据访问层的功能是为业务逻辑层提供必要的数据支持,保证数据的持久性和一致性。
  • 层与层之间的关系:
    • 表示层依赖于业务逻辑层
    • 业务逻辑层依赖于数据访问层
      在这里插入图片描述

1.3.2 为什么需要三层架构?

  • 分层的目的: 三层架构的核心思想是 “高内聚,低耦合”。在设计和开发软件系统时,应当使模块之间的关系更加紧密,同时避免模块之间的过度依赖,以便提升系统的可维护性、可扩展性和可重用性。
    • 内聚:指的是一个模块内部各个元素的关联度。高内聚意味着模块内部的功能紧密相关,职责明确。这样的模块容易理解、修改和维护,且出错的可能性较小。
    • 耦合:指的是模块之间的关联度。低耦合意味着模块之间的依赖关系尽量减少,避免牵一发而动全身的情况。低耦合的设计能降低系统的复杂性,使得模块可以独立工作,易于扩展和修改。
  • 三层架构的出现是为了实现“高内聚,低耦合”:三层架构通过将系统划分为不同的层次,使得每一层关注不同的功能,并减少层与层之间的依赖。具体来说:
    • 高内聚:每个模块尽量只负责一个功能。比如,数据访问层(DAL)只负责数据操作,业务逻辑层(BLL)只处理业务逻辑,表示层(UI)只负责用户界面展示。
    • 低耦合:不同模块之间的依赖关系尽可能减少,模块间的交互复杂度降低。比如,业务逻辑层和数据访问层通过接口进行交互,而不直接调用具体的实现类。
  • 两层架构 vs 三层架构
    • 两层架构:所有功能都放在一层中,耦合度较高。如果某一部分发生变化,整个系统都需要重新开发。这样设计不利于扩展和维护,难以适应需求变化。
      在这里插入图片描述
    • 三层架构:通过分层设计,减少了层与层之间的耦合度。每层的职责清晰,发生变化时只需修改相关层,而不会影响到其他层。此设计不仅提高了系统的可维护性和可扩展性,也使得系统更易于适应需求变化。
      在这里插入图片描述
  • 面向接口编程与弱耦合:在三层架构中,采用 面向接口编程,使得不同层次之间通过接口来实现交互。具体来说,各层之间通过接口而非直接依赖具体实现类来进行通信,这减少了层与层之间的耦合度。通过这种方式,实现类是可以替换的,只要接口不变,新的实现类可以轻松替换旧的实现,不影响其他层次。这样就实现了各层之间的解耦,提高了系统的灵活性和可扩展性。
    • 接口:提供服务标准,定义了不同层之间交互的规范。
    • 实现类:具体实现接口的服务逻辑,提供实际的业务操作。
      在这里插入图片描述

1.3.3 三层架构之间如何联系?

为了将三层有效连接,实体层(Entity) 起着关键作用,它不是三层架构中的一部分,但它在三层架构中扮演着至关重要的角色。实体层用于在各层之间传递数据,并实现面向对象的封装

  • 实体层的作用

    • 实现封装,遵循面向对象思想
    • 在三层之间传递数据
    • 每一层(UI → BLL → DAL)通过传递实体作为参数来进行数据交换,确保三层之间的连接和数据流动,从而实现功能
  • 实体层在三层架构中贯穿各个层次,通过单向数据传递完成层与层之间的协调,如下图
    在这里插入图片描述

  • 实体类实体层的核心,它代表了数据库表的结构,并用于存储和操作业务数据。实体类通常使用ORM框架(如JPA、Hibernate)来将对象与数据库表中的记录进行映射。实体类通常实现了JavaBean规范,具有无参构造器、私有字段和公共的getter/setter方法。具体的实体传输示意图如下图:
    在这里插入图片描述

1.4 三层架构与MVC的区别

  • MVC架构:主要目的是将应用的视图层业务逻辑分离,从而实现内聚和低耦合。通过这种分离,开发人员可以更方便地替换视图样式,而不影响核心业务逻辑。例如,用户界面的变化不需要重新修改后台的业务代码。
  • 三层架构:是从应用程序整体结构的角度进行分层,通常包括表示层(即UI层)、业务逻辑层和数据访问层。三层架构强调每一层的职责单一,并要求业务逻辑层数据访问层遵循面向接口编程,实现模块化、可扩展和可维护的设计。
  • 总结两者的核心思想:
    • 都是为了实现内聚和低耦合
    • MVC重点在于界面与业务逻辑分离。
    • 三层架构则从更高层次上实现系统的分层,确保每一层的职责清晰。
  • 两者之间的联系和区别可以通过下面两张图结合着理解:
    在这里插入图片描述
    在这里插入图片描述

2.实体类对象

在这里插入图片描述

2.1 基本概念

  • 根据 三层架构(表现层/视图层、业务逻辑层、数据访问层)中的不同层职责与交互,以及涉及到的 跨层数据传输,最后还需处理 请求与响应,我们可以按照数据流转的顺序和对象的作用重新整理如下:
    • 数据持久化(PO):数据从数据库中取出或存入数据库,通常通过 DAO 进行操作
    • 业务逻辑(DO 和 BO):DO 代表领域模型中的核心对象,包含业务逻辑,BO 是 PO 和 DO 的组合,封装业务操作
    • 数据传输(DTO):DTO 用于跨层或跨系统传递数据,封装了跨层调用所需的字段
    • 数据展示(VO):VO 是展示层使用的对象,主要用于格式化和展示数据
    • 请求与响应(req 和 rsp)req 是客户端请求对象,rsp 是服务器响应对象,用于前后端或服务间的通信
  • 下面将一一介绍每个实体类的具体信息

2.1.1 POJO(Plain Old Java Object)

  • 位置:可以出现在任何层,通常在业务层或传输层使用
  • 作用POJO 是 “Plain Old Java Object” 的缩写,意思是“普通的 Java 对象”。它是一个简单的 Java 类,不依赖于任何特定的框架或库,不包含业务逻辑,通常只包含数据字段、构造函数、getter 和 setter 方法。POJO 类不需要任何特定的注解或继承自特定的类,因此它是非常简单且独立的 Java 类。
  • 特点:
    • 没有依赖于任何特定的框架或技术。
    • 只包含属性、构造方法、getter 和 setter 方法,不包含复杂的逻辑。
    • 通常用于数据传输或表示一些简单的业务实体。
    • 不需要任何特定的注解,完全符合 Java Bean 规范。
  • 示例
public class UserPOJO {private Long id;private String name;private String email;public UserPOJO(Long id, String name, String email) {this.id = id;this.name = name;this.email = email;}// getters and setters
}
  • 用途POJO 主要用于表示数据结构或数据传输对象,通常不会直接与数据库交互。它可以在业务逻辑中使用,也可以作为 DTO 传递数据。

2.1.2 Entity

  • 作用:Entity 是持久化层中的实体对象,通常与 PO 类似。Entity 通常是与数据库表结构对应的对象,用于表示一条记录。
  • 内容:Entity 和 PO 类似,都是数据库表中一行数据的映射对象,通常包含与数据库表字段一一对应的属性。这个术语在不同上下文中有时被用来表示 PO,也有时用于表示领域模型中的实体。
  • 用法:
    • Entity 为结尾(阿里是以 DO 为结尾)
    • Xxxx 与数据库表名保持一致
    • 类中字段要与数据库字段保持一致,不能缺失或者多余
    • 类中的每个字段添加注释,并与数据库注释保持一致
    • 不允许有组合
  • 示例
    UserEntity 可能是与 user 表中的一行记录对应的类。

2.1.3 PO(Persistent Object)

  • 作用:PO 是数据库层的对象,用于与数据库的记录进行映射,通常是数据库表中的一行数据。
  • 内容:PO 的结构直接对应数据库表的结构,每个 PO 对象通常代表数据库表中的一条记录。PO 类通常没有业务逻辑,主要负责存储数据,包含基本的 getter 和 setter 方法。
  • 示例
    • 数据库表 user 存储用户信息,PO 对象 User 就代表该表中的一条记录。

    • 示例:

      public class UserPO {private int id;private String name;private String email;// getters and setters
      }
      

2.1.4 DAO(Data Access Object)

  • 作用:DAO 是数据访问对象,提供与数据库交互的接口,封装了对 PO 对象的增、删、改、查操作。

  • 内容:DAO 负责从数据库中获取数据,并将数据封装成 PO 对象。它不包含业务逻辑,而是专注于数据存取和数据库操作。

  • 示例

    • UserDao 类提供了对 User PO 对象的操作方法,例如获取用户、添加用户等。
    public class UserDao {public UserPO getUserById(int id) {// 从数据库查询并返回 UserPO 对象}public void saveUser(UserPO user) {// 保存 UserPO 到数据库}
    }
    

2.1.5 DO(Domain Object)

  • 作用:DO 是领域对象,在领域驱动设计(DDD)中,DO 代表业务逻辑中的核心实体。它通常包含业务逻辑,并与 PO 或 Entity 映射,但其重点在于业务逻辑而非数据库操作。
  • 内容:DO 可以包含与 PO 一样的字段,但它比 PO 更加关注业务规则和业务计算。DO 代表了一个业务实体,通常与业务需求密切相关。
  • 示例
    • 在电商应用中,Order(订单)对象通常是 DO,包含订单的相关信息(如商品、数量、价格等)和业务方法(如计算总金额)。
    public class OrderDO {private List<Product> products;private double totalAmount;public double calculateTotal() {// 计算订单总金额return totalAmount;}
    }
    

2.1.6 BO(Business Object)

  • 作用:BO 是业务对象,它通常由多个 PO 对象组合而成,并包含业务逻辑。BO 聚焦于业务操作,除了数据字段外,还包含用于处理业务的计算方法。
  • 内容:BO 将多个 PO 或 DO 组合起来,处理复杂的业务逻辑。BO 可能是跨多个 PO 的聚合对象,用于封装某个完整的业务场景,可能包含多个属性和方法。
  • 用法:
    • 不可以继承自 Entity
    • BO 对象不得用于 controller
  • 示例
    • 在电商应用中,ShoppingCart(购物车)可能是一个 BO,包含多个 Product(商品) PO 和相关的业务方法(如计算总价、应用折扣等)。
    public class ShoppingCartBO {private List<ProductPO> products;public double calculateTotalPrice() {// 计算购物车商品的总价}
    }
    

2.1.7 DTO(Data Transfer Object)

  • 概念来源:DTO 起源于 J2EE 的设计模式,最初用于 EJB 的分布式应用。其目的是通过提供粗粒度的数据实体,减少分布式调用的次数,从而提升性能并降低网络负载。
  • 定义与功能:DTO(数据传输对象)是一种用于在软件应用系统之间传输数据的设计模式。通常情况下,数据传输对象从数据库中检索数据后,用于在不同系统或模块之间传递。与数据交互对象(Data Interaction Object)或数据访问对象(DAO)不同,DTO 不包含复杂的行为,主要功能是存储和传递数据。简而言之,开发中并不需要将整个PO(持久化对象)的所有字段传输到客户端,而是通过重新封装DTO传递所需的数据。如果这种传输对象用于界面展示,则被称为VO(View Object)。
  • 主要作用
    • 数据传递:DTO 用于不同系统、不同层级(如前后端、服务与服务)之间的数据传输。
    • 封装字段:DTO 能根据业务需求封装特定字段,从而简化数据结构、优化传输效率。
  • 内容特点
    • DTO 通常包含跨层传输所需的数据字段,可以是完整数据,也可以是根据需求筛选后的部分字段。
    • DTO 不包含复杂业务逻辑,仅负责存储和传递数据,确保通信简洁明了。
  • 用法:
    • 不可继承自 Entity或者PO
    • DTO 可以继承、组合其他 DTO,VO,BO 等对象
    • DTO 只能用于前端、RPC 的请求参数
  • 示例
    • 假设需要将用户信息从后端传递到前端,DTO 可能会包含用户的姓名、性别、年龄等信息,可能有多个字段。
    public class UserDTO {private String name;private String gender;private int age;// getters and setters
    }
    

2.1.8 VO(View Object)

  • 作用:VO 是视图对象,用于展示层,通常是展示给用户的数据。VO 主要关注的是数据的展示形式,可能会对 DTO 进行数据格式化或解释。
  • 内容:VO 可以从 DTO 或 BO 中派生,通常是展示层需要的简化版本,它可能只包含必要的数据字段,并且进行业务解释和格式化。
  • 用法:
    • 不可继承自 Entity或者PO
    • VO 可以继承、组合其他 DTO,VO,BO 等对象
    • VO 只能用于返回前端、rpc 的业务数据封装对象
  • 示例
    • 假设前端只需要展示用户的性别,且需要将性别展示为“公子”而不是“男”,VO 就是格式化后的数据。
    public class UserVO {private String gender;// getters and setters
    }
    

2.1.9 req(Request)rsp(Response)

  • 作用reqrsp 是与客户端和服务端通信相关的对象,通常用于 API 调用。req 是请求对象,rsp 是响应对象。
  • req(Request):请求对象,包含客户端发起的请求数据,如查询条件、请求参数等。它通常是 HTTP 请求中的数据体或 API 请求的参数。
  • rsp(Response):响应对象,包含服务器对请求的响应数据,如操作结果、状态码、错误信息等。它通常是 HTTP 响应中的数据体或 API 响应的内容。
  • 示例
    • req:API 请求体包含一个查询参数。

      { "userId": 123, "query": "product" }
      
    • rsp:服务器返回的数据和状态。

      { "status": "success", "data": [{"productId": 1, "name": "Product A"}] }
      

2.2 区别与联系

  • 展示与传输
    • VODTO 都是用于传输数据的对象,但 VO 更侧重于展示层,DTO 更侧重于不同层或系统之间的数据传输。DTO 可以包含更多的字段,而 VO 主要关注展示所需的信息。简单来说,我们不需要把整个PO对象的全部字段传输到客户端,而是可以用DTO重新封装,传递到客户端。此时,如果这个对象用来对应界面的展现,就叫VO
  • DTO与DO:
    • 在设计层面上,展示层传递给服务层的 DTO 和服务层返回给展示层的 DTO 在概念上是不同的,但在实际实现中,通常会设计一个通用的 DTO。这样可以避免为每种场景定义多个类似的对象(例如多个 UserInfo),从而简化代码。对于服务层接收的数据,展示层不应设置的属性(例如订单总价,应由单价、数量和折扣计算得出)会被服务层忽略;而服务层返回数据时,也会过滤掉不应暴露给展示层的敏感信息(例如用户密码)。
    • 至于 DO(领域对象),在服务层中直接返回给展示层并不合理,原因如下:
      • 多对多关系:一个 DTO 可能对应多个 DO,或反之,甚至存在复杂的多对多映射关系。直接返回 DO 会导致设计复杂化。
      • 数据安全性:DO 包含某些敏感数据,这些数据不应被展示层知晓。
      • 业务方法暴露问题:DO 通常包含业务方法,直接暴露给展示层可能导致展示层绕过服务层调用 DO 的方法,破坏业务逻辑的封装。此外,这种设计对基于 AOP 的访问控制机制尤其不友好,还可能引发事务管理问题
      • 延迟加载问题:某些 ORM 框架(如 Hibernate)使用延迟加载技术,而展示层通常不在事务范围内。如果展示层在事务关闭后尝试访问未加载的关联对象,会导致运行时异常(如 Hibernate 的 LazyInitializationException)。
      • 跨层依赖耦合:从设计角度来看,展示层应依赖服务层,服务层再依赖领域层。如果直接将 DO 暴露给展示层,就会导致展示层依赖领域层,增加不必要的耦合。
    • 对于 DTO,还需要注意其设计原则:DTO 应该是“扁平化”的。比如,当 User 关联了多个实体(如 AddressAccountRegion),不应直接返回这些关联对象的完整结构。如果 getUser() 方法需要返回用户的基本信息以及 AccountIdAccountNameRegionIdRegionName,则应将这些字段直接定义在 DTO(如 UserInfo)中,将复杂的对象树“压扁”为简单的二维结构。这种设计减少了数据传输量,特别是在分布式系统中,可以有效避免因传输、序列化和反序列化开销过大而导致的性能问题。
  • DO与PO:在大多数情况下,DO(Data Object)和 PO(Persistent Object)是一一对应的,但在不同应用场景下,它们有显著的区别:
    • DO 在某些场景下不需要持久化:在某些情况下,DO 不需要持久化到数据库,因此不会有对应的 PO 对象。DO 仅用于业务层数据的处理,不涉及持久化操作。
    • PO 在某些场景下没有对应的 DO:同样的道理,在一些场景中,PO 可能没有直接对应的 DO。PO 主要用于数据库持久化操作,因此其设计和使用场景不同于 DO。
    • 一个 PO 可能对应多个 DO,反之亦然:为了满足某些持久化策略或性能优化需求,可能会出现一个 PO 对应多个 DO 的情况,或者一个 DO 被多个 PO 共享,尤其是在复杂的业务场景下。
    • PO 中某些属性对 DO 没有意义:PO 中有些属性可能是为了实现某些持久化策略或优化(如乐观锁机制)而设计的,这些属性对于 DO 没有任何业务意义。例如,PO 中可能会有一个 version 属性用于乐观锁,而这个属性对 DO 来说并不重要,因此不应包含在 DO 中。反之,DO 中也可能包含一些不需要持久化的属性,这些属性对 PO 无意义。
  • DTO与BO:
    • DTO(Data Transfer Object)用于在不同系统或层之间传递数据,通常只包含数据本身,不包含业务逻辑。它的作用是简化数据传输,避免传递过多无关信息。
    • BO(Business Object)则是业务逻辑的载体,主要用于内部业务层,包含与业务相关的数据和行为。
    • 与 DTO 不同,BO 关注的是如何实现和处理具体的业务规则。通过将外部服务返回的 DTO 转换为 BO,可以隔离外部变动对内部系统的影响,同时按需处理数据,使业务逻辑更清晰和稳定。
  • 业务与持久化
    • DOBO 都是业务层的对象,但 DO 更侧重于领域模型(DDD),而 BO 更侧重于具体的业务处理。PO 主要是持久化对象,直接与数据库表结构对应。
  • 持久化与数据访问
    • POEntity 其实是很相似的,主要都用于持久化层表示数据库记录。而 DAO 是与持久化交互的对象,负责从数据库中读取、写入数据。
  • 请求与响应
    • reqrsp 分别表示客户端请求和服务器响应,通常与 API 交互或服务调用相关。

2.3 阿里巴巴技术规范

  • 阿里巴巴 Java 开发手册中的分层领域模型规约:
    • DO(Data Object):此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象
    • DTO(Data Transfer Object):数据传输对象,Service 或 Manager 向外传输的对象
    • BO(Business Object):业务对象,可以由 Service 层输出的封装业务逻辑的对象
    • Query:数据查询对象,各层接收上层的查询请求。注意超过 2 个参数的查询封装,禁止使用 Map 类 来传输
    • VO(View Object):显示层对象,通常是 Web 向模板渲染引擎层传输的对象
  • 领域模型命名规约:
    • 数据对象:xxxDO,xxx 即为数据表名
    • 数据传输对象:xxxDTO,xxx 为业务领域相关的名称
    • 展示对象:xxxVO,xxx 一般为网页名称
    • POJO 是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO

参考文献

  • https://xie.infoq.cn/article/bf881a59e1c4693bdc93d378c
  • https://lux-sun.blog.csdn.net/article/details/113695259
  • https://blog.csdn.net/baichoufei90/article/details/129424234
  • 三层架构介绍-CSDN博客
  • MVC架构与三层架构的关系 - 知乎 (zhihu.com)

都看到这了,不妨一键三连再走吧!
🌈欢迎和毛毛张一起探讨和交流!
联系方式点击下方个人名片

相关文章:

详解MVC架构与三层架构以及DO、VO、DTO、BO、PO | SpringBoot基础概念

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 今天毛毛张分享的是SpeingBoot框架学习中的一些基础概念性的东西&#xff1a;MVC结构、三层架构、POJO、Entity、PO、VO、DO、BO、DTO、DAO 文章目录 1.架构1.1 基本…...

QML学习 —— 30、图片翻转效果(附源码)

效果 说明 Flipable是一种可以在正面和背面之间明显“翻转”的物品,就像卡片一样。它可以与“旋转”、“状态”和“过渡”类型一起使用,以产生翻转效果。正面和背面属性用于固定分别显示在可翻转物品正面和背面的物品。 代码 import QtQuick 2.12 import QtQuick.Window 2.1…...

rk3588交叉编译opencv

基于forlinx开发板Linux5.10.66Qt5.15.2的环境 交叉编译工具链&#xff1a;aarch64-buildroot-linux-gnu-gcc、aarch64-buildroot-linux-gnu-g opencv版本&#xff1a;3.4.15 创建toolchain.cmake # 工具链路径 set(CMAKE_C_COMPILER /home/forlinx/aarch64-buildroot-linux…...

Kubernetes 之 Ingress 和 Service 的异同点

1. 概念与作用 1.1 Ingress Ingress 是什么&#xff1f; Ingress主要负责七层负载&#xff0c;将外部 HTTP/HTTPS 请求路由到集群内部的服务。它可以基于域名和路径定义规则&#xff0c;从而将外部请求分配到不同的服务。 ingress作用 提供 基于 HTTP/HTTPS 的路由。 支持 …...

Java 反射(Reflection)

Java 反射&#xff08;Reflection&#xff09; Java 反射&#xff08;Reflection&#xff09;是一个强大的特性&#xff0c;它允许程序在运行时查询、访问和修改类、接口、字段和方法的信息。反射提供了一种动态地操作类的能力&#xff0c;这在很多框架和库中被广泛使用&#…...

C语言刷题笔记3(7)

7.1 数组处理斐波那契数列 题目描述:用数组来处理Fibonacci数列并输出。 输入:一个不超过40且大于2的整数n&#xff0c;表示需要处理并输出的Fibonacci数个数。 输出:输出前n个Fibonacci数&#xff0c;每行输出5个值&#xff0c;按每12位向右对齐的方式输出。请注意不要在第…...

【新人系列】Python 入门(十四):文件操作

✍ 个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4dd; 专栏地址&#xff1a;https://blog.csdn.net/newin2020/category_12801353.html &#x1f4e3; 专栏定位&#xff1a;为 0 基础刚入门 Python 的小伙伴提供详细的讲解&#xff0c;也欢迎大佬们…...

学成在线day06

上传视屏 断点续传 通常视频文件都比较大&#xff0c;所以对于媒资系统上传文件的需求要满足大文件的上传要求。http协议本身对上传文件大小没有限制&#xff0c;但是客户的网络环境质量、电脑硬件环境等参差不齐&#xff0c;如果一个大文件快上传完了网断了没有上传完成&…...

详细介绍HTTP与RPC:为什么有了HTTP,还需要RPC?

目录 一、HTTP 二、RPC 介绍 工作原理 核心功能 如何服务寻址 如何进行序列化和反序列化 如何网络传输 基于 TCP 协议的 RPC 调用 基于 HTTP 协议的 RPC 调用 实现方式 优点和缺点 使用场景 常见框架 示例 三、问题 问题一&#xff1a;是先有HTTP还是先有RPC&…...

ffmpeg 各版本号对应表格

想看看ffmpeg各个版本对应表&#xff0c; #! /bin/bashFF_PATH$1 CURRENTpwd RESULT"$CURRENT/test_version.txt"cd $FF_PATHif [ -f $RESULT ]; thenrm $RESULT fifor i in git branch -a | grep remotes/origin/release/ | grep -v HEAD | grep -v master; dogit…...

cesium 3Dtiles变量

原本有一个变亮的属性luminanceAtZenith&#xff0c;但是新版本的cesium没有这个属性了。于是 let lightColor 3.0result._customShader new this.ffCesium.Cesium.CustomShader({fragmentShaderText:void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial mate…...

如何分析Windows防火墙日志

Windows防火墙&#xff0c;也被称为Windows Defender Firewall&#xff0c;是一种内置的安全功能&#xff0c;可以主动监控和分析运行Windows操作系统的计算机上通过Windows防火墙的网络流量&#xff0c;主要目的是作为计算机和互联网或其他网络之间的屏障&#xff0c;使管理员…...

Linux下 history 命令输出时间

在 Linux 中&#xff0c;查看每条命令的执行时间。 文章目录 [toc]**1. 配置 Shell 以记录命令执行时间****1.1 Bash Shell****步骤&#xff1a;****注意事项&#xff1a;** **1.2 Zsh Shell****步骤&#xff1a;****注意事项&#xff1a;** 1. 配置 Shell 以记录命令执行时间 …...

ChatGPT/AI辅助网络安全运营之-数据解压缩

在网络安全的世界中&#xff0c;经常会遇到各种压缩的数据&#xff0c;比如zip压缩&#xff0c;比如bzip2压缩&#xff0c;gzip压缩&#xff0c;xz压缩&#xff0c;7z压缩等。网络安全运营中需要对这些不同的压缩数据进行解压缩&#xff0c;解读其本意&#xff0c;本文将探索一…...

导入 OpenCV for Android 的技巧

下载了 OpenCV for Android Sdk 以后&#xff0c;一头雾水&#xff0c;不知道从哪里下手&#xff0c;既不是jar、也不是aar&#xff0c;没关系&#xff0c;简单几步即可使用 OpenCV。 1、使用 Android Studio 打开 samples &#xff08;示例&#xff09;项目 2、同步项目&…...

云原生时代的轻量级反向代理Traefik

Traefik 是一个用于路由和管理网络流量的反向代理&#xff0c;同时也是一个支持多种协议&#xff08;HTTP、HTTPS、TCP、UDP&#xff09;的负载均衡器。它通过自动服务发现和动态配置&#xff0c;帮助开发者和运维团队轻松管理复杂的应用架构。 Traefik 的主要特点如下&#x…...

3D扫描对文博行业有哪些影响?

三维扫描技术对文博行业产生了深远的影响&#xff0c;主要体现在以下几个方面&#xff1a; 一、高精度建模与数字化保护 三维扫描技术通过高精度扫描设备&#xff0c;能够捕捉到文物的每一个细节&#xff0c;包括形状、纹理、颜色等&#xff0c;从而生成逼真的3D模型。这些模…...

linux安全管理-会话安全

文章目录 1 设置命令行界面超时退出2 配置终端登录失败策略3 配置 SSH 登录失败策略 1 设置命令行界面超时退出 1、检查内容 检查操作系统是否设置命令行界面超时退出。 2、配置要求 操作系统设置命令行界面超时退出。 3、配置方法 配置命令行界面超时时间&#xff0c;编辑/et…...

未来已来?AI技术革新改变我们的生活

在21世纪的今天&#xff0c;人工智能&#xff08;AI&#xff09;不再是一个遥远的概念&#xff0c;而是逐渐渗透到我们生活的方方面面。从智能家居到自动驾驶汽车&#xff0c;从个性化推荐系统到医疗诊断辅助&#xff0c;AI技术正在以惊人的速度发展&#xff0c;并深刻地影响着…...

列表上移下移功能实现

后台管理某列表需实现上移下移功能&#xff0c;并与前端展示列表排序相关。 现将开发完成过程笔记记录下来。 目录 列表增加属性 JQuery脚本 服务端 控制器 服务层 总结 列表增加属性 在循环渲染时&#xff0c;在table表格的tr上增加id和排序的属性值&#xff0c;以便传…...

[保姆式教程]使用labelimg2软件标注定向目标检测数据和格式转换

定向目标检测是一种在图像或视频中识别和定位对象的同时&#xff0c;还估计它们方向的技术。这种技术特别适用于处理有一定旋转或方向变化的对象&#xff0c;例如汽车、飞机或文本。定向目标检测器的输出是一组旋转的边界框&#xff0c;这些框精确地包围了图像中的对象&#xf…...

qt音频实战

一、Qt音频基础知识 1、QT multimedia 2、QMediaPlayer类&#xff1a;媒体播放器&#xff0c;主要用于播放歌曲、网络收音机等功能。 3、QMediaPlaylist类&#xff1a;专用于播放媒体内容的列表。 二、界面设计 三、代码 #include "mainwindow.h" #include "…...

【C++】static修饰的“静态成员函数“--静态成员在哪定义?静态成员函数的作用?

声明为static的类成员称为类的静态成员&#xff0c;用static修饰的成员变量&#xff0c;称之为静态成员变量&#xff1b;用 static修饰的成员函数&#xff0c;称之为静态成员函数。静态成员变量一定要在类外进行初始化 一、静态成员变量 1)特性 所有静态成员为所有类对象所共…...

『Linux学习笔记』linux系统有哪些方法计算文件的md5!

linux系统有哪些方法计算文件的md5&#xff01; 文章目录 一. linux系统有哪些方法计算文件的md5&#xff01;1. 使用 md5sum 命令(推荐)示例&#xff1a;输出&#xff1a;使用方法&#xff1a; 2. 使用 openssl 命令计算MD5值&#xff1a;输出&#xff1a;使用方法&#xff1…...

css vue vxe-text-ellipsis table 实现多行文本超出隐藏省略

分享 vxe-text-ellipsis table grid 多行文本溢出省略的用法 正常情况下如果需要使用文本超出隐藏&#xff0c;通过 css 就可以完成 overflow: hidden; text-overflow: ellipsis; white-space: nowrap;但是如果需要实现多行文本溢出&#xff0c;就很难实现里&#xff0c;谷歌…...

构建现代Web应用:FastAPI、SQLModel、Vue 3与Axios的结合使用

FastAPI介绍 FastAPI是一个用于构建API的现代、快速&#xff08;高性能&#xff09;的Web框架&#xff0c;使用Python并基于标准的Python类型提示。它的关键特性包括快速性能、高效编码、减少bug、智能编辑器支持、简单易学、简短代码、健壮性以及标准化。FastAPI自动提供了交互…...

图像边界填充算法详解与Python实现

目录 图像边界填充算法详解与实现1. 基础概念1.1 边界填充的意义与应用场景1.2 常见填充策略概览2. 零填充算法(Zero Padding)2.1 理论介绍2.2 Python实现及代码详解2.3 案例分析3. 镜像填充算法(Mirror Padding)3.1 理论介绍3.2 Python实现及代码详解3.3 案例分析4. 重复填…...

中兴机顶盒B860AV1.1刷机固件升级和教程「适用4/8G版」

准备工作&#xff1a; TTL 线&#xff08;CH340G 按系统版本找到要对应驱动&#xff09;下载 putty 软件拆开电视盒接好 TTL 线&#xff08;2、5、6 针脚对应GND、RX、TX&#xff09;在资源管理器的端口选项下找到 CH340G&#xff0c;记住端口号&#xff08;如 COM4&#xff0…...

JVM 性能调优 -- CMS 垃圾回收器 GC 日志分析【Full GC】

前言&#xff1a; 上一篇我们分析了 Minor GC 的发生过程&#xff0c;因为 GC 日志没有按我们预估的思路进行打印&#xff0c;其中打印了 CMS 垃圾回收器的部分日志&#xff0c;本篇我们就来分析一下 CMS 垃圾收集日志。 JVM 系列文章传送门 初识 JVM&#xff08;Java 虚拟机…...

重塑视频新语言,让每一帧都焕发新生——Video-Retalking,开启数字人沉浸式交流新纪元!

模型简介 Video-Retalking 模型是一种基于深度学习的视频再谈话技术&#xff0c;它通过分析视频中的音频和图像信息&#xff0c;实现视频角色口型、表情乃至肢体动作的精准控制与合成。这一技术的实现依赖于强大的技术架构和核心算法&#xff0c;特别是生成对抗网络&#xff0…...

C#中面试的常见问题001

1、c#访问修饰符有哪些 public&#xff1a;公共访问级别&#xff0c;成员可以被任何其他代码访问。private&#xff1a;私有访问级别&#xff0c;成员只能在定义它的类内部访问。protected&#xff1a;受保护的访问级别&#xff0c;成员可以被定义它的类及其子类访问。interna…...

webGis 气象站点数据解析渲染

1.站点数据说明 1.1 数据来源 站点数据来源多样。 1.2数据传输 实现前端的展示&#xff0c;数据传输的方式有&#xff1a; json等等 1.2数据格式 let arr [{ lat:1,//经纬度 lng:1, value:2//值 },{},...] 1.3站点数据转格点数据 turf.interpolate克里金插值qgis等ID…...

Vue3+Typescript+Axios+.NetCore实现导出Excel文件功能

前端代码 //导出Excel const exportMaintenanceOrderSettlementItemExcelClick async () > {let url ${VITE_APP_API_URL}/api/app/maintenance/settlement-service-item/${currentMaintenanceOrderId.value}/${currentMaintenanceOrderSettlementRow.value.id};let file…...

专属主机服务器和ECS服务器有什么区别?

‌专属主机服务器和ECS服务器的主要区别在于资源隔离、计费方式、管理权限等方面。‌ 资源隔离 ‌专属主机服务器‌&#xff1a;用户可以独享整台物理服务器资源&#xff0c;与其他租户的服务器物理隔离。这意味着用户不需要与其他租户共享物理资源&#xff0c;可以获取服务器…...

MySQL索引与分区:性能优化的关键

在开发过程中&#xff0c;随着数据量的不断增长&#xff0c;MySQL 查询的性能问题会逐渐显现。特别是在大数据量下&#xff0c;查询变得越来越慢&#xff0c;甚至可能导致系统崩溃。为了优化查询&#xff0c;MySQL 提供了 分区&#xff08;Partitioning&#xff09; 和 索引&am…...

VUE项目部署服务器之后刷新页面异常

情况&#xff1a; vue项目在本地完美运行&#xff0c;经过npm run build之后把dist目录上传到服务后。只有访问文件跟目录可以运行&#xff0c;但刷新之后会找不到相应的页面。 网上都说是hository路由的问题导致&#xff0c;需要修改成hash模式。如果不想修改为hash模式&…...

【实验13】使用预训练ResNet18进行CIFAR10分类

目录 1 数据处理 1.1 数据集介绍 1.2数据处理与划分 2 模型构建- Pytorch高层API中的Resnet18 3 模型训练 4 模型评价 5 比较“使用预训练模型”和“不使用预训练模型”的效果&#xff1a; 6 模型预测 7 完整代码 8 参考链接 1 数据处理 1.1 数据集介绍 数据规模&…...

如何将 GitHub 私有仓库(private)转换为公共仓库(public)

文章目录 如何将 GitHub 私有仓库转换为公共仓库步骤 1: 登录 GitHub步骤 2: 导航到目标仓库步骤 3: 访问仓库设置步骤 4: 更改仓库可见性步骤 5: 确认更改步骤 6: 验证更改注意事项 如何将 GitHub 私有仓库转换为公共仓库 在软件开发领域&#xff0c;GitHub 是一个广受欢迎的…...

进制的问题

蓝桥2015某题 计算数字x在进制p 下的各位数字之和 ​ int calc(int x,int p) {int res0;while(x){resx%p;//取当前位累加x/p;//去掉最低位}return res; }​...

【配置】如何下载和配置Android studio?

下载Android Studio 1、下载链接 https://developer.android.google.cn/studio?hlzh-cn​​​​​​​​​​​​​​​​​​​​ 注意&#xff1a;下载的时候要关闭代理服务器 2、安装软件 根据提示进行安装 3、配置proxy 这里建议配置代理而不是配置国内镜像源 所以…...

CA系统(file.h---申请认证的处理)

#pragma once #ifndef FILEMANAGER_H #define FILEMANAGER_H #include <string> namespace F_ile {// 读取文件&#xff0c;返回文件内容bool readFilename(const std::string& filePath);bool readFilePubilcpath(const std::string& filePath);bool getNameFro…...

Redis开发04:Redis的INFO信息解析

命令解释redis_versionRedis 的版本号&#xff0c;这里是 3.2.100。redis_git_sha1Redis 使用的 Git SHA1 校验值&#xff0c;表示当前代码的版本。redis_git_dirty如果 Redis 当前运行的代码是脏版本&#xff08;未提交的修改&#xff09;&#xff0c;该值为 1&#xff0c;否则…...

《Learn Three.js》学习(2)构建Three.js基本组件

前言&#xff1a; 本章将了解内容包括Three中的主要组件&#xff1b;THERE.SCENE对象的作用&#xff1b;几何图形和格网如何关联&#xff1b;区别正射/透视投影摄像机 基础理论知识&#xff1a; Three.scene&#xff08;场景图&#xff09;保存所有对象、光源和渲染所需的其他…...

VLLM 格式化LLM输出

文章目录 前言guided_jsonguided_choiceguided_regexguided_grammar总结 前言 vllm OpenAI Compatible Server 提供了格式化LLM输出的能力&#xff0c;默认的格式化解码后端应该是outlines 目前提供了四个参数来控制格式化输出&#xff0c;分别是&#xff1a; guided_json: …...

Java篇——Java通过JNA调用c++库时传参含有结构体时数据错乱的解决办法

Java通过JNA调用c库时传参含有结构体时&#xff0c;只继承Structure是不够的&#xff0c;还需要实现Structure.ByValue&#xff0c;或者强制指定结构体字节对齐。示例如下&#xff1a; 1、c库中的结构体定义&#xff1a; 2、java中结构体定义&#xff1a; 3、java中调用 如果没…...

sql分类

SQL&#xff08;Structured Query Language&#xff09;是一种用于管理和操作关系数据库管理系统&#xff08;RDBMS&#xff09;的编程语言。SQL 可以分为几个主要类别&#xff0c;每个类别都有其特定的用途和功能。以下是 SQL 的主要分类&#xff1a; 1. 数据定义语言&#x…...

LayaBox1.8.4实现战争迷雾效果

实现思路&#xff1a; 和Unity实现思路一样&#xff0c;可看我写的下面的一篇文章 战争迷雾FogOfWar---Unity中实现-CSDN博客 根据碰撞点可以计算出需要透明的位置&#xff0c;怎样计算如下&#xff1a; 根据迷雾mesh的长宽和纵向横向的的像素数可以得出&#xff0c;每个小方…...

Python打包元数据困境:约束的重要性

在Python社区中&#xff0c;一项旨在建立新的通用锁文件标准的努力正在展开&#xff0c;这一努力主要在Python讨论论坛上进行。此倡议凸显了创建一个让所有人都满意的标准化方案的难度。不同Python打包工具对锁文件应有的形态和用途有着略微不同的理解。然而&#xff0c;在这些…...

第29天 MCU入门

目录 MCU介绍 MCU的组成与作用 电子产品项目开发流程 硬件开发流程 常用元器件初步了解 硬件原理图与PCB板 常见电源符号和名称 电阻 电阻的分类 贴片电阻的封装说明&#xff1a; 色环电阻的计算 贴片电阻阻值计算 上拉电阻与下拉电阻 电容 电容的读数 二极管 LED 灯电路 钳位作…...

三分钟快速掌握——Linux【vim】的使用及操作方法

一、vim的使用 vim是一个文本编辑器 非常小巧轻便 1.1如何进入vim编辑器 方法一&#xff1a; 首先使用touch 1.c 创建一个源文件 然后使用vim 1.c进入 方法二&#xff1a; 直接使用指令 vim 2.c 会直接创建一个2.c的源文件 退出时记得保存&#xff08;使用wq或者x&am…...