12 KiB
12 KiB
5.10 字典模块
:::tip 概述
字典体系由三个服务组成:DictService(字典 CRUD,DictController 注入)、DictItemService(字典项 CRUD)、DictCacheService(字典项读取、正反向转换与缓存管理,本页主体)。读取侧采用两级缓存(请求级 + 持久缓存),同一请求内不重复查库,跨请求复用持久缓存;字典项变更时 DictItemObserver 自动失效对应缓存。
:::
字典体系架构
┌─────────────────────────────────────────────────────────────────────┐
│ 字典体系 │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ laravel_dict │ │ laravel_dict_item│ │
│ │ 字典主表 │ │ 字典项表 │ │
│ │ │ │ │ │
│ │ id │◄───│ dict_id │ │
│ │ name (字典名称) │ │ name (项名称) │ │
│ │ code (字典编码) │ │ value (项值) │ │
│ │ remark │ │ sort (排序) │ │
│ └──────────────────┘ │ note (备注) │ │
│ └──────────────────┘ │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ DictCacheService │ │ Service 层 │ │
│ │ 字典服务 │ │ serializeMaps │ │
│ │ │ │ 自动翻译 │ │
│ │ getText() │ │ │ │
│ │ getValue() │◄───│ 'status' => │ │
│ │ getOptions() │ │ 'user_status' │ │
│ │ clearCache() │ │ │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ DictItemObserver(字典项变更 → 自动清除所属字典缓存) │ │
│ └──────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
缓存架构
请求级缓存(静态变量) ← 同一请求内不重复查库
│ 未命中
▼
持久缓存(cache() 门面,1小时) ← 跨请求复用(Redis)
│ 未命中
▼
数据库查询(dict → dict_item) ← 查询后写入两级缓存
缓存 Key 格式
| 缓存类型 | Key 格式 | 存储内容 |
|---|---|---|
| 请求级 | $localCache['gender'] |
['1'=>'男', '2'=>'女'] |
| 持久缓存 | dict_gender(前缀 CACHE_PREFIX='dict_') |
['1'=>'男', '2'=>'女'] |
缓存生命周期
1. 首次查询 → 数据库 → 写入持久缓存 + 请求级缓存
2. 同一请求再次命中 → 直接返回请求级缓存(最快)
3. 不同请求命中 → 读取持久缓存(不查库)
4. 缓存过期(TTL 见 DictCacheService::CACHE_TTL)→ 重新查库 → 更新两级缓存
5. 字典项变更 → DictItemObserver 自动调用 clearCache() → 下次查询重新加载
核心方法
getText — 根据值获取名称(最常用)
DictCacheService::getText('gender', 1); // '男'
DictCacheService::getText('user_status', 1); // '正常'
DictCacheService::getText('gender', ''); // ''(空值返回空字符串)
DictCacheService::getText('gender', null); // ''(空值返回空字符串)
用途: 列表展示时将数据库值转换为可读名称。
getValue — 根据名称反向获取值
DictCacheService::getValue('gender', '男'); // '1'
DictCacheService::getValue('user_status', '正常'); // '1'
DictCacheService::getValue('gender', ''); // ''(空值返回空字符串)
用途: Excel 导入时将中文文字转换为数据库存储的数值(ExampleService::import() 即用此方法反查状态文本)。
getOptions — 获取下拉框选项
DictCacheService::getOptions('gender');
// [
// ['label' => '男', 'value' => '1'],
// ['label' => '女', 'value' => '2'],
// ]
用途: 前端下拉框、单选框、复选框组件的数据源。
getItems — 获取值→名称映射
DictCacheService::getItems('gender');
// ['1' => '男', '2' => '女']
getBatchTextMaps — 批量获取多个字典的映射
DictCacheService::getBatchTextMaps(['gender', 'user_status']);
// [
// 'gender' => ['1' => '男', '2' => '女'],
// 'user_status' => ['1' => '正常', '2' => '禁用'],
// ]
用途: 列表翻译时一次取多个字典,避免逐个查询。
clearCache / clearAllCache — 缓存管理
DictCacheService::clearCache('gender'); // 清除指定字典的缓存
DictCacheService::clearCache(); // 仅清空请求级缓存
DictCacheService::clearAllCache(); // 清除所有字典持久缓存
方法清单
| 方法 | 说明 | 返回值 |
|---|---|---|
getText($dictCode, $value) |
值 → 名称 | string |
getValue($dictCode, $text) |
名称 → 值 | string |
getItems($dictCode) |
获取值→名称映射 | array ['1'=>'男', '2'=>'女'] |
getOptions($dictCode) |
获取下拉框选项 | array [['label'=>'男','value'=>'1'], ...] |
getBatchTextMaps($codes) |
批量获取多个字典映射 | array [code => map, ...] |
clearCache($dictCode?) |
清除指定/请求级缓存 | void |
clearAllCache() |
清除所有字典缓存 | void |
在 Service 中使用
自动翻译(serializeMaps)
配置 serializeMaps 后(需 use HasSerializeMaps),查询数据时自动补全 {字段名}Text 字段,无需手动调用 DictCacheService:
class UserService extends BaseTenantService
{
/**
* 字典翻译配置:[字段 => 字典编码]
*
* @var array<string, string>
*/
protected array $serializeMaps = [
'gender' => 'gender',
'status' => 'user_status',
];
}
效果:
数据库:{ gender: 1, status: 1 }
│
▼ processSerializeMapsList()
│ DictCacheService 批量取词(getBatchTextMaps,同一请求只查一次)
│ getText('gender', 1) → '男'
│ getText('user_status', 1) → '正常'
▼
前端接收:{ gender: 1, genderText: '男', status: 1, statusText: '正常' }
手动调用
// 在 Service 中手动调用
$genderText = DictCacheService::getText('gender', $user['gender']);
$options = DictCacheService::getOptions('gender');
在 Controller 中使用
获取字典项(前端下拉数据源)
# routes/api.php(认证组内)
GET /api/dict/item/getDictItemList/{code}
刷新字典缓存
/**
* 刷新字典缓存
*
* GET /api/dict/refreshCache
*/
public function refreshCache(): JsonResponse
{
DictCacheService::clearAllCache();
return $this->success(null, '缓存刷新成功');
}
在导入导出中使用
导入时:文字转值
// ExampleService::import()(来自项目实际代码)
foreach ($data as &$row) {
// Excel 中"在用" → 数据库中 1
if (! empty($row['status']) && ! is_numeric($row['status'])) {
$row['status'] = DictCacheService::getValue('example_status', $row['status']);
}
}
unset($row);
导出时:值转文字
// 导出表头使用 Text 后缀字段(由 serializeMaps 自动补全)
$headers = [
'name' => '名称',
'statusText' => '状态', // 自动翻译后的字段
];
前端集成
获取字典选项
// API
export function getDictItemByCode(code: string) {
return http.request({ url: `/dict/item/getDictItemList/${code}`, method: 'GET' });
}
// 使用
const genderOptions = ref([]);
onMounted(async () => {
genderOptions.value = await getDictItemByCode('gender');
});
下拉框组件
<template>
<el-select v-model="form.gender" placeholder="请选择性别">
<el-option
v-for="item in genderOptions"
:key="item.value"
:label="item.name"
:value="item.value"
/>
</el-select>
</template>
数据库表结构
laravel_dict(字典主表)
| 字段 | 类型 | 说明 | 示例 |
|---|---|---|---|
id |
INT | 主键 | 1 |
name |
VARCHAR(50) | 字典名称 | 性别 |
code |
VARCHAR(50) | 字典编码(唯一) | gender |
remark |
VARCHAR(500) | 备注 | 性别字典 |
... |
公共字段 |
laravel_dict_item(字典项表)
| 字段 | 类型 | 说明 | 示例 |
|---|---|---|---|
id |
INT | 主键 | 1 |
dict_id |
INT | 字典 ID(外键) | 1 |
name |
VARCHAR(50) | 项名称(显示标签) | 男 |
value |
VARCHAR(50) | 项值 | 1 |
sort |
INT | 排序 | 1 |
note |
VARCHAR(200) | 备注 | |
... |
公共字段 |
字典编码规范
| 字典编码 | 名称 | 项值 | 用途 |
|---|---|---|---|
gender |
性别 | 1=男, 2=女, 3=保密 | 用户性别 |
user_status |
用户状态 | 1=正常, 2=禁用 | 用户账号状态 |
tenant_status |
租户状态 | 1=启用, 0=禁用 | 租户状态 |
example_type |
案例类型 | 1=类型1, 2=类型2, 3=类型3, 4=类型4 | 案例分类 |
example_status |
案例状态 | 1=在用, 2=停用 | 案例状态 |
(项值以数据库初始化脚本中的实际字典项为准。)
缓存管理
缓存失效时机
| 时机 | 操作 | 说明 |
|---|---|---|
| 字典项新增/修改/删除 | DictItemObserver 自动清除 |
模型事件触发,无需手动 |
| 手动刷新 | GET /api/dict/refreshCache |
清除所有字典缓存 |
| 命令行清理 | php artisan dict:clear-cache |
运维兜底 |
| 缓存过期 | 自动失效 | TTL 见 CACHE_TTL |
:::tip 缓存一致性已自动保障
字典项(DictItem)保存/删除时 DictItemObserver 自动调用 clearCache($code)——业务代码无需手动刷新;上面的手动接口与命令仅作兜底(如直接改库绕过模型事件)。
:::
安全特性
| 特性 | 说明 |
|---|---|
| 两级缓存 | 请求级 + 持久缓存,减少数据库压力 |
| 空值安全 | getText/getValue 对 null/空字符串返回空字符串 |
| 类型安全 | 值统一转为字符串比较,避免类型松散比较问题 |
| 缓存隔离 | 每个字典编码独立缓存,互不影响 |
| 自动失效 | Observer 保证数据变更后缓存不脏 |