字典注解
类注解
import lombok.NonNull;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DictClass {
String dictJsonFile() default "dict";
@NonNull
String dictKey();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
属性注解
import lombok.NonNull;
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DictField {
String cssClass() default "";
@NonNull
String dictLabelZH();
@NonNull
String dictLabelEN();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
属性拓展注解
import lombok.NonNull;
import java.lang.annotation.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DictFieldEx {
@NonNull
String[] propKey();
@NonNull
String[] propValue();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
工具类
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;
@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.";
private static String jsonDirUrl = DictUtils.class.getResource("/").getPath() + "dict/";
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());
}
}
}
}
}
public static String getDictText(String dictKey, String dictValue, String language) {
return dictMap.get(dictKey + ":" + dictValue + ":" + language);
}
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();
if (jsonFile != null && !jsonFile.equals("dict")) {
StringBuffer ss = new StringBuffer();
ss.append("{ \n");
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}");
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");
}
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("]");
}
}
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();
}
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;
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 + "}");
}
}

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
字典常量类配置示例
import com.paratera.console.dict.annotation.DictClass;
import com.paratera.console.dict.annotation.DictField;
import com.paratera.console.dict.annotation.DictFieldEx;
@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;
}

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63