字典注解

类注解

import lombok.NonNull;
import java.lang.annotation.*;/*** 数据字典类注解** @author huxiang*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DictClass {/*** js字典文件名称 ,不填生成公用js 字典文件*/String dictJsonFile() default "dict";/*** 字典key*/@NonNullString dictKey();
}

属性注解

import lombok.NonNull;import java.lang.annotation.*;/*** 数据字典属性注解** @author huxiang*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DictField {/*** 字典值样式 生成js用*/String cssClass() default "";/*** 字典值对应描述-中文*/@NonNullString dictLabelZH();/*** 字典值对应描述-英文*/@NonNullString dictLabelEN();}

属性拓展注解

import lombok.NonNull;import java.lang.annotation.*;/*** 数据字典拓展属性注解---用于标准数据字典外需要额外生成key-value** @author huxiang*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DictFieldEx {/*** 拓展属性名*/@NonNullString[] propKey();/*** 拓展属性值*/@NonNullString[] propValue();
}

工具类

import com.paratera.console.dict.annotation.DictClass;
import com.paratera.console.dict.annotation.DictField;
import com.paratera.console.dict.annotation.DictFieldEx;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.StringUtils;import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** 数据字典工具类** @author huxiang*/
@Slf4j
public class DictUtils {/*** 缓存后台数据字典数据*/private static ConcurrentHashMap<String, String> dictMap = new ConcurrentHashMap<String, String>();/*** 空格常量*/private static String SPACE1 = "  ";private static String SPACE2 = "    ";private static String SPACE3 = "      ";/*** 数据字典常量类路径*/private static String constansFilePath = "classpath:com/paratera/console/dict/constants/*.class";/*** 数据字典 全限定类名前缀*/private static String constansClassPrefix = "com.paratera.console.dict.constants.";/*** 生成前端json 字典文件路径*/private static String jsonDirUrl = DictUtils.class.getResource("/").getPath() + "dict/";/*** 初始化数据字典数据到缓存(可以在引入项目启动时加载)** @throws IOException* @throws ClassNotFoundException*/public static void initDictMapCache() throws IOException, ClassNotFoundException, NoSuchMethodException,IllegalAccessException, InvocationTargetException, InstantiationException {PathMatchingResourcePatternResolver util = new PathMatchingResourcePatternResolver();Resource[] files = util.getResources(constansFilePath);for (Resource resource : files) {String className = constansClassPrefix+ resource.getFilename().substring(0, resource.getFilename().lastIndexOf("."));Class<?> clazz = Class.forName(className);if (clazz.isAnnotationPresent(DictClass.class)) {DictClass dictClass = clazz.getAnnotation(DictClass.class);String dictKey = dictClass.dictKey();Field[] fields = clazz.getDeclaredFields();Object instance = clazz.getDeclaredConstructor().newInstance();for (Field field : fields) {if (field.isAnnotationPresent(DictField.class)) {DictField dictField = field.getAnnotation(DictField.class);dictMap.put(dictKey + ":" + field.get(instance) + ":zh", dictField.dictLabelZH());dictMap.put(dictKey + ":" + field.get(instance) + ":en", dictField.dictLabelEN());}}}}}/*** 从缓存中获取数据字典值对应的text** @param dictKey* @param dictValue* @param language* @return*/public static String getDictText(String dictKey, String dictValue, String language) {return dictMap.get(dictKey + ":" + dictValue + ":" + language);}/*** 生成json字典文件,可用于前端使用,统一前后端字典值** @throws IOException* @throws ClassNotFoundException*/public static void genJsonFile() throws IOException, ClassNotFoundException, InstantiationException,IllegalAccessException, InvocationTargetException, NoSuchMethodException {PathMatchingResourcePatternResolver util = new PathMatchingResourcePatternResolver();Resource[] files = util.getResources(constansFilePath);StringBuffer sb = new StringBuffer();sb.append("{ \n");for (int j = 0; j < files.length; j++) {Resource resource = files[j];String className = constansClassPrefix+ resource.getFilename().substring(0, resource.getFilename().lastIndexOf("."));Class<?> clazz = Class.forName(className);if (clazz.isAnnotationPresent(DictClass.class)) {DictClass dictClass = clazz.getAnnotation(DictClass.class);String jsonFile = dictClass.dictJsonFile();// 私有json输出流if (jsonFile != null && !jsonFile.equals("dict")) {StringBuffer ss = new StringBuffer();ss.append("{ \n");// 这个地方第二个参数设置为0,主要是区别公用字典的逻辑settingjsonInfo(ss, 0, clazz, dictClass, jsonFile);ss.append("\n}");OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(new File(jsonDirUrl + jsonFile + ".json")), "utf-8");osw.append(sb.toString());osw.close();} else {settingjsonInfo(sb, j, clazz, dictClass, jsonFile);if (j == files.length - 1) {sb.append("\n");}}}}sb.append("\n}");// 公用dict.json输出流OutputStreamWriter outStreamWriter = new OutputStreamWriter(new FileOutputStream(new File(jsonDirUrl + "dict.json")), "utf-8");outStreamWriter.append(sb.toString());outStreamWriter.close();log.debug("json文件已生成,路径为:" + jsonDirUrl + "dict.json");}/*** 设置json内容** @param sb* @param j* @param clazz* @param dictClass* @param jsonFile* @throws IOException*/private static void settingjsonInfo(StringBuffer sb, int j, Class<?> clazz, DictClass dictClass, String jsonFile)throws IOException, InstantiationException, IllegalAccessException, NoSuchMethodException,InvocationTargetException {File file = new File(jsonDirUrl + jsonFile + ".json");if (file.exists()) {log.debug("json文件:" + jsonFile + ".json存在,开始覆盖!");} else {log.debug("json文件:" + jsonFile + ".json不存在,开始创建!");File fileParent = new File(jsonDirUrl);if (!fileParent.exists()) {fileParent.mkdir();}file.createNewFile();}if (j != 0) {sb.append(",\n");}// 添加常量配置Field[] fields = clazz.getDeclaredFields();Object instance = clazz.getDeclaredConstructor().newInstance();boolean dictFieldGenerated = false;for (int i = 0; i < fields.length; i++) {Field field = fields[i];if (field.isAnnotationPresent(DictField.class)) {if (dictFieldGenerated) {sb.append(",");} else {sb.append(SPACE1 + "\"" + dictClass.dictKey() + "\": [");}sb.append("{\n");if (field.getGenericType().toString().equals("class java.lang.Integer")) {sb.append(SPACE2 + "\"dictValue\":" + field.get(instance) + ",\n");} else {sb.append(SPACE2 + "\"dictValue\":\"" + field.get(instance) + "\",\n");}DictField dictField = field.getAnnotation(DictField.class);sb.append(SPACE2 + "\"dictClass\":\"" + dictField.cssClass() + "\",\n");sb.append(SPACE2 + "\"dictLabel\": {\n");sb.append(SPACE3 + "\"zh\": \"" + dictField.dictLabelZH() + "\",\n");sb.append(SPACE3 + "\"en\": \"" + dictField.dictLabelEN() + "\"\n");//拼接拓展属性settingDictFieldEx(sb, field);if (!dictFieldGenerated) {dictFieldGenerated = true;}}}if (dictFieldGenerated) {sb.append("]");}}/*** 根据className生成数据字典json数据** @param className* @return*/public static String getJsonDictByClass(String className) {//如果缓存有,从缓存取,没有,解析后缓存if (dictMap.containsKey(className)) {return dictMap.get(className);}Class<?> clazz = null;try {clazz = Class.forName(className);} catch (ClassNotFoundException e) {log.error("反射获取Class失败:" + e.getMessage());}StringBuffer sb = new StringBuffer();if (clazz.isAnnotationPresent(DictClass.class)) {DictClass dictClass = clazz.getAnnotation(DictClass.class);// 添加常量配置Field[] fields = clazz.getDeclaredFields();Object instance = null;try {instance = clazz.getDeclaredConstructor().newInstance();} catch (Exception e) {log.error("反射获取对象实例失败:" + e.getMessage());}boolean dictFieldGenerated = false;for (int i = 0; i < fields.length; i++) {Field field = fields[i];if (field.isAnnotationPresent(DictField.class)) {if (dictFieldGenerated) {sb.append(",");} else {sb.append("[");}sb.append("{\n");try {if (field.getGenericType().toString().equals("class java.lang.Integer")) {sb.append(SPACE2 + "\"dictValue\":" + field.get(instance) + ",\n");} else {sb.append(SPACE2 + "\"dictValue\":\"" + field.get(instance) + "\",\n");}} catch (IllegalAccessException e) {log.error("反射获取对象实例字段值失败:" + e.getMessage());}sb.append(SPACE2 + "\"dictLabel\": {\n");DictField dictField = field.getAnnotation(DictField.class);sb.append(SPACE3 + "\"zh\": \"" + dictField.dictLabelZH() + "\",\n");sb.append(SPACE3 + "\"en\": \"" + dictField.dictLabelEN() + "\"\n");//拼接拓展属性settingDictFieldEx(sb, field);if (!dictFieldGenerated) {dictFieldGenerated = true;}}}sb.append("]");}//缓存dictMap.put(className, sb.toString());return sb.toString();}/*** 拓展注解处理@DictFieldEx** @param sb* @param field*/private static void settingDictFieldEx(StringBuffer sb, Field field) {DictFieldEx dictFieldEx = field.getAnnotation(DictFieldEx.class);if (dictFieldEx != null) {sb.append(SPACE2 + "},\n");String[] keys = dictFieldEx.propKey();String[] values = dictFieldEx.propValue();for (int k = 0; k < keys.length; k++) {String label = null;//如果value是json字符串,则不再加双引号包裹boolean flag = values[k].trim().startsWith("{") && values[k].trim().endsWith("}");if (flag) {label = SPACE2 + "\"" + keys[k] + "\":" + values[k];} else {label = SPACE2 + "\"" + keys[k] + "\":" + "\"" + values[k];label = label + "\"";}if (k == keys.length - 1) {sb.append(label);continue;}sb.append(label).append(",\n");}} else {sb.append(SPACE2 + "}\n");}sb.append(SPACE1 + "}");}
}

字典常量类配置示例

import com.paratera.console.dict.annotation.DictClass;
import com.paratera.console.dict.annotation.DictField;
import com.paratera.console.dict.annotation.DictFieldEx;/*** 消息类型字典常量类* @date 2021-09-29 10:18:45*/
@DictClass(dictKey = AlarmMessageTypeConstants.DICT_KEY)
public class AlarmMessageTypeConstants {public static final String DICT_KEY = "alarmMessageType";@DictField(dictLabelZH = "存储使用量预警通知", dictLabelEN = "Storage")@DictFieldEx(propKey = {"labelType", "thresholdType", "onOff", "thresholdProps"},propValue = {AlarmMessageCategoriesConstants.STORAGE, "1", "1", """{"unit":"int","unitName":"百分比","descZH":"存储使用量预警阈值(最小70%, 最大100%)","descEN":"Storage usage alarm threshold(min 70%, max 100%)","defaultValue":80,"minValue":70,"maxValue":100,"step":1}"""})public static final Integer STORAGE = 1;@DictField(dictLabelZH = "作业长时间运行通知", dictLabelEN = "Job running overtime")@DictFieldEx(propKey = {"labelType", "thresholdType", "onOff", "thresholdProps"},propValue = {AlarmMessageCategoriesConstants.JOB, "1", "1", """{"unit":"float","unitName":"天","descZH":"作业长时间运行预警阈值(天)","descEN":"Warning threshold for long-time operation of job (days)","defaultValue":1,"minValue":0.5,"maxValue":14,"step":0.5}"""})public static final Integer LONG_JOB = 2;@DictField(dictLabelZH = "账户余额预警通知", dictLabelEN = "Balance not enough")@DictFieldEx(propKey = {"labelType", "thresholdType", "onOff", "thresholdProps"},propValue = {AlarmMessageCategoriesConstants.FEE, "1", "1", """{"unit":"int","unitName":"元","descZH":"账户余额预警阈值(元)","descEN":"Insufficient balance alarm threshold (元)","defaultValue":200,"minValue":1,"maxValue":50000,"step":1}"""})public static final Integer AMOUNT_AVAILABLE = 3;
}

JSON文件格式

{"alarmMessageType": [{"dictValue":1,"dictClass":"","dictLabel": {"zh": "存储使用量预警通知","en": "Storage"},"labelType":"storage","thresholdType":"1","onOff":"1","thresholdProps":{"unit":"int","unitName":"百分比","descZH":"存储使用量预警阈值(最小70%, 最大100%)","descEN":"Storage usage alarm threshold(min 70%, max 100%)","defaultValue":80,"minValue":70,"maxValue":100,"step":1}},{"dictValue":2,"dictClass":"","dictLabel": {"zh": "作业长时间运行通知","en": "Job running overtime"},"labelType":"job","thresholdType":"1","onOff":"1","thresholdProps":{"unit":"float","unitName":"天","descZH":"作业长时间运行预警阈值(天)","descEN":"Warning threshold for long-time operation of job (days)","defaultValue":1,"minValue":0.5,"maxValue":14,"step":0.5}},{"dictValue":3,"dictClass":"","dictLabel": {"zh": "账户余额预警通知","en": "Balance not enough"},"labelType":"fee","thresholdType":"1","onOff":"1","thresholdProps":{"unit":"int","unitName":"元","descZH":"账户余额预警阈值(元)","descEN":"Insufficient balance alarm threshold (元)","defaultValue":200,"minValue":1,"maxValue":50000,"step":1}}]
}

自定义数据字典工具类相关推荐

  1. 自定义日期工具类 java 1614698552

    自定义日期工具类 java 1614698552 需求 思路 演练 日期转字符串的方法 字符串转日期方法 测试类 更多尝试 测试另一个方法

  2. 解密android日志xlog,安卓开发技巧2:自定义日志工具类XLog的实现

    安卓开发技巧二:自定义日志工具类XLog的实现 我们在开发过程中,打印日志是必不可少的一个调试环节,然而,直接使用系统自带的Log日志类,并不能满足我们实际项目的需求:假如我们现在在开发一款比较大的项 ...

  3. 自定义反序列化工具类

    自定义反序列化工具类 在实体类中实现了 implements Serializable 序列化 还实现了 UserDetails 对传入的字段 authorities 返序列化失败 对字段 autho ...

  4. 弄清std::chrono::system_clock::time_point,自定义时间工具类

    time_t 是32位的整数,用来存放格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数,不能表示毫秒,约能表示135年 time ...

  5. hutool 自定义excel_HuTool工具类使用之Excel文档的导入导出

    HuTool工具类使用之Excel文档的导入导出 前言 在日常的工作开发中,Excel的导入和导出是必不可少的,如果自己写相应的导入导出方法,会显得十分繁琐,本文采用Hutool工具类实现的Excel ...

  6. 自定义RunTimeException工具类

    文章目录 自定义异常MyInfoException,将异常提示传递给前端 1. 定义一个异常的工具类extends RuntimeException 2. 封装统一的响应工具类 自定义异常MyInfo ...

  7. JDBC基础篇(MYSQL)——自定义JDBCUtil工具类

    package util;import java.io.File; import java.io.InputStream; import java.sql.Connection; import jav ...

  8. ThinkPHP3验证码、文件上传、缩略图、分页(自定义工具类、session和cookie)

    验证码 TP框架中自带了验证码类 位置:Think/verify.class.php 在LoginController控制器中创建生存验证码的方法 login.html登陆模板中 在LoginCont ...

  9. JAVA集合框架工具类自定义Collections集合方法

    项目中有需要多次统计 某些集合中 的某个属性值,所以考虑封装一个方法,让其其定义实现计算方式. 话不多说,看代码: 1.封装的自定义集合工具类:CollectionsCustom [Java] 纯文本 ...

最新文章

  1. 大四狗找工作,持续更新
  2. AOP通过开启注解方式自动注入值
  3. synchronized 与 Reentrant均为可重入锁 区别后者比前者增加了长时等待可中断 设置是否公平锁 绑定多个条件
  4. Python调用MongoDB使用心得
  5. 手把手教你安装VMtools
  6. c语言分组求和函数,R语言 实现data.frame 分组计数、求和等
  7. vim 编程常用的指令和快捷键
  8. 人类为什么没有尾巴?这个跳跃基因抹去了人类的尾巴,并带来了额外风险
  9. mongodb聚合操作之group
  10. 输入5个整形数据_妙招技法:Excel表格数据录入的5个小技巧
  11. 公共 API 的错误次数远超你想象!
  12. L1-044 稳赢-PAT团体程序设计天梯赛GPLT
  13. matlab生成范德蒙矩阵
  14. julia 调用python库_install julia with python
  15. SNAP 4. 使用snap进行地物光谱分析
  16. 水电图纸——管道的预埋和盒子的放置-1
  17. 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.ecli
  18. 刚换了Mac本这些快捷键你知道吗?
  19. 美颜SDK免费版怎么样?应该如何选择美颜SDK?
  20. 毕业设计 基于JavaWeb的奖学金评定管理系统

热门文章

  1. python oledb dbf_在Python中打开和搜索dBase III(DBF)数据库
  2. 学数控编程,知道这三段代码就够了,很实用
  3. disableHostCheck: true 报错
  4. 通过pyautogui和excel插件方方格子来实现excel图片导入
  5. 2022企业级BI平台白皮书(附下载)
  6. linux快速入门 快捷高效学习方法
  7. C++中%lu,%u,%hu,%i,%o,%x,%X,%E/e,%c,%s表示含义
  8. “双一流”,中国矿业大学(北京)和华为签约
  9. 计算机专业需要用独显吗,集显 or 独显 我的程序用哪个必须由我定
  10. 芋道 Apollo 极简入门