RuoYi扩展插件开发:自定义字典类型实战案例

RuoYi扩展插件开发:自定义字典类型实战案例

【免费下载链接】RuoYi :tada: (RuoYi)官方仓库 基于SpringBoot的权限管理系统 易读易懂、界面简洁美观。 核心技术采用Spring、MyBatis、Shiro没有任何其它重度依赖。直接运行即可用 【免费下载链接】RuoYi 项目地址: https://gitcode.com/gh_mirrors/ruoyi/RuoYi

一、痛点解析:为什么需要自定义字典类型?

你是否还在为系统中充斥的硬编码枚举值而烦恼?当业务需要新增状态类型时,是否必须修改Java代码并重启服务?在企业级应用开发中,字典管理(Dictionary Management)是解决这类问题的关键组件。RuoYi框架作为基于SpringBoot的权限管理系统,内置了完善的字典管理功能,但多数开发者仅停留在基础使用层面,未能充分发挥其扩展能力。

本文将通过一个实战案例,带你从零构建一个"订单状态"自定义字典插件,彻底解决硬编码痛点。读完本文后,你将掌握

  • 字典类型的设计原理与缓存机制
  • 自定义字典的完整开发流程(后端接口+前端界面)
  • 字典数据在代码生成器中的集成应用
  • 高性能字典查询的实现方案

二、字典类型系统架构深度剖析

2.1 核心类关系图

mermaid

2.2 字典系统工作流程图

mermaid

三、开发准备:环境与技术栈

3.1 开发环境配置

组件版本要求备注
JDK1.8+推荐OpenJDK 1.8.0_301
SpringBoot2.5.xRuoYi框架默认版本
Maven3.6+依赖管理工具
MySQL8.0+数据库服务器
IDEIntelliJ IDEA推荐2021.2+版本
Git2.30+版本控制工具

3.2 项目目录结构解析

RuoYi/
├── ruoyi-admin/           # 管理后台模块
│   └── src/main/java/com/ruoyi/web/controller/system/
│       └── SysDictTypeController.java  # 字典类型控制器
├── ruoyi-common/          # 通用工具模块
│   └── src/main/java/com/ruoyi/common/core/domain/entity/
│       ├── SysDictType.java            # 字典类型实体
│       └── SysDictData.java            # 字典数据实体
├── ruoyi-system/          # 系统核心模块
│   ├── src/main/java/com/ruoyi/system/service/
│   │   ├── ISysDictTypeService.java    # 字典类型服务接口
│   │   └── impl/SysDictTypeServiceImpl.java  # 服务实现类
│   └── src/main/java/com/ruoyi/system/mapper/
│       ├── SysDictTypeMapper.java      # 字典类型数据访问接口
│       └── SysDictDataMapper.java      # 字典数据访问接口
└── sql/                   # 数据库脚本
    └── ry_20250416.sql    # 包含字典表结构的初始化脚本

3.3 核心依赖引入

ruoyi-system/pom.xml中确认以下依赖:

<!-- 字典核心依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3.4</version>
</dependency>

四、实战开发:自定义"订单状态"字典类型

4.1 数据库表结构设计

虽然RuoYi框架已提供字典表结构,我们仍需了解其设计细节:

sys_dict_type表结构(字典类型表):

CREATE TABLE `sys_dict_type` (
  `dict_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '字典主键',
  `dict_name` varchar(100) NOT NULL COMMENT '字典名称',
  `dict_type` varchar(100) NOT NULL COMMENT '字典类型',
  `status` char(1) NOT NULL DEFAULT '0' COMMENT '状态(0正常 1停用)',
  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`dict_id`),
  UNIQUE KEY `uk_dict_type` (`dict_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='字典类型表';

sys_dict_data表结构(字典数据表):

CREATE TABLE `sys_dict_data` (
  `dict_code` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '字典编码',
  `dict_sort` int(11) NOT NULL DEFAULT '0' COMMENT '字典排序',
  `dict_label` varchar(100) NOT NULL COMMENT '字典标签',
  `dict_value` varchar(100) NOT NULL COMMENT '字典键值',
  `dict_type` varchar(100) NOT NULL COMMENT '字典类型',
  `css_class` varchar(100) DEFAULT NULL COMMENT '样式属性(其他样式扩展)',
  `list_class` varchar(100) DEFAULT NULL COMMENT '表格字典样式',
  `is_default` char(1) DEFAULT 'N' COMMENT '是否默认(Y是 N否)',
  `status` char(1) NOT NULL DEFAULT '0' COMMENT '状态(0正常 1停用)',
  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`dict_code`),
  KEY `idx_dict_type` (`dict_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='字典数据表';

4.2 实体类定义

SysDictType.java(字典类型实体):

package com.ruoyi.common.core.domain.entity;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.annotation.Excel.ColumnType;
import com.ruoyi.common.core.domain.BaseEntity;

public class SysDictType extends BaseEntity {
    private static final long serialVersionUID = 1L;

    /** 字典主键 */
    @Excel(name = "字典主键", cellType = ColumnType.NUMERIC)
    private Long dictId;

    /** 字典名称 */
    @Excel(name = "字典名称")
    @NotBlank(message = "字典名称不能为空")
    @Size(min = 0, max = 100, message = "字典类型名称长度不能超过100个字符")
    private String dictName;

    /** 字典类型 */
    @Excel(name = "字典类型")
    @NotBlank(message = "字典类型不能为空")
    @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符")
    private String dictType;

    /** 状态(0正常 1停用) */
    @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
    private String status;

    // Getters and Setters
    @Override
    public String toString() {
        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
            .append("dictId", getDictId())
            .append("dictName", getDictName())
            .append("dictType", getDictType())
            .append("status", getStatus())
            .append("createBy", getCreateBy())
            .append("createTime", getCreateTime())
            .append("updateBy", getUpdateBy())
            .append("updateTime", getUpdateTime())
            .append("remark", getRemark())
            .toString();
    }
}

4.3 服务层实现

ISysDictTypeService接口

public interface ISysDictTypeService {
    /**
     * 根据条件分页查询字典类型
     * 
     * @param dictType 字典类型信息
     * @return 字典类型集合信息
     */
    public List<SysDictType> selectDictTypeList(SysDictType dictType);
    
    /**
     * 根据所有字典类型
     * 
     * @return 字典类型集合信息
     */
    public List<SysDictType> selectDictTypeAll();
    
    /**
     * 根据字典类型查询字典数据
     * 
     * @param dictType 字典类型
     * @return 字典数据集合信息
     */
    public List<SysDictData> selectDictDataByType(String dictType);
    
    /**
     * 通过字典ID查询字典类型信息
     * 
     * @param dictId 字典ID
     * @return 字典类型信息
     */
    public SysDictType selectDictTypeById(Long dictId);
    
    /**
     * 通过字典类型查询字典类型信息
     * 
     * @param dictType 字典类型
     * @return 字典类型信息
     */
    public SysDictType selectDictTypeByType(String dictType);
    
    /**
     * 批量删除字典类型
     * 
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    public int deleteDictTypeByIds(String ids);
    
    /**
     * 清空缓存数据
     */
    public void resetDictCache();
    
    /**
     * 新增保存字典类型信息
     * 
     * @param dictType 字典类型信息
     * @return 结果
     */
    public int insertDictType(SysDictType dictType);
    
    /**
     * 修改保存字典类型信息
     * 
     * @param dictType 字典类型信息
     * @return 结果
     */
    public int updateDictType(SysDictType dictType);
    
    /**
     * 校验字典类型称是否唯一
     * 
     * @param dictType 字典类型
     * @return 结果
     */
    public boolean checkDictTypeUnique(SysDictType dictType);
}

SysDictTypeServiceImpl实现类

@Service
public class SysDictTypeServiceImpl implements ISysDictTypeService {
    @Autowired
    private SysDictTypeMapper dictTypeMapper;
    
    @Autowired
    private SysDictDataMapper dictDataMapper;

    @Override
    public List<SysDictType> selectDictTypeList(SysDictType dictType) {
        return dictTypeMapper.selectDictTypeList(dictType);
    }

    @Override
    public List<SysDictData> selectDictDataByType(String dictType) {
        List<SysDictData> dictDatas = DictUtils.getDictCache(dictType);
        if (StringUtils.isNotNull(dictDatas)) {
            return dictDatas;
        }
        dictDatas = dictDataMapper.selectDictDataByType(dictType);
        if (StringUtils.isNotNull(dictDatas)) {
            DictUtils.setDictCache(dictType, dictDatas);
        }
        return dictDatas;
    }

    @Override
    public int insertDictType(SysDictType dictType) {
        int row = dictTypeMapper.insertDictType(dictType);
        if (row > 0) {
            DictUtils.clearDictCache();
        }
        return row;
    }

    @Override
    public int updateDictType(SysDictType dictType) {
        SysDictType oldDict = dictTypeMapper.selectDictTypeById(dictType.getDictId());
        dictDataMapper.updateDictDataType(oldDict.getDictType(), dictType.getDictType());
        int row = dictTypeMapper.updateDictType(dictType);
        if (row > 0) {
            DictUtils.clearDictCache();
        }
        return row;
    }

    @Override
    public boolean checkDictTypeUnique(SysDictType dictType) {
        Long dictId = StringUtils.isNull(dictType.getDictId()) ? -1L : dictType.getDictId();
        SysDictType info = dictTypeMapper.checkDictTypeUnique(dictType.getDictType());
        if (StringUtils.isNotNull(info) && info.getDictId().longValue() != dictId.longValue()) {
            return false;
        }
        return true;
    }
}

4.4 控制器实现

SysDictTypeController.java

@Controller
@RequestMapping("/system/dict")
public class SysDictTypeController extends BaseController {
    private String prefix = "system/dict/type";

    @Autowired
    private ISysDictTypeService dictTypeService;

    @RequiresPermissions("system:dict:view")
    @GetMapping()
    public String dictType() {
        return prefix + "/type";
    }

    @RequiresPermissions("system:dict:list")
    @PostMapping("/list")
    @ResponseBody
    public TableDataInfo list(SysDictType dictType) {
        startPage();
        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
        return getDataTable(list);
    }
    
    @RequiresPermissions("system:dict:add")
    @GetMapping("/add")
    public String add() {
        return prefix + "/add";
    }

    @RequiresPermissions("system:dict:add")
    @Log(title = "字典类型", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @ResponseBody
    public AjaxResult addSave(@Validated SysDictType dict) {
        if (!dictTypeService.checkDictTypeUnique(dict)) {
            return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
        }
        dict.setCreateBy(getLoginName());
        return toAjax(dictTypeService.insertDictType(dict));
    }

    @RequiresPermissions("system:dict:edit")
    @GetMapping("/edit/{dictId}")
    public String edit(@PathVariable("dictId") Long dictId, ModelMap mmap) {
        mmap.put("dict", dictTypeService.selectDictTypeById(dictId));
        return prefix + "/edit";
    }

    @RequiresPermissions("system:dict:edit")
    @Log(title = "字典类型", businessType = BusinessType.UPDATE)
    @PostMapping("/edit")
    @ResponseBody
    public AjaxResult editSave(@Validated SysDictType dict) {
        if (!dictTypeService.checkDictTypeUnique(dict)) {
            return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
        }
        dict.setUpdateBy(getLoginName());
        return toAjax(dictTypeService.updateDictType(dict));
    }

    @RequiresPermissions("system:dict:remove")
    @Log(title = "字典类型", businessType = BusinessType.DELETE)
    @PostMapping("/remove")
    @ResponseBody
    public AjaxResult remove(String ids) {
        return toAjax(dictTypeService.deleteDictTypeByIds(ids));
    }

    @RequiresPermissions("system:dict:remove")
    @Log(title = "字典类型", businessType = BusinessType.CLEAN)
    @GetMapping("/refreshCache")
    @ResponseBody
    public AjaxResult refreshCache() {  
        dictTypeService.resetDictCache();
        return success();
    }
}

4.5 字典工具类DictUtils

DictUtils是字典缓存管理的核心工具类,负责字典数据的缓存读写:

public class DictUtils {
    /**
     * 分隔符
     */
    public static final String SEPARATOR = ",";

    /**
     * 设置字典缓存
     * 
     * @param key 参数键
     * @param dictDatas 字典数据列表
     */
    public static void setDictCache(String key, List<SysDictData> dictDatas) {
        CacheUtils.put(getCacheName(), getCacheKey(key), dictDatas);
    }

    /**
     * 获取字典缓存
     * 
     * @param key 参数键
     * @return dictDatas 字典数据列表
     */
    public static List<SysDictData> getDictCache(String key) {
        Object cacheObj = CacheUtils.get(getCacheName(), getCacheKey(key));
        if (StringUtils.isNotNull(cacheObj)) {
            return StringUtils.cast(cacheObj);
        }
        return null;
    }

    /**
     * 根据字典类型和字典值获取字典标签
     * 
     * @param dictType 字典类型
     * @param dictValue 字典值
     * @return 字典标签
     */
    public static String getDictLabel(String dictType, String dictValue) {
        if (StringUtils.isEmpty(dictValue)) {
            return StringUtils.EMPTY;
        }
        StringBuilder propertyString = new StringBuilder();
        List<SysDictData> datas = getDictCache(dictType);
        if (StringUtils.isNull(datas)) {
            return StringUtils.EMPTY;
        }
        for (SysDictData dict : datas) {
            if (dictValue.equals(dict.getDictValue())) {
                propertyString.append(dict.getDictLabel()).append(SEPARATOR);
            }
        }
        return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
    }

    /**
     * 删除指定字典缓存
     * 
     * @param key 字典键
     */
    public static void removeDictCache(String key) {
        CacheUtils.remove(getCacheName(), getCacheKey(key));
    }

    /**
     * 清空字典缓存
     */
    public static void clearDictCache() {
        CacheUtils.removeAll(getCacheName());
    }

    /**
     * 获取cache name
     * 
     * @return 缓存名
     */
    public static String getCacheName() {
        return Constants.SYS_DICT_CACHE;
    }

    /**
     * 设置cache key
     * 
     * @param configKey 参数键
     * @return 缓存键key
     */
    public static String getCacheKey(String configKey) {
        return Constants.SYS_DICT_KEY + configKey;
    }
}

四、实战案例:创建"订单状态"自定义字典

5.1 步骤1:新增字典类型

  1. 访问系统管理 → 字典管理 → 字典类型页面

  2. 点击"新增"按钮,填写以下信息:

    • 字典名称:订单状态
    • 字典类型:order_status(必须小写字母+下划线)
    • 状态:正常
    • 备注:订单流程状态管理
  3. 点击保存,完成字典类型创建

后台接口调用流程

  • 前端调用 /system/dict/add 接口
  • 后端执行 dictTypeService.insertDictType(dictType)
  • 数据写入 sys_dict_type
  • 清除字典缓存 DictUtils.clearDictCache()

5.2 步骤2:添加字典数据

为"订单状态"字典类型添加具体数据项:

  1. 在字典类型列表点击"订单状态"的"字典数据"按钮
  2. 依次添加以下字典数据:
排序字典标签字典键值状态是否默认样式属性
1待支付0正常Ysuccess
2已支付1正常Nprimary
3已发货2正常Ninfo
4已完成3正常Nsuccess
5已取消4正常Ndanger

数据插入SQL示例

INSERT INTO `sys_dict_data` (`dict_sort`, `dict_label`, `dict_value`, `dict_type`, `is_default`, `status`) 
VALUES 
(1, '待支付', '0', 'order_status', 'Y', '0'),
(2, '已支付', '1', 'order_status', 'N', '0'),
(3, '已发货', '2', 'order_status', 'N', '0'),
(4, '已完成', '3', 'order_status', 'N', '0'),
(5, '已取消', '4', 'order_status', 'N', '0');

5.3 步骤3:前端页面集成

在订单管理页面中使用自定义字典:

订单列表页面(order.html)

<!-- 订单状态列 -->
<th data-field="orderStatus" data-formatter="orderStatusFormatter">订单状态</th>

<script>
// 订单状态格式化函数  
function orderStatusFormatter(value, row, index) {
    // 调用RuoYi框架的字典格式化方法
    return $.table.selectDictLabel('order_status', value);
}

// 订单状态筛选下拉框
<select name="orderStatus" class="form-control selectpicker" data-live-search="true">
    <option value="">所有状态</option>
    <!-- 动态加载字典数据 -->
    <#list @dict.getType("order_status") as dict>
        <option value="${dict.dictValue}">${dict.dictLabel}</option>
    </#list>
</select>
</script>

字典数据加载JavaScript代码

// 页面加载时获取字典数据
$(function() {
    // 获取订单状态字典
    $.get(ctx + "system/dict/data/type/order_status", function(data) {
        // 将字典数据缓存到页面
        window.orderStatusDict = data;
        // 渲染下拉框
        renderOrderStatusSelect();
    });
});

// 渲染订单状态下拉框
function renderOrderStatusSelect() {
    var html = '<option value="">所有状态</option>';
    $.each(window.orderStatusDict, function(index, dict) {
        html += '<option value="' + dict.dictValue + '">' + dict.dictLabel + '</option>';
    });
    $("#orderStatus").html(html);
    // 刷新selectpicker
    $("#orderStatus").selectpicker('refresh');
}

5.4 步骤4:后端业务代码中使用

在Service层使用字典工具类获取字典数据:

@Service
public class OrderServiceImpl implements IOrderService {
    
    @Override
    public List<Order> selectOrderList(Order order) {
        List<Order> orderList = orderMapper.selectOrderList(order);
        
        // 转换订单状态为字典标签
        for (Order item : orderList) {
            // 使用DictUtils获取字典标签
            String statusLabel = DictUtils.getDictLabel("order_status", item.getOrderStatus());
            item.setOrderStatusLabel(statusLabel);
        }
        return orderList;
    }
    
    @Override
    public AjaxResult changeOrderStatus(Long orderId, String status) {
        // 校验状态值是否在字典范围内
        List<SysDictData> statusDict = dictTypeService.selectDictDataByType("order_status");
        boolean isValid = statusDict.stream()
                .anyMatch(dict -> dict.getDictValue().equals(status));
                
        if (!isValid) {
            return AjaxResult.error("订单状态值无效");
        }
        
        Order order = new Order();
        order.setId(orderId);
        order.setOrderStatus(status);
        order.setUpdateBy(SecurityUtils.getUsername());
        return toAjax(orderMapper.updateOrder(order));
    }
}

六、高级应用:集成代码生成器

RuoYi框架的代码生成器支持将字典类型与实体类字段关联,实现自动生成带字典功能的CRUD代码。

6.1 在代码生成器中配置字典

  1. 进入代码生成 → 导入表 → 选择目标表
  2. 点击"编辑"进入字段配置页面
  3. 对需要使用字典的字段(如order_status)进行配置:
    • 字段名称:order_status
    • 字典类型:order_status(选择已创建的字典类型)
    • HTML类型:select(下拉选择框)

配置效果:生成的代码将自动包含:

  • 页面下拉框使用字典数据
  • 列表页状态值自动转换为字典标签
  • 表单验证包含字典值范围检查

6.2 生成代码中的字典应用

生成的Controller层代码示例:

@RestController
@RequestMapping("/system/order")
public class OrderController extends BaseController {
    @Autowired
    private IOrderService orderService;
    
    @GetMapping("/list")
    public TableDataInfo list(Order order) {
        startPage();
        List<Order> list = orderService.selectOrderList(order);
        return getDataTable(list);
    }
    
    // 其他接口...
}

生成的前端页面代码示例(列表页状态列):

{
    field: 'orderStatus', 
    title: '订单状态',
    formatter: function(value, row, index) {
        return $.table.selectDictLabel('order_status', value);
    }
}

生成的表单页面代码示例(状态选择框):

<div class="form-group">
    <label class="col-sm-3 control-label">订单状态:</label>
    <div class="col-sm-8">
        <select name="orderStatus" class="form-control" th:with="type=${@dict.getType('order_status')}">
            <option value="">请选择</option>
            <option th:each="dict : ${type}" th:text="${dict.dictLabel}" th:value="${dict.dictValue}"></option>
        </select>
    </div>
</div>

七、性能优化:字典缓存策略

7.1 缓存实现原理

RuoYi字典系统使用多级缓存机制:

  1. 本地缓存:使用 CacheUtils 工具类(基于ConcurrentHashMap)
  2. Redis缓存:若配置Redis则使用分布式缓存(默认未启用)

缓存更新策略

  • 新增/修改/删除字典时清除缓存
  • 定时任务定期刷新缓存(默认未启用)
  • 支持手动刷新缓存(通过"刷新缓存"按钮)

7.2 性能优化建议

  1. 批量查询优化
// 优化前:多次查询
String status1 = DictUtils.getDictLabel("order_status", "0");
String status2 = DictUtils.getDictLabel("pay_type", "1");

// 优化后:一次查询整个字典
List<SysDictData> orderStatusDict = dictTypeService.selectDictDataByType("order_status");
  1. 缓存预热

在系统启动时加载常用字典到缓存:

@Component
public class DictCacheInitializer implements CommandLineRunner {
    
    @Autowired
    private ISysDictTypeService dictTypeService;
    
    @Override
    public void run(String... args) throws Exception {
        // 预热常用字典缓存
        List<String> commonDictTypes = Arrays.asList("order_status", "pay_type", "user_status");
        for (String dictType : commonDictTypes) {
            dictTypeService.selectDictDataByType(dictType);
        }
    }
}
  1. 使用Redis分布式缓存

修改 application.yml 配置:

# 启用Redis缓存
spring:
  redis:
    host: localhost
    port: 6379
    password: 
    database: 0

# 配置缓存类型为Redis
ruoyi:
  cache:
    type: redis

八、常见问题与解决方案

8.1 字典缓存不刷新问题

问题描述:新增字典数据后,页面仍显示旧数据。

解决方案

  1. 检查是否调用了缓存清除方法 DictUtils.clearDictCache()
  2. 确认当前用户有刷新缓存权限(system:dict:remove
  3. 手动调用刷新缓存接口:GET /system/dict/refreshCache

代码修复示例

// 修改字典数据后强制刷新缓存
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(SysDictData dictData) {
    int rows = dictDataService.updateDictData(dictData);
    if (rows > 0) {
        // 只清除当前字典类型的缓存,而非全部缓存
        DictUtils.removeDictCache(dictData.getDictType());
        return success();
    }
    return error();
}

8.2 字典类型唯一性冲突

问题描述:创建字典类型时提示"字典类型已存在"。

解决方案

  1. 查询数据库确认是否存在重复记录:
    SELECT * FROM sys_dict_type WHERE dict_type = 'order_status';
    
  2. 若存在重复记录,可删除或重命名已有字典类型
  3. 检查是否有其他模块已定义相同字典类型

8.3 字典数据排序异常

问题描述:字典数据显示顺序与配置不符。

解决方案

  1. 确认 dict_sort 字段值是否正确设置
  2. 检查查询SQL是否包含排序条件:
    // 正确的查询方式(包含排序)
    SELECT * FROM sys_dict_data WHERE dict_type = ? ORDER BY dict_sort ASC
    
  3. 清除缓存后重试:DictUtils.removeDictCache("order_status")

九、总结与扩展

9.1 本文核心要点回顾

  1. 字典系统架构:基于sys_dict_typesys_dict_data双表设计,采用缓存机制提高性能
  2. 开发流程:定义字典类型→添加字典数据→前后端集成→业务应用
  3. 性能优化:合理使用缓存、批量查询、缓存预热等技术
  4. 代码生成器集成:通过配置字典类型实现自动化CRUD代码生成

9.2 扩展方向

  1. 字典数据权限控制:基于部门/角色的字典数据隔离
  2. 字典变更日志:记录字典修改历史,支持审计和回滚
  3. 字典导入导出:Excel批量导入导出字典数据
  4. 高级缓存策略:实现字典缓存的过期时间和自动刷新

9.3 下期预告

《RuoYi框架代码生成器高级应用:自定义模板开发实战》

通过本文学习,你已掌握RuoYi框架自定义字典类型的完整开发流程。合理使用字典功能可以显著提高系统的灵活性和可维护性,减少硬编码带来的问题。建议在实际项目中,将所有状态码、类型码等统一使用字典管理,为系统后期扩展奠定基础。

如果你觉得本文对你有帮助,请点赞、收藏、关注三连支持!如有任何问题,欢迎在评论区留言讨论。

【免费下载链接】RuoYi :tada: (RuoYi)官方仓库 基于SpringBoot的权限管理系统 易读易懂、界面简洁美观。 核心技术采用Spring、MyBatis、Shiro没有任何其它重度依赖。直接运行即可用 【免费下载链接】RuoYi 项目地址: https://gitcode.com/gh_mirrors/ruoyi/RuoYi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值