Files
easygoadmin-wiki/EasyGoAdmin_Gin_EleVue/zh/architecture/backend-layer.md
T
2026-10-25 17:24:27 +08:00

88 lines
2.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 4.3 后端分层架构
:::tip 概述
后端按职责分为五层:契约(dto)、接口(handler)、业务(service)、数据(repository)、横切(middleware + hooks)。每层只做一件事,依赖单向向下。
:::
## 分层与依赖方向
```text
middleware 横切处理(认证/租户/权限/日志/限流)
│ 注入身份与上下文到 ctx
▼
handler 极薄委托(签名固定,反射注册)
│
▼
service 业务规则(ModuleSpec 声明 + 手写逻辑 + 事务)
│
▼
repository 数据访问(Ctx 入口注入软删/租户 Scope)
│
▼
gorm + db 连接(多方言驱动注册表 + 全局钩子盖章)
```
dto 被所有层引用(契约);utility 被任意层引用(无业务语义)。
## 各层职责边界
| 层 | 做什么 | 不做什么 |
|---|---|---|
| dto | 请求/响应结构、binding/msg/form/json 标签、UnmarshalBody | 业务判断 |
| handler | 委托调用、调用转换 | 参数解析、权限、规则 |
| service | 业务规则、事务、错误上抛、ModuleSpec 声明 | HTTP 响应构造、裸 SQL 拼接 |
| repository | 条件查询、软删除、存在性判断 | 业务条件决策 |
| middleware | 认证、租户、鉴权、日志、限流、信封 | 业务逻辑 |
## 单例与调用约定
```text
service:var Xxx *sXxx(init 注册,全进程单例,方法必须并发安全)
跨模块:同包直调 —— User.Page(...)、repository.NewDeptRepo()(无需 import)
仓储:无状态(仅持表名),NewXxxRepo() 按需构造、可并发使用
```
## 事务边界
事务是 service 的职责:
```go
db.WithTrans(ctx, func(ctx context.Context) error {
// 回调内使用入参 ctx——它携带事务连接
// 内部所有 repository.Ctx(ctx) 自动加入事务
// 返回非 nil 错误整体回滚
})
```
repository 无感知事务——它永远从 ctx 取连接,这是 ctx 贯穿设计的直接收益。
## 错误传播
```text
repository 返回 gorm 错误
↓
service 映射为业务错误(consts 哨兵 / apperr.Newf)或原样上抛
↓
handler 不接触,透传
↓
response 中间件统一映射为信封(apperr 按码输出,其余通用失败)
```
## 横切的两个执行点
| 执行点 | 时机 | 承担什么 |
|---|---|---|
| 中间件链 | HTTP 请求级 | 身份、租户、权限、日志、限流、信封 |
| GORM 全局钩子 | SQL 语句级 | 审计盖章、物理删除拦截 |
| repository Scope | SQL 构建前 | del_flag=0、租户过滤 |
同一个红线(软删/租户)在读写两侧分别由 Scope 与钩子执行,业务代码零参与。
## 模块文件规约回顾
一个模块固定四文件,写法见 [第 3 章 模块开发实战](/zh/guide/overview.html) 与 [12.4 模块开发规约](/zh/standards/module-code.html)。
## 下一步
→ [4.4 反射元数据驱动机制](/zh/architecture/bind-mechanism.html)