# 4.1 整体架构概览 :::tip 概述 本章从全局视角阐述系统的整体技术架构,涵盖前端、后端、数据库及基础设施等核心组成部分,旨在帮助开发者快速建立对系统全貌的清晰认知。 ::: ## 架构总览 ```text ┌─────────────────────────────────────────────────────────────────┐ │ 浏览器(Vue3 + ElementPlus) │ │ Axios HTTP 请求 / Vite 开发代理 │ └──────────────────────────────┬──────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Nginx(反向代理) │ │ 静态资源托管 / SSL 终止 / gzip 压缩 / 仅放行入口PHP │ └──────────────────────────────┬──────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Laravel 13 Application │ │ │ │ ┌───────────────────────────────────────────────────────────┐ │ │ │ 中间件链(按注册顺序执行) │ │ │ │ ┌───────┐ ┌──────┐ ┌───────────┐ ┌──────────┐ │ │ │ │ │ Proxy │→│ Cors │→│ForceJson │→│ auth.jwt │ │ │ │ │ │真实IP │ │ 跨域 │ │ 强制JSON │ │JWT+权限 │ │ │ │ │ └───────┘ └──────┘ └───────────┘ └──────────┘ │ │ │ │ 全局组(api prepend) 路由组 │ │ │ │ ┌────────┐ ┌─────────┐ │ │ │ │ │ tenant │→│log.oper.│ │ │ │ │ │租户上下文│ │操作日志 │ │ │ │ │ └────────┘ └─────────┘ │ │ │ │ 另有 DemoMiddleware(演示拦截,按路由别名启用) │ │ │ └───────────────────────────────┬───────────────────────────┘ │ │ ▼ │ │ ┌───────────────────────────────────────────────────────────┐ │ │ │ 控制器层(Controller) │ │ │ │ Controller 基类 → success/fail/paginate · _page/_add 等 │ │ │ │ #[Permission] 权限注解 · #[OperationLog] 日志注解 │ │ │ │ FormRequest 类型注入 → 参数格式校验 │ │ │ └───────────────────────────────┬───────────────────────────┘ │ │ ▼ │ │ ┌───────────────────────────────────────────────────────────┐ │ │ │ 服务层(Service) │ │ │ │ BaseService / BaseTenantService │ │ │ │ 属性配置 · 生命周期钩子 · 6 个 Concerns Trait 组合 │ │ │ │ 文件处理 · 字典翻译 · 唯一性校验 · 数据权限 · 租户隔离 │ │ │ │ DB::transaction 事务管理 · BizException 业务异常 │ │ │ └───────────────────────────────┬───────────────────────────┘ │ │ ▼ │ │ ┌───────────────────────────────────────────────────────────┐ │ │ │ 模型层(Eloquent Model) │ │ │ │ SoftDeletesByFlag(is_delete 软删除)· HasAuditColumns │ │ │ └───────────────────────────────┬───────────────────────────┘ │ │ ▼ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ │ │ MySQL 等 │ │ Redis │ │ 文件系统 │ │ │ │ 五种数据库 │ │ 会话/缓存/队列│ │ public/uploads/ │ │ │ └─────────────┘ └─────────────┘ └─────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ## 架构特征 :::tip 核心设计原则 遵循以下架构设计原则,确保系统在长期演进中保持高质量和可维护性: ::: ### 1. 前后端分离 前端 Vue3 应用通过 HTTP API 调用后端 Laravel 服务,两者独立开发、独立部署。前端开发阶段通过 Vite 的 `proxy` 配置将 `/api` 请求代理到后端 `http://localhost:8000`,生产环境由 Nginx 统一反向代理。 ### 2. 分层架构 后端严格分为三层,每层职责单一、依赖单向: | 层次 | 目录 | 职责 | |------|------|------| | 控制器层 | `app/Http/Controllers/Api/` | 路由入口、权限注解、参数注入、响应返回 | | 服务层 | `app/Services/` | 业务逻辑、属性配置、生命周期钩子、横切处理 | | 模型层 | `app/Models/` | 数据库表映射、软删除、审计字段 | 验证职责分层:**FormRequest 只做格式验证,Service 只做业务规则**(唯一性、状态依赖)。 ### 3. 模板方法模式(声明式 CRUD) 通过 `BaseService` 基类,将通用 CRUD 流程固化为模板方法。子类只需声明差异点(过滤字段、排序规则、唯一性校验等),即可获得完整的增删改查能力,极大减少重复代码。 ```php // 子类只需声明差异点,即可获得完整 CRUD 能力 class ExampleService extends BaseService { use HasCrudOperations, HasQueryScopes, HasSerializeMaps, HasUniqueCheck; /** * 绑定的模型类 */ protected string $modelClass = Example::class; /** * LIKE 模糊匹配字段 * * @var array */ protected array $pageLikeFields = ['name']; /** * 精确匹配字段 * * @var array */ protected array $pageEqFields = ['status']; /** * 唯一性校验字段 * * @var array */ protected array $uniqueFields = ['name']; /** * 枚举显示名映射 * * @var array */ protected array $serializeMaps = ['status' => 'example_status']; } ``` ### 4. 中间件链式处理 请求处理采用中间件链,在 `bootstrap/app.php` 中注册别名与分组: ```text 请求进入 → Proxy → Cors → ForceJson → auth.jwt → tenant → log.operation → 控制器 └────────── 全局 api 组 ─────────┘└──────── 路由中间件组 ────────┘ │ 响应返回 ←────────────(逆向穿过)──────────────────┘ (log.operation 在响应后 terminable 阶段落库) ``` | 中间件 | 别名 | 作用域 | 职责 | |--------|------|--------|------| | `ProxyMiddleware` | proxy | 全局(api prepend) | 受信代理真实 IP 提取 | | `Cors` | cors | 全局 | 跨域处理(`config/cors.php`) | | `ForceJsonResponse` | force.json | 全局 | 强制 JSON Accept 头 | | `Authenticate` | auth.jwt | 路由组 | JWT 认证 + `#[Permission]` 反射鉴权 | | `ResolveTenant` | tenant | 路由组 | 租户上下文解析注入 | | `LogOperation` | log.operation | 路由组 | 操作日志采集(terminable 落库) | | `DemoMiddleware` | demo | 路由别名 | 演示环境写操作拦截(`#[DemoAllow]` 放行) | ### 5. 全局异常处理 `App\Exceptions\Handler` 统一捕获 `api/*` 请求的异常并返回标准 JSON 响应: | 来源 | 异常类型 | 触发场景 | 响应 | |------|---------|---------|------| | Handler | `BizException` | 业务规则失败(Service 抛出) | `{code:异常code(默认1), msg:"业务提示"}` | | Handler | `ValidationException` | 代码内手动校验失败 | `{code:422, msg:"参数验证失败", data:{错误明细}}` | | Handler | `AuthenticationException` | 未登录 / 令牌失效 | `{code:401, msg:"未授权,请先登录"}` | | Handler | `NotFoundHttpException` | 路由不存在 | `{code:404, msg:"数据不存在"}` | | Handler | 其它异常 | 未捕获异常 | `{code:500, msg:调试模式为原文,生产为"操作失败"}` | | FormRequest | `HttpResponseException` | 表单格式校验失败 | `{code:1, msg:"参数验证失败", data:{字段=>错误数组}}` | | auth.jwt 中间件 | — | Token 缺失/过期/无权限 | `{code:401/403, ...}`(到达控制器前拦截) | ### 6. 统一响应格式 所有 API 端点返回统一的 JSON 结构: ```json { "code": 0, "ok": true, "msg": "操作成功", "data": {} } ``` 成功响应 `code=0`,失败响应 `code=1`。HTTP 状态码默认 200,仅 403 同时设置对应 HTTP 状态码(便于网关处理),`code=401` 由前端跳转登录。前端无需针对不同接口做差异化解析。见 [5.16 统一响应与异常抛出](/zh/core/exception.html)。 ### 7. 软删除策略 :::warning 禁止物理删除 所有业务数据必须使用软删除(`is_delete` 字段),禁止物理删除。物理删除仅用于日志清理等特殊场景。 ::: 所有业务表通过 `is_delete` 字段实现软删除(0=正常,1=已删除)。`SoftDeleteFlagScope` 全局查询范围自动追加 `is_delete=0` 过滤,业务代码无需关心已删除数据。 ```php // 自动过滤已删除数据 $users = User::query()->get(); // WHERE is_delete = 0 // 查询已删除数据 $deleted = User::withoutGlobalScope(SoftDeleteFlagScope::class)->get(); // 软删除 $user->softDelete(); // UPDATE SET is_delete = 1 // 批量软删除 User::batchSoftDelete([1, 2, 3]); ``` ### 8. 审计字段自动写入 通过 `HasAuditColumns` Trait 的模型事件自动填充审计字段: ```php // 创建时自动填充(已赋值则保留原值) static::creating(function ($model) { $model->create_user = $model->create_user ?? Auth::username(); $model->create_time = $model->create_time ?? now(); }); // 更新时自动填充(强制覆盖) static::updating(function ($model) { $model->update_user = Auth::username(); $model->update_time = now(); }); ``` ### 9. 多数据库支持 通过 `DB_CONNECTION` 环境变量切换数据库驱动(MySQL / PostgreSQL / SQL Server / Oracle / SQLite),`document/` 下提供五套初始化脚本;Oracle 通过自定义 `oci` 驱动接入(`AppServiceProvider` 注册,配套 `OracleGrammar` / `OracleProcessor`)。业务代码无需修改。 ### 10. 两级缓存架构 ```text 请求级缓存(static 变量) ← 同一请求内不重复查库 │ 未命中 ▼ 持久缓存(Cache 门面/Redis) ← 跨请求复用,1小时过期 │ 未命中 ▼ 数据库查询 ← 查询后写入两级缓存 ``` `DictCacheService` 采用此架构,配合 Observer(`DictItemObserver` / `MenuObserver` / `RoleMenuObserver`)在数据变更时自动失效缓存。详见 [4.8 缓存架构设计](/zh/architecture/cache.html)。 ## 技术分层图 ```text ┌──────────────────────────────────────────────────────────────┐ │ 前端(Vue3 + ElementPlus) │ │ Pinia · Vue Router · Axios · TinyMce · ECharts │ └──────────────────────────┬───────────────────────────────────┘ │ HTTP / JSON ┌──────────────────────────┴───────────────────────────────────┐ │ Laravel 13 Application │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌──────────────────────┐ │ │ │ 中间件 │ │ 路由 │ │ 异常处理器 │ │ │ │ ───────── │ │ ───────── │ │ ───────────────── │ │ │ │ Proxy │ │ routes/ │ │ BizException │ │ │ │ Cors │ │ api.php │ │ ValidationException │ │ │ │ ForceJson │ │ web.php │ │ Authentication │ │ │ │ auth.jwt │ │ console.php│ │ NotFoundHttp │ │ │ │ tenant │ │ │ │ Exception(500) │ │ │ │ log.oper. │ │ │ │ │ │ │ │ demo │ │ │ │ │ │ │ └─────────────┘ └─────────────┘ └──────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ 控制器层(app/Http/Controllers/Api/)28 个 │ │ │ │ Controller 基类 · #[Permission] · #[OperationLog] │ │ │ │ FormRequest 注入(24 个) │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ 服务层(app/Services/)36 个 │ │ │ │ BaseService / BaseTenantService │ │ │ │ 6 Trait:CRUD · 查询 · 文件 · 数据权限 · 字典 · 唯一 │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ 模型层(app/Models/)25 个 │ │ │ │ SoftDeletesByFlag · HasAuditColumns │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────┐ ┌─────────────┐ ┌──────────────────┐ │ │ │ 横切服务 │ │ FormRequest │ │ 注解(Attributes)│ │ │ │ ────────────── │ │ ────────── │ │ ────────────── │ │ │ │ JwtService │ │ BaseRequest │ │ Permission │ │ │ │ PasswordService │ │ 24 个 │ │ OperationLog │ │ │ │ DictCacheService │ │ │ │ DemoAllow │ │ │ │ CaptchaService │ │ │ │ │ │ │ │ ExcelService │ │ │ │ │ │ │ │ GeneratorService│ │ │ │ │ │ │ │ DbMigrateService│ │ │ │ │ │ │ │ RequestInfo... │ │ │ │ │ │ │ └──────────────────┘ └─────────────┘ └──────────────────┘ │ └──────────────────────────┬───────────────────────────────────┘ │ ┌────────────┴────────────┐ ▼ ▼ ┌─────────────┐ ┌─────────────┐ │ MySQL │ │ Redis │ │ PostgreSQL │ │ 会话/缓存/队列│ │ SQL Server │ └─────────────┘ │ Oracle │ │ SQLite │ └─────────────┘ ``` ## 模块化设计 每个业务模块遵循统一的文件结构: ```text app/Http/Controllers/Api/UserController.php # HTTP 入口 app/Http/Requests/UserRequest.php # 参数验证 app/Services/UserService.php # 业务逻辑 app/Models/User.php # 数据模型 ``` | 文件 | 职责 | 基类 | |------|------|------| | Controller | 接收请求、调用 Service、返回响应 | `App\Http\Controllers\Controller` | | Request | 参数格式校验 | `BaseRequest` | | Service | 业务逻辑、属性配置、钩子处理 | `BaseService` / `BaseTenantService` | | Model | 数据库表映射 | Eloquent Model + Concerns Trait | ## 关键设计决策 | 决策 | 选择 | 原因 | |------|------|------| | 认证方案 | JWT 双令牌(Redis 有状态) | 无状态便于水平扩展,有状态支持踢下线/改密全端失效 | | 删除策略 | 软删除(`is_delete`) | 数据可恢复,唯一性校验可排除已删数据 | | 字段命名 | 数据库 snake_case / 响应 camelCase | `API_CAMEL_SNAKE_CONVERT` 自动转换,各端遵循各自惯例 | | 缓存策略 | 两级缓存(请求级 + Redis) | 减少数据库查询,Observer 保证一致性 | | 数据库 | 五种数据库 + 五套脚本 | 适配不同客户需求 | | 权限模型 | RBAC(用户→角色→菜单,菜单即权限) | 灵活的权限配置,注解声明即生效 | | 安全基线 | JWT_SECRET fail-close、生产 APP_DEBUG=false | 敏感信息不泄露、弱密钥不启动 |