java枚举怎样使用较为方便 (java枚举类型实用性)

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

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

实现原理

java枚举作为字典使用,java枚举缺点及改善

字典的工作原理图

数据库表设计

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 = '节点键值对';

管理效果图

java枚举作为字典使用,java枚举缺点及改善

字典管理界面

说明:

节点支持多级

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

数据变更后,点击“更新缓存”,则会把数据库中所有的 节点数据 和 键值数据 以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

@Autowired
private DictCache dictCache;

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

Map<String,String> qqLoginSdkData = dictCache.getDictNodeList("SDK.QQ.LOGIN");

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

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

应用实例:

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

java枚举作为字典使用,java枚举缺点及改善

实例效果图

提问

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