zoukankan      html  css  js  c++  java
  • 基于SpringBoot 、AOP与自定义注解转义字典值

      一直以来,前端展示字典一般以中文展示为主,若在表中存字典值中文,当字典表更改字典值对应的中文,会造成数据不一致,为此设置冗余字段并非最优方案,若由前端自己写死转义,不够灵活,若在业务代码转义,臃肿也不够通用,从网络上了解到注解、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

  • 相关阅读:
    我想操作的是利用SqlDataAdapter的几个Command属性(InsertCommand,UpdateCommand,DeleteCommand)来更新数据库
    有两个数据库A和B,数据库A中有表a,如何把表a映射到数据库B中,sql 2005
    代码生成器
    IWorkSpace接口介绍
    空间数据库介绍
    IGeoFeatureLayer
    IFeatureLayer
    Python ML环境搭建与学习资料推荐
    Python ML环境搭建与学习资料推荐
    TypeError: Can not convert a float32 into a Tensor or Operation.
  • 原文地址:https://www.cnblogs.com/gdwkong/p/14949417.html
Copyright © 2011-2022 走看看