前言:
现在我们对“dictionaryjava”大体比较关注,看官们都想要学习一些“dictionaryjava”的相关知识。那么小编在网上汇集了一些有关“dictionaryjava””的相关内容,希望同学们能喜欢,我们一起来了解一下吧!Java枚举的一大缺点:增加一个枚举项,需要重新发版,不易扩展
数据字典:可以存储key=value形式的任何数据,变更不需要发版,易扩展
实现原理
数据库表设计
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 = '节点键值对';
管理效果图
说明:
节点支持多级
每个节点中可以有任意多个有顺序的“键值”对
数据变更后,点击“更新缓存”,则会把数据库中所有的 节点数据 和 键值数据 以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<String,String> 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<String, Map<String, String>> cache = new HashMap(); //字典本地缓存(速度更快) private String lastUpdateTime = ""; private RedisTemplate<String,String> systemRedisTemplate; public DictCache(RedisTemplate<String,String> 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<String, String> 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<String, Map<String, String>> cache = new HashMap(); //临时的字典缓存 Map<String, JSONObject> 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<String, String> 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<String,String> qqLoginSdkData = dictCache.getDictNodeList("SDK.QQ.LOGIN");
获取某一节点下 某一键 的值,如下:
String appid = dictCache.getDictNodeValue("SDK.QQ.LOGIN", "appid");
应用实例:存放第三方的 appid和appkey等信息存放 状态信息(0-禁用 1-启用)、打开方式(_blank-新窗口 _self-当前窗口...)、... 可以直接返回一个节点列表给前端,展示给用户,让其选择...
提问
如果您对此文档有什么不明白的,可以直接回复 或 联系作者,会第一时间给你解答,写的不好,请见谅