在SpringBoot项目中,代码通常按照功能职责进行分层设计,每层有明确的职责边界。清晰的分层和规范的模型定义对构建可维护、可扩展的系统至关重要。下面这个表格汇总了这些常见概念的核心区别,希望能帮你快速建立整体认知。
分类 | 术语 | 核心职责与定位 | 常见位置/别名 |
---|---|---|---|
数据模型/对象 | Entity / PO / DO | 与数据库表结构直接映射的实体对象,通常是"贫血模型",主要包含属性和get/set方法。 | model/entity , pojo |
Model | 一个相对宽泛的概念,在MVC中可指代视图层(View)所需的模型,可能是Entity的精简或组合。 | 视图层 | |
Domain / BO | 领域对象 ,强调业务逻辑,是"充血模型"。除数据外,可包含其自身的业务行为(如order.calculateTotal() )。 |
domain , bo |
|
DTO | 数据传输对象 ,用于服务层内部 或层与层之间(如Service与Controller间)传输数据,可聚合多个Entity的数据。 | dto |
|
VO | 视图对象 ,专用于Controller的返回结果,封装前端所需的数据,通常为Entity的裁剪或转换。 | vo , dto/response |
|
数据访问层 | DAO / Mapper | 数据持久层组件,负责与数据库交互,执行具体的CRUD操作。DAO是设计模式概念,Mapper是MyBatis中的具体实现。 | dao , mapper |
Repository | 概念上比DAO更高级,更贴近领域模型。Spring Data JPA提供的接口,内置通用方法,简化DAO开发。 | repository |
|
业务层 | Service | 业务逻辑层,协调多个DAO/Repository操作,实现复杂的业务逻辑和流程。事务控制通常在此层。 | service |
Logic / Module | "Logic"通常指代更细粒度的业务逻辑模块;"Module"指按功能划分的大型模块。 | 非标准分层 | |
表现层 | Controller | 控制层,处理HTTP请求,调用Service后返回响应(JSON/页面)。 | controller |
View | 视图层,渲染展示页面(如Thymeleaf、FreeMarker模板)。在前后端分离架构中由前端框架承担。 | 前端技术 |
核心分层架构
1. Model/Entity/POJO/PO/DO层
这些术语通常指代同一概念,即数据模型层:
-
作用:表示与数据库表对应的实体类,属性与数据库字段一一对应,包含getter/setter方法
-
特点:
- 一般一个数据库表对应一个实体类
- 类属性与表字段保持完全一致
- 通常不包含业务逻辑,仅作为数据载体
- 可能使用JPA注解如
@Entity
、@Table
或MyBatis的映射配置
less
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
// getters and setters
}
这些类在不同上下文可能有不同名称:POJO(Plain Old Java Object)、PO(Persistent Object)、DO(Domain Object),但本质相同
2. DAO/Mapper/Repository层
这组术语指数据访问层,负责与数据库直接交互:
- DAO(Data Access Object):传统名称,定义数据访问接口
- Mapper:MyBatis框架中的术语,通过XML或注解定义SQL映射
- Repository:Spring Data中的术语,扩展了JpaRepository等接口
核心作用:
- 封装对数据库的CRUD操作
- 执行SQL语句,完成数据的增删改查
- 为Service层提供数据访问接口
- 使用
@Mapper
或@Repository
注解标识
java
@Mapper
public interface UserMapper {
@Insert("INSERT INTO user(username, password) VALUES(#{username}, #{password})")
int insert(User user);
@Select("SELECT * FROM user WHERE id = #{id}")
User selectById(Long id);
}
DAO层应保持"原子性",只封装对单表的操作,不涉及业务逻辑组合
业务逻辑层
3. Service层
作用:
- 实现核心业务逻辑
- 组合多个DAO操作完成复杂业务
- 管理事务(
@Transactional
) - 处理业务规则验证和计算
特点:
- 分为接口和实现类(通常放在service/impl目录下)
- 调用DAO层方法,但不直接操作数据库
- 使用
@Service
注解标识
less
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
@Transactional
public User register(String username, String password) {
// 业务逻辑处理
User user = new User(username, password);
userMapper.insert(user);
return user;
}
}
Service层应保持"高内聚",一个Service类应只处理相关业务
4. BO(Business Object)
作用:
- 业务对象,封装业务逻辑的复合对象
- 可能组合多个Entity的数据和业务方法
- 在复杂业务场景中使用,简单项目可能不需要
csharp
public class OrderBO {
private Order order;
private List<OrderItem> items;
private User user;
public BigDecimal calculateTotalPrice() {
// 计算订单总价的业务逻辑
}
}
表现层
5. Controller层
作用:
- 处理HTTP请求和响应
- 接收前端参数,调用Service层,返回结果
- 负责参数校验和格式转换
- 使用
@RestController
或@Controller
注解标识
less
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity<User> createUser(@RequestBody UserDTO userDTO) {
User user = userService.register(userDTO);
return ResponseEntity.ok(user);
}
}
Controller应保持"薄",只处理请求响应,不包含业务逻辑
6. DTO/VO
这些是数据传输对象,用于各层之间的数据传递:
- DTO(Data Transfer Object):通常用于Controller接收请求参数或Service间传输
- VO(View Object):用于返回给前端的展示数据,可能包含多个实体的组合数据
- 特点:根据不同场景定制字段,与Entity解耦
kotlin
@Data
public class UserDTO {
private String username;
private String password;
}
@Data
public class UserVO {
private Long id;
private String username;
private LocalDateTime createTime;
}
使用DTO/VO可以避免直接暴露Entity,提高安全性并适应不同场景的需求
其他辅助分层
7. View层
作用:
- 前端展示层(如JSP、Thymeleaf、FreeMarker模板)
- 现代前后端分离项目中,可能由独立前端项目实现
- 负责数据渲染和用户交互
8. Domain/Module
作用:
- 领域模型层,在DDD(Domain-Driven Design)中使用的概念
- 包含实体、值对象、领域服务等
- 封装核心业务规则和领域逻辑
9. Config/Util/Exception等辅助包
- Config :配置类,如
@Configuration
类定义Bean - Util:工具类,提供静态方法
- Exception:自定义异常类
- Interceptor:拦截器处理如登录验证等
各层协作流程
典型请求处理流程:
- 前端请求 → Controller接收并转换为DTO
- Controller调用Service方法 → Service执行业务逻辑
- Service调用DAO/Mapper → DAO操作数据库
- 数据库返回 → DAO → Service → Controller
- Controller将结果转换为VO → 返回给前端
arduino
Client → Controller → Service → DAO → Database
↑ ↓
BO Entity
这种分层架构实现了"高内聚低耦合",使系统更易维护、测试和扩展
分层架构的优势
- 解耦:各层职责单一,修改一层不影响其他层
- 复用:如Service可被多个Controller复用
- 可测试性:可单独测试每一层
- 团队协作:不同开发者可并行开发不同层
- 可维护性:问题定位更快速,代码更清晰
总结表格
层级/对象 | 主要职责 | 常用注解 | 备注 |
---|---|---|---|
Entity/POJO | 数据库映射 | @Entity , @Table |
与表结构对应 |
DAO/Mapper | 数据访问 | @Mapper , @Repository |
执行SQL语句 |
Repository | 数据访问(Spring Data) | @Repository |
扩展JpaRepository |
Service | 业务逻辑 | @Service , @Transactional |
业务规则实现 |
Controller | 请求处理 | @RestController , @RequestMapping |
前后端交互 |
DTO | 参数接收/传输 | 无 | 定制化请求参数 |
VO | 响应数据 | 无 | 定制化响应数据 |
BO | 业务对象 | 无 | 复杂业务场景使用 |
Config | 配置定义 | @Configuration |
Bean配置 |
Util | 工具方法 | 无 | 静态方法集合 |
在实际项目中,可以根据项目复杂度和团队习惯适当调整分层结构,但保持清晰的职责划分是关键
📊 项目结构建议
根据项目复杂度,包结构可以有不同的组织方式:
-
中小型项目(简单清晰):
bashcom.example.project ├── controller ├── service ├── dao 或 mapper └── model # 统一存放各种对象 ├── entity ├── dto └── vo
-
大型复杂项目(推荐DDD模式):
bashcom.example.project ├── domain/ # 领域层(核心) │ ├── User.java # 富含业务逻辑的领域模型 │ └── Order.java ├── infrastructure/ # 基础设施层 │ ├── entity/ # 持久化实体(贫血模型) │ └── repository/ # 仓储实现 ├── application/ # 应用层 │ ├── dto/ # 应用服务间的DTO │ └── service/ # 应用服务(协调领域层) └── presentation/ # 表现层 ├── controller/ ├── request/ # 专属API入参 └── response/ # 专属API出参
💎 总结与最佳实践
- 明确目的:Entity/Domain对应数据和业务本体,DTO/VO对应数据传输和展示,DAO/Mapper/Repository对应数据访问,Service对应业务组合,Controller对应请求处理。
- 灵活应用:对于非常简单的项目(如内部工具、原型),严格区分所有对象可能过度设计,将Entity直接用于前后端传输也无妨。但随着项目发展,应逐步规范。
- 核心原则:遵循"高内聚,低耦合"。禁止DTO/VO直接引用Entity或与数据库表耦合,Entity自身也应避免包含过于复杂的业务逻辑,可将核心业务逻辑放在Domain或Service中。