后端项目目录结构规范
模块分层、包划分(DDD / 分层架构)
- Standard:后端项目默认采用经典四层分层架构,自顶向下依赖,禁止反向依赖。
| 层级 | 职责 | 依赖方向 |
|---|---|---|
| Controller 层 | HTTP 入口、请求校验、响应组装 | → Service |
| Service 层 | 业务逻辑编排、事务控制 | → Repository / Domain |
| Repository 层 | 数据访问(DAO)、ORM 映射 | → Database |
| Entity/Model 层 | 数据模型定义 | — |
- Requirement:上层可依赖下层,下层 禁止 依赖上层。
- Requirement:同层模块之间通过接口依赖,禁止直接依赖具体实现类。
- Standard:Controller 层不得包含业务逻辑,仅做参数校验与响应转换。
- Standard:Service 层不得直接处理 HTTP 请求对象(
Request/Response),应接收领域对象或 DTO。 - Caution:禁止跨层调用,如 Controller 直接调用 Repository。
Controller → Service → Repository → Database │ │ ▼ ▼ Request Domain Response Object- Standard:业务复杂度高、领域模型丰富的项目,采用 DDD(领域驱动设计)分层。
| 层级 | 包名 | 职责 |
|---|---|---|
| 用户接口层 | interfaces | Controller、DTO、Assembler |
| 应用层 | application | 应用服务、Command/Query、事件编排 |
| 领域层 | domain | 实体、值对象、聚合根、领域服务、仓储接口 |
| 基础设施层 | infrastructure | 仓储实现、外部 API 客户端、消息队列 |
- Requirement:领域层定义仓储接口(
Repository),基础设施层提供实现。 - Requirement:领域层 禁止 依赖基础设施层,通过依赖注入解耦。
- Standard:应用层编排多个领域服务,不包含核心业务规则。
- Caution:禁止将领域逻辑泄漏到应用层或基础设施层。
- Standard:按业务领域划分为独立的模块(限界上下文),每个模块拥有独立的领域层与基础设施层。
- Standard:跨上下文通信通过应用服务或领域事件,禁止直接访问其他上下文的领域对象。
- Requirement:包名全部小写,使用点分隔,禁止使用下划线或驼峰。
- Requirement:包名前缀为
com.<公司>.<项目>,如com.example.user。 - Standard:按分层或领域组织包,以下两种方式二选一:
按分层组织(简单项目):
com.example.user├── controller├── service├── repository├── entity├── dto└── config按领域组织(DDD / 复杂项目):
com.example.user├── interfaces│ ├── controller│ ├── dto│ └── assembler├── application│ ├── command│ ├── query│ └── service├── domain│ ├── model│ ├── service│ └── repository└── infrastructure ├── repository ├── client └── mq- Requirement:包名全部小写,使用下划线分隔多单词(PEP 8)。
- Standard:按模块划分顶层包,模块内部按职责划分子包。
user_service/├── api/ # Controller 层(路由、请求/响应模型)├── service/ # 业务逻辑├── repository/ # 数据访问├── models/ # 数据模型 / ORM 实体├── schemas/ # Pydantic 模型(请求/响应 DTO)├── core/ # 配置、安全、工具└── tests/ # 测试- Requirement:包名全部小写,简短且语义明确,禁止使用下划线或驼峰。
- Standard:按职责或领域组织包,避免
common、utils等含义模糊的包名。
user-service/├── cmd/ # 入口 main├── internal/ # 内部包(不对外暴露)│ ├── handler/ # HTTP handler│ ├── service/ # 业务逻辑│ ├── repository/ # 数据访问│ ├── model/ # 领域模型│ └── config/ # 配置├── pkg/ # 可复用的公共包└── api/ # API 定义(protobuf / OpenAPI)user-service/├── src/main/java/com/example/user/│ ├── UserServiceApplication.java│ ├── interfaces/│ │ ├── controller/│ │ │ └── UserController.java│ │ ├── dto/│ │ │ ├── request/│ │ │ └── response/│ │ └── assembler/│ ├── application/│ │ ├── command/│ │ ├── query/│ │ └── UserApplicationService.java│ ├── domain/│ │ ├── model/│ │ │ ├── User.java│ │ │ └── UserId.java # 值对象│ │ ├── service/│ │ │ └── UserDomainService.java│ │ └── repository/│ │ └── UserRepository.java # 接口│ └── infrastructure/│ ├── repository/│ │ └── UserRepositoryImpl.java│ ├── persistence/│ │ └── entity/ # JPA Entity│ ├── client/ # 外部 API 客户端│ └── config/│ └── DataSourceConfig.java├── src/main/resources/│ ├── application.yml│ ├── application-dev.yml│ ├── application-prod.yml│ ├── mapper/ # MyBatis XML(如使用)│ └── db/migration/ # Flyway 脚本└── src/test/java/com/example/user/ ├── unit/ ├── integration/ └── e2e/user-service/├── app/│ ├── main.py # 应用入口│ ├── api/│ │ ├── __init__.py│ │ ├── routes/│ │ │ ├── __init__.py│ │ │ └── user.py│ │ └── deps.py # 依赖注入│ ├── schemas/ # Pydantic 请求/响应模型│ │ ├── __init__.py│ │ ├── user.py│ │ └── common.py│ ├── services/ # 业务逻辑│ │ ├── __init__.py│ │ └── user_service.py│ ├── repositories/ # 数据访问│ │ ├── __init__.py│ │ └── user_repository.py│ ├── models/ # ORM 模型(SQLAlchemy)│ │ ├── __init__.py│ │ └── user.py│ ├── core/ # 配置、安全、工具│ │ ├── __init__.py│ │ ├── config.py│ │ ├── security.py│ │ └── exceptions.py│ └── db/│ ├── __init__.py│ ├── base.py│ └── session.py├── alembic/ # 数据库迁移├── tests/│ ├── unit/│ ├── integration/│ └── conftest.py├── pyproject.toml└── .env.exampleuser-service/├── cmd/│ └── server/│ └── main.go├── internal/│ ├── handler/ # HTTP handler│ │ ├── user_handler.go│ │ └── response.go│ ├── service/ # 业务逻辑│ │ └── user_service.go│ ├── repository/ # 数据访问│ │ └── user_repository.go│ ├── model/ # 领域模型│ │ └── user.go│ ├── config/ # 配置│ │ └── config.go│ └── middleware/├── pkg/ # 公共可复用包│ ├── logger/│ └── errors/├── api/ # API 定义│ └── openapi.yaml├── migrations/ # 数据库迁移├── configs/│ ├── config.yaml│ └── config.prod.yaml└── tests/| 反模式 | 问题 | 建议 |
|---|---|---|
| 所有类放在一个包下 | 无法区分职责,难以维护 | 按分层/领域分包 |
common / utils 大包 | 什么都往里塞,变成垃圾桶 | 按职责拆分到具体模块 |
| Controller 包含业务逻辑 | 违反分层,无法复用 | 业务逻辑移到 Service |
| Service 直接操作 HTTP 请求对象 | 耦合传输层 | 用 DTO 解耦 |
| 领域层依赖 ORM 框架 | 领域模型被基础设施污染 | 领域层定义接口,基础设施层实现 |
| 跨模块直接访问数据库表 | 破坏模块边界 | 通过服务接口或事件通信 |
| 测试与源码混放 | 构建产物包含测试代码 | 测试独立 tests/ 目录 |
- ❌ 包名使用大写或驼峰:
com.example.UserService。 - ❌ 包名使用下划线:
com.example.user_service。 - ❌ 类名与包名重复:
user/user/User.java。 - ❌ 文件名与类名不一致(Java)。
- ❌ Python 模块使用驼峰命名:
userService.py。 - ❌ Go 包名使用下划线:
user_service。
- Caution:禁止创建无边界的
Utils、Helper、Common类。 - Standard:工具方法应归属到具体领域模块,或按职责拆分为独立工具包(如
DateUtils、StringUtils、CryptoUtils)。 - Standard:每个工具类职责单一,方法数 ≤ 20,超过应拆分。