从0到1构建MES系统5-字典管理

191 阅读4分钟

今天我们来讲MES系统的字典管理。字典管理看上去功能可能很简单,实际上他包含的内容还是比较多,麻雀虽小五脏俱全。其中包括:字典管理、缓存管理、枚举类生成、字典解析。

1. 数据库设计

1.1 ER图

Pasted image 20250527153147.png

1.2 表明细

系统字典

字段名类型是否为空默认值描述主键
idBIGINTNOT NULL主键ID
dict_nameVARCHAR(128)NOT NULL字典名称
dict_codeVARCHAR(128)NOT NULL字典编码
descriptionVARCHAR(128)描述
statusINTNOT NULL状态
create_byBIGINT
create_timeDATETIME
update_byBIGINT
update_timeDATETIME
字典项
字段名类型是否为空默认值描述主键
idBIGINTNOT NULL主键ID
dict_idBIGINTNOT NULL字典ID
dict_codeVARCHAR(128)NOT NULL字典编码
item_codeVARCHAR(128)NOT NULL字典项编码
item_textVARCHAR(128)NOT NULL字典项文本
item_valueVARCHAR(128)NOT NULL字典项键值
colorVARCHAR(128)标签颜色
descriptionVARCHAR(128)描述
sortINT排序
statusINT状态
create_timeDATETIME
update_timeDATETIME
create_byBIGINT
update_byBIGINT

2. 功能讲解

2.1 增删查改

Pasted image 20250527160424.png 点击新增,添加字典信息;字典编码、字典名称是必填项

Pasted image 20250527160500.png 点击列表操作列中的【字典项】添加字典项

Pasted image 20250527160611.png 注: 这里的标签颜色,会在使用到字典的对应字段以Tag的形式展示;如下面的客户类型和是否启用。

Pasted image 20250527160816.png

补充: 列表中有一个“刷新缓存”的按钮,虽然字典保存和更新都做了自动刷新,但是有时候也可能出现一些异常情况没有刷新到缓存,所以我在这里做了一个手动刷新的功能。

2.2 生成Java枚举类

很多时候我们创建了字典,但是在后端java代码也需要创建对应的枚举类,这里提供了直接在界面上生成Java枚举类代码。 操作如下: 选择要生产枚举类的字典,点击操作栏中字典项,在弹出的抽屉上点击“生成枚举类按钮”。

Pasted image 20250527161119.png

Pasted image 20250527161140.png 这里实现是通过自定义的Freemarker模版,把字典信息传入生产枚举类。

2.3 后端启动设置字典缓存

应用启动后执行有很多种方法,这里我选择了比较简单的做法:使用@PostContrut注解

//src/main/java/com/hgyc/mom/system/service/impl/SysDictItemServiceImpl.java

/**  
 * 项目启动时,初始化字典到缓存  
 */  
@PostConstruct  
public void init()  
{  
    log.info("加载字典缓存数据!");  
    loadingDictCache();  
}

/**  
 * 加载字典缓存数据  
 */  
@Override  
public void loadingDictCache()  
{  
    LambdaQueryWrapper<SysDictItem> queryWrapper = new LambdaQueryWrapper<>();  
    queryWrapper.eq(SysDictItem::getStatus, CommonStatus.ENABLE.getValue());  
    List<SysDictItem> itemList = this.list(queryWrapper);  
    if (!CollectionUtils.isEmpty(itemList)) {  
        Map<String, List<SysDictItem>> dictDataMap = itemList.stream().collect(Collectors.groupingBy(SysDictItem::getDictCode));  
        for (Map.Entry<String, List<SysDictItem>> entry : dictDataMap.entrySet())  
        {  
            DictUtils.setDictCache(entry.getKey(), entry.getValue().stream().sorted(Comparator.comparing(SysDictItem::getSort)).collect(Collectors.toList()));  
        }  
    }  
}

2.4 字典工具类

/**  
 * 字典工具类  
 *   
 * @author fwj  
 */@Slf4j  
public class DictUtils  
{  
    /**  
     * 分隔符  
     */  
    public static final String SEPARATOR = ",";  
  
    /**  
     * 设置字典缓存  
     *   
* @param key 参数键  
     * @param dictDatas 字典数据列表  
     */  
    public static void setDictCache(String key, List<SysDictItem> dictDatas)  
    {  
        SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas);  
    }  
  
    /**  
     * 获取字典缓存  
     *   
* @param key 参数键  
     * @return dictDatas 字典数据列表  
     */  
    public static List<SysDictItem> getDictCache(String key)  
    {  
        return SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));  
    }  
  
    /**  
     * 根据字典类型和字典值获取字典标签  
     *   
* @param dictType 字典类型  
     * @param dictValue 字典值  
     * @return 字典标签  
     */  
    public static String getDictLabel(String dictType, String dictValue)  
    {  
        if (StringUtils.isEmpty(dictValue))  
        {  
            return StringUtils.EMPTY;  
        }  
        return getDictLabel(dictType, dictValue, SEPARATOR);  
    }  
  
    /**  
     * 根据字典类型和字典标签获取字典值  
     *   
* @param dictType 字典类型  
     * @param dictLabel 字典标签  
     * @return 字典值  
     */  
    public static String getDictValue(String dictType, String dictLabel)  
    {  
        if (StringUtils.isEmpty(dictLabel))  
        {  
            return StringUtils.EMPTY;  
        }  
        return getDictValue(dictType, dictLabel, SEPARATOR);  
    }  
  
    /**  
     * 根据字典类型和字典值获取字典标签  
     *   
* @param dictType 字典类型  
     * @param dictValue 字典值  
     * @param separator 分隔符  
     * @return 字典标签  
     */  
    public static String getDictLabel(String dictType, String dictValue, String separator)  
    {  
        StringBuilder propertyString = new StringBuilder();  
        List<SysDictItem> datas = getDictCache(dictType);  
        if (StringUtils.isNull(datas))  
        {  
            return StringUtils.EMPTY;  
        }  
        if (StringUtils.containsAny(separator, dictValue))  
        {  
            for (SysDictItem dict : datas)  
            {  
                for (String value : dictValue.split(separator))  
                {  
                    if (value.equals(dict.getItemValue()))  
                    {  
                        propertyString.append(dict.getItemText()).append(separator);  
                        break;  
                    }  
                }  
            }  
        }  
        else  
        {  
            for (SysDictItem dict : datas)  
            {  
                if (dictValue.equals(dict.getItemValue()))  
                {  
                    return dict.getItemText();  
                }  
            }  
        }  
        return StringUtils.stripEnd(propertyString.toString(), separator);  
    }  
  
    /**  
     * 根据字典类型和字典标签获取字典值  
     *   
* @param dictType 字典类型  
     * @param dictLabel 字典标签  
     * @param separator 分隔符  
     * @return 字典值  
     */  
    public static String getDictValue(String dictType, String dictLabel, String separator)  
    {  
        StringBuilder propertyString = new StringBuilder();  
        List<SysDictItem> datas = getDictCache(dictType);  
        if (StringUtils.isNull(datas))  
        {  
            return StringUtils.EMPTY;  
        }  
        if (StringUtils.containsAny(separator, dictLabel))  
        {  
            for (SysDictItem dict : datas)  
            {  
                for (String label : dictLabel.split(separator))  
                {  
                    if (label.equals(dict.getItemText()))  
                    {  
                        propertyString.append(dict.getItemValue()).append(separator);  
                        break;  
                    }  
                }  
            }  
        }  
        else  
        {  
            for (SysDictItem dict : datas)  
            {  
                if (dictLabel.equals(dict.getItemText()))  
                {  
                    return dict.getItemValue();  
                }  
            }  
        }  
        return StringUtils.stripEnd(propertyString.toString(), separator);  
    }  
  
    /**  
     * 根据字典类型获取字典所有值  
     *  
     * @param dictType 字典类型  
     * @return 字典值  
     */  
    public static String getDictValues(String dictType)  
    {  
        StringBuilder propertyString = new StringBuilder();  
        List<SysDictItem> datas = getDictCache(dictType);  
        if (StringUtils.isNull(datas))  
        {  
            return StringUtils.EMPTY;  
        }  
        for (SysDictItem dict : datas)  
        {  
            propertyString.append(dict.getItemValue()).append(SEPARATOR);  
        }  
        return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);  
    }  
  
    /**  
     * 根据字典类型获取字典所有标签  
     *  
     * @param dictType 字典类型  
     * @return 字典值  
     */  
    public static String getDictLabels(String dictType)  
    {  
        StringBuilder propertyString = new StringBuilder();  
        List<SysDictItem> datas = getDictCache(dictType);  
        if (StringUtils.isNull(datas))  
        {  
            return StringUtils.EMPTY;  
        }  
        for (SysDictItem dict : datas)  
        {  
            propertyString.append(dict.getItemText()).append(SEPARATOR);  
        }  
        return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);  
    }  
  
    /**  
     * 删除指定字典缓存  
     *   
* @param key 字典键  
     */  
    public static void removeDictCache(String key)  
    {  
        SpringUtils.getBean(RedisCache.class).deleteObject(getCacheKey(key));  
    }  
  
    /**  
     * 清空字典缓存  
     */  
    public static void clearDictCache()  
    {  
        Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.SYS_DICT_KEY + "*");  
        SpringUtils.getBean(RedisCache.class).deleteObject(keys);  
    }  
  
    /**  
     * 设置cache key  
     ** @param configKey 参数键  
     * @return 缓存键key  
     */    public static String getCacheKey(String configKey)  
    {  
        return CacheConstants.SYS_DICT_KEY + configKey;  
    }

2.5 前端表格自动翻译字典

使用自定义组件 <TableDictTag>

import TableDictTag from "@/components/grid/TableDictTag";

···

const columns: ColumnsType<Client> = [
	{
		title: "客户类型",
		width: 120,
		key: "clientType",
		dataIndex: "clientType",
		render: (_, record) => (
			<TableDictTag dictCode="client_type" value={record.clientType ??''}/>)
	},
]

参数说明: dictCode : 字典编码 value : 字典值

效果如下: Pasted image 20250527160816.png

2.6 下拉组件使用字典

使用自定义Hooks :useDictionary 使用如下:

import useDictionary from "@/hooks/system/useDictionary";

...

const statusOptions = useDictionary("system_status");

...

<Select options={statusOptions} allowClear/>

说明: 这里除了使用了自定义hooks外还使用了zustand做了一个本地的store缓存,详细请看源码:

  • src/store/useDictionaryStore.ts
  • src/hooks/system/useDictionary.ts

开源项目地址

欢迎在评论区分享你的技术选型经验,或对本文方案的改进建议!