import{_ as a,o as i,c as n,a2 as t}from"./chunks/framework.B-QBKwc1.js";const c=JSON.parse('{"title":"后端分层架构","description":"后端采用\\"三层主干 + 三层支撑\\"架构:Controller → Service → Model 构成主干链路,FormRequest、横切服务、Middleware 分别提供参数校验、通用能力、","frontmatter":{},"headers":[],"relativePath":"zh/architecture/backend-layer.md","filePath":"zh/architecture/backend-layer.md"}'),e={name:"zh/architecture/backend-layer.md"};function l(p,s,h,d,k,r){return i(),n("div",null,[...s[0]||(s[0]=[t(`

4.3 后端分层架构 ​

概述

后端采用"三层主干 + 三层支撑"架构:Controller → Service → Model 构成主干链路,FormRequest、横切服务、Middleware 分别提供参数校验、通用能力、请求拦截等支撑。各层职责明确,层间通过方法调用串联,不越层访问。

架构全景 ​

text
┌─────────────────────────────────────────────────────────────────────┐
│                           支撑层                                     │
│                                                                     │
│  FormRequest(参数校验)  横切 Service(通用能力) Middleware(请求拦截)│
│  Http/Requests/*.php     Services/(Jwt/Dict…)   Http/Middleware/   │
└──────────────────────────────┬──────────────────────────────────────┘
                               │ 被主干层调用 / 前置拦截
                               ▼
┌─────────────────────────────────────────────────────────────────────┐
│                           主干链路                                    │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ Controller(控制器层)                                        │   │
│  │ 注解标注 → 参数注入 → 调用 Service → 封装响应                  │   │
│  │ 基类:Controller | 文件:app/Http/Controllers/Api/*.php        │   │
│  └──────────────────────────┬──────────────────────────────────┘   │
│                             │ 调用 Service 方法                      │
│                             ▼                                       │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ Service(服务层)                                             │   │
│  │ 属性配置 → 唯一性校验 → 生命周期钩子 → 事务 → 调用 Model       │   │
│  │ 基类:BaseService / BaseTenantService | Services/*.php        │   │
│  └──────────────────────────┬──────────────────────────────────┘   │
│                             │ 调用 Eloquent ORM                      │
│                             ▼                                       │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ Model(模型层)                                               │   │
│  │ 表映射 → 软删除 → 审计字段 → 关联关系 → ORM → SQL              │   │
│  │ Trait:SoftDeletesByFlag / HasAuditColumns | Models/*.php     │   │
│  └──────────────────────────┬──────────────────────────────────┘   │
│                             ▼                                       │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ Database(五种数据库:MySQL / PG / SQL Server / Oracle / SQLite)│
│  └─────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────┘

各层职责详解 ​

Controller 层 ​

文件:app/Http/Controllers/Api/{Module}Controller.php基类:App\\Http\\Controllers\\Controller职责:HTTP 请求入口,只做"编排"不做"判断"

职责说明示例
参数注入类型注入 FormRequest 完成格式校验add(ExampleRequest $request)
调用 Service委托业务逻辑(快捷方法一行调用)$this->_add($service, $data)
响应封装统一 JSON 格式返回$this->success() / $this->fail()
注解标注声明权限和日志#[Permission]、#[OperationLog]

Controller 不应该做:业务判断、数据库操作、文件处理、重复的格式校验。

php
class ExampleController extends Controller
{
    public function __construct(protected ExampleService $exampleService) {}

    // 标准 CRUD —— 一行调用(构造注入,无需 initialize)
    #[OperationLog('示例管理-查询分页', OperationLog::TYPE_QUERY)]
    #[Permission('sys:example:page', '示例分页')]
    public function page(): JsonResponse
    {
        return $this->_page($this->exampleService);
    }

    #[OperationLog('示例管理-新增', OperationLog::TYPE_ADD, '新增示例:{name}')]
    #[Permission('sys:example:add', '添加示例')]
    public function add(ExampleRequest $request): JsonResponse
    {
        return $this->_add($this->exampleService, $request->validated());
    }
}

Service 层 ​

文件:app/Services/{Module}Service.php基类:BaseService(系统共享)/ BaseTenantService(租户隔离) 职责:业务核心,通过"属性配置 + 生命周期钩子"声明式 CRUD

职责方式说明
行为定义属性配置$pageLikeFields、$uniqueFields、$serializeMaps 等 16 个声明式属性
业务定制生命周期钩子beforeAdd、afterUpdate、beforeDelete 等 10 个钩子
横切处理Trait 组合文件字段、字典翻译、数据权限、租户隔离(6 个 Concerns Trait)
数据安全DB::transactionadd/update/delete/batchDelete 主流程事务包裹

Service 不应该做:直接 HTTP 交互、直接返回 JSON 响应。

php
class ExampleService extends BaseService
{
    use HasCrudOperations, HasQueryScopes, HasSerializeMaps, HasUniqueCheck;

    protected string $modelClass = Example::class;
    protected array $pageLikeFields = ['name'];
    protected array $pageEqFields = ['status'];
    protected array $uniqueFields = ['name'];
    protected array $serializeMaps = ['status' => 'example_status'];

    // 业务定制:钩子按需重写
    protected function beforeAdd(array $data): array
    {
        $data['sort'] = $data['sort'] ?? 0;
        return $data;
    }
}

Model 层 ​

文件:app/Models/{TableName}.php基类:Eloquent Model + Concerns Trait 职责:数据持久化,只做表映射和自动维护

职责说明
表映射protected $table = 'example'(不含前缀,DB_PREFIX 自动拼接)
软删除SoftDeletesByFlag 注册全局范围自动过滤 is_delete=1
审计字段HasAuditColumns 的 creating/updating 事件自动填充
关联关系hasMany、belongsTo、belongsToMany 等

Model 不应该做:业务判断、复杂查询编排(交给 Service)。

php
class Example extends Model
{
    use HasAuditColumns, SoftDeletesByFlag;

    protected $table = 'example';

    // 关联关系(按需定义)
    public function category()
    {
        return $this->belongsTo(Category::class, 'category_id');
    }
}

FormRequest 层(参数校验支撑) ​

文件:app/Http/Requests/{Module}Request.php基类:BaseRequest职责:参数格式校验(必填、类型、长度、枚举),不含业务规则

php
class ExampleRequest extends BaseRequest
{
    public function rules(): array
    {
        return [
            'name' => 'required|string|max:255',
            'type' => 'nullable|integer|in:1,2,3,4',
        ];
    }
}

触发方式:控制器方法类型注入,方法执行前自动校验;失败由 failedValidation() 返回统一 JSON(code=1 + 字段明细)。

横切 Service(通用能力支撑) ​

文件:app/Services/{Name}Service.php(横切类) 职责:跨模块通用能力,无状态、无副作用

服务能力
JwtService令牌签发/刷新/解析(Redis 有状态)
DictCacheService字典查询(两级缓存)
PasswordService密码加密(bcrypt,成本因子 12)
ExcelServiceExcel 导入导出(表头映射、分批)
CaptchaService图片验证码(IP 限流)
RequestInfoServiceIP 归属地 / OS / 浏览器解析

横切 Service 不应该做:持有请求状态、直接返回响应。

Middleware 层(请求拦截支撑) ​

文件:app/Http/Middleware/*.php职责:请求拦截,在 Controller 前后执行

text
ProxyMiddleware → Cors → ForceJsonResponse → Authenticate → ResolveTenant → LogOperation → Controller
中间件作用注入数据
AuthenticateJWT 认证 + 权限校验attributes['userInfo']
ResolveTenant租户上下文attributes['tenantId'] / isSuperAdmin / tenantInfo
LogOperation操作日志(handle 采集,terminate 落库)—

详见 4.2 请求处理链路。

各层方法对照表 ​

分页查询链路 ​

层方法输入输出
Controller_page($service)HTTP 请求参数JsonResponse
ServicepageList($params, $where, $with)参数数组['records'=>[], 'total'=>int, 'current'=>int, 'size'=>int]
ModelModel::query()->paginate(...)分页条件LengthAwarePaginator

新增链路 ​

层方法输入输出
Controller_add($service, $data)FormRequest 校验后的数组JsonResponse
Serviceadd($data)snake_case 关联数组int(新记录 ID)
ModelModel::create($data)关联数组Model 实例

Service::add 内部流程(HasCrudOperations):

beforeAdd → checkUnique → DB::transaction { Model::create(HasAuditColumns 审计填充)} → afterAdd

修改链路 ​

层方法输入输出
Controller_update($service, $id, $data)id + 请求数据JsonResponse
Serviceupdate($id, $data)id + 关联数组bool
ModelModel::find($id)->update($data)模型 + 关联数组bool

删除链路 ​

层方法输入输出
Controller_delete($service, $id)idJsonResponse
Servicedelete($id)idbool
Model$model->softDelete()软删除标记bool(UPDATE SET is_delete=1)

数据流向 ​

请求方向(前端 → 后端 → 数据库) ​

text
前端请求(camelCase JSON)
    │
    ▼
FormRequest::validated()              ← 格式校验(camelCase 规则),原样传递
    │
    ▼
Controller::_add($service, $data)     ← 编排 + 注解元数据
    │
    ▼
Service::doAdd 入口                    ← 键名统一转为 snake_case
    │
    ▼
Service::beforeAdd($data)             ← 钩子:预处理
    │
    ▼
Service::checkUnique($data)           ← 唯一性校验(BizException 拦截)
    │
    ▼
DB::transaction {
    Service::processTenantId($data)   ← 租户填充(HasDataScope 启用时)
    Service::processFileFieldsOnSave  ← 文件字段处理(HasFileProcessing 启用时)
    Model::create($data)              ← 审计字段自动填充(creating 事件)
}
    │
    ▼
Database(snake_case)

响应方向(数据库 → 后端 → 前端) ​

text
Database(snake_case 数据)
    │
    ▼
Model                                 ← ORM 查询(软删除全局范围生效)
    │
    ▼
Service 处理(processAfterRead 处理链)
    │ processFileFieldsOnRead()       ← 文件字段补全域名(启用时)
    │ processSerializeMapsList()      ← 字典显示名补全(status → statusText)
    │ afterDetail()/afterPageList()   ← 钩子:补充关联数据
    ▼
Result::success() / page()            ← snake_case → camelCase 转换
    │
    ▼
JSON 响应 → 前端

异常处理传播 ​

text
Model 层异常(如数据库连接失败)
    │
    ▼ 向上抛出
Service 层异常
    │ beforeAdd/beforeDelete 抛出 BizException(业务规则)
    │ 唯一性校验抛出 BizException
    │ DB::transaction 自动回滚
    ▼ 向上抛出
Controller 层
    │ 方式一:_add/_update/_delete 等快捷方法捕获 BizException → fail(消息, code)
    │ 方式二:不捕获,由全局 Handler 统一处理
    ▼
Exceptions\\Handler::render()
    │ BizException            → {code:异常code(默认1), msg:"业务提示"}
    │ ValidationException     → {code:422, msg:"参数验证失败", data:...}
    │ AuthenticationException → {code:401}
    │ NotFoundHttpException   → {code:404}
    │ 其它异常                 → {code:500, msg:调试原文/生产"操作失败"}
    ▼
JSON 响应

推荐做法:

完整请求示例 ​

以"新增案例"为例,展示一个请求从进入到返回的完整链路:

text
POST /api/example/add
Content-Type: application/json
Authorization: Bearer <token>

{"name": "新案例", "type": 1, "status": 1}
text
1. ProxyMiddleware         → 真实 IP 识别(受信代理)
2. Cors                    → 非 OPTIONS,放行(响应时追加 CORS 头)
3. ForceJsonResponse       → Accept 强制 JSON
4. Authenticate            → 校验 Token → 注入 attributes['userInfo']
                             → 反射 #[Permission] → checkPermission('sys:example:add') ✓
5. ResolveTenant           → 注入 tenantId / isSuperAdmin
6. LogOperation(handle)    → 收集上下文,读 #[OperationLog]

7. ExampleRequest
   │ rules() 校验 name/type/status ✓
   │ validated() → ["name"=>"新案例", "type"=>1, "status"=>1]
   ▼
8. ExampleController::add()
   │ 注解元数据已由 4/6 读取
   │ $this->_add($service, $data)
   ▼
9. ExampleService::add($data)
   │ 入口键名转换            → array_camel_to_snake()
   │ beforeAdd($data)            → 默认 sort(钩子)
   │ checkUnique($data)          → name 唯一 ✓
   │ DB::transaction {
   │     Example::create($data)  → creating:create_user/create_time 自动填充
   │ }
   │ afterAdd($id, $data)        → 无额外操作
   ▼
10. Database INSERT → laravel_example → 自增 ID 42

11. 返回 {"code":0, "ok":true, "msg":"添加成功", "data":{"id":42}}

12. LogOperation(terminate) → 写入 laravel_operation_log(响应后,不影响业务)

层间通信规范 ​

规则说明
Controller → Service✅ 允许,标准调用
Controller → Model❌ 禁止,越层
Controller → FormRequest✅ 允许,类型注入
Service → Model✅ 允许,标准调用
Service → 横切 Service✅ 允许,调用通用能力(静态/注入均可)
Service → Controller❌ 禁止,反向依赖
Service → FormRequest❌ 禁止,格式校验在 HTTP 入口完成
Model → Service / Controller❌ 禁止,反向依赖
Middleware → 后续链路✅ 通过 request->attributes 注入数据
FormRequest → 业务规则❌ 禁止,只做格式校验(业务规则在 Service)
`,59)])])}const F=a(e,[["render",l]]);export{c as __pageData,F as default};