Skip to content

数据字典

在业务开发中,数据字典是管理关键枚举、状态和下拉选项的基础能力。它可以让数据库值、页面展示、Excel 导入导出、代码生成器和业务校验保持同一套口径。

v2.0.0 在原有“字典类型 + 字典项”的基础上新增了 字典来源,用于区分框架内置字典、业务自定义字典以及派生模块字典,避免后续升级时 ID 号段和初始化脚本相互覆盖。

当前模型

v2.0.0 的数据字典由三层组成:

层级表 / 实现说明
字典来源sys_dict_source管理来源编码、来源名称和字典类型 ID 号段,例如 frameworkcustom
字典类型sys_dict_type管理 type_codetype_name,并通过 source_code 归属到某个来源
字典项sys_dict管理具体选项,包含 code_namealiascallback_show_style、排序和显示状态

默认来源如下:

source_codesource_nameID 区间说明
framework框架内置1000 - 1999官方内置字典,升级时应尽量跟随官方
custom业务自定义2000 - 2999默认业务字典来源,适合普通二开业务

字典 ID 仍保持可读规则:

  • 字典类型 ID:在来源区间内递增,例如 framework 下的 10001001
  • 字典项 ID:字典类型ID + 三位自增序号,例如类型 1001 下的字典项为 10010011001002

TIP

如果你维护独立业务模块,建议新增自己的字典来源,例如 shopssocrm,并规划独立号段。这样生成初始化脚本、迁移字典和合并官方升级时更容易判断归属。

管理入口

字典类型与字典项

字典管理页面包含“字典类型”和“字典来源”两个页签:

  • “字典类型”页签用于新增、编辑、删除字典类型,并通过类型编码进入字典项维护。
  • 新增字典类型时必须选择 sourceCode;编辑时来源不允许修改。
  • 框架锁定的字典类型和字典项不建议在页面直接删除或改名。
  • 字典类型列表展示来源名称和来源区间,便于判断当前字典属于框架还是业务。

字典来源入口

字典来源列表

字典来源

字典来源页签用于维护来源编码与 ID 号段。它解决的是“哪些字典由框架维护、哪些字典由业务维护、不同模块是否会抢占同一段 ID”的问题。

字典来源字段:

字段说明
sourceCode来源编码,唯一,新增后不允许修改
sourceName来源名称,用于页面展示
startId / endId字典类型 ID 可用区间
status启用状态
remark备注

后端校验规则:

  • startId 不能大于 endId
  • 来源编码不能重复。
  • 新来源区间不能与已有来源区间重叠。
  • 新来源区间不能覆盖已有字典类型 ID。
  • 修改来源区间时,如果原来源下已有字典类型落在新区间外,则不允许缩小或移动该区间。
  • 删除来源前,必须确保该来源下没有字典类型。

NOTE

sys_dict_source 使用 TableSysDictSourceListener 自动清理 dynamic_dict_source_options 缓存。前端新增、编辑或删除来源后,也会重新拉取该动态字典,让“新增字典类型”弹窗里的来源下拉保持最新。

TIP

截图占位:后续可补充“字典来源列表页”“新增/编辑字典来源弹窗”“字典类型关联来源字段”的截图。

静态字典与动态字典

静态字典

静态字典来自 sys_dict_typesys_dict。系统通过 DefaultStaticDictLoader 加载并缓存字典数据,前端路由初始化时优先获取静态字典,动态字典再按页面需要延迟加载。

常用接口:

能力接口
查询全部字典GET /sys-dict/dict
查询静态字典GET /sys-dict/static
批量按类型查询GET /sys-dict/code?typeCode=account_status&typeCode=data_scope

当前没有 GET /sys-dict/dict/{typeCode} 路径;按类型查询请使用 GET /sys-dict/code,并通过多个 typeCode 参数批量传入。

字典项新增、修改、删除后,后端会清除对应 typeCode 的 Redis 缓存,重新加载字典,并通过 WebSocket 同步字典变更。静态字典全量加载后会写入以下 Redis Key:

Key说明
sys_dict字典 hash 数据,field 为 typeCode
sys_dict:static_loaded静态字典是否已全量加载的标记
sys_dict:static_types已加载的静态字典 typeCode 列表

动态字典

动态字典不固定落库到 sys_dict,而是由业务 Loader 实时生成。例如系统用户、部门、角色、字典来源等选项,会随业务表变化而变化。

当前内置动态字典:

typeCode说明
dynamic_user_options用户信息
dynamic_dept_options部门信息
dynamic_role_options角色信息
dynamic_dict_source_options字典来源

动态字典实现接口为 DynamicDictLoader

java
public interface DynamicDictLoader extends DictLoader {

    String getTypeCode();

    String getTypeName();

    default String getDynamicPrefix() {
        return DYNAMIC_DICT_PREFIX;
    }

    default String getDynamicTypeCode() {
        return getDynamicPrefix() + getTypeCode();
    }
}

DictLoaderFactory 会按完整动态 typeCode 精确注册动态字典加载器。完整 typeCode 默认为 dynamic_ + getTypeCode(),例如 dict_source_options 会变成 dynamic_dict_source_options。如果动态 typeCode 为空或重复,服务启动时会抛出异常,避免同一个下拉来源被多个 Loader 覆盖。

示例:字典来源动态字典会把 sys_dict_source 转为页面下拉选项:

java
@Component
@RequiredArgsConstructor
public class DictSourceOptionDictLoader implements DynamicDictLoader {

    private final RedisCache redisCache;
    private final SysDictSourceService sysDictSourceService;

    @Override
    public String getTypeCode() {
        return DynamicDictEnum.DYNAMIC_DICT_SOURCE_OPTIONS.getTypeCode();
    }

    @Override
    public String getTypeName() {
        return DynamicDictEnum.DYNAMIC_DICT_SOURCE_OPTIONS.getName();
    }

    @Override
    public Map<String, List<DictVO>> loadDict() {
        String key = getDynamicTypeCode();
        if (redisCache.hasHashKey(key)) {
            return Map.of(key, redisCache.getDictByType(key));
        }
        List<DictVO> list = new ArrayList<>();
        // 查询来源并转换为 DictVO 后写入 list
        redisCache.setDict(key, list);
        return Map.of(key, list);
    }
}

前端使用

页面中可以通过 useDict 主动加载字典,并通过 useDictOptions 获取响应式选项:

vue
<script setup lang="ts">
import { useDict } from '@/hooks/useDict';
import { useDictOptions } from '@/hooks/useDictOptions';

useDict(['account_status', 'data_scope', 'dynamic_user_options']);

const accountStatusOptions = useDictOptions('account_status');
const dataScopeOptions = useDictOptions('data_scope');
</script>

ProTable 中,可以把字典选项传给 enum,并通过 fieldNames 指定展示字段:

ts
{
  prop: 'status',
  label: '状态',
  tag: true,
  enum: useDictOptions('account_status'),
  fieldNames: { label: 'codeName', value: 'id', tagType: 'callbackShowStyle' }
}

前端 optionsStore 的加载策略:

  • getAllDictList() 调用 GET /sys-dict/static,用于预热静态字典。
  • getDictOptions(typeCode) 如果发现当前 typeCode 未加载或已过期,会触发 ensureDictByCodes([typeCode])
  • getDictByCodes(typeCodes) 调用 GET /sys-dict/code 批量补拉静态或动态字典。
  • Store 内部通过 loadedTypesexpiredTypesloadingTypes 避免重复请求,并在收到 WebSocket SYNC_DICT 后标记已加载字典过期。

脚本预览与导出

字典管理原本已支持脚本预览与导出。v2.0.0 主要对该能力做了数据库兼容性适配:导出的初始化脚本可按目标数据库生成 MySQL 或 PostgreSQL 口径,便于在不同数据库部署、模块初始化、字典迁移和二开模块发布时复用。

导出前建议确认字典类型、字典项和 sourceCode 都已归属到正确来源,并根据实际部署数据库选择对应脚本类型。MySQL 与 PostgreSQL 在批量插入、冲突处理、字段类型和转义细节上存在差异,不建议跨数据库直接混用导出脚本。

TIP

多维liquibase迁移SQL

使用场景

1. Table、Excel 的展示

表格中显示的数据可以根据字典关联项自动将值转换为对应的名称。例如字段存储的是状态 ID,页面展示的是“正常、禁用、禁言”等可读名称。

dict-table-column

dict-excel-column

2. 编辑页面选择

在编辑页面,字典提供了统一的下拉选项来源。静态字典适合固定状态,动态字典适合用户、部门、角色等实时变化的数据。

dict-edit

3. 代码生成器与字典关联设置

代码生成器支持为字段选择字典类型和字典展示方式。v2.0.0 中生成器会读取静态字典和动态字典类型,并按来源分组展示,便于选择框架内置字典或业务字典。

dict-generator

4. Excel 导入导出

Excel 模板下载和导入解析可以复用字典能力:下载模板时提供可选项,导入时将展示值转换为系统内的字典 ID,减少用户手填编码的错误率。