文章目录
- [JEECG Boot------数据字典管理](#JEECG Boot——数据字典管理)
-
- 一、核心定位与设计理念
-
- [1. 核心价值](#1. 核心价值)
- [2. 整体架构分层](#2. 整体架构分层)
- 二、底层数据模型与存储设计
-
- [1. 字典主表:sys_dict](#1. 字典主表:sys_dict)
- [2. 字典项从表:sys_dict_item](#2. 字典项从表:sys_dict_item)
- 三、后端核心能力体系
-
- [1. 核心注解:@Dict 字典翻译注解](#1. 核心注解:@Dict 字典翻译注解)
-
- [1.1 注解核心参数](#1.1 注解核心参数)
- [1.2 两大核心用法](#1.2 两大核心用法)
- [1.3 配套校验注解:@DictVerify](#1.3 配套校验注解:@DictVerify)
- [2. 翻译核心:DictAspect AOP切面](#2. 翻译核心:DictAspect AOP切面)
-
- [2.1 核心工作机制](#2.1 核心工作机制)
- [2.2 关键特性](#2.2 关键特性)
- [3. 缓存机制](#3. 缓存机制)
-
- [3.1 后端Redis缓存](#3.1 后端Redis缓存)
- [3.2 前端本地缓存](#3.2 前端本地缓存)
- [4. 核心API接口](#4. 核心API接口)
- [5. 高级扩展能力](#5. 高级扩展能力)
- [四、前端核心组件:JDictSelectTag 全解析](#四、前端核心组件:JDictSelectTag 全解析)
-
- [1. 组件核心定位](#1. 组件核心定位)
- [2. 核心API参数](#2. 核心API参数)
- [3. 基础用法示例](#3. 基础用法示例)
-
- [3.1 普通字典用法](#3.1 普通字典用法)
- [3.2 表字典用法(动态业务表数据)](#3.2 表字典用法(动态业务表数据))
- [3.3 带过滤条件的表字典用法](#3.3 带过滤条件的表字典用法)
- [3.4 不同渲染类型用法](#3.4 不同渲染类型用法)
- [4. 高级用法](#4. 高级用法)
-
- [4.1 表单校验集成](#4.1 表单校验集成)
- [4.2 动态加载与手动获取字典数据](#4.2 动态加载与手动获取字典数据)
- [4.3 表格列自定义渲染](#4.3 表格列自定义渲染)
- 五、全链路工作流程
- 六、最佳实践与规范
-
- [1. 字典设计规范](#1. 字典设计规范)
- [2. 性能优化最佳实践](#2. 性能优化最佳实践)
- [3. 安全规范](#3. 安全规范)
- 七、常见问题与解决方案
-
- [1. @Dict注解翻译不生效](#1. @Dict注解翻译不生效)
- [2. 字典修改后,前端显示旧数据](#2. 字典修改后,前端显示旧数据)
- [3. JDictSelectTag组件数值回显失败](#3. JDictSelectTag组件数值回显失败)
- [4. 表字典查询报SQL注入错误](#4. 表字典查询报SQL注入错误)
JEECG Boot------数据字典管理
JEECG Boot 数据字典管理是平台核心基础能力,通过后端统一配置+注解自动翻译+前端组件化渲染的全链路设计,解决企业级应用中枚举值、状态码、业务常量等静态数据的统一管理、动态更新、全局复用问题,彻底消除代码硬编码,实现一处配置、全系统生效。
一、核心定位与设计理念
1. 核心价值
- 统一管控:集中管理系统内所有静态枚举数据,支持可视化增删改查,无需修改代码即可调整业务选项
- 自动翻译:通过注解实现数据库存储值(如1/2)与前端展示文本(男/女)的自动双向转换,无需手动写翻译逻辑
- 组件化复用 :前端封装
JDictSelectTag等专用组件,一行代码实现字典下拉、单选等渲染,大幅降低开发成本 - 高性能保障:多层级缓存机制,针对读多写少的字典场景做深度优化,减少数据库与接口请求压力
- 扩展性极强:支持普通字典、动态表字典、多租户、多数据源、多级联动等复杂场景,适配各类业务需求
2. 整体架构分层
JEECG Boot 数据字典体系采用前后端分离的四层架构设计,从上到下依次为:
| 架构层级 | 核心载体 | 核心能力 |
|---|---|---|
| 前端渲染层 | JDictSelectTag组件、配套工具函数 | 字典数据渲染、表单绑定、值转换、本地缓存 |
| 接口服务层 | 字典Controller、OpenAPI | 字典数据查询、管理、缓存刷新、权限控制 |
| 核心能力层 | @Dict注解、DictAspect切面、缓存服务 | 自动翻译、动态解析、缓存管理、安全校验 |
| 数据存储层 | sys_dict(主表)、sys_dict_item(从表) | 字典元数据与字典项数据的持久化存储 |
二、底层数据模型与存储设计
JEECG Boot 采用主从表结构实现字典数据的规范化存储,两张核心表通过字典ID关联,支持多租户、低代码应用隔离。
1. 字典主表:sys_dict
存储字典的元数据信息,一个字典编码对应一条主表记录,是全局唯一标识。
| 核心字段 | 字段类型 | 字段说明 | 核心约束 |
|---|---|---|---|
| id | varchar(32) | 主键ID | 非空、主键 |
| dict_name | varchar(100) | 字典名称(界面展示) | 非空 |
| dict_code | varchar(100) | 字典编码(全局唯一调用标识) | 非空、唯一索引 |
| description | varchar(500) | 字典描述 | - |
| del_flag | int(1) | 逻辑删除标志(0未删除 1已删除) | 默认0 |
| tenant_id | int | 租户ID(多租户隔离) | - |
| low_app_id | varchar(32) | 低代码应用ID | - |
2. 字典项从表:sys_dict_item
存储字典对应的具体选项数据,一条主表记录对应多条从表记录,支持排序、禁用、颜色标识等扩展能力。
| 核心字段 | 字段类型 | 字段说明 | 核心约束 |
|---|---|---|---|
| id | varchar(32) | 主键ID | 非空、主键 |
| dict_id | varchar(32) | 关联主表的字典ID | 非空、外键关联 |
| item_text | varchar(100) | 字典项文本(前端展示值) | 非空 |
| item_value | varchar(100) | 字典项值(数据库存储值) | 非空 |
| sort_order | int | 排序号(控制前端展示顺序) | 默认0 |
| status | int(1) | 状态(1启用 0禁用) | 默认1 |
| item_color | varchar(100) | 字典项颜色标识(用于标签、状态展示) | - |
三、后端核心能力体系
1. 核心注解:@Dict 字典翻译注解
@Dict是后端字典能力的核心载体,标注在实体类字段上,框架通过AOP自动完成字典值的翻译,生成字段名_dictText格式的翻译字段。
1.1 注解核心参数
| 参数名 | 适用场景 | 说明 | 示例 |
|---|---|---|---|
| dicCode | 普通字典 | 对应sys_dict表中的字典编码,必填 | @Dict(dicCode = "sex") |
| dictTable | 表字典 | 动态从业务表获取字典数据的表名 | @Dict(dictTable = "sys_user") |
| dicText | 表字典 | 业务表中作为展示文本的字段名 | @Dict(dicText = "realname") |
| dicCode | 表字典 | 业务表中作为存储值的字段名 | @Dict(dicCode = "id") |
| ds | 多数据源场景 | 指定表字典所在的数据源名称 | @Dict(ds = "multi-datasource1") |
1.2 两大核心用法
(1)普通字典用法(系统内置字典)
适用于系统通用枚举值,在字典管理界面配置完成后使用,是最常用的场景。
java
/**
* 性别(1:男 2:女)
* 对应字典编码sex,系统会自动翻译生成 sex_dictText 字段
*/
@Dict(dicCode = "sex")
private Integer sex;
(2)表字典用法(动态业务字典)
适用于需要从业务表动态获取选项的场景,无需在字典管理界面配置,直接关联业务表数据。
java
/**
* 创建人ID,关联用户表,自动翻译为用户真实姓名
* 格式:dictTable=表名, dicText=展示字段, dicCode=存储字段
*/
@Dict(dictTable = "sys_user", dicText = "realname", dicCode = "id")
private String createBy;
1.3 配套校验注解:@DictVerify
用于入参合法性校验,自动校验前端传入的值是否在字典定义的有效值范围内,避免非法数据入库。
java
/**
* 用户状态,仅允许传入字典user_status中定义的有效值
*/
@DictVerify(dictCode = "user_status", message = "用户状态值无效")
private Integer status;
2. 翻译核心:DictAspect AOP切面
字典自动翻译的底层实现基于Spring AOP环绕通知,核心类为DictAspect(部分版本为DictTransformAspect),在接口响应数据返回给前端前,自动扫描@Dict注解并完成翻译注入。
2.1 核心工作机制
- 拦截Controller层返回的响应结果,解析返回数据类型
- 通过反射扫描实体类字段上的
@Dict注解,收集需要翻译的字段 - 批量查询字典数据(普通字典查sys_dict,表字典动态执行SQL查询)
- 将字典值翻译为对应的展示文本,注入到返回对象的
字段名_dictText属性中 - 支持分页对象
IPage、列表List、单个实体等多种返回类型
2.2 关键特性
- 批量查询优化:避免N+1查询问题,一次性加载所有需要翻译的字典数据
- 缓存优先:优先从缓存中读取字典数据,大幅提升翻译性能
- 多数据源支持:通过
ds参数支持跨数据源的表字典翻译 - 白名单防护:表字典查询内置SQL注入防护,仅允许查询白名单内的表与字段
3. 缓存机制
针对字典数据读多写少的特性,JEECG Boot 设计了前后端双层缓存架构,保障高性能访问,同时提供完善的缓存一致性方案。
3.1 后端Redis缓存
| 缓存类型 | 缓存key | 失效策略 | 适用场景 |
|---|---|---|---|
| 普通字典缓存 | sys:dict:cache |
字典新增/编辑/删除时,通过@CacheEvict全量清空主动失效 |
系统内置的固定字典 |
| 表字典缓存 | sys:table:dict:cache:* |
定时失效,默认缓存5分钟,避免业务表数据变更导致的不一致 | 动态业务表字典 |
3.2 前端本地缓存
- 缓存载体:Pinia/Vuex Store + localStorage(支持AES加密)
- 加载策略:懒加载,字典组件首次使用时才请求数据,请求后缓存到Store中
- 刷新机制:支持手动触发全局缓存刷新,字典管理界面修改数据后自动推送刷新事件
4. 核心API接口
平台提供了完善的RESTful API,支持字典的管理、查询、缓存刷新等操作,核心接口如下:
| 接口地址 | 请求方式 | 接口说明 | 核心参数 |
|---|---|---|---|
/sys/dict/list |
GET | 字典主表分页列表 | 字典名称、编码、状态 |
/sys/dict/getDictItems/{dictCode} |
GET | 根据字典编码获取字典项列表 | dictCode(字典编码) |
/sys/dict/queryTableDictItemsByCode |
GET | 获取表字典数据 | table、text、code、filterSql |
/sys/dict/refreshCache |
DELETE | 刷新字典全局缓存 | - |
5. 高级扩展能力
- 多租户隔离:通过tenant_id字段实现不同租户之间的字典数据完全隔离,互不影响
- 多数据源支持:表字典支持指定数据源,实现跨库的字典数据查询与翻译
- Excel导入导出适配:导出时自动将字典值翻译为文本,导入时自动将文本转换为字典存储值,无需手动处理
- AI智能匹配 :代码生成器AI能力可根据字段名称、注释自动匹配对应的字典编码,自动添加
@Dict注解
四、前端核心组件:JDictSelectTag 全解析
JDictSelectTag是JEECG Boot 专为数据字典封装的前端组件,基于Ant Design Vue二次封装,实现了字典数据的一键渲染、双向绑定、自动加载,是前端使用字典的核心载体。
1. 组件核心定位
- 一行代码实现字典下拉、单选框、按钮式单选的渲染
- 自动根据dictCode加载字典数据,无需手动调用接口
- 与平台表单体系深度集成,支持校验、双向绑定、联动等能力
- 内置缓存机制,同字典编码多次使用仅发起一次接口请求
2. 核心API参数
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| dictCode | string | 是 | - | 字典配置核心参数,支持两种格式: 1. 普通字典:字典编码(如sex) 2. 表字典:表名,文本字段,取值字段[,过滤条件] |
| type | string | 否 | select | 组件渲染类型,支持: select:下拉选择框 radio:单选框组 radioButton:按钮式单选框 |
| v-model:value | string/number/array | 是 | - | 双向绑定的值,对应字典项的itemValue |
| placeholder | string | 否 | - | 输入框占位提示文本 |
| stringToNumber | boolean | 否 | false | 是否将字典value从string自动转为number,解决数值类型回显失败问题 |
| disabled | boolean | 否 | false | 是否禁用整个组件 |
| showChooseOption | boolean | 否 | true | 是否显示【请选择】默认选项 |
| getPopupContainer | function | 否 | () => document.body | 下拉菜单渲染父节点,解决滚动定位问题 |
3. 基础用法示例
3.1 普通字典用法
vue
<template>
<!-- 性别字典下拉框,对应字典编码sex -->
<JDictSelectTag
v-model:value="queryParam.sex"
placeholder="请选择用户性别"
dictCode="sex"
/>
</template>
<script setup>
import { ref } from 'vue';
const queryParam = ref({
sex: ''
});
</script>
3.2 表字典用法(动态业务表数据)
vue
<!-- 从用户表获取数据,展示realname,存储id -->
<JDictSelectTag
v-model:value="queryParam.userId"
placeholder="请选择用户"
dictCode="sys_user,realname,id"
/>
3.3 带过滤条件的表字典用法
vue
<!-- 只查询性别为女的用户,过滤条件sex = '2' -->
<JDictSelectTag
v-model:value="queryParam.userId"
placeholder="请选择女性用户"
dictCode="sys_user,realname,id,sex = '2'"
/>
3.4 不同渲染类型用法
vue
<!-- 按钮式单选框 -->
<JDictSelectTag
v-model:value="formData.status"
dictCode="order_status"
type="radioButton"
/>
<!-- 普通单选框组 -->
<JDictSelectTag
v-model:value="formData.auditType"
dictCode="audit_type"
type="radio"
/>
4. 高级用法
4.1 表单校验集成
vue
<template>
<a-form :model="formData" :rules="rules">
<a-form-item label="用户性别" name="sex">
<JDictSelectTag
v-model:value="formData.sex"
dictCode="sex"
placeholder="请选择性别"
/>
</a-form-item>
</a-form>
</template>
<script setup>
import { reactive, ref } from 'vue';
const formData = reactive({ sex: '' });
const rules = {
sex: [{ required: true, message: '请选择性别', trigger: 'change' }]
};
</script>
4.2 动态加载与手动获取字典数据
组件配套提供了工具函数,支持手动加载字典数据、自定义翻译场景,核心函数位于@/components/dict/JDictSelectUtil.ts。
vue
<script setup>
import { initDictOptions, filterDictText } from '@/components/dict/JDictSelectUtil';
import { ref, onMounted } from 'vue';
const sexDictOptions = ref([]);
// 手动加载字典数据
const loadDictData = async () => {
const res = await initDictOptions('sex');
if (res.success) {
sexDictOptions.value = res.result;
}
};
// 手动翻译字典值
const getSexText = (value) => {
return filterDictText(sexDictOptions.value, value);
};
onMounted(() => {
loadDictData();
});
</script>
4.3 表格列自定义渲染
vue
<template>
<a-table :columns="columns" :data-source="tableData" />
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { initDictOptions, filterDictText } from '@/components/dict/JDictSelectUtil';
const sexDictOptions = ref([]);
const tableData = ref([]);
const columns = [
{
title: '用户名',
dataIndex: 'username',
align: 'center'
},
{
title: '性别',
dataIndex: 'sex',
align: 'center',
customRender: ({ text }) => {
// 手动翻译字典值为文本
return filterDictText(sexDictOptions.value, text);
}
}
];
onMounted(async () => {
// 初始化字典数据
const res = await initDictOptions('sex');
sexDictOptions.value = res.success ? res.result : [];
});
</script>
五、全链路工作流程
从字典配置到前端渲染的完整闭环流程如下:
- 后台配置:管理员在系统管理-字典管理界面,新增字典主表记录,维护对应的字典项,配置完成后保存
- 后端实体配置 :在业务实体类的对应字段上,添加
@Dict注解,指定字典编码或表字典配置 - 接口响应翻译 :前端请求业务接口时,
DictAspect切面自动拦截响应数据,扫描@Dict注解,完成字典翻译,注入_dictText字段返回给前端 - 前端组件渲染 :前端页面使用
JDictSelectTag组件,通过dictCode指定字典编码,组件自动加载字典数据,渲染为下拉/单选组件,实现双向绑定 - 缓存更新:当字典数据发生修改时,系统自动清空后端Redis缓存,同时推送事件通知前端刷新本地缓存,保障前后端数据一致性
- 数据入库校验 :前端提交表单时,可通过
@DictVerify注解自动校验提交的值是否在字典有效值范围内,拦截非法数据
六、最佳实践与规范
1. 字典设计规范
- 编码规范 :字典编码使用下划线命名法,语义清晰,如
user_status、order_type,禁止使用拼音、无意义缩写 - 值类型规范:字典项值优先使用数字编码(1/2/3),避免使用中文,特殊场景可使用字符串,保持全系统统一
- 分类规范:按业务模块对字典进行分类,如系统模块、订单模块、用户模块,避免混乱
- 禁用规范:字典项废弃时优先禁用,而非直接删除,避免历史数据翻译失败
2. 性能优化最佳实践
- 高频使用的字典,在系统启动时进行缓存预热,减少首次访问延迟
- 表字典尽量使用简单过滤条件,避免复杂SQL导致的性能问题
- 前端页面多个地方使用同一字典时,优先在页面初始化时一次性加载,而非每个组件单独加载
- 大批量数据翻译时,优先使用后端
@Dict注解自动翻译,避免前端循环翻译导致的页面卡顿
3. 安全规范
- 表字典严格遵守平台白名单机制,禁止在dictCode中拼接复杂SQL、子查询,避免SQL注入风险
- 敏感业务表禁止作为表字典使用,避免数据泄露
- 字典管理界面配置严格的权限控制,仅允许管理员进行字典的增删改操作
七、常见问题与解决方案
1. @Dict注解翻译不生效
问题表现 :接口返回数据中没有生成_dictText字段
核心原因与解决方案:
- 原因1:接口返回类型不是
IPage、Result<IPage>等切面默认支持的类型
解决方案:扩展DictAspect切面,增加对List、Result<T>等类型的支持 - 原因2:实体类字段使用了
private修饰,且没有对应的getter方法
解决方案:为字段添加getter/setter方法,或使用lombok的@Data注解 - 原因3:字典编码配置错误,或字典项被禁用
解决方案:检查字典管理界面,确认字典编码正确、字典项状态为启用
2. 字典修改后,前端显示旧数据
问题表现 :后台修改字典项后,前端页面仍显示旧的字典数据,刷新页面也不生效
解决方案:
- 手动点击系统右上角的【刷新缓存】按钮,清空前端本地缓存
- 检查后端字典编辑接口是否添加了
@CacheEvict注解,确保修改后清空Redis缓存 - 表字典数据修改后,等待缓存自动过期(默认5分钟),或手动调用缓存刷新接口
3. JDictSelectTag组件数值回显失败
问题表现 :编辑表单时,数据库中的数值无法回显到组件中
核心原因 :字典itemValue是string类型,而表单绑定的值是number类型,类型不匹配
解决方案 :添加stringToNumber属性,自动将字典value转为number类型
vue
<JDictSelectTag
v-model:value="formData.sex"
dictCode="sex"
:stringToNumber="true"
/>
4. 表字典查询报SQL注入错误
问题表现 :使用表字典时,控制台提示SQL注入拦截,无法查询数据
解决方案:
- 检查使用的表名、字段名是否在平台的字典表白名单中
- 过滤条件仅支持简单的
字段=值格式,禁止使用子查询、函数、OR等复杂语法 - 避免在表名、字段名中使用关键字、特殊字符