若依(微服务版)导入导出关联动态字典值

前言

需求背景:
     业务系统需要做EXCEL的导入和导出功能,某些字段是系统字典值,改造之前只能应用@Excel注解的combo属性来做下拉限制,用readConverterExp属性来做表达式实际值和显示值的转换。

每当运维人员在系统增加一个字典值的时候,都要来修改代码,太麻烦了。

期望效果:

能够根据系统字典值,动态限制下拉框内容,动态进行实际值和显示值的转换,无需每次都修改代码。同时保留readConverterExp和combo属性的效果

单体版若依

单体版若依网上有很多,这里不在赘述,上连接

  • 文章1:

https://blog.csdn.net/wangmj518/article/details/128438841?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-128438841-blog-126104814.235%5Ev38%5Epc_relevant_sort_base3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-128438841-blog-126104814.235%5Ev38%5Epc_relevant_sort_base3&utm_relevant_index=2

  • 文章2:

https://blog.csdn.net/wcnmbbbb/article/details/117952232

两个文章内容基本一样,下边的微服务版,也是这种思路,不过需要做一点特殊处理

微服务版若依

在网上找了很多都是单体版的解决方式,微服务版目前,官方目前还没有给出解决思路,这里就套用一下单体版的修改做一点修改

整体思路

  1. 修改或者新建一个新的@Excel进行修改

  2. 转移或者新建ExcelUtil.java,并进行修改

  3. 新建DictUtils.java

  4. 想办法让ExcelUtil.java中可以调用DictUtils.java(坑点)

  5. 修改RedisService.java,添加方法(坑点)

套用单体版修改会有两大坑:

坑一

这里主要是针对上述中的第4点( 想办法让ExcelUtil.java中可以调用DictUtils.java )

若依(微服务版)把@Excel注解写在了[ruoyi-common-core] 模块,这是一个底层模块,但是我们需要拿缓存,即需要操作redis,

把单体版的操作,转移到[ruoyi-common-redis]模块

所以我们有两种思路解决

  • 思路一: 不如大胆的在别的模块再搞一个@Excel

优点:不影响原来的注解,完全独立,改动小

缺点: 以后使用注解的时候要注意导包不要导错,使用ExcelUtil也要注意要使用自己新创建的

  • 思路二: 转移 [ExcelUtil.java]文件位置到可以操作的转移到[ruoyi-common-redis]模块下

优点:直接在原注解上进行操作,不会出现两个@Excel注解

缺点:需要把我们之前所有引用过ExcelUtil.java的包都改成自己的,改动文件很多

选什么自己决定把,这里就不做推荐了,最后的完整代码是使用的思路一

坑二

这里针对的上述的第5点(修改RedisService.java,添加方法(坑点))

当我们解决完坑一的时候,就遇到了坑二

image-20230724153706390

其中DictUtils.java有一个方法

     /**
      * 获取字典缓存
      *
      * @param key 参数键
      * @return dictDatas 字典数据列表
      */
     public static List<SysDictData> getDictCache(String key)
    {
         Object cacheObj = SpringUtils.getBean(RedisService.class).getCacheObject(getCacheKey(key));
         if (StringUtils.isNotNull(cacheObj))
        {
             // 这一步在转类型 会报转换异常 失败原因主要是redis里有一个 @type 会规定必须转换的包一致
             List<SysDictData> dictDatas = StringUtils.cast(cacheObj);
             return dictDatas;
        }
         return null;
    }

知道了原因,就好搞了,具体解决办法网上有很多

https://blog.csdn.net/weixin_42169734/article/details/119609957

 
 // 修改getDictCache
     public static List<SysDictData> getDictCache(String key)
    {
         List<JSONArray> cacheListString = SpringUtils.getBean(RedisService.class).getCacheListString(getCacheKey(key));
 
         if (StringUtils.isNotNull(cacheListString)){
             JSONArray objects = cacheListString.get(0);
             List<SysDictData> sysDictData = JSONArray.parseArray(objects.toJSONString(), SysDictData.class);
             return sysDictData;
        }
         return null;
    }

// 在RedisService类中方法中添加getCacheListString方法

     public  List<JSONArray>   getCacheListString(final String key)
    {
         return  redisTemplate.opsForValue().multiGet(Arrays.asList(key));
    }

完整代码

Excel注解

 /**
  * 自定义导出Excel数据注解
  *
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.FIELD)
 public @interface Excel
 {
     /**
      * 导出时在excel中排序
      */
     public int sort() default Integer.MAX_VALUE;
 
     /**
      * 导出到Excel中的名字.
      */
     public String name() default "";
 
     /**
      * 日期格式, 如: yyyy-MM-dd
      */
     public String dateFormat() default "";
 
     /**
      * 读取内容转表达式 (如: 0=男,1=女,2=未知)
      */
     public String readConverterExp() default "";
     /**
      * 如果是字典类型,请设置字典的type值
      * >>>>>>>特别提醒,如若配置该字段,则“combo”和“readConverterExp”不启用
      */
     public String dictType() default "";
     /**
      * 分隔符,读取字符串组内容
      */
     public String separator() default ",";
 
     /**
      * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
      */
     public int scale() default -1;
 
     /**
      * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
      */
     public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
 
     /**
      * 导出类型(0数字 1字符串)
      */
     public ColumnType cellType() default ColumnType.STRING;
 
     /**
      * 导出时在excel中每个列的高度 单位为字符
      */
     public double height() default 14;
 
     /**
      * 导出时在excel中每个列的宽 单位为字符
      */
     public double width() default 16;
 
     /**
      * 文字后缀,如% 90 变成90%
      */
     public String suffix() default "";
 
     /**
      * 当值为空时,字段的默认值
      */
     public String defaultValue() default "";
 
     /**
      * 提示信息
      */
     public String prompt() default "";
 
     /**
      * 设置只能选择不能输入的列内容.
      */
     public String[] combo() default {};
 
     /**
      * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
      */
     public boolean isExport() default true;
 
     /**
      * 另一个类中的属性名称,支持多级获取,以小数点隔开
      */
     public String targetAttr() default "";
 
     /**
      * 是否自动统计数据,在最后追加一行统计数据总和
      */
     public boolean isStatistics() default false;
 
     /**
      * 导出字段对齐方式(0:默认;1:靠左;2:居中;3:靠右)
      */
     Align align() default Align.AUTO;
 
     public enum Align
    {
         AUTO(0), LEFT(1), CENTER(2), RIGHT(3);
         private final int value;
 
         Align(int value)
        {
             this.value = value;
        }
 
         public int value()
        {
             return this.value;
        }
    }
 
     /**
      * 字段类型(0:导出导入;1:仅导出;2:仅导入)
      */
     Type type() default Type.ALL;
 
     public enum Type
    {
         ALL(0), EXPORT(1), IMPORT(2);
         private final int value;
 
         Type(int value)
        {
             this.value = value;
        }
 
         public int value()
        {
             return this.value;
        }
    }
 
     public enum ColumnType
    {
         NUMERIC(0), STRING(1), IMAGE(2);
         private final int value;
 
         ColumnType(int value)
        {
             this.value = value;
        }
 
         public int value()
        {
             return this.value;
        }
    }
 }

 

DictUtils.java

 /**
  * 字典工具类
  *
  */
 public class DictUtils
 {
     /**
      * 设置字典缓存
      *
      * @param key 参数键
      * @param dictDatas 字典数据列表
      */
     public static void setDictCache(String key, List<SysDictData> dictDatas)
    {
         SpringUtils.getBean(RedisService.class).setCacheObject(getCacheKey(key), dictDatas);
    }
 
     /**
      * 获取字典缓存
      *
      * @param key 参数键
      * @return dictDatas 字典数据列表
      */
     public static List<SysDictData> getDictCache(String key)
    {
         List<JSONArray> cacheListString = SpringUtils.getBean(RedisService.class).getCacheListString(getCacheKey(key));
 
         if (StringUtils.isNotNull(cacheListString)){
             JSONArray objects = cacheListString.get(0);
             List<SysDictData> sysDictData = JSONArray.parseArray(objects.toJSONString(), SysDictData.class);
             return sysDictData;
        }
         return null;
    }
 
     /**
      * 清空字典缓存
      */
     public static void clearDictCache()
    {
         Collection<String> keys = SpringUtils.getBean(RedisService.class).keys(Constants.SYS_DICT_KEY + "*");
         SpringUtils.getBean(RedisService.class).deleteObject(keys);
    }
 
     /**
      * 设置cache key
      *
      * @param configKey 参数键
      * @return 缓存键key
      */
     public static String getCacheKey(String configKey)
    {
         return Constants.SYS_DICT_KEY + configKey;
    }
 
 
 
     /**
      * 根据指定的type ,value 获取 label
      * @param value
      * @param type
      * @param defaultLabel 默认label
      * @return
      */
     public static String getDictLabelByTypeAndValue(String value, String type, String defaultLabel){
         if (StringUtils.isNotBlank(type) && StringUtils.isNotBlank(value)){
             for (SysDictData dict : getDictCache(type)){
                 if (type.equals(dict.getDictType()) && value.equals(dict.getDictValue())){
                     return dict.getDictLabel();
                }
            }
        }
         return defaultLabel;
    }
     /**
      * 根据type,label 获取value
      *
      * @param label
      * @param type
      * @param
      * @return
      */
     public static String  getDictValueByTypeAndLabel(String label,String type,String defaultValue) {
         if (StringUtils.isNotBlank(type) && StringUtils.isNotBlank(label)){
             for (SysDictData dict : getDictCache(type)){
                 if(type.equals(dict.getDictType())  && label.equals(dict.getDictLabel())) {
                     return dict.getDictValue();
                }
            }
        }
         return defaultValue;
    }
 
     /**
      * 根据 type 将 lable组成 string数组
      * @param type
      * @return
      */
     public static String[] getLabelArr(String type) {
         String[] arr0 = new String[0];
         if (StringUtils.isNotBlank(type)) {
             List<SysDictData> dictList = getDictCache(type);
             String[] strArr = new String[dictList.size()];
             for (int i = 0 ; i < dictList.size() ; i ++) {
                 strArr[i] = dictList.get(i).getDictLabel();
            }
             return strArr;
        }
         return arr0;
    }
 
 }

ExcelUtil.java

 /**
  * Excel相关处理
  *
  */
 public class ExcelUtil<T>
 {
     private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
 
     /**
      * Excel sheet最大行数,默认65536
      */
     public static final int sheetSize = 65536;
 
     /**
      * 工作表名称
      */
     private String sheetName;
 
     /**
      * 导出类型(EXPORT:导出数据;IMPORT:导入模板)
      */
     private Excel.Type type;
 
     /**
      * 工作薄对象
      */
     private Workbook wb;
 
     /**
      * 工作表对象
      */
     private Sheet sheet;
 
     /**
      * 样式列表
      */
     private Map<String, CellStyle> styles;
 
     /**
      * 导入导出数据列表
      */
     private List<T> list;
 
     /**
      * 注解列表
      */
     private List<Object[]> fields;
 
     /**
      * 最大高度
      */
     private short maxHeight;
 
     /**
      * 统计列表
      */
     private Map<Integer, Double> statistics = new HashMap<Integer, Double>();
 
     /**
      * 数字格式
      */
     private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00");
 
     /**
      * 实体对象
      */
     public Class<T> clazz;
 
     public ExcelUtil(Class<T> clazz)
    {
         this.clazz = clazz;
    }
 
     public void init(List<T> list, String sheetName, Excel.Type type)
    {
         if (list == null)
        {
             list = new ArrayList<T>();
        }
         this.list = list;
         this.sheetName = sheetName;
         this.type = type;
         createExcelField();
         createWorkbook();
    }
 
     /**
      * 对excel表单默认第一个索引名转换成list
      *
      * @param is 输入流
      * @return 转换后集合
      */
     public List<T> importExcel(InputStream is) throws Exception
    {
         return importExcel(StringUtils.EMPTY, is);
    }
 
     /**
      * 对excel表单指定表格索引名转换成list
      *
      * @param sheetName 表格索引名
      * @param is 输入流
      * @return 转换后集合
      */
     public List<T> importExcel(String sheetName, InputStream is) throws Exception
    {
         this.type = Excel.Type.IMPORT;
         this.wb = WorkbookFactory.create(is);
         List<T> list = new ArrayList<T>();
         Sheet sheet = null;
         if (StringUtils.isNotEmpty(sheetName))
        {
             // 如果指定sheet名,则取指定sheet中的内容.
             sheet = wb.getSheet(sheetName);
        }
         else
        {
             // 如果传入的sheet名不存在则默认指向第1个sheet.
             sheet = wb.getSheetAt(0);
        }
 
         if (sheet == null)
        {
             throw new IOException("文件sheet不存在");
        }
 
         int rows = sheet.getPhysicalNumberOfRows();
 
         if (rows > 0)
        {
             // 定义一个map用于存放excel列的序号和field.
             Map<String, Integer> cellMap = new HashMap<String, Integer>();
             // 获取表头
             Row heard = sheet.getRow(0);
             for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++)
            {
                 Cell cell = heard.getCell(i);
                 if (StringUtils.isNotNull(cell))
                {
                     String value = this.getCellValue(heard, i).toString();
                     cellMap.put(value, i);
                }
                 else
                {
                     cellMap.put(null, i);
                }
            }
             // 有数据时才处理 得到类的所有field.
             Field[] allFields = clazz.getDeclaredFields();
             // 定义一个map用于存放列的序号和field. 
           Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>(); 
           for (int col = 0; col < allFields.length; col++) 
          { 
               Field field = allFields[col]; 
               Excel attr = field.getAnnotation(Excel.class); 
               if (attr != null && (attr.type() == Excel.Type.ALL || attr.type() == type)) 
              { 
                   // 设置类的私有字段属性可访问. 
                   field.setAccessible(true); 
                   Integer column = cellMap.get(attr.name()); 
                   if (column != null) 
                  { 
                       fieldsMap.put(column, field); 
                  } 
              } 
          } 
           for (int i = 1; i < rows; i++) 
          { 
               // 从第2行开始取数据,默认第一行是表头. 
               Row row = sheet.getRow(i); 
               T entity = null; 
               for (Map.Entry<Integer, Field> entry : fieldsMap.entrySet()) 
              { 
                   Object val = this.getCellValue(row, entry.getKey()); 
​ 
                   // 如果不存在实例则新建. 
                   entity = (entity == null ? clazz.newInstance() : entity); 
                   // 从map中得到对应列的field. 
                   Field field = fieldsMap.get(entry.getKey()); 
                   // 取得类型,并根据对象类型设置值. 
                   Class<?> fieldType = field.getType(); 
                   if (String.class == fieldType) 
                  { 
                       String s = Convert.toStr(val); 
                       if (StringUtils.endsWith(s, ".0")) 
                      { 
                           val = StringUtils.substringBefore(s, ".0"); 
                      } 
                       else 
                      { 
                           String dateFormat = field.getAnnotation(Excel.class).dateFormat(); 
                           if (StringUtils.isNotEmpty(dateFormat)) 
                          { 
                               val = DateUtils.parseDateToStr(dateFormat, (Date) val); 
                          } 
                           else 
                          { 
                               val = Convert.toStr(val); 
                          } 
                      } 
                  } 
                   else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) 
                  { 
                       val = Convert.toInt(val); 
                  } 
                   else if (Long.TYPE == fieldType || Long.class == fieldType) 
                  { 
                       val = Convert.toLong(val); 
                  } 
                   else if (Double.TYPE == fieldType || Double.class == fieldType) 
                  { 
                       val = Convert.toDouble(val); 
                  } 
                   else if (Float.TYPE == fieldType || Float.class == fieldType) 
                  { 
                       val = Convert.toFloat(val); 
                  } 
                   else if (BigDecimal.class == fieldType) 
                  { 
                       val = Convert.toBigDecimal(val); 
                  } 
                   else if (Date.class == fieldType) 
                  { 
                       if (val instanceof String) 
                      { 
                           val = DateUtils.parseDate(val); 
                      } 
                       else if (val instanceof Double) 
                      { 
                           val = DateUtil.getJavaDate((Double) val); 
                      } 
                  } 
                   else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) 
                  { 
                       val = Convert.toBool(val, false); 
                  } 
                   if (StringUtils.isNotNull(fieldType)) 
                  { 
                       Excel attr = field.getAnnotation(Excel.class); 
                       String propertyName = field.getName(); 
                       if (StringUtils.isNotEmpty(attr.targetAttr())) 
                      { 
                           propertyName = field.getName() + "." + attr.targetAttr(); 
                      }else if(StringUtils.isNotEmpty(attr.dictType())) { 
                           val = getDictValueByTypeAndLabel(String.valueOf(val), attr.dictType()); 
                      } else if (StringUtils.isNotEmpty(attr.readConverterExp())) 
                      { 
                           val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); 
                      } 
                       ReflectUtils.invokeSetter(entity, propertyName, val); 
                  } 
              } 
               list.add(entity); 
          } 
      } 
       return list; 
  } 
​ 
   /** 
    * 根据type,label 获取value 
    * @param 
    * @param dictType 
    * @return 
    * @throws Exception 
    */ 
   public static String getDictValueByTypeAndLabel(String propertyLabel, String dictType) throws Exception { 
       String value = propertyLabel; 
       try { 
           value = DictUtils.getDictValueByTypeAndLabel(propertyLabel, dictType, propertyLabel); 
      } catch (Exception e) { 
           throw e; 
      } 
       return value; 
  } 
   /** 
    * 对list数据源将其里面的数据导入到excel表单 
   
    * @param response 返回数据 
    * @param list 导出数据集合 
    * @param sheetName 工作表的名称 
    * @return 结果 
    * @throws IOException 
    */ 
   public void exportExcel(HttpServletResponse response, List<T> list, String sheetName) throws IOException 
  { 
       response.setContentType("application/vnd.ms-excel"); 
       response.setCharacterEncoding("utf-8"); 
       this.init(list, sheetName, Excel.Type.EXPORT); 
       exportExcel(response.getOutputStream()); 
  } 
​ 
   /** 
    * 对list数据源将其里面的数据导入到excel表单 
   
    * @param sheetName 工作表的名称 
    * @return 结果 
    */ 
   public void importTemplateExcel(HttpServletResponse response, String sheetName) throws IOException 
  { 
       response.setContentType("application/vnd.ms-excel"); 
       response.setCharacterEncoding("utf-8"); 
       this.init(null, sheetName, Excel.Type.IMPORT); 
       exportExcel(response.getOutputStream()); 
  } 
​ 
   /** 
    * 对list数据源将其里面的数据导入到excel表单 
   
    * @return 结果 
    */ 
   public void exportExcel(OutputStream outputStream) 
  { 
       try 
      { 
           // 取出一共有多少个sheet. 
           double sheetNo = Math.ceil(list.size() / sheetSize); 
           for (int index = 0; index <= sheetNo; index++) 
          { 
               createSheet(sheetNo, index); 
​ 
               // 产生一行 
               Row row = sheet.createRow(0); 
               int column = 0; 
               // 写入各个字段的列头名称 
               for (Object[] os : fields) 
              { 
                   Excel excel = (Excel) os[1]; 
                   this.createCell(excel, row, column++); 
              } 
               if (Excel.Type.EXPORT.equals(type)) 
              { 
                   fillExcelData(index, row); 
                   addStatisticsRow(); 
              } 
          } 
           wb.write(outputStream); 
      } 
       catch (Exception e) 
      { 
           log.error("导出Excel异常{}", e.getMessage()); 
      } 
       finally 
      { 
           if (wb != null) 
          { 
               try 
              { 
                   wb.close(); 
              } 
               catch (IOException e1) 
              { 
                   e1.printStackTrace(); 
              } 
          } 
           if (outputStream != null) 
          { 
               try 
              { 
                   outputStream.close(); 
              } 
               catch (IOException e1) 
              { 
                   e1.printStackTrace(); 
              } 
          } 
      } 
  } 
​ 
   /** 
    * 填充excel数据 
   
    * @param index 序号 
    * @param row 单元格行 
    */ 
   public void fillExcelData(int index, Row row) 
  { 
       int startNo = index * sheetSize; 
       int endNo = Math.min(startNo + sheetSize, list.size()); 
       for (int i = startNo; i < endNo; i++) 
      { 
           row = sheet.createRow(i + 1 - startNo); 
           // 得到导出对象. 
           T vo = (T) list.get(i); 
           int column = 0; 
           for (Object[] os : fields) 
          { 
               Field field = (Field) os[0]; 
               Excel excel = (Excel) os[1]; 
               // 设置实体类私有属性可访问 
               field.setAccessible(true); 
               this.addCell(excel, row, vo, field, column++); 
          } 
      } 
  } 
​ 
   /** 
    * 创建表格样式 
   
    * @param wb 工作薄对象 
    * @return 样式列表 
    */ 
   private Map<String, CellStyle> createStyles(Workbook wb) 
  { 
       // 写入各条记录,每条记录对应excel表中的一行 
       Map<String, CellStyle> styles = new HashMap<String, CellStyle>(); 
       CellStyle style = wb.createCellStyle(); 
       style.setAlignment(HorizontalAlignment.CENTER); 
       style.setVerticalAlignment(VerticalAlignment.CENTER); 
       style.setBorderRight(BorderStyle.THIN); 
       style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); 
       style.setBorderLeft(BorderStyle.THIN); 
       style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); 
       style.setBorderTop(BorderStyle.THIN); 
       style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); 
       style.setBorderBottom(BorderStyle.THIN); 
       style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); 
       Font dataFont = wb.createFont(); 
       dataFont.setFontName("Arial"); 
       dataFont.setFontHeightInPoints((short) 10); 
       style.setFont(dataFont); 
       styles.put("data", style); 
​ 
       style = wb.createCellStyle(); 
       style.cloneStyleFrom(styles.get("data")); 
       style.setAlignment(HorizontalAlignment.CENTER); 
       style.setVerticalAlignment(VerticalAlignment.CENTER); 
       style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); 
       style.setFillPattern(FillPatternType.SOLID_FOREGROUND); 
       Font headerFont = wb.createFont(); 
       headerFont.setFontName("Arial"); 
       headerFont.setFontHeightInPoints((short) 10); 
       headerFont.setBold(true); 
       headerFont.setColor(IndexedColors.WHITE.getIndex()); 
       style.setFont(headerFont); 
       styles.put("header", style); 
​ 
       style = wb.createCellStyle(); 
       style.setAlignment(HorizontalAlignment.CENTER); 
       style.setVerticalAlignment(VerticalAlignment.CENTER); 
       Font totalFont = wb.createFont(); 
       totalFont.setFontName("Arial"); 
       totalFont.setFontHeightInPoints((short) 10); 
       style.setFont(totalFont); 
       styles.put("total", style); 
​ 
       style = wb.createCellStyle(); 
       style.cloneStyleFrom(styles.get("data")); 
       style.setAlignment(HorizontalAlignment.LEFT); 
       styles.put("data1", style); 
​ 
       style = wb.createCellStyle(); 
       style.cloneStyleFrom(styles.get("data")); 
       style.setAlignment(HorizontalAlignment.CENTER); 
       styles.put("data2", style); 
​ 
       style = wb.createCellStyle(); 
       style.cloneStyleFrom(styles.get("data")); 
       style.setAlignment(HorizontalAlignment.RIGHT); 
       styles.put("data3", style); 
​ 
       return styles; 
  } 
​ 
   /** 
    * 创建单元格 
    */ 
   public Cell createCell(Excel attr, Row row, int column) 
  { 
       // 创建列 
       Cell cell = row.createCell(column); 
       // 写入列信息 
       cell.setCellValue(attr.name()); 
       setDataValidation(attr, row, column); 
       cell.setCellStyle(styles.get("header")); 
       return cell; 
  } 
​ 
   /** 
    * 设置单元格信息 
   
    * @param value 单元格值 
    * @param attr 注解相关 
    * @param cell 单元格信息 
    */ 
   public void setCellVo(Object value, Excel attr, Cell cell) 
  { 
       if (Excel.ColumnType.STRING == attr.cellType()) 
      { 
           cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix()); 
      } 
       else if (Excel.ColumnType.NUMERIC == attr.cellType()) 
      { 
           cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); 
      } 
       else if (Excel.ColumnType.IMAGE == attr.cellType()) 
      { 
           ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), 
                   cell.getRow().getRowNum() + 1); 
           String imagePath = Convert.toStr(value); 
           if (StringUtils.isNotEmpty(imagePath)) 
          { 
               byte[] data = ImageUtils.getImage(imagePath); 
               getDrawingPatriarch(cell.getSheet()).createPicture(anchor, 
                       cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); 
          } 
      } 
  } 
​ 
   /** 
    * 获取画布 
    */ 
   public static Drawing<?> getDrawingPatriarch(Sheet sheet) 
  { 
       if (sheet.getDrawingPatriarch() == null) 
      { 
           sheet.createDrawingPatriarch(); 
      } 
       return sheet.getDrawingPatriarch(); 
  } 
​ 
   /** 
    * 获取图片类型,设置图片插入类型 
    */ 
   public int getImageType(byte[] value) 
  { 
       String type = FileTypeUtils.getFileExtendName(value); 
       if ("JPG".equalsIgnoreCase(type)) 
      { 
           return Workbook.PICTURE_TYPE_JPEG; 
      } 
       else if ("PNG".equalsIgnoreCase(type)) 
      { 
           return Workbook.PICTURE_TYPE_PNG; 
      } 
       return Workbook.PICTURE_TYPE_JPEG; 
  } 
​ 
   /** 
    * 创建表格样式 
    */ 
   public void setDataValidation(Excel attr, Row row, int column) 
  { 
       if (attr.name().indexOf("注:") >= 0) 
      { 
           sheet.setColumnWidth(column, 6000); 
      } 
       else 
      { 
           // 设置列宽 
           sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); 
      } 
       // 如果设置了提示信息则鼠标放上去提示. 
       if (StringUtils.isNotEmpty(attr.prompt())) 
      { 
           // 这里默认设了2-101列提示. 
           setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column); 
      } 
​ 
       if(StringUtils.isNotEmpty(attr.dictType())) {//有字典 则取字典下拉 
           setXSSFValidation(sheet, DictUtils.getLabelArr(attr.dictType()), 1, 100, column, column); 
      }else if (attr.combo().length > 0)// 如果设置了combo属性则本列只能选择不能输入 
      { 
           // 这里默认设了2-101列只能选择不能输入. 
           setXSSFValidation(sheet, attr.combo(), 1, 100, column, column); 
      } 
  } 
​ 
   /** 
    * 添加单元格 
    */ 
   public Cell addCell(Excel attr, Row row, T vo, Field field, int column) 
  { 
       Cell cell = null; 
       try 
      { 
           // 设置行高 
           row.setHeight(maxHeight); 
           // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. 
           if (attr.isExport()) 
          { 
               // 创建cell 
               cell = row.createCell(column); 
               int align = attr.align().value(); 
               cell.setCellStyle(styles.get("data" + (align >= 1 && align <= 3 ? align : ""))); 
​ 
               // 用于读取对象中的属性 
               Object value = getTargetValue(vo, field, attr); 
               String dateFormat = attr.dateFormat(); 
               String readConverterExp = attr.readConverterExp(); 
               String separator = attr.separator(); 
               String dictType = attr.dictType(); 
               if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) 
              { 
                   cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value)); 
              } 
               else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value)) 
              { 
                   cell.setCellValue(getDictLabelByTypeAndValue(String.valueOf(value), dictType)); 
              } 
               else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) 
              { 
                   cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); 
              } 
               else if (value instanceof BigDecimal && -1 != attr.scale()) 
              { 
                   cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString()); 
              } 
               else 
              { 
                   // 设置列类型 
                   setCellVo(value, attr, cell); 
              } 
               addStatisticsData(column, Convert.toStr(value), attr); 
          } 
      } 
       catch (Exception e) 
      { 
           log.error("导出Excel失败{}", e); 
      } 
       return cell; 
  } 
   /** 
    * 根据指定的type ,value 获取 label 
    * @param value 
    * @param dictType 
    * @return 
    * @throws Exception 
    */ 
   public static String getDictLabelByTypeAndValue(String value,String dictType) throws Exception { 
       String label = value; 
       try { 
           label = DictUtils.getDictLabelByTypeAndValue(value, dictType, value); 
      } catch (Exception e) { 
           throw e; 
      } 
       return label; 
  } 
   /** 
    * 设置 POI XSSFSheet 单元格提示 
   
    * @param sheet 表单 
    * @param promptTitle 提示标题 
    * @param promptContent 提示内容 
    * @param firstRow 开始行 
    * @param endRow 结束行 
    * @param firstCol 开始列 
    * @param endCol 结束列 
    */ 
   public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow, 
           int firstCol, int endCol) 
  { 
       DataValidationHelper helper = sheet.getDataValidationHelper(); 
       DataValidationConstraint constraint = helper.createCustomConstraint("DD1"); 
       CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); 
       DataValidation dataValidation = helper.createValidation(constraint, regions); 
       dataValidation.createPromptBox(promptTitle, promptContent); 
       dataValidation.setShowPromptBox(true); 
       sheet.addValidationData(dataValidation); 
  } 
​ 
   /** 
    * 设置某些列的值只能输入预制的数据,显示下拉框. 
   
    * @param sheet 要设置的sheet. 
    * @param textlist 下拉框显示的内容 
    * @param firstRow 开始行 
    * @param endRow 结束行 
    * @param firstCol 开始列 
    * @param endCol 结束列 
    * @return 设置好的sheet. 
    */ 
   public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) 
  { 
       DataValidationHelper helper = sheet.getDataValidationHelper(); 
       // 加载下拉列表内容 
       DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist); 
       // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 
       CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); 
       // 数据有效性对象 
       DataValidation dataValidation = helper.createValidation(constraint, regions); 
       // 处理Excel兼容性问题 
       if (dataValidation instanceof XSSFDataValidation) 
      { 
           dataValidation.setSuppressDropDownArrow(true); 
           dataValidation.setShowErrorBox(true); 
      } 
       else 
      { 
           dataValidation.setSuppressDropDownArrow(false); 
      } 
​ 
       sheet.addValidationData(dataValidation); 
  } 
​ 
   /** 
    * 解析导出值 0=男,1=女,2=未知 
   
    * @param propertyValue 参数值 
    * @param converterExp 翻译注解 
    * @param separator 分隔符 
    * @return 解析后值 
    */ 
   public static String convertByExp(String propertyValue, String converterExp, String separator) 
  { 
       StringBuilder propertyString = new StringBuilder(); 
       String[] convertSource = converterExp.split(","); 
       for (String item : convertSource) 
      { 
           String[] itemArray = item.split("="); 
           if (StringUtils.containsAny(separator, propertyValue)) 
          { 
               for (String value : propertyValue.split(separator)) 
              { 
                   if (itemArray[0].equals(value)) 
                  { 
                       propertyString.append(itemArray[1] + separator); 
                       break; 
                  } 
              } 
          } 
           else 
          { 
               if (itemArray[0].equals(propertyValue)) 
              { 
                   return itemArray[1]; 
              } 
          } 
      } 
       return StringUtils.stripEnd(propertyString.toString(), separator); 
  } 
​ 
   /** 
    * 反向解析值 男=0,女=1,未知=2 
   
    * @param propertyValue 参数值 
    * @param converterExp 翻译注解 
    * @param separator 分隔符 
    * @return 解析后值 
    */ 
   public static String reverseByExp(String propertyValue, String converterExp, String separator) 
  { 
       StringBuilder propertyString = new StringBuilder(); 
       String[] convertSource = converterExp.split(","); 
       for (String item : convertSource) 
      { 
           String[] itemArray = item.split("="); 
           if (StringUtils.containsAny(separator, propertyValue)) 
          { 
               for (String value : propertyValue.split(separator)) 
              { 
                   if (itemArray[1].equals(value)) 
                  { 
                       propertyString.append(itemArray[0] + separator); 
                       break; 
                  } 
              } 
          } 
           else 
          { 
               if (itemArray[1].equals(propertyValue)) 
              { 
                   return itemArray[0]; 
              } 
          } 
      } 
       return StringUtils.stripEnd(propertyString.toString(), separator); 
  } 
​ 
   /** 
    * 合计统计信息 
    */ 
   private void addStatisticsData(Integer index, String text, Excel entity) 
  { 
       if (entity != null && entity.isStatistics()) 
      { 
           Double temp = 0D; 
           if (!statistics.containsKey(index)) 
          { 
               statistics.put(index, temp); 
          } 
           try 
          { 
               temp = Double.valueOf(text); 
          } 
           catch (NumberFormatException e) 
          { 
          } 
           statistics.put(index, statistics.get(index) + temp); 
      } 
  } 
​ 
   /** 
    * 创建统计行 
    */ 
   public void addStatisticsRow() 
  { 
       if (statistics.size() > 0) 
      { 
           Cell cell = null; 
           Row row = sheet.createRow(sheet.getLastRowNum() + 1); 
           Set<Integer> keys = statistics.keySet(); 
           cell = row.createCell(0); 
           cell.setCellStyle(styles.get("total")); 
           cell.setCellValue("合计"); 
​ 
           for (Integer key : keys) 
          { 
               cell = row.createCell(key); 
               cell.setCellStyle(styles.get("total")); 
               cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key))); 
          } 
           statistics.clear(); 
      } 
  } 
​ 
   /** 
    * 获取bean中的属性值 
   
    * @param vo 实体对象 
    * @param field 字段 
    * @param excel 注解 
    * @return 最终的属性值 
    * @throws Exception 
    */ 
   private Object getTargetValue(T vo, Field field, Excel excel) throws Exception 
  { 
       Object o = field.get(vo); 
       if (StringUtils.isNotEmpty(excel.targetAttr())) 
      { 
           String target = excel.targetAttr(); 
           if (target.indexOf(".") > -1) 
          { 
               String[] targets = target.split("[.]"); 
               for (String name : targets) 
              { 
                   o = getValue(o, name); 
              } 
          } 
           else 
          { 
               o = getValue(o, target); 
          } 
      } 
       return o; 
  } 
​ 
   /** 
    * 以类的属性的get方法方法形式获取值 
   
    * @param o 
    * @param name 
    * @return value 
    * @throws Exception 
    */ 
   private Object getValue(Object o, String name) throws Exception 
  { 
       if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name)) 
      { 
           Class<?> clazz = o.getClass(); 
           Field field = clazz.getDeclaredField(name); 
           field.setAccessible(true); 
           o = field.get(o); 
      } 
       return o; 
  } 
​ 
   /** 
    * 得到所有定义字段 
    */ 
   private void createExcelField() 
  { 
       this.fields = new ArrayList<Object[]>(); 
       List<Field> tempFields = new ArrayList<>(); 
       tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); 
       tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); 
       for (Field field : tempFields) 
      { 
           // 单注解 
           if (field.isAnnotationPresent(Excel.class)) 
          { 
               putToField(field, field.getAnnotation(Excel.class)); 
          } 
​ 
           // 多注解 
           if (field.isAnnotationPresent(Excels.class)) 
          { 
               Excels attrs = field.getAnnotation(Excels.class); 
               Excel[] excels = attrs.value(); 
               for (Excel excel : excels) 
              { 
                   putToField(field, excel); 
              } 
          } 
      } 
       this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); 
       this.maxHeight = getRowHeight(); 
  } 
​ 
   /** 
    * 根据注解获取最大行高 
    */ 
   public short getRowHeight() 
  { 
       double maxHeight = 0; 
       for (Object[] os : this.fields) 
      { 
           Excel excel = (Excel) os[1]; 
           maxHeight = maxHeight > excel.height() ? maxHeight : excel.height(); 
      } 
       return (short) (maxHeight * 20); 
  } 
​ 
   /** 
    * 放到字段集合中 
    */ 
   private void putToField(Field field, Excel attr) 
  { 
       if (attr != null && (attr.type() == Excel.Type.ALL || attr.type() == type)) 
      { 
           this.fields.add(new Object[] { field, attr }); 
      } 
  } 
​ 
   /** 
    * 创建一个工作簿 
    */ 
   public void createWorkbook() 
  { 
       this.wb = new SXSSFWorkbook(500); 
  } 
​ 
   /** 
    * 创建工作表 
   
    * @param sheetNo sheet数量 
    * @param index 序号 
    */ 
   public void createSheet(double sheetNo, int index) 
  { 
       this.sheet = wb.createSheet(); 
       this.styles = createStyles(wb); 
       // 设置工作表的名称. 
       if (sheetNo == 0) 
      { 
           wb.setSheetName(index, sheetName); 
      } 
       else 
      { 
           wb.setSheetName(index, sheetName + index); 
      } 
  } 
​ 
   /** 
    * 获取单元格值 
   
    * @param row 获取的行 
    * @param column 获取单元格列号 
    * @return 单元格值 
    */ 
   public Object getCellValue(Row row, int column) 
  { 
       if (row == null) 
      { 
           return row; 
      } 
       Object val = ""; 
       try 
      { 
           Cell cell = row.getCell(column); 
           if (StringUtils.isNotNull(cell)) 
          { 
               if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA) 
              { 
                   val = cell.getNumericCellValue(); 
                   if (DateUtil.isCellDateFormatted(cell)) 
                  { 
                       val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换 
                  } 
                   else 
                  { 
                       if ((Double) val % 1 != 0) 
                      { 
                           val = new BigDecimal(val.toString()); 
                      } 
                       else 
                      { 
                           val = new DecimalFormat("0").format(val); 
                      } 
                  } 
              } 
               else if (cell.getCellType() == CellType.STRING) 
              { 
                   val = cell.getStringCellValue(); 
              } 
               else if (cell.getCellType() == CellType.BOOLEAN) 
              { 
                   val = cell.getBooleanCellValue(); 
              } 
               else if (cell.getCellType() == CellType.ERROR) 
              { 
                   val = cell.getErrorCellValue(); 
              } 
​ 
          } 
      } 
       catch (Exception e) 
      { 
           return val; 
      } 
       return val; 
  } 

SysDictData.java

 @JSONType(typeName = "com.ruoyi.system.api.domain.SysDictData") // 这里要看你的redis里的@type 上对应的vaule是什么
 public class SysDictData implements Serializable {
     private static final long serialVersionUID = 1L;
 
 
     private Long dictCode;
 
 
     private Long dictSort;
 
 
     private String dictLabel;
 
 
 
     private String dictValue;
 
 
     private String dictType;
 
     /** 样式属性(其他样式扩展) */
     private String cssClass;
 
     /** 表格字典样式 */
     private String listClass;
 
 
     private String isDefault;
 
 
     private String status;
 
     public SysDictData() {
    }
 
     public SysDictData(Long dictCode, Long dictSort, String dictLabel, String dictValue, String dictType, String cssClass, String listClass, String isDefault, String status) {
         this.dictCode = dictCode;
         this.dictSort = dictSort;
         this.dictLabel = dictLabel;
         this.dictValue = dictValue;
         this.dictType = dictType;
         this.cssClass = cssClass;
         this.listClass = listClass;
         this.isDefault = isDefault;
         this.status = status;
    }
 
     public Long getDictCode() {
         return dictCode;
    }
 
     public void setDictCode(Long dictCode) {
         this.dictCode = dictCode;
    }
 
     public Long getDictSort() {
         return dictSort;
    }
 
     public void setDictSort(Long dictSort) {
         this.dictSort = dictSort;
    }
 
     public String getDictLabel() {
         return dictLabel;
    }
 
     public void setDictLabel(String dictLabel) {
         this.dictLabel = dictLabel;
    }
 
     public String getDictValue() {
         return dictValue;
    }
 
     public void setDictValue(String dictValue) {
         this.dictValue = dictValue;
    }
 
     public String getDictType() {
         return dictType;
    }
 
     public void setDictType(String dictType) {
         this.dictType = dictType;
    }
 
     public String getCssClass() {
         return cssClass;
    }
 
     public void setCssClass(String cssClass) {
         this.cssClass = cssClass;
    }
 
     public String getListClass() {
         return listClass;
    }
 
     public void setListClass(String listClass) {
         this.listClass = listClass;
    }
 
     public String getIsDefault() {
         return isDefault;
    }
 
     public void setIsDefault(String isDefault) {
         this.isDefault = isDefault;
    }
 
     public String getStatus() {
         return status;
    }
 
     public void setStatus(String status) {
         this.status = status;
    }
 }

修改 RedisService 添加 getCacheListString方法

    public  List<JSONArray>   getCacheListString(final String key)
{
List<JSONArray> list = redisTemplate.opsForValue().multiGet(Arrays.asList(key));
return list;
}
 

热门相关:恭喜你被逮捕了   闺范   上神来了   闺范   上神来了