一直以來,前端展示字典一般以中文展示為主,若在表中存字典值中文,當字典表更改字典值對應的中文,會造成資料不一致,為此設定冗餘欄位並非最優方案,若由前端自己寫死轉義,不夠靈活,若在業務程式碼轉義,臃腫也不夠通用,從網路上了解到註解、AOP是一種不錯的解決方案,主要有兩種方式:
1、通過註解獲取結果集轉為JSON字串,通過正則查詢附加欄位;
2、通過獲取結果集中相關欄位上註解,此種方法有兩個需要解決的問題,父類繼承欄位、嵌合物件難以解決獲取對應註解欄位問題,解決起來均比較麻煩;
因此本文采用第一種方法,能有效規避第二種方法相關問題,做到邏輯相對簡單,引入快取提高效率。
一、新建註解
標註方法上使用
1 @Retention(RetentionPolicy.RUNTIME)
2 @Target(ElementType.METHOD)
3 @Documented
4 public @interface TranslationDict {
5 FieldParam[] value();
6 }
註解引數:FieldParam
1 @Retention(RetentionPolicy.RUNTIME)
2 @Target({ElementType.FIELD})
3 @Documented
4 public @interface FieldParam {
5
6 /**
7 * 欄位型別 預設字典
8 * Constant.FIELDTYPE_DICT 為自定義常量
9 * @return
10 */
11 int type() default Constant.FIELDTYPE_DICT;
12
13 /**
14 * 字典dictType
15 * @return
16 */
17 String dictType() default "";
18
19 /**
20 * 要翻譯的欄位 目標欄位為翻譯的欄位+Str
21 * @return
22 */
23 String targetField() default "";
24
25 /**
26 * 要翻譯的欄位值型別
27 * @return
28 */
29 Class targetFieldValueClazz() default String.class;
30
31 }
二、註解的使用
在需要轉義方法體上添加註解,在註解上指定需要轉義的欄位,不宣告則使用預設值。
@TranslationDict({@FieldParam(dictType = "CUSTOMER_SEX", targetField = "sex"),
@FieldParam(dictType = "CUSTOMER_STATUS", targetField = "status", targetFieldValueClazz = Integer.class)})
三、新建切面
切面核心在於將結果集轉為JSON字串,通過正則查詢需要轉義的欄位,進行拼接替換,以增加屬性。
1 @Aspect
2 @Component
3 @Slf4j
4 public class TranslateFieldAspect {
5
6 /**
7 * 翻譯字典值
8 * @param joinPoint
9 * @return
10 * @throws Throwable
11 */
12 @Around("@annotation(com.vfangtuan.vft.common.annotation.TranslationDict)")
13 public Object aroundMethodDict(ProceedingJoinPoint joinPoint) throws Throwable {
14 //接收到請求時間
15 Long startTime = System.currentTimeMillis();
16 //注意,如果呼叫joinPoint.proceed()方法,則修改的引數值不會生效,必須呼叫joinPoint.proceed(Object[] args)
17 Object result = joinPoint.proceed();
18
19 // 第一步、獲取返回值型別
20 Class returnType = ((MethodSignature) joinPoint.getSignature()).getReturnType();
21
22 //首先,取出要翻譯欄位的字典值
23 String returnJsonResult = JSONObject.toJSONString(result);
24 //開始解析(翻譯欄位註解引數指定的欄位)
25 Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
26 //獲取註解上引數
27 TranslationDict annotation = method.getAnnotation(TranslationDict.class);
28 FieldParam[] fieldParams = annotation.value();
29 //遍歷
30 for (FieldParam fieldParam : fieldParams) {
31 log.info("開始翻譯字典CODE:{},取值欄位:{},取值欄位值型別:{}.",
32 fieldParam.dictType(),fieldParam.targetField(),fieldParam.targetFieldValueClazz());
33 Pattern dictPattern = getPattern(fieldParam);
34 Matcher dictMatcher=dictPattern.matcher(returnJsonResult);
35 StringBuffer sb = new StringBuffer();
36 //轉義欄位
37 this.translateDict(fieldParam,dictPattern,dictMatcher,sb);
38 dictMatcher.appendTail(sb);
39 returnJsonResult = sb.toString();
40 }
41
42 result = JSONObject.parseObject(returnJsonResult,returnType);
43 //如果這裡不返回result,則目標物件實際返回值會被置為null
44 //處理完請求時間
45 Long endTime = System.currentTimeMillis();
46 log.info("The request takes {}ms",endTime-startTime);
47 return result;
48 }
49 /**
50 * 字典值轉義為中文
51 * @param fieldParam
52 * @param fieldPattern
53 * @param fieldMatcher
54 * @param sb
55 */
56 private void translateDict(FieldParam fieldParam, Pattern fieldPattern, Matcher fieldMatcher, StringBuffer sb) {
57 //從快取中一次性取值
58 Map<String, String> dictNames = DictData.getDictNames(fieldParam.dictType());
59 while (fieldMatcher.find()){
60
61 //取出要翻譯欄位對應的值
62 Matcher dictValueMatcher = fieldPattern.matcher(fieldMatcher.group());
63 dictValueMatcher.find();
64 String group = dictValueMatcher.group();
65 //""sex":1", ""sex":"1"",""sex":null"
66 //屬性無值
67 if (group.split(":").length <= 1) continue;
68 String dictName = "";
69
70 //獲取字典值
71 String dictValue = group.split(":")[1].replace("\"", "");
72 //屬性值非為空 為空賦值空串
73 if (StringUtils.isNotBlank(dictValue) && !dictValue.toLowerCase().equals("null")){
74 //多值
75 if (dictValue.split(",").length > 1){
76 for (String s : dictValue.split(",")) {
77 //fieldParam.dictType() + "_" + s 根據自己字典表設定的規則去查詢
78 dictName += dictNames.get(fieldParam.dictType() + "_" + s) + "/";
79 }
80 }else {
81 dictName = dictNames.get(fieldParam.dictType() + "_" + dictValue);
82 }
83 }
84
85 String s = "\"" + fieldParam.targetField() + "Str" + "\":\"" + dictName + "\"," + fieldMatcher.group();
86 log.debug("拼接後字串:{}",s);
87 fieldMatcher.appendReplacement(sb, s);
88 }
89 }
90 /**
91 * 獲取對應的正則式
92 * @param fieldParam
93 * @return
94 */
95 private Pattern getPattern(FieldParam fieldParam) {
96 Pattern fieldPattern;//屬性整型 字元型
97 if (fieldParam.targetFieldValueClazz().equals(Integer.class) ){
98 fieldPattern= Pattern.compile("\""+fieldParam.targetField() +"\":(\\d+)?");
99 }else {
100 fieldPattern= Pattern.compile("\""+fieldParam.targetField() +"\":\"([0-9a-zA-Z_,]+)?\"");
101 }
102 return fieldPattern;
103 }
104 }
四、測試
測試類
1 @Slf4j
2 @RestController
3 @RequestMapping("/demo")
4 @Api(tags="demo")
5 public class DemoController {
6
7
8 /**
9 * 測試註解字典
10 * @return
11 */
12 @TranslationDict({@FieldParam(dictType = "CUSTOMER_SEX", targetField = "sex"),
13 @FieldParam(dictType = "CUSTOMER_STATUS", targetField = "status", targetFieldValueClazz = Integer.class)})
14 @GetMapping("/test")
15 @ApiOperation(value = "測試字典轉義")
16 public ResultVo test1() {
17 //接收到請求時間
18 Long startTime = System.currentTimeMillis();
19 List result = this.getResult();
20 //處理完請求時間
21 Long endTime = System.currentTimeMillis();
22 log.info("The request takes {}ms",endTime-startTime);
23 return new ResultVo().success(result);
24 }
25
26 private List getResult() {
27 List demos = new ArrayList<>();
28 Demo demo = new Demo("張三","1,2",1);
29 Demo demo2= new Demo("李四","2,1",2);
30 demos.add(demo);
31 demos.add(demo2);
32
33 for (int i = 0; i < 5; i++) {
34 demos.add(new Demo("張三"+i,"1",1) );
35 }
36 return demos;
37 }
實體物件
1 @Data
2 public class Demo {
3
4 private String name;
5
6 private String sex;
7
8 private Integer status;
9
10 public Demo() {
11 }
12
13 public Demo(String name, String sex, Integer status) {
14 this.name = name;
15 this.sex = sex;
16 this.status = status;
17 }
18
19 public Demo(String name) {
20 this.name = name;
21 }
22
23 public Demo(String name, String sex) {
24 this.name = name;
25 this.sex = sex;
26 }
27
28 }
測試效果
{
"code": 0,
"message": "success",
"data": [
{
"statusStr": "報備",
"sex": "1,2",
"name": "張三",
"sexStr": "男/女/",
"status": 1
},
{
"statusStr": "到訪",
"sex": "2,1",
"name": "李四",
"sexStr": "女/男/",
"status": 2
},
{
"statusStr": "報備",
"sex": "1",
"name": "張三0",
"sexStr": "男",
"status": 1
},...
]
}
到此本文結束,如您有更好的解決方案,還請留言告知,非常感謝。
參考資料:https://blog.csdn.net/qq_44754081/article/details/106142458
https://blog.csdn.net/Better_Mei/article/details/103901273
https://my.oschina.net/angelbo/blog/2875887