java 字典_Java枚举"已过时"-改用“数据字典”

Java枚举的一大缺点:增加一个枚举项,需要重新发版,不易扩展

数据字典:可以存储key=value形式的任何数据,变更不需要发版,易扩展

实现原理

dd9d841cb0eda3467e7663aa300268fa.png

字典的工作原理图

数据库表设计

CREATE TABLE `system_dict_node`  (  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',  `pid` bigint(20) NOT NULL DEFAULT 0 COMMENT '上级ID',  `code` varchar(20) NOT NULL COMMENT '字典code 保存前统一转为大写/小写',  --只能包含字典、数字、下划线  `title` varchar(20) NOT NULL DEFAULT '' COMMENT '字典值',  `leaf` tinyint(1) NOT NULL DEFAULT 0 COMMENT '末级 0-是 1-否',  `remark` varchar(255) DEFAULT NULL COMMENT '说明',  `status` tinyint(1) NULL DEFAULT NULL COMMENT '0-禁用 1-启用',  `order` int(5) NOT NULL COMMENT '显示顺序',  `time` int(10) NULL DEFAULT NULL COMMENT '创建时间',  PRIMARY KEY (`id`) USING BTREE,  INDEX `idx_pid`(`pid`) USING BTREE) ENGINE = InnoDB COMMENT = '节点树';
CREATE TABLE `system_dict_value`  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',  `nid` bigint(20) NOT NULL COMMENT '节点ID',  `code` varchar(255) NOT NULL COMMENT '健',  `value` varchar(2048) NOT NULL COMMENT '值',  `remark` varchar(255) NULL DEFAULT NULL COMMENT '说明',  `status` tinyint(1) NULL DEFAULT NULL COMMENT '0-禁用 1-启用',  `order` int(5) NOT NULL COMMENT '索引 显示顺序 值越大越靠前',  `time` int(10) NULL DEFAULT NULL COMMENT '创建时间',  PRIMARY KEY (`id`) USING BTREE,  INDEX `idx_nid`(`nid`) USING BTREE) ENGINE = InnoDB COMMENT = '节点键值对';

管理效果图

056262ed6ca7ae53fbb0accbb2005195.png

字典管理界面

说明:

节点支持多级

每个节点中可以有任意多个有顺序的“键值”对

数据变更后,点击“更新缓存”,则会把数据库中所有的 节点数据 和 键值数据 以json的形式存到 缓存(Redis中),并更新字典的最后变更时间到缓存(Redis)中

增加字典公共类

下面代码是SpringBoot实现,并封装到Starter中 (不明白什么是SpringBoot Starter可以参考我的其它文章)

@Configuration@ConditionalOnProperty(prefix = "codeyyy.dict", name = "enable", matchIfMissing = true) //是否启用字典@ConditionalOnClass({ EnableScheduling.class, RedisTemplate.class })@EnableScheduling@AutoConfigureAfter(RedisAutoConfiguration.class) //以来缓存(Redis)public class DictConfiguration {    public DictConfiguration() {        log.info("======= SpringBootStarter ======= {}", "dict");    }    @Bean    public DictCache dictCache(RedisTemplate redisTemplate) {        return new DictCache(redisTemplate);    }}
public class DictCache {    private final String KEY_COMMON_DICT_NODE = "common:dict:node:data"; //保存的是节点数据列表    private final String KEY_COMMON_DICT_VALUE = "common:dict:value:data"; //保存的是键值对数据列表    private final String KEY_COMMON_DICT_TIME = "common:dict:time"; //保存的是字典最后变更的时间    protected static Map> cache = new HashMap();  //字典本地缓存(速度更快)    private String lastUpdateTime = "";    private RedisTemplate systemRedisTemplate;    public DictCache(RedisTemplate redisTemplate) {        this.systemRedisTemplate = redisTemplate;        reload();    }    //开放接口:通过节点 和 键 获取 值    public String getDictNodeValue(String dict, String code) {        if(cache.containsKey(dict)) {            return cache.get(dict).get(code);        }else{            return null;        }    }   //通过节点获取键值对列表(有序)    public Map getDictNodeList(String dict) {        if(cache.containsKey(dict)) {            return cache.get(dict);        }else{            return new HashMap();        }    }    //定时监控字典数据是否变更    @Scheduled(fixedDelay = 1000)    public synchronized void reload() {        String value = systemRedisTemplate.opsForValue().get(KEY_COMMON_DICT_TIME);        if(value == null || lastUpdateTime.equals(value)) return; //字典数据是否变更        this.id = value;        Map> cache = new HashMap();        //临时的字典缓存        Map dictCache = new HashMap();        String json = systemRedisTemplate.opsForValue().get(KEY_COMMON_DICT_VALUE);        if(json == null) {            log.warn("Dict Tree Data IS NULL.");            return;        }        JSONArray data = JSONArray.parseArray(json);        for(int i = 0; i < data.size(); i++) {            JSONObject item = data.getJSONObject(i);            dictCache.put(item.getString("id"), item);        }        //dict_node节点缓存        String did = null;        Map codeCache = new HashMap();        json = systemRedisTemplate.opsForValue().get(KEY_COMMON_DICT_NODE);        if(json == null) {            log.warn("Dict Node Data IS NULL.");            return;        }        JSONArray nodeList = JSONArray.parseArray(json);        for(int i = 0; i < nodeList.size(); i++) {            JSONObject item = nodeList.getJSONObject(i);            String code = "";            did = item.getString("tid");            if(!codeCache.containsKey(did)) {                code = "";                JSONObject temp = null;                while(dictCache.containsKey(did)) {                    temp = dictCache.get(did);                    did = temp.getString("pid");                    code = temp.getString("code") + "." + code;                }                if(code.length() > 0) {                    code = code.substring(0, code.length() - 1);                }                codeCache.put(did, code);            }else{                code = codeCache.get(did);            }            if(!cache.containsKey(code)) {                cache.put(code, new LinkedHashMap());            }            cache.get(code).put(item.getString("code").trim(), item.getString("value").trim());        }        DictCache.cache = cache;        log.info("Reload Dict Data Success.");    }}

项目中的使用

action/service中注入dictCache

@Autowiredprivate DictCache dictCache;

获取某一节点下的所有键值,如下:

Map qqLoginSdkData = dictCache.getDictNodeList("SDK.QQ.LOGIN");

获取某一节点下 某一键 的值,如下:

String appid = dictCache.getDictNodeValue("SDK.QQ.LOGIN", "appid");

应用实例:

  1. 存放第三方的 appid和appkey等信息
  2. 存放 状态信息(0-禁用 1-启用)、打开方式(_blank-新窗口 _self-当前窗口...)、... 可以直接返回一个节点列表给前端,展示给用户,让其选择
  3. ...
60459d856155c3d39c4dc8a2cced6cb0.png

实例效果图

提问

如果您对此文档有什么不明白的,可以直接回复 或 联系作者,会第一时间给你解答,写的不好,请见谅

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值