精华内容
下载资源
问答
  • 字典翻译工具介绍

    2020-06-24 17:03:38
    字典翻译工具介绍DircConvertUtil一、使用教程1.1 添加依赖1.2 你需要提供什么接口1.3 你需要修改的地方二、设计实现2.1 场景2.2 疑问2.3 演示2.4 思考2.5 场景与技术2.6 数据结构2.7 mybatis 拦截器2.8 并发安全2.9...

    DircConvertUtil

    字典翻译工具类,支持正向翻译,方向翻译,翻译map,翻译标签。
    目前只支持Mybatis.

    一、使用教程

    1.1 添加依赖

    在 pom.xml中添加依赖:

    <!--yaml jar包-->
    <dependency>
        <groupId>org.yaml</groupId>
        <artifactId>snakeyaml</artifactId>
        <version>1.25</version>
    </dependency>
    
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    
    <!--日志-->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
    </dependency>
    

    2、控制台打印日志

    mybatis:
      configuration:
        map-underscore-to-camel-case: true
        # 当查询数据为空时字段返回为null,不加这个查询数据为空时,字段将被隐藏
        call-setters-on-nulls: true
        # mybatis 在控制台打印sql日志
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      mapper-locations: classpath:mapper/*.xml
    

    1.2 你需要提供什么接口

    1、字典全表扫描接口 selectAll

      <select id="selectAll" resultMap="BaseResultMap">
        select row_id, f_type, f_key, f_value, parent_id, is_leaf, opt_status, opt_sort_by,
        opt_flag, create_by, create_time, update_by, update_time, remark
        from tb_dirc
      </select>
    

    注意:目前你可将标签翻译的部分注掉

    1.3 你需要修改的地方

    1、把test.yml 替换成你的yml,注意此yml非application.yml

    //yaml name
    private static final String YAML_NAME = "test.yml";
    

    2、将TbDircMapper TbLabelFieldMapper TbDirc分别替换成你的mapper和实体类。 目前可将TbLabelFieldMapper 注释掉。

    3、在test.yml中添加自己的域
    添加自己的域,添加待翻译的字段名和对应的字典类型。

    zzq: # 这是域
      popu_type: "10101"
      popuType: "10101"
      sex: "10102"
      religion :  "10107"
    jack: # 这是域
      popu_type: "10101" # 翻译Map数据中的字段
      popuType: "10101"  #翻译实体中的字段
      sex: "10102"
      marital_status : "10104"
      religion :  "10107"
    

    4、使用方式类型于pageHelper分页

        @GetMapping("/id")
        public Object getPopu() {
            ResultSetConvert.onWithFresh(2,"zzq"); //设置翻译次数 和 域
            //ResultSetConvert.onNoFresh(); //不同步、不设翻译次数;默认只翻译一次 不使用域 则会使用默认的FIELDNAME_FTYPE_MAP
            //ResultSetConvert.onWithFresh(); //只进行同步
            //ResultSetConvert.onWithFresh(1);//同步、并设翻译次数为1
            return popuService.selectPeopleByRowId("faf6e00b7aef11ea9c2c005056b17b89");
        }
    

    二、设计实现

    2.1 场景

    在这里插入图片描述

    2.2 疑问

    以前翻译要写case when或者子查询才能翻译,能不能把翻译过程和业务查询分离开,只用写简单的sql就能完成翻译呢?
    在这里插入图片描述

    2.3 演示

    用法如图
    在这里插入图片描述

    2.4 思考

    在这里插入图片描述

    2.5 场景与技术

    在这里插入图片描述

    2.6 数据结构

    在这里插入图片描述

    2.7 mybatis 拦截器

    在这里插入图片描述

    2.8 并发安全

    在这里插入图片描述

    2.9 bean 生命周期

    在这里插入图片描述

    2.10 可配置化

    在这里插入图片描述

    三、特别鸣谢

    ゝLibra `

    展开全文
  • 字典 | springboot 返回数据字典翻译

    千次阅读 2020-11-20 18:10:20
    在处理完数据返回前端时,通常需要做字典翻译,此时就需要一个好用的处理工具,但是依然不方便,对此,再次封装了一次。 原理 在接口返回时拦截 --- 反射获取对应字典信息 -- 查询字典值 --- 再次塞入对象里面 ---...

    1.前言

    在处理完数据返回前端时,通常需要做字典翻译,此时就需要一个好用的处理工具,但是依然不方便,对此,再次封装了一次。

    原理 在接口返回时拦截 --- 反射获取对应字典信息 -- 查询字典值 --- 再次塞入对象里面 --- 返回信息

    2.代码

    字典类型处理
    import java.lang.annotation.*;
    
    /**
     * 字典类型处理 拦截
     * <p>常用返回类型处理,不进行四层深层处理</p>
     *
     * @author wbw
     * @date 2020/11/10 11:40
     */
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface DictTypeSensible {
        /**
         * 实体类字段
         */
        String value();
    
        /**
         * 字典code,默认使用 value 转下划线形式
         */
        String code() default "";
    
    }
    
    多个字典值
    import java.lang.annotation.*;
    
    /**
     * 多个字典值
     *
     * @author wbw
     * @date 2020/11/1316:53
     */
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface DictTypeSensibles {
        /**
         * 多个字典值
         *
         * @return 多个值
         */
        DictTypeSensible[] value();
    }
    
    字典拦截转换处理
    
    import cn.hutool.core.util.ObjectUtil;
    import cn.hutool.core.util.ReflectUtil;
    import cn.hutool.core.util.StrUtil;
    import com.baomidou.mybatisplus.core.metadata.IPage;
    import com.gl.common.core.domain.AjaxResult;
    import com.gl.common.data.page.TableDataInfo;
    import com.gl.common.data.vo.R;
    import com.gl.core.annotation.DictTypeSensible;
    import com.gl.core.annotation.DictTypeSensibles;
    import com.gl.system.service.ISysDictDataService;
    import lombok.AllArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.core.MethodParameter;
    import org.springframework.http.MediaType;
    import org.springframework.http.server.ServerHttpRequest;
    import org.springframework.http.server.ServerHttpResponse;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.Map;
    
    /**
     * 字典拦截转换处理
     *
     * @author wbw
     * @date 2020/11/10 17:55
     */
    @ControllerAdvice
    @AllArgsConstructor
    @Slf4j
    public class DictTypeSensibleAspect implements ResponseBodyAdvice<Object> {
    
        private final ISysDictDataService dictDataService;
    
        @Override
        public boolean supports(MethodParameter methodParameter, Class aClass) {
            return methodParameter.hasMethodAnnotation(DictTypeSensible.class)
                    || methodParameter.hasMethodAnnotation(DictTypeSensibles.class);
        }
    
        @Override
        public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType
                , Class clazz, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
            if (ObjectUtil.isEmpty(o)) {
                return null;
            }
            // 获取方法 注解参数
            Method method = methodParameter.getMethod();
            final String methodName = method == null ? ""
                    : (method.getDeclaringClass().getSimpleName() + "." + method.getName());
            DictTypeSensible[] sensibles;
            if (methodParameter.hasMethodAnnotation(DictTypeSensible.class)) {
                DictTypeSensible sensible = methodParameter.getMethodAnnotation(DictTypeSensible.class);
                sensibles = new DictTypeSensible[]{sensible};
            } else {
                DictTypeSensibles typeSensibles = methodParameter.getMethodAnnotation(DictTypeSensibles.class);
                sensibles = typeSensibles == null ? new DictTypeSensible[]{} : typeSensibles.value();
            }
            // 处理返回值
            this.dis(o, sensibles, methodName);
            return o;
        }
    
        /**
         * 处理返回数据
         *
         * @param obj       对象
         * @param sensibles 字典类型
         */
        private void dis(Object obj, DictTypeSensible[] sensibles, String methodName) {
            // 处理返回类型
            if (obj instanceof TableDataInfo) {
                this.dis(((TableDataInfo) obj).getRows(), sensibles, methodName);
                return;
            }
            if (obj instanceof AjaxResult) {
                this.dis(((AjaxResult) obj).get(AjaxResult.DATA_TAG), sensibles, methodName);
                return;
            }
            if (obj instanceof R) {
                this.dis(((R) obj).getData(), sensibles, methodName);
                return;
            }
            if (obj instanceof IPage) {
                ((IPage) obj).getRecords().forEach(e -> this.dis(e, sensibles, methodName));
                return;
            }
            if (obj instanceof Iterable) {
                ((Iterable) obj).forEach(e -> this.dis(e, sensibles, methodName));
                return;
            }
            if (obj instanceof Map) {
                Map<String, Object> map = (Map<String, Object>) obj;
                for (DictTypeSensible sensible : sensibles) {
                    if (!map.containsKey(sensible.value())) {
                        log.warn("--- 方法 {},字典 {} 进行忽略,不存在 ------", methodName, sensible.value());
                        continue;
                    }
                    Object o = map.get(sensible.value());
                    if (o instanceof Iterable) {
                        this.dis(o, sensibles, methodName);
                        continue;
                    }
                    String code = StrUtil.isEmpty(sensible.code())
                            ? StrUtil.toUnderlineCase(sensible.value()) : sensible.code();
                    String label = dictDataService.selectDictLabel(code, String.valueOf(o));
                    map.put(sensible.value(), label);
                }
                return;
            }
            Class<?> clazz = obj.getClass();
            for (DictTypeSensible sensible : sensibles) {
                try {
                    Field field = ReflectUtil.getField(clazz, sensible.value());
                    if (field == null || !field.getType().getSimpleName().contains("String")) {
                        log.warn("--- 方法 {},字典 {} 进行忽略,不存在 || 非String类型 ------", methodName, sensible.value());
                        continue;
                    }
                    Object val = ReflectUtil.getFieldValue(obj, field);
                    if (ObjectUtil.isEmpty(val)) {
                        continue;
                    }
                    String code = StrUtil.isEmpty(sensible.code())
                            ? StrUtil.toUnderlineCase(sensible.value()) : sensible.code();
                    String label = dictDataService.selectDictLabel(code, String.valueOf(val));
                    ReflectUtil.setFieldValue(obj, field, label);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    3.使用

    展开全文
  • 并且其中还伴随DTO中的数据字典翻译, 所以特意写个工具类,主要利用spring提供的BeanUtils工具类,用redis翻译字典 其中功能包括: 翻译JavaBean中带有@CacheFormat的属性 /** * 翻译当前类中需要翻译的...

    JavaBean相互转换

    在升级公司架构过程中,发现有大量Entity与DTO相互转换的问题,
    并且其中还伴随DTO中的数据字典翻译,
    所以特意写个工具类,主要利用spring提供的BeanUtils工具类,用redis翻译字典

    其中功能包括:

    • 翻译JavaBean中带有@CacheFormat的属性

       /**
        * 翻译当前类中需要翻译的字典值
        *
        * @param source 待翻译的对象
        */
       public static <T> void dataFormatter(T source) {
      
           //判断原对象是否为null
           Assert.notNull(source, "待翻译的原对象不能为null");
      
           //获取所有属性并翻译字典
           Field[] declaredFields = source.getClass().getDeclaredFields();
           //翻译字典:找出所有含有@CacheFormatter的属性
           Stream<Field> fieldStream = Arrays.stream(declaredFields)
                   //排除没有注解@CacheFormatter的字段
                   .filter(field -> field.isAnnotationPresent(CacheFormat.class));
           //翻译
           doFormatter(fieldStream, source, source.getClass());
       }
    • 翻译List中带有@CacheFormat的属性

       /**
        * 翻译当前集合类中需要翻译的字典值
        *
        * @param sources 待翻译的集合对象
        */
       public static <T> void dataFormatter(List<T> sources) {
      
           //当翻译的集合为空时,返回空的集合
           if (sources == null || sources.isEmpty()) {
               return;
           }
      
           Class targetClass = sources.get(0).getClass();
           //获取所有属性并翻译字典
           Field[] declaredFields = targetClass.getDeclaredFields();
           //翻译字典:找出所有含有@CacheFormat的属性集合
           List<Field> formatterFields = Arrays.stream(declaredFields)
                   //排除没有注解@CacheFormat的字段
                   .filter(field -> field.isAnnotationPresent(CacheFormat.class))
                 .collect(Collectors.toList());
           //循环列表(并行操作)
           sources.parallelStream().forEach(target -> {
               //翻译
               doFormatter(formatterFields.stream(), target, targetClass);
           });
      }
    • Entity 与DTO互转

      /**
       * 把原对象转换成目标类的对象,并翻译目标类的属性字典
       * 只针对目标类没有范型或者范型与原对象一样
       * @param source      原对象
       * @param targetClass 目标类
       * @return 目标对象
       */
      public static <T> T dataConvert(Object source, Class<T> targetClass) {
      
          Assert.isTrue(source != null && targetClass != null, "原对象或目标class不能为null");
      
          T target = BeanUtils.instantiateClass(targetClass);
          //把目标对象的属性设置成原对象中对应的属性
          BeanUtils.copyProperties(source, target);
      
          dataFormatter(target);
          return target;
      }
      
      /**
       * 实体属性互转
       *
       * @param source 原对象
       * @param target 目标对象
       * @return 目标对象
       */
      public static <T> T dataObjConvert(Object source, T target) {
      
          Assert.isTrue(source != null && target != null, "待转换的原对象或目标对象不能为null");
          //转换
          BeanUtils.copyProperties(source, target);
          //翻译
          dataFormatter(target);
          return target;
      }
    • List与List互转

      /**
       * 批量把原对象转换成目标对象,并翻译目标对象的属性字典
       * 如果想返回指定类型的集合即List的子类,参考{@link  HyBeanUtils#dataConverts2}
       *
       * @param sources     原对象集合
       * @param targetClass 目标对象的类
       * @return 返回转换后的目标集合
       */
      public static <T, E> List<T> dataConverts(List<E> sources, Class<T> targetClass) {
      
          Assert.notNull(targetClass, "转换的目标Class不能为null");
      
          //当翻译的集合为空时,返回空的集合
          if (sources == null || sources.isEmpty()) {
              List<T> targetList = new ArrayList<>();
              return targetList;
          }
          //获取原集合的类型
          Class<? extends List> aClass = sources.getClass();
          //目标集合
          List<T> targetList = BeanUtils.instantiateClass(aClass);
      
          //把目标对象的属性设置成原对象中对应的属性(并行操作)
          sources.parallelStream().forEach(item -> {
              T target = BeanUtils.instantiateClass(targetClass);
              BeanUtils.copyProperties(item, target);
              targetList.add(target);
          });
      
          //翻译字典
          dataFormatter(targetList);
      
          return targetList;
       }
    • 这个是List转换的升级版 T与T互转,这里的T是List的子类
      之所以写这个,就是为了解决mybatis的Page转换问题

      /**
       * 返回指定类型的方法,这里的类型必须是List的子类
       * 批量把原对象转换成目标对象,并翻译目标对象的属性字典,
       *
       * @param sources     原对象集合
       * @param targetClass 目标对象的类
       * @param returnType  返回值类型
       * @return 返回转换后的目标集合
       */
      public static <T, E, R extends List<T>> R dataConverts2(List<E> sources, Class<T> targetClass, Class<R> returnType) {
      
          Assert.notNull(targetClass, "转换的目标Class不能为null");
          Assert.notNull(returnType, "返回值类型Class不能为null");
      
          //当翻译的集合为空时,返回空的集合
          if (sources == null || sources.isEmpty()) {
              return null;
          }
          //目标集合
          R targetList = BeanUtils.instantiateClass(returnType);
      
          //把目标对象的属性设置成原对象中对应的属性(并行操作)
          sources.parallelStream().forEach(item -> {
              T target = BeanUtils.instantiateClass(targetClass);
              BeanUtils.copyProperties(item, target);
              targetList.add(target);
          });
      
          //翻译字典
          dataFormatter(targetList);
      
          return targetList;
      }
    • 上述所用到的公共方法

      /**
       * 对目标类需要翻译的字段进行翻译
       *
       * @param stream
       * @param target      目标对象
       * @param targetClass 目标对象类
       */
      private static <T> void doFormatter(Stream<Field> stream, Object target, Class<T> targetClass) {
      
          //排除目标对象中字段值为null的字段
          stream.filter(field -> {
              PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(targetClass, field.getName());
              Object invoke = null;
              try {
                  invoke = propertyDescriptor.getReadMethod().invoke(target, new Object[]{});
              } catch (IllegalAccessException e) {
                  logger.warn("待翻译的字段的get是无法访问的", e);
              } catch (InvocationTargetException e) {
                  logger.warn("调用待翻译的字段的get方法时报错", e);
              } catch (Exception e) {
                  logger.warn("确保属性有get,set方法", e);
              }
              return invoke != null;
              //遍历需要翻译的字段
          }).forEach(field -> {
              CacheFormat annotation = field.getAnnotation(CacheFormat.class);
      
              //缓存系统编号,如果不指定则默认为当前系统编号
              String systemCode = "system_code";
              if (StringUtils.isNotBlank(annotation.systemCode())) {
                  systemCode = annotation.systemCode();
              }
              //缓存key,如果不指定,则默认为字段名称
              String key = annotation.key();
              if (StringUtils.isBlank(key)) {
                  key = field.getName();
              }
      
              //判断注解@CacheFormatter是否指定把字典翻译到另一个字段上
              String formatterField = annotation.destination();
              if (StringUtils.isBlank(formatterField)) {
                  //当注解中不指定其他字段时,默认翻译到加注解的属性上
                  formatterField = field.getName();
              }
      
              try {
                  PropertyDescriptor orginPropertyDescriptor = BeanUtils.getPropertyDescriptor(targetClass, field.getName());
                  Object value = orginPropertyDescriptor.getReadMethod().invoke(target, new Object[]{});
                  //设置目标字段值
                  PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(targetClass, formatterField);
                  //取缓存
                  String cacheValue = RedisUtils.hget(systemCode +":valueset:" + key, value + "");
                  //如果数据字典中查询不到,则取业务缓存中取
                  if (StringUtils.isBlank(cacheValue)) {
                      cacheValue = RedisUtils.hget(systemCode + ":valueset:" + key, value + "");
                  }
      
                  Assert.hasLength(cacheValue, "在缓存" + key + "中没有找到" + value + "对应的缓存");
                  //设置缓存值到属性字段中
                  propertyDescriptor.getWriteMethod().invoke(target, cacheValue);
      
              } catch (IllegalAccessException e) {
                  logger.warn("待翻译的字段的set是无法访问的", e);
              } catch (InvocationTargetException e) {
                  logger.warn("调用待翻译的字段的set方法时报错", e);
              } catch (Exception e) {
                  e.printStackTrace();
                  logger.warn("调用待翻译的字段的set方法时报错,推测类型不匹配", e);
              }
          });
      
      }
    • 注解 CacheFormat

      @Target(ElementType.FIELD)
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      public @interface CacheFormat {
      
        /**
         *  缓存key
         * @return
         */
        String key();
      
        /**
         * 指定翻译值存放字段, 例如:userType的翻译结果放到userTypeName上
         * @return
         */
        String destination() default "";
      
        /**
         * 系统编号
         * @return
         */
        String systemCode() default "";

    注意:该翻译只关注第一层即当前对象的属性,并不会递归翻译

    比如:当前类有一个属性为对象实例,该对象也有被@CacheFormat注解的属性

    这时该工具类不会去翻译这个属性中的属性,需要开发者先用当前工具类转换该属性

    然后再设置到目标类中

     

    展开全文
  • 自定义数据字典翻译注解

    千次阅读 2020-05-15 15:57:06
    自定义数据字典翻译注解参考出处代码背景@Dict注解注解对应实现类工具类service层查询接口service实现类和Mybatis的SQL语句实体类缓存的ehcache.xml存放在项目的位置ehcache.xmlehcache.xsd项目位置ehcache.xsd内容...

    参考出处

    (非常感谢)https://blog.csdn.net/weixin_42687829/article/details/103289383

    代码背景

    小公司新项目加上本人也就两个开发,很多地方用到了字典,于是在网上参考一篇数据字典翻译类,自己记录一下,方便之后项目用到使用。

    @Dict注解

    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * @Author: Yin XX
     * @Description:
     * @Date: Create in 11:33 2020/4/30
     */
    
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Dict {
        /**
         * 方法描述:数据dataSource
         * @return 返回类型: String
         */
        String dictDataSource();
    
        /**
         * 方法描述:这是返回后Put到josn中的文本key值
         * @return 返回类型: String
         */
        String dictText() default "";
    }
    

    注解对应实现类

    
    import com.alibaba.fastjson.JSONObject;
    import com.fasterxml.jackson.annotation.JsonFormat;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import io.renren.common.annotation.Dict;
    import io.renren.common.utils.ObjConvertUtils;
    import io.renren.common.utils.PageUtils;
    import io.renren.modules.dictionaries.service.DictionariesService;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang.StringUtils;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Field;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    /**
     * @Author: Yin XX
     * @Description:
     * @Date: Create in 11:26 2020/4/30
     */
    @Aspect
    @Component
    @Slf4j
    public class DictAspect {
    
    	//表对应字段加上_dictText即可显示出文本
        private static String DICT_TEXT_SUFFIX = "_dictText";
    
        @Autowired
        private DictionariesService dataItemService;
    
        //定义切点Pointcut拦截所有对服务器的请求
        @Pointcut("execution(* io.renren.modules.*.service.*.*(..))")
        public void excudeService() {
    
        }
    
        /**
         * 这是触发DictionariesService的时候会执行的,在环绕通知中目标对象方法被调用后的结果进行再处理
         * @param pjp
         * @return
         * @throws Throwable
         */
        @Around("excudeService()")
        public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
            //这是定义开始事件
            long time1 = System.currentTimeMillis();
            //这是方法并获取返回结果
            Object result = pjp.proceed();
            //这是获取到结束时间
            long time2 = System.currentTimeMillis();
            log.info("获取JSON数据耗时:" + (time2 - time1) + "ms");
            //解析开始时间
            long start = System.currentTimeMillis();
            //开始解析(翻译字段内部的值凡是打了@Dict这玩意的都会被翻译)
            this.parseDictText(result);
            //解析结束时间
            long end = System.currentTimeMillis();
            log.info("解析注入JSON数据耗时:" + (end - start) + "ms");
            return result;
        }
    
    
        private void parseDictText(Object result) {
            if (result instanceof PageUtils) {
                List<JSONObject> items = new ArrayList<>();
                PageUtils pageUtils = (PageUtils) result;
                //循环查找出来的数据
                for (Object record : pageUtils.getList()) {
                    ObjectMapper mapper = new ObjectMapper();
                    String json = "{}";
                    try {
                        //解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormat
                        json = mapper.writeValueAsString(record);
                    } catch (JsonProcessingException e) {
                        log.error("Json解析失败:" + e);
                    }
                    JSONObject item = JSONObject.parseObject(json);
    
                    //解决继承实体字段无法翻译问题
                    for (Field field : ObjConvertUtils.getAllFields(record)) {
                        //解决继承实体字段无法翻译问题
                        if (field.getAnnotation(Dict.class) != null) {//如果该属性上面有@Dict注解,则进行翻译
                            String datasource = field.getAnnotation(Dict.class).dictDataSource();//拿到注解的dictDataSource属性的值
                            String text = field.getAnnotation(Dict.class).dictText();//拿到注解的dictText属性的值
                            //获取当前带翻译的值
                            String key = String.valueOf(item.get(field.getName()));
                            //翻译字典值对应的text值
                            String textValue = translateDictValue(datasource, key);
                            //DICT_TEXT_SUFFIX的值为,是默认值:
                            //public static final String DICT_TEXT_SUFFIX = "_dictText";
                            log.debug("字典Val: " + textValue);
                            log.debug("翻译字典字段:" + field.getName() + DICT_TEXT_SUFFIX + ": " + textValue);
                            //如果给了文本名
                            if (!StringUtils.isBlank(text)) {
                                item.put(text, textValue);
                            } else {
                                //走默认策略
                                item.put(field.getName() + DICT_TEXT_SUFFIX, textValue);
                            }
                        }
                        //date类型默认转换string格式化日期
                        if (field.getType().getName().equals("java.util.Date") && field.getAnnotation(JsonFormat.class) == null && item.get(field.getName()) != null) {
                            SimpleDateFormat aDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));
                        }
                    }
                    items.add(item);
                }
                pageUtils.setList(items);
            }
        }
    
    
        /**
         * 翻译字典文本
         * @param datasource
         * @param key
         * @return
         */
        private String translateDictValue(String datasource, String key) {
            //如果key为空直接返回就好了
            if (ObjConvertUtils.isEmpty(key)) {
                return null;
            }
            StringBuffer textValue = new StringBuffer();
            //分割key值
            String[] keys = key.split(",");
            //循环keys中的所有值
            for (String k : keys) {
                String tmpValue = null;
                log.debug("字典key:" + k);
                if (k.trim().length() == 0) {
                    continue;//跳过循环
                }
                tmpValue = dataItemService.selectByFieldNameAndFieldValue(datasource, k.trim());
    
                if (tmpValue != null) {
                    if (!"".equals(textValue.toString())) {
                        textValue.append(",");
                    }
                    textValue.append(tmpValue);
                }
            }
            //返回翻译的值
            return textValue.toString();
        }
    }
    
    

    工具类

    
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * @Author: Yin xx
     * @Description:
     * @Date: Create in 11:38 2020/4/30
     */
    public class ObjConvertUtils {
        /**
         * 获取类的所有属性,包括父类
         * @param object
         * @return
         */
        public static Field[] getAllFields(Object object) {
            Class<?> clazz = object.getClass();
            List<Field> fieldList = new ArrayList<>();
            while (clazz != null) {
                fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
                clazz = clazz.getSuperclass();
            }
            Field[] fields = new Field[fieldList.size()];
            fieldList.toArray(fields);
            return fields;
        }
    
        public static boolean isEmpty(Object object) {
            if (object == null) {
                return (true);
            }
            if ("".equals(object)) {
                return (true);
            }
            if ("null".equals(object)) {
                return (true);
            }
            return (false);
        }
    }
    
    

    分页工具类

    /**
     * Copyright (c) 2016-2019 人人开源 All rights reserved.
     *
     * https://www.renren.io
     *
     * 版权所有,侵权必究!
     */
    
    package io.renren.common.utils;
    
    import com.baomidou.mybatisplus.core.metadata.IPage;
    
    import java.io.Serializable;
    import java.util.List;
    
    /**
     * 分页工具类
     *
     * @author Mark sunlightcs@gmail.com
     */
    public class PageUtils implements Serializable {
    	private static final long serialVersionUID = 1L;
    	/**
    	 * 总记录数
    	 */
    	private int totalCount;
    	/**
    	 * 每页记录数
    	 */
    	private int pageSize;
    	/**
    	 * 总页数
    	 */
    	private int totalPage;
    	/**
    	 * 当前页数
    	 */
    	private int currPage;
    	/**
    	 * 列表数据
    	 */
    	private List<?> list;
    	
    	/**
    	 * 分页
    	 * @param list        列表数据
    	 * @param totalCount  总记录数
    	 * @param pageSize    每页记录数
    	 * @param currPage    当前页数
    	 */
    	public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) {
    		this.list = list;
    		this.totalCount = totalCount;
    		this.pageSize = pageSize;
    		this.currPage = currPage;
    		this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
    	}
    
    	/**
    	 * 分页
    	 */
    	public PageUtils(IPage<?> page) {
    		this.list = page.getRecords();
    		this.totalCount = (int)page.getTotal();
    		this.pageSize = (int)page.getSize();
    		this.currPage = (int)page.getCurrent();
    		this.totalPage = (int)page.getPages();
    	}
    
    	public int getTotalCount() {
    		return totalCount;
    	}
    
    	public void setTotalCount(int totalCount) {
    		this.totalCount = totalCount;
    	}
    
    	public int getPageSize() {
    		return pageSize;
    	}
    
    	public void setPageSize(int pageSize) {
    		this.pageSize = pageSize;
    	}
    
    	public int getTotalPage() {
    		return totalPage;
    	}
    
    	public void setTotalPage(int totalPage) {
    		this.totalPage = totalPage;
    	}
    
    	public int getCurrPage() {
    		return currPage;
    	}
    
    	public void setCurrPage(int currPage) {
    		this.currPage = currPage;
    	}
    
    	public List<?> getList() {
    		return list;
    	}
    
    	public void setList(List<?> list) {
    		this.list = list;
    	}
    	
    }
    
    

    service层查询接口

    
    import com.baomidou.mybatisplus.extension.service.IService;
    import io.renren.common.utils.PageUtils;
    import io.renren.modules.dictionaries.entity.DictionariesEntity;
    import org.springframework.cache.annotation.Cacheable;
    
    import java.util.Map;
    
    /**
     * @Author: Yin xx
     * @Description:
     * @Date: Create in 16:06 2020/4/29
     */
    public interface DictionariesService extends IService<DictionariesEntity> {
    
        /**
         * 列表查询
         * @param params
         * @return
         */
        PageUtils queryPage(Map<String, Object> params);
    
        /**
         * 将查询出来的字段存放在缓存中
         * @param fieldName
         * @param fieldValue
         * @return
         */
        @Cacheable(value = "dictEhcache") //把数据缓存到本地
        String selectByFieldNameAndFieldValue(String fieldName,String fieldValue);
    
    }
    

    service实现类和Mybatis的SQL语句

        @Override
        public String selectByFieldNameAndFieldValue(String fieldName, String fieldValue) {
            DictionariesEntity entity = this.baseMapper.selectByFieldNameAndFieldValue(fieldName, fieldValue);
            if(entity ==null){
                return "无翻译词汇";
            }
            return entity.getFieldDetail();
        }
    
    ==============================分割线,以下是SQL=================================================
    
       <!--通过表格字段名和字段值查询该字典信息-->
        <select id="selectByFieldNameAndFieldValue" parameterType="java.lang.String"
                resultType="io.renren.modules.dictionaries.entity.DictionariesEntity">
            SELECT * FROM pz_dictionaries
            <where>
                <if test="fieldName != null and fieldName !=''">
                    field_name = #{fieldName}
                </if>
                <if test="fieldValue != null and fieldValue !=''">
                    and field_value = #{fieldValue}
                </if>
            </where>
        </select>
    

    实体类

    
    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    import lombok.Data;
    
    import java.io.Serializable;
    
    /**
     * @Author: Yin xx
     * @Description: 数据字典表
     * @Date: Create in 16:11 2020/4/29
     */
    @Data
    @TableName("pz_dictionaries")
    public class DictionariesEntity implements Serializable {
    
        /**
         * 字段唯一标识
         */
        @TableId(value = "id",type = IdType.UUID)
        private String id;
    
        /**
         * 字段名
         */
        @TableField("field_name")
        private String fieldName;
    
        /**
         * 字段值
         */
        @TableField("field_value")
        private String fieldValue;
    
        /**
         * 字段说明
         */
        @TableField("field_detail")
        private String fieldDetail;
    
        /**
         * 具体描述
         */
        @TableField("field_describe")
        private String fieldDescribe;
    }
    
    

    缓存的ehcache.xml存放在项目的位置

    在这里插入图片描述

    ehcache.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="./config/ehcache.xsd"
             updateCheck="false">
    
        <!--这个是磁盘存储路径,当内存缓存满了的时候,就会往这里面放,java.io.tmdir是操作系统缓存的临时目录,不同操作系统缓存目录不一样。-->
        <diskStore path="D:/ehcacheData"/>
    
        <!--maxElementsInMemory      内存缓存中最多可以存放的元素数量,若放入Cache中的元素超过这个数值,则有以下两种情况
                             1)若overflowToDisk=true,则会将Cache中多出的元素放入磁盘文件中
                             2)若overflowToDisk=false,则根据memoryStoreEvictionPolicy策略替换Cache中原有的元素overflowToDisk,
                             内存不足时,是否启用磁盘缓存-->
        <!--eternal:缓存中对象是否永久有效-->
        <!--timeToIdleSeconds:缓存数据在失效前的允许闲置时间(单位:),仅当eternal=false时使用,
                              默认值是0表示可闲置时间无穷大,若超过这个时间没有访问此Cache中的某个元素,那么此元素将被从Cache中清除-->
        <!--timeToLiveSeconds:缓存数据的总的存活时间(单位:秒),仅当eternal=false时使用,从创建开始计时,失效结束。-->
        <!--maxElementsOnDisk:磁盘缓存中最多可以存放的元素数量,0表示无穷大-->
        <defaultCache
                eternal="false"
                maxElementsInMemory="10000"
                overflowToDisk="false"
                diskPersistent="false"
                timeToIdleSeconds="600"
                timeToLiveSeconds="600"
                maxElementsOnDisk="10000000"
                memoryStoreEvictionPolicy="LRU" />
    
        <!-- 这里的 dictEhcache 缓存空间是为了缓存字典数据做准备 -->
        <cache
                name="dictEhcache"
                eternal="false"
                maxElementsInMemory="1000"
                overflowToDisk="false"
                diskPersistent="false"
                timeToIdleSeconds="600"
                timeToLiveSeconds="600"
                memoryStoreEvictionPolicy="LRU" />
    </ehcache>
    
    

    ehcache.xsd项目位置

    在这里插入图片描述

    ehcache.xsd内容

    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" version="1.7">
        <xs:element name="ehcache">
            <xs:complexType>
                <xs:sequence>
                    <xs:element maxOccurs="1" minOccurs="0" ref="diskStore"/>
                    <xs:element maxOccurs="1" minOccurs="0" ref="sizeOfPolicy"/>
                    <xs:element maxOccurs="1" minOccurs="0" ref="transactionManagerLookup"/>
                    <xs:element maxOccurs="1" minOccurs="0" ref="cacheManagerEventListenerFactory"/>
                    <xs:element maxOccurs="1" minOccurs="0" ref="managementRESTService"/>
                    <xs:element maxOccurs="unbounded" minOccurs="0" ref="cacheManagerPeerProviderFactory"/>
                    <xs:element maxOccurs="unbounded" minOccurs="0" ref="cacheManagerPeerListenerFactory"/>
                    <xs:element maxOccurs="1" minOccurs="0" ref="terracottaConfig"/>
                    <xs:element maxOccurs="1" minOccurs="0" ref="defaultCache"/>
                    <xs:element maxOccurs="unbounded" minOccurs="0" ref="cache"/>
                </xs:sequence>
                <xs:attribute name="name" use="optional"/>
                <xs:attribute default="true" name="updateCheck" type="xs:boolean" use="optional"/>
                <xs:attribute default="autodetect" name="monitoring" type="monitoringType" use="optional"/>
                <xs:attribute default="true" name="dynamicConfig" type="xs:boolean" use="optional"/>
                <xs:attribute default="15" name="defaultTransactionTimeoutInSeconds" type="xs:integer" use="optional"/>
                <xs:attribute default="0" name="maxBytesLocalHeap" type="memoryUnitOrPercentage" use="optional"/>
                <xs:attribute default="0" name="maxBytesLocalOffHeap" type="memoryUnit" use="optional"/>
                <xs:attribute default="0" name="maxBytesLocalDisk" type="memoryUnit" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="managementRESTService">
            <xs:complexType>
                <xs:attribute name="enabled" type="xs:boolean" use="optional"/>
                <xs:attribute name="bind" use="optional"/>
                <xs:attribute name="securityServiceLocation" use="optional"/>
                <xs:attribute name="securityServiceTimeout" use="optional" type="xs:integer"/>
                <xs:attribute name="sslEnabled" use="optional" type="xs:boolean"/>
                <xs:attribute name="needClientAuth" use="optional" type="xs:boolean"/>
                <xs:attribute name="sampleHistorySize" use="optional" type="xs:integer"/>
                <xs:attribute name="sampleIntervalSeconds" use="optional" type="xs:integer"/>
                <xs:attribute name="sampleSearchIntervalSeconds" use="optional" type="xs:integer"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="diskStore">
            <xs:complexType>
                <xs:attribute name="path" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="transactionManagerLookup">
            <xs:complexType>
                <xs:attribute name="class" use="required"/>
                <xs:attribute name="properties" use="optional"/>
                <xs:attribute name="propertySeparator" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="cacheManagerEventListenerFactory">
            <xs:complexType>
                <xs:attribute name="class" use="required"/>
                <xs:attribute name="properties" use="optional"/>
                <xs:attribute name="propertySeparator" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="cacheManagerPeerProviderFactory">
            <xs:complexType>
                <xs:attribute name="class" use="required"/>
                <xs:attribute name="properties" use="optional"/>
                <xs:attribute name="propertySeparator" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="cacheManagerPeerListenerFactory">
            <xs:complexType>
                <xs:attribute name="class" use="required"/>
                <xs:attribute name="properties" use="optional"/>
                <xs:attribute name="propertySeparator" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="terracottaConfig">
            <xs:complexType>
                <xs:sequence>
                    <xs:element maxOccurs="1" minOccurs="0" name="tc-config">
                        <xs:complexType>
                            <xs:sequence>
                                <xs:any maxOccurs="unbounded" minOccurs="0" processContents="skip"/>
                            </xs:sequence>
                        </xs:complexType>
                    </xs:element>
                </xs:sequence>
                <xs:attribute default="localhost:9510" name="url" use="optional"/>
                <xs:attribute name="rejoin" type="xs:boolean" use="optional" default="false"/>
                <xs:attribute name="wanEnabledTSA" type="xs:boolean" use="optional" default="false"/>
            </xs:complexType>
        </xs:element>
        <!--
         add clone support for addition of cacheExceptionHandler. Important!
        -->
        <xs:element name="defaultCache">
            <xs:complexType>
                <xs:sequence>
                    <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheEventListenerFactory"/>
                    <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheExtensionFactory"/>
                    <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheLoaderFactory"/>
                    <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheDecoratorFactory"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="bootstrapCacheLoaderFactory"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="cacheExceptionHandlerFactory"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="pinning"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="terracotta"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="cacheWriter"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="copyStrategy"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="elementValueComparator"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="sizeOfPolicy"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="persistence"/>
                </xs:sequence>
                <xs:attribute name="diskExpiryThreadIntervalSeconds" type="xs:integer" use="optional"/>
                <xs:attribute name="diskSpoolBufferSizeMB" type="xs:integer" use="optional"/>
                <xs:attribute name="diskPersistent" type="xs:boolean" use="optional"/>
                <xs:attribute name="diskAccessStripes" type="xs:integer" use="optional" default="1"/>
                <xs:attribute name="eternal" type="xs:boolean" use="optional" default="false"/>
                <xs:attribute name="maxElementsInMemory" type="xs:nonNegativeInteger" use="optional"/>
                <xs:attribute name="maxEntriesLocalHeap" type="xs:nonNegativeInteger" use="optional"/>
                <xs:attribute name="clearOnFlush" type="xs:boolean" use="optional"/>
                <xs:attribute name="memoryStoreEvictionPolicy" type="xs:string" use="optional"/>
                <xs:attribute name="overflowToDisk" type="xs:boolean" use="optional"/>
                <xs:attribute name="timeToIdleSeconds" type="xs:nonNegativeInteger" use="optional"/>
                <xs:attribute name="timeToLiveSeconds" type="xs:nonNegativeInteger" use="optional"/>
                <xs:attribute name="maxElementsOnDisk" type="xs:nonNegativeInteger" use="optional"/>
                <xs:attribute name="maxEntriesLocalDisk" type="xs:nonNegativeInteger" use="optional"/>
                <xs:attribute name="transactionalMode" type="transactionalMode" use="optional" default="off"/>
                <xs:attribute name="statistics" type="xs:boolean" use="optional" default="false"/>
                <xs:attribute name="copyOnRead" type="xs:boolean" use="optional" default="false"/>
                <xs:attribute name="copyOnWrite" type="xs:boolean" use="optional" default="false"/>
                <xs:attribute name="cacheLoaderTimeoutMillis" type="xs:integer" use="optional" default="0"/>
                <xs:attribute name="overflowToOffHeap" type="xs:boolean" use="optional" default="false"/>
                <xs:attribute name="maxMemoryOffHeap" type="xs:string" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="cache">
            <xs:complexType>
                <xs:sequence>
                    <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheEventListenerFactory"/>
                    <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheExtensionFactory"/>
                    <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheLoaderFactory"/>
                    <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheDecoratorFactory"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="bootstrapCacheLoaderFactory"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="cacheExceptionHandlerFactory"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="pinning"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="terracotta"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="cacheWriter"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="copyStrategy"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="searchable"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="elementValueComparator"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="sizeOfPolicy"/>
                    <xs:element minOccurs="0" maxOccurs="1" ref="persistence"/>
                </xs:sequence>
                <xs:attribute name="diskExpiryThreadIntervalSeconds" type="xs:integer" use="optional"/>
                <xs:attribute name="diskSpoolBufferSizeMB" type="xs:integer" use="optional"/>
                <xs:attribute name="diskPersistent" type="xs:boolean" use="optional"/>
                <xs:attribute name="diskAccessStripes" type="xs:integer" use="optional" default="1"/>
                <xs:attribute name="eternal" type="xs:boolean" use="optional" default="false"/>
                <xs:attribute name="maxElementsInMemory" type="xs:nonNegativeInteger" use="optional"/>
                <xs:attribute name="maxEntriesLocalHeap" type="xs:nonNegativeInteger" use="optional"/>
                <xs:attribute name="memoryStoreEvictionPolicy" type="xs:string" use="optional"/>
                <xs:attribute name="clearOnFlush" type="xs:boolean" use="optional"/>
                <xs:attribute name="name" type="xs:string" use="required"/>
                <xs:attribute name="overflowToDisk" type="xs:boolean" use="optional"/>
                <xs:attribute name="timeToIdleSeconds" type="xs:nonNegativeInteger" use="optional"/>
                <xs:attribute name="timeToLiveSeconds" type="xs:nonNegativeInteger" use="optional"/>
                <xs:attribute name="maxElementsOnDisk" type="xs:nonNegativeInteger" use="optional"/>
                <xs:attribute name="maxEntriesLocalDisk" type="xs:nonNegativeInteger" use="optional"/>
                <xs:attribute name="maxEntriesInCache" type="xs:nonNegativeInteger" use="optional"/>
                <xs:attribute name="transactionalMode" type="transactionalMode" use="optional" default="off"/>
                <xs:attribute name="statistics" type="xs:boolean" use="optional" default="false"/>
                <xs:attribute name="copyOnRead" type="xs:boolean" use="optional" default="false"/>
                <xs:attribute name="copyOnWrite" type="xs:boolean" use="optional" default="false"/>
                <xs:attribute name="logging" type="xs:boolean" use="optional" default="false"/>
                <xs:attribute name="cacheLoaderTimeoutMillis" type="xs:integer" use="optional" default="0"/>
                <xs:attribute name="overflowToOffHeap" type="xs:boolean" use="optional" default="false"/>
                <xs:attribute name="maxMemoryOffHeap" type="xs:string" use="optional"/>
                <xs:attribute default="0" name="maxBytesLocalHeap" type="memoryUnitOrPercentage" use="optional"/>
                <xs:attribute default="0" name="maxBytesLocalOffHeap" type="memoryUnitOrPercentage" use="optional"/>
                <xs:attribute default="0" name="maxBytesLocalDisk" type="memoryUnitOrPercentage" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="cacheEventListenerFactory">
            <xs:complexType>
                <xs:attribute name="class" use="required"/>
                <xs:attribute name="properties" use="optional"/>
                <xs:attribute name="propertySeparator" use="optional"/>
                <xs:attribute name="listenFor" use="optional" type="notificationScope" default="all"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="bootstrapCacheLoaderFactory">
            <xs:complexType>
                <xs:attribute name="class" use="required"/>
                <xs:attribute name="properties" use="optional"/>
                <xs:attribute name="propertySeparator" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="cacheExtensionFactory">
            <xs:complexType>
                <xs:attribute name="class" use="required"/>
                <xs:attribute name="properties" use="optional"/>
                <xs:attribute name="propertySeparator" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="cacheExceptionHandlerFactory">
            <xs:complexType>
                <xs:attribute name="class" use="required"/>
                <xs:attribute name="properties" use="optional"/>
                <xs:attribute name="propertySeparator" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="cacheLoaderFactory">
            <xs:complexType>
                <xs:attribute name="class" use="required"/>
                <xs:attribute name="properties" use="optional"/>
                <xs:attribute name="propertySeparator" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="cacheDecoratorFactory">
            <xs:complexType>
                <xs:attribute name="class" use="required"/>
                <xs:attribute name="properties" use="optional"/>
                <xs:attribute name="propertySeparator" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="searchAttribute">
            <xs:complexType>
                <xs:attribute name="name" use="required" type="xs:string"/>
                <xs:attribute name="expression" type="xs:string"/>
                <xs:attribute name="class" type="xs:string"/>
                <xs:attribute name="type" type="xs:string" use="optional"/>
                <xs:attribute name="properties" use="optional"/>
                <xs:attribute name="propertySeparator" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="searchable">
            <xs:complexType>
                <xs:sequence>
                    <xs:element minOccurs="0" maxOccurs="unbounded" ref="searchAttribute"/>
                </xs:sequence>
                <xs:attribute name="keys" use="optional" type="xs:boolean" default="true"/>
                <xs:attribute name="values" use="optional" type="xs:boolean" default="true"/>
                <xs:attribute name="allowDynamicIndexing" use="optional" type="xs:boolean" default="false"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="pinning">
            <xs:complexType>
                <xs:attribute name="store" use="required" type="pinningStoreType"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="terracotta">
            <xs:complexType>
                <xs:sequence>
                    <xs:element minOccurs="0" maxOccurs="1" ref="nonstop"/>
                </xs:sequence>
                <xs:attribute name="clustered" use="optional" type="xs:boolean" default="true"/>
                <xs:attribute name="coherentReads" use="optional" type="xs:boolean" default="true"/>
                <xs:attribute name="localKeyCache" use="optional" type="xs:boolean" default="false"/>
                <xs:attribute name="localKeyCacheSize" use="optional" type="xs:positiveInteger" default="300000"/>
                <xs:attribute name="orphanEviction" use="optional" type="xs:boolean" default="true"/>
                <xs:attribute name="orphanEvictionPeriod" use="optional" type="xs:positiveInteger" default="4"/>
                <xs:attribute name="copyOnRead" use="optional" type="xs:boolean" default="false"/>
                <xs:attribute name="coherent" use="optional" type="xs:boolean" default="false"/>
                <xs:attribute name="consistency" use="optional" type="consistencyType" default="eventual"/>
                <xs:attribute name="synchronousWrites" use="optional" type="xs:boolean" default="false"/>
                <xs:attribute name="concurrency" use="optional" type="xs:nonNegativeInteger" default="0"/>
                <xs:attribute name="localCacheEnabled" use="optional" type="xs:boolean" default="true"/>
                <xs:attribute name="compressionEnabled" use="optional" type="xs:boolean" default="false"/>
            </xs:complexType>
        </xs:element>
        <xs:simpleType name="consistencyType">
            <xs:restriction base="xs:string">
                <xs:enumeration value="strong"/>
                <xs:enumeration value="eventual"/>
            </xs:restriction>
        </xs:simpleType>
        <xs:element name="nonstop">
            <xs:complexType>
                <xs:sequence>
                    <xs:element minOccurs="0" maxOccurs="1" ref="timeoutBehavior"/>
                </xs:sequence>
                <xs:attribute name="enabled" use="optional" type="xs:boolean" default="true"/>
                <xs:attribute name="immediateTimeout" use="optional" type="xs:boolean" default="false"/>
                <xs:attribute name="timeoutMillis" use="optional" type="xs:positiveInteger" default="30000"/>
                <xs:attribute name="searchTimeoutMillis" use="optional" type="xs:positiveInteger" default="30000"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="timeoutBehavior">
            <xs:complexType>
                <xs:attribute name="type" use="optional" type="timeoutBehaviorType" default="exception"/>
                <xs:attribute name="properties" use="optional" default=""/>
                <xs:attribute name="propertySeparator" use="optional" default=","/>
            </xs:complexType>
        </xs:element>
        <xs:simpleType name="timeoutBehaviorType">
            <xs:restriction base="xs:string">
                <xs:enumeration value="noop"/>
                <xs:enumeration value="exception"/>
                <xs:enumeration value="localReads"/>
                <xs:enumeration value="localReadsAndExceptionOnWrite"/>
            </xs:restriction>
        </xs:simpleType>
        <xs:simpleType name="monitoringType">
            <xs:restriction base="xs:string">
                <xs:enumeration value="autodetect"/>
                <xs:enumeration value="on"/>
                <xs:enumeration value="off"/>
            </xs:restriction>
        </xs:simpleType>
        <xs:simpleType name="pinningStoreType">
            <xs:restriction base="xs:string">
                <xs:enumeration value="localMemory"/>
                <xs:enumeration value="inCache"/>
            </xs:restriction>
        </xs:simpleType>
        <xs:simpleType name="terracottaCacheValueType">
            <xs:restriction base="xs:string">
                <xs:enumeration value="serialization"/>
                <xs:enumeration value="identity"/>
            </xs:restriction>
        </xs:simpleType>
        <xs:simpleType name="transactionalMode">
            <xs:restriction base="xs:string">
                <xs:enumeration value="off"/>
                <xs:enumeration value="xa_strict"/>
                <xs:enumeration value="xa"/>
                <xs:enumeration value="local"/>
            </xs:restriction>
        </xs:simpleType>
        <xs:element name="cacheWriter">
            <xs:complexType>
                <xs:sequence>
                    <xs:element minOccurs="0" maxOccurs="1" ref="cacheWriterFactory"/>
                </xs:sequence>
                <xs:attribute name="writeMode" use="optional" type="writeModeType" default="write-through"/>
                <xs:attribute name="notifyListenersOnException" use="optional" type="xs:boolean" default="false"/>
                <xs:attribute name="minWriteDelay" use="optional" type="xs:nonNegativeInteger" default="1"/>
                <xs:attribute name="maxWriteDelay" use="optional" type="xs:nonNegativeInteger" default="1"/>
                <xs:attribute name="rateLimitPerSecond" use="optional" type="xs:nonNegativeInteger" default="0"/>
                <xs:attribute name="writeCoalescing" use="optional" type="xs:boolean" default="false"/>
                <xs:attribute name="writeBatching" use="optional" type="xs:boolean" default="false"/>
                <xs:attribute name="writeBatchSize" use="optional" type="xs:positiveInteger" default="1"/>
                <xs:attribute name="retryAttempts" use="optional" type="xs:nonNegativeInteger" default="0"/>
                <xs:attribute name="retryAttemptDelaySeconds" use="optional" type="xs:nonNegativeInteger" default="1"/>
                <xs:attribute name="writeBehindConcurrency" use="optional" type="xs:nonNegativeInteger" default="1"/>
                <xs:attribute name="writeBehindMaxQueueSize" use="optional" type="xs:nonNegativeInteger" default="0"/>
            </xs:complexType>
        </xs:element>
        <xs:simpleType name="writeModeType">
            <xs:restriction base="xs:string">
                <xs:enumeration value="write-through"/>
                <xs:enumeration value="write-behind"/>
            </xs:restriction>
        </xs:simpleType>
        <xs:element name="cacheWriterFactory">
            <xs:complexType>
                <xs:attribute name="class" use="required"/>
                <xs:attribute name="properties" use="optional"/>
                <xs:attribute name="propertySeparator" use="optional"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="copyStrategy">
            <xs:complexType>
                <xs:attribute name="class" use="required" type="xs:string"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="elementValueComparator">
            <xs:complexType>
                <xs:attribute name="class" use="required" type="xs:string"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="sizeOfPolicy">
            <xs:complexType>
                <xs:attribute name="maxDepth" use="required" type="xs:integer"/>
                <xs:attribute name="maxDepthExceededBehavior" use="optional" default="continue"
                              type="maxDepthExceededBehavior"/>
            </xs:complexType>
        </xs:element>
        <xs:element name="persistence">
            <xs:complexType>
                <xs:attribute name="strategy" use="required" type="persistenceStrategy"/>
                <xs:attribute name="synchronousWrites" use="optional" default="false" type="xs:boolean"/>
            </xs:complexType>
        </xs:element>
        <xs:simpleType name="persistenceStrategy">
            <xs:restriction base="xs:string">
                <xs:enumeration value="localTempSwap"/>
                <xs:enumeration value="localRestartable"/>
                <xs:enumeration value="none"/>
                <xs:enumeration value="distributed"/>
            </xs:restriction>
        </xs:simpleType>
        <xs:simpleType name="maxDepthExceededBehavior">
            <xs:restriction base="xs:string">
                <xs:enumeration value="continue"/>
                <xs:enumeration value="abort"/>
            </xs:restriction>
        </xs:simpleType>
        <xs:simpleType name="notificationScope">
            <xs:restriction base="xs:string">
                <xs:enumeration value="local"/>
                <xs:enumeration value="remote"/>
                <xs:enumeration value="all"/>
            </xs:restriction>
        </xs:simpleType>
        <xs:simpleType name="memoryUnit">
            <xs:restriction base="xs:token">
                <xs:pattern value="[0-9]+[bBkKmMgG]?"/>
            </xs:restriction>
        </xs:simpleType>
        <xs:simpleType name="memoryUnitOrPercentage">
            <xs:restriction base="xs:token">
                <xs:pattern value="([0-9]+[bBkKmMgG]?|100%|[0-9]{1,2}%)"/>
            </xs:restriction>
        </xs:simpleType>
    </xs:schema>
    

    每次新增或修改数据字典时候清空当前缓存

    /**
         * 保存
         * @param entity
         * @return
         */
        @RequestMapping("/save")
        @RequiresPermissions("dictionaries:list")
        @CacheEvict(value="dictEhcache", allEntries=true) //清空缓存
        public R save(@RequestBody DictionariesEntity entity) {
            String errMassage = "保存失败";
            if(entity != null){
                Map<String,Object> parMap = new HashMap<>();
                parMap.put("field_name",entity.getFieldName());
                parMap.put("field_value",entity.getFieldValue());
                Collection<DictionariesEntity> collections = service.listByMap(parMap);
                if(collections.size()==0){
                    boolean b = service.save(entity);
                    if (b) {
                        return R.ok();
                    }
                }else {
                    errMassage="该表'字段名'和'字段码值'已存在";
                }
            }
            return R.error().put("msg",errMassage);
        }
    
    

    数据表

    pz_dictionaries表字段:

    字段名类型备注
    idvarcharuuid,唯一标识
    field_namevarchar对应表格字段名
    field_valuevarchar字段值
    field_detailvarchar字段说明
    field_describevarchar具体描述

    表格图片:

    在这里插入图片描述

    表格数据样例

    在这里插入图片描述

    使用样例

    
    
     /**
         * 子任务状态
         */
        @TableField("subtask_status")
        @Dict(dictDataSource = "subtask_status")//需要翻译的实体类字段加上注解
        private String subtaskStatus;
    
    
    ==============================前端样例======================================
    
    <el-table-column
              prop="subtaskStatus_dictText" //在字段后加上_dictText
              header-align="center"
              align="center"
              label="子任务状态">
            </el-table-column>
    
    展开全文
  • 后台字典翻译

    2019-05-04 14:29:12
  • 1、编写视图时遇到多选的字典编码需要转换多选的名称时,比如将‘1,2,3...’ 转换成‘是,否,未知’ 2、通过函数实现,传入值1)字段名,2)对应关系,返回翻译后的中文多选字符串。
  • 适用于Spring Boot的字典翻译扩展 在常见的web应用中,有很多数据库字段会使用字典值,但是在数据查询时,我们需要将存储的字典值转换成对应的字典标签(value>>name),用于展示给用户。常见的转换方式为从...
  • 字典翻译注解 @Dict : 用于列表字段字典翻译,将数据库某一列的值按照字典配置翻译成对应的文字描述。(比如字段status存的值是1,会自动生成一个翻译字段 status_dictText 值是‘已付款’) 实现步骤: 1.配置数据...
  • wintersweet 字典翻译

    2010-05-18 10:09:38
    可以不联网实用,方便。快速查阅英文,准确具体,深受众多用户的喜爱
  • 字典翻译注解讲解

    千次阅读 2019-04-16 10:43:00
    dictNameFiled 目标字段,将字典翻译后的值存入的字段名,为了维护需要在javabean中包含这个字段 例子 注解需要使用在service方法上 翻译完成后 注意 使用时要引入 <groupId>...
  • 找到字典切面类(DictAspect) 改造方法(parseDictText) 支持自动生成的列表接口/单个实体类查询翻译 代码如下: private void parseDictText(Object result) { if (result instanceof Result) { if (((Result) ...
  • 本博文用自定义注解结合aop实现数据字典的自动翻译 源码 首先附上数据库表结构: 数据字典表(dict) 数据字典类型中间表(dict_type) 用户表(user) 注解类(Dict) package com.xiaoyang.annotation; ...
  • java枚举类-字典翻译

    2020-04-22 08:58:13
    枚举类 public enum TestEnum { SEX_01("男性", "SEX_01"), SEX_02("女性", "SEX_02"), ... } } 翻译方法 if (person.getSexCode() != null) { person.setSexText(TestEnum.valueOf(person.getSexCode()).getText()); }
  • 标签: 假设表A是常见的系统字典表,包括id和name两个字段。 表B中某字段存的是表A的id,B表页面数据增加、修改时,那个...在我看来,就是页面字典翻译。   做了一天的尝试,先尝试把combobox嵌入grid的column
  • 一 Vim中取词翻译 1.先安装sdcv sdcv全称为stardictconsole version,即终端下的词典。 首先,安装:sudoapt-get install sdcv 安装后可以在命令行查单词,输入sdcv ,按下ENTER键进入字典  当然是查不到的,...
  • }, // 学历字典翻译 highestEducationFormat(row, column) { return this.selectDictLabel(this.educationList, row.highestEducation); }, // 专业字典翻译 majorTypeFormat(row, column) { return this....
  • * 动态表格字典翻译 */ showDictValue(val,dictnum){ var dict_val= dict$.getOpts(dictnum); for (var i=0;i;i++) { if (val == dict_val[i].dictItem) { return dict_val[i].dictItemName } } } /...
  • 牛津字典英文翻译配合字典软件使用
  • java通过注解翻译字典

    2021-05-15 17:28:50
    最近在写代码时遇到一个需要将entity字段通过字典翻译成真实值的场景,原来的做法是通过主表字段和字典表关联的形式,当一个需要大量翻译的场景时,大量的关联会造成sql阅读的不友好,所以就在想有什么可以偷懒的...
  • 海朗道电脑科技发展有限公司开发的集专业化的多媒体电脑字典、即时全 屏汉化系统、全文翻译系统为一体的电脑字典翻译系统, 适 用于DOS、WIN3.X、WIN9X、WINNT等所有中西文操作系统, 支持IE、Netscape等所有网络...
  • 字典软件是一款为用户提供汉语字典,词语字典,成语字典,在线翻译,繁体转换等一系列工具性的软件。 提供查作文,查课件等功能为老师同学提供必备工具。另包含散文通读,对联、笑话、网络红人、科普知识、 歇后...
  • 最近项目中数据字典的配置使用越来越多,导致代码中有大量的数据字典翻译工作,使得代码的整洁性和维护性变差。排除掉对数据结果进行“清洗”的方案后,还是决定通过注解的方式来解决这个问题。参考了一些文章后完成...
  • 字典翻译在我们应用里是一个很正常普遍的需求。 对于小型项目我们可能在数据库设计层面通常不会进行分库处理,那么对于此类项目,通常字典翻译会通过sql语句的子查询来处理,如果业务系统中存在较多的字段为code值...
  • 在数据清洗转换中,常见的字典翻译,如性别在原表中是1(男)、2(女)等,类似还有很多较大的字典需要翻译,若同一个表中有很多个字典需要翻译,采用【数据库查询】方式翻译的话效率就会相当低下。  这里采用java...
  • oracle 多选字典翻译

    2011-07-29 16:26:49
    该函数主要对oracle 中数据表中存在的多选字典值进行翻译
  • #初学python,字典实现翻译系统 学习字典时的突发奇想,不多说,上代码。 #!/usr/bin/env python #-*- coding utf-8 -*- # author:luoyejingchen import string import sys print(&amp;quot;------欢迎使用翻译...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 56,888
精华内容 22,755
关键字:

字典翻译