全栈项目分层架构如何设计?

访客 全栈框架 1

本文目录导读:

  1. 核心原则
  2. 典型的三层至四层架构(后端视角)
  3. 项目目录结构示例(以 Java Spring Boot + TypeScript React 为例)
  4. 层间通信与数据流 (以创建用户为例)
  5. 关键设计要点与最佳实践

这是一个非常经典且重要的问题,全栈项目的分层架构设计,核心目标是实现高内聚、低耦合,让代码易于维护、测试和扩展。

下面我将以目前最主流的前后端分离模式(前端 SPA + 后端 API)为例,详细阐述一种被广泛验证的分层架构设计。

核心原则

  1. 单一职责:每一层只负责一个特定的功能领域。
  2. 依赖倒置:高层模块(如业务逻辑)不应依赖低层模块(如数据库),两者都应依赖抽象(如接口)。
  3. 接口隔离:层与层之间通过明确的接口(API、DTO、Interface)进行通信。

典型的三层至四层架构(后端视角)

这是最经典的分层方式,根据项目复杂度,可以拆分为更细的层。

展示层 (Presentation Layer / Controller)

  • 职责:处理用户界面(Web、移动端、CLI)的请求和响应,它是系统的入口和出口。
  • 核心工作
    • 接收HTTP请求,解析参数(Query、Path、Body)。
    • 调用业务逻辑层(Service)的方法。
    • 将业务逻辑层返回的结果转换成前端需要的格式(通常是JSON)。
    • 处理全局异常,返回统一格式的错误响应。
    • 不包含任何业务逻辑或数据访问逻辑。
  • 技术示例UserController.java, @RestController, req/, res/ 目录(用于定义请求/响应对象)。

业务逻辑层 (Business Logic Layer / Service)

  • 职责:系统的核心,处理所有业务规则工作流,这是项目中“大脑”所在的位置。
  • 核心工作
    • 校验用户输入的业务规则(用户名唯一性、余额是否足够、订单状态流转)。
    • 编排多个底层服务或数据访问对象(DAO)来完成一个完整的业务用例(创建订单需要同时扣减库存、生成支付记录、发送通知)。
    • 处理事务(ACID)。
    • 不包含HTTP API 的具体实现细节(如 @GetMapping),也不直接操作数据库。
  • 技术示例UserService.java, OrderService.java, CustomerService.java

数据访问层 (Data Access Layer / Repository / DAO)

  • 职责:封装与数据源(数据库、缓存、搜索引擎、外部API)的所有交互。
  • 核心工作
    • 执行CRUD(增删改查)操作。
    • 将数据库查询结果映射为业务对象(如 UserEntity, OrderDO)。
    • 管理数据库连接、SQL语句、ORM映射(如 JPA, MyBatis)。
    • 注意:这一层的接口应面向业务(如 findByUsername(String username)),而不是面向数据库(如 selectById(Long id))。
  • 技术示例UserRepository.java, UserMapper.java, RedisCache.java

领域层 (Domain Layer / Model) - 可选但非常推荐

  • 职责:存放核心的业务对象和业务规则(实体、值对象、领域服务),这个层是“业务逻辑层”的基石。
  • 核心工作
    • 定义 Entity(实体):如 User, Order,可以包含简单的业务方法(如 order.cancel())。
    • 定义 Value Object(值对象):如 Money, Address, Email
    • 定义 Domain Event(领域事件):如 OrderCreatedEvent
  • 为什么推荐:将核心实体和其行为从Service层剥离出来,避免了面向过程的Service(即一个巨大Service类里塞满各种if-else),让业务逻辑更清晰、可测试性更强。
  • 与其它层的关系:Service层创建、获取、修改领域对象;Repository层负责持久化或读取领域对象。

项目目录结构示例(以 Java Spring Boot + TypeScript React 为例)

这个结构体现了上述分层思想。

后端 (Java/Spring Boot)

src/main/java/com/youcompany/yourproject/
├── YourApplication.java
├── controller/            // 展示层
│   ├── UserController.java
│   └── request/
│       └── CreateUserRequest.java
│   └── response/
│       └── UserResponse.java
├── service/               // 业务逻辑层
│   ├── UserService.java
│   └── impl/
│       └── UserServiceImpl.java
├── domain/                // 领域层 (核心模型)
│   ├── model/
│   │   ├── User.java          // Entity
│   │   ├── Money.java         // Value Object
│   │   └── eunms/
│   │       └── UserStatus.java
│   └── service/           // 领域服务 (跨实体的业务逻辑)
│       └── UserDomainService.java
├── repository/            // 数据访问层
│   ├── UserRepository.java // 接口,定义数据库操作
│   └── impl/
│       └── UserRepositoryImpl.java // 使用 JPA/MyBatis 实现
├── infrastructure/        // 基础设施 (可选,与外部系统的交互)
│   ├── config/            // 配置
│   ├── security/          // 安全
│   └── cache/             // 缓存实现
└── shared/                // 通用工具、常量、异常
    ├── exception/
    └── util/

前端 (React/TypeScript)

src/
├── api/                   // 网络请求层 (对应后端的Controller)
│   ├── user.ts            // 定义调用后端API的函数 (如 getUser, createUser)
│   └── types.ts           // 定义请求/响应DTO接口
├── store/                 // 状态管理层 (Redux/Zustand/Context)
│   ├── userStore.ts
│   └── types.ts
├── model/                 // 领域模型 (对应后端的Domain)
│   ├── User.ts            // 前端用的User接口/类
│   └── enums/
│       └── UserStatus.ts
├── service/               // 业务逻辑层 (可选,复杂逻辑时才需要)
│   └── userService.ts     // 组合API调用、状态更新、数据转换
├── components/            // 展示层
│   ├── common/            // 通用组件
│   └── features/          // 功能组件
│       ├── UserList/
│       └── UserDetail/
└── pages/                 // 页面 (路由组件)
    ├── HomePage.tsx
    └── UserPage.tsx

层间通信与数据流 (以创建用户为例)

  1. 前端:用户在页面填写 CreateUserForm -> 点击提交 -> 调用 api/user.tscreateUser() 函数 -> 发送HTTP POST请求/api/users
  2. 后端
    • ControllerUserController.createUser(CreateUserRequest req) 接收请求,验证请求参数格式(非空、类型正确)。
    • Service:调用 UserService.createUser(CreateUserDTO dto)
      • Service 层执行业务逻辑:检查用户名是否已存在 -> 调用 UserRepository.findByUsername()
      • 如果已存在,抛出 BusinessException
      • 如果不存在,创建 User 领域对象
      • Service 层调用 UserRepository.save(user)
    • RepositoryUserRepositoryImpl.save(User user) -> 使用 JPA save() 方法 -> 保存到数据库
    • Controller:收到 Service 返回的 User 对象 -> 调用 UserResponse.from(user) 转为 UserResponse DTO -> 返回HTTP 201 JSON响应
  3. 前端api/user.ts 收到响应 -> 解析JSON -> store/userStore.ts 更新状态 users.push(newUser) -> React组件自动重新渲染,展示新用户。

关键设计要点与最佳实践

  1. DTO (数据传输对象)层与层之间传递的对象

    • CreateUserRequest (Controller 接收){username, email, password}
    • UserResponse (Controller 返回){id, username, email, createTime} (通常不返回敏感字段如密码)
    • UserDTO (Service 内部使用):可以包含更多业务属性,{username, email, encodedPassword, status}
    • 原则不要将内部 Entity 直接暴露给 Controller 或前端,这样可以隐藏内部实现细节,避免因数据库字段变化导致前端掉线。
  2. 依赖注入 (DI):各层之间通过接口依赖,而不是具体实现类。

    • UserService 依赖 UserRepository 接口,而不是 UserRepositoryImpl 类,这样方便测试(Mock)和更换实现(例如从MySQL切换到PostgreSQL)。
  3. 异常处理

    • 定义业务异常BusinessException(ErrorCode code, String message)
    • 全局异常处理器:在Controller层捕获所有未处理的异常,返回统一的错误JSON格式(如 {code: 1001, message: "用户名已存在"})。不要在每一个Controller方法里都写try-catch
  4. 事务管理

    • 事务边界通常设置在 Service层(一个 @Transactional 注解),一个业务用例对应一个事务,确保ACID。
  5. 测试

    • 单元测试:重点测试Service层(业务逻辑)和Domain层(实体方法),通过Mock Repository来隔离外部依赖。
    • 集成测试:测试Controller + Service + Repository 的完整链路(使用内嵌数据库如 H2)。
    • 前端测试:测试Service(API调用)和Store(状态管理),使用Mock API。

一个好的全栈分层架构不是一蹴而就的,需要根据项目规模和团队情况进行权衡。

项目类型 建议架构模式 关键考量
小型/原型项目 简约的三层:Controller -> Service -> DAO 快速迭代,不必过度设计。
中型/核心业务 推荐的四层:Controller -> Service -> Domain -> Repository 清晰的业务边界,易于测试和维护。
大型/复杂/团队多 领域驱动设计 (DDD) + 微服务 解决复杂业务耦合,提升团队并行开发效率。

核心思想:让每一层只做它该做的事,Controller 只关心网络,Domain 只关心业务,Repository 只关心存储。 这样你的代码才能像乐高积木一样,灵活组装,易于修改。

标签: 项目分层

抱歉,评论功能暂时关闭!