Files
rxthinkcmf-wiki/RXThinkCMF_Laravel13_NaiveVue/zh/architecture/overview.md
T
2026-10-08 17:50:29 +08:00

336 lines
21 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.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<int, string>
*/
protected array $pageLikeFields = ['name'];
/**
* 精确匹配字段
*
* @var array<int, string>
*/
protected array $pageEqFields = ['status'];
/**
* 唯一性校验字段
*
* @var array<int, string>
*/
protected array $uniqueFields = ['name'];
/**
* 枚举显示名映射
*
* @var array<string, string>
*/
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 | 敏感信息不泄露、弱密钥不启动 |