使用若依excel导入导出优化,涉及到字典值、外键下拉
发现若依的导入导出涉及到字典值、外键导出是一个Long值。然后想着是不是可以从redis中得到字典,从数据库得到数据。动态绑定起来
本着说做就做的动手能力。
从@Excel的枚举入手,加入两个枚举类型
/** * 如果是字典类型,请设置字典的type值 (如: sys_user_sex) */ public String dictType() default ""; /** * 如果是外键,请设置类的路径值 (如: com.yz.service.impl.StudentServiceImpl) */ public String classType() default "";
继续写它的导入导出功能。导入导出功能在ExcelUtil中
添加字典、外键的导入实现 。在 public List<T> importExcel(String sheetName, InputStream is, int titleNum) throws Exception 这个方法中。修改实现
if (StringUtils.isNotNull(fieldType)) { String propertyName = field.getName(); if (StringUtils.isNotEmpty(attr.targetAttr())) { propertyName = field.getName() + "." + attr.targetAttr(); } else if (StringUtils.isNotEmpty(attr.readConverterExp())) { val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); } else if (StringUtils.isNotEmpty(attr.dictType())) { // 根据类型跟名称字典id。表存的是id。 val = getDictValueByTypeAndLabel(String.valueOf(val), attr.dictType()); } else if (StringUtils.isNotEmpty(attr.classType())){
// 根据类路径跟名称获得id,getClassIdByTypeAndName下面有写 val = getClassIdByTypeAndName(String.valueOf(val), attr.classType()); } else if (!attr.handler().equals(ExcelHandlerAdapter.class)) { val = dataFormatHandlerAdapter(val, attr); } else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures)) { PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey()); if (image == null) { val = ""; } else { byte[] data = image.getData(); val = FileUtils.writeImportBytes(data); } } ReflectUtils.invokeSetter(entity, propertyName, val); }
接着是模板导出,public void setDataValidation(Excel attr, Row row, int column) 实现在这个方法里面。现在加入字典跟外键的导出
if(StringUtils.isNotEmpty(attr.dictType())) {//有字典 则取字典下拉 setXSSFValidation(sheet, DictUtils.getLabelArr(attr.dictType()), 1, 100, column, column); }else if(StringUtils.isNotEmpty(attr.classType())) {//有外键 则取类的属性下拉,getClassLabelArr是新加的方法。下面有写 setXSSFValidation(sheet, getClassLabelArr(attr.classType()), 1, 100, column, column); } else if (attr.combo().length > 0)// 如果设置了combo属性则本列只能选择不能输入 { // 这里默认设了2-101列只能选择不能输入. setXSSFValidation(sheet, attr.combo(), 1, 100, column, column); }
上面这里对照着这个方法是能知道改动的地方的。
接着是数据导出。public List<T> importExcel(String sheetName, InputStream is, int titleNum) 实现在这个方法里面。
if (StringUtils.isNotNull(fieldType)) { String propertyName = field.getName(); if (StringUtils.isNotEmpty(attr.targetAttr())) { propertyName = field.getName() + "." + attr.targetAttr(); } else if (StringUtils.isNotEmpty(attr.readConverterExp())) { val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); } else if (StringUtils.isNotEmpty(attr.dictType())) {
// 字典数据导出 // val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator()); val = getDictValueByTypeAndLabel(String.valueOf(val), attr.dictType()); } else if (StringUtils.isNotEmpty(attr.classType())){
// 外键数据导出 val = getClassIdByTypeAndName(String.valueOf(val), attr.classType()); }
添加的方法
/** * 根据指定的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; } /** * 根据type,label 获取value * @param propertyValue * @param dictType * @return * @throws Exception */ public static Long getDictValueByTypeAndLabel(String propertyLabel, String dictType) throws Exception{ Long value = null; try { value = DictUtils.getDictValueByTypeAndLabel(propertyLabel, dictType, propertyLabel); } catch (Exception e) { throw e; } return value; } /** * 根据type,名称 获取id * @param * @param classType * @return * @throws Exception */ public static Long getClassIdByTypeAndName(String propertyLabel, String classType) throws Exception{ Long value = null; try { // 通过反射获取类 Class clz = Class.forName(classType); Object bean = SpringUtils.getBean(clz); Method getIdByName = clz.getMethod("getOne", Wrapper.class); QueryWrapper wrapper = new QueryWrapper(); wrapper.eq("name",propertyLabel); Object invoke = getIdByName.invoke(bean, wrapper); Class<?> aClass = invoke.getClass(); Method method = aClass.getMethod("getId"); value = (Long) method.invoke(invoke); } catch (Exception e) { throw e; } return value; } /** * 通过反射获取单元格的值 * @param valueOf id * @param classType 类的路径 * @return */ private String getDictNameAndValue(Long valueOf, String classType) throws Exception { // 通过反射获取类 Class clz = Class.forName(classType); Object bean = SpringUtils.getBean(clz); Method getIdByName = clz.getMethod("getById", Serializable.class); Object invoke = getIdByName.invoke(bean, valueOf); Class<?> aClass = invoke.getClass(); Method method = aClass.getMethod("getName"); String value = (String) method.invoke(invoke); return value; } /** * 根据类的路径获取名称 * @param classType * @return * @throws Exception */ private String[] getClassLabelArr(String classType){ List<Object> objects = null; try { // 获取反射的class Class clz = Class.forName(classType); // 从启动类中得到bean;spring工具类 方便在非spring管理环境中获取bean Object bean = SpringUtils.getBean(clz); Method listMethod = clz.getMethod("list"); // 通过反射获取方法,方法调用得到一个list(因为调用list方法得到的一定是list) objects = (List<Object>) listMethod.invoke(bean); } catch (Exception e) { e.printStackTrace(); } // 数组长度即使集合的长度 List<String> result = new ArrayList<>(); // 遍历数组得到名称label,如果数据多的话。性能低,需优化 objects.forEach(obj -> { Class<?> aClass = obj.getClass(); try { Method method = aClass.getMethod("getName"); String value = (String) method.invoke(obj); result.add(value); } catch (Exception e) { e.printStackTrace(); } }); // 把String集合转成String数组返回出去 return result.toArray(new String[result.size()]); }
然后是DictUtils的修改。在里面加入这些方法。
/** * 根据指定的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) && ObjectUtils.isNotNull(value)){ List<SysDictData> dataList = getDictCache(type); for (SysDictData dict : dataList){ if (type.equals(dict.getDictType()) && value.equals(dict.getDictCode().toString())){ return dict.getDictLabel(); } } } return defaultLabel; } /** * 根据type,label 获取value * * @param label * @param type * @param defaultValue * @return */ public static Long 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.getDictCode(); } } } return null; } /** * 根据 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; }
差不多就可以了。使用的话
/** * 交易方式id这个是字典值 */ @Excel(name = "交易方式",dictType = "transaction_mode") private Long tradeId; /** * 应用情况id,这个是外键(外键类型) */ @Excel(name = "应用情况",classType = "com.yz.service.impl.xxxImpl") private Long usedId;