当前位置: 首页 > news >正文

RuoYi/ExcelUtil修改(导入excel表时,表中字段没有映射上数据库表字段)

RuoYi/ExcelUtil修改

  • 描述
  • 原因
  • 解决

描述

使用ruoyi框架时,需要使用到导入、导出功能,涉及到ExcelUtil工具类,但是在导入具体实现中,遇到问题
具体问题:

  1. 实体类字段,对应数据库表。
  2. 添加完了注解,没有使用注解中的readConverterExp@Excel(name = “用户性别”, readConverterExp = “0=男,1=女,2=未知”),readConverterExp转换不正确也会导致问题)
  3. 但是在导时老是,表格中有的列有值,但是导入到数据库表中时却没有值

原因

  1. 排除实体类字段值与数据库值不一致
  2. 排除注解问题
  3. 最后想到,第二步中注解中readConverterExp转换不正确会导致表有值但是数据库没有值,是不是数据库的列名读取时又问题(和看到的不一致,导致在工具类中读取到的和注解中的name对不上),于是将表格中的值copy出来,发现问题:注解name中的值是“xx”,但是表格中是“xx ”或者“ xx” (表格列太多了很多缩在一起,并且只是一个空格,看不出来)

解决

发现原因:表格中的列值和注解name对不上,可能会有差距(空格等)

  1. 在系统中设计一个功能,到处具体的规范模版下载给用户使用,再用该模版导入数据
  2. 在代码中处理,想办法在读取时,去除掉前后空格
    我的需求是,导入数据,分析数据,不可能给人家一个模版用,所以采用修改代码

具体代码:修改ExcelUtil中的importExcel方法

 /*** 对excel表单指定表格索引名转换成list** @param sheetName 表格索引名* @param titleNum 标题占用行数* @param is 输入流* @return 转换后集合*/public List<T> importExcel(String sheetName, InputStream is, int titleNum) throws Exception{this.type = Type.IMPORT;this.wb = WorkbookFactory.create(is);List<T> list = new ArrayList<T>();// 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheetSheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0);if (sheet == null){throw new IOException("文件sheet不存在");}boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook);Map<String, List<PictureData>> pictures = null;if (isXSSFWorkbook){pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb);}else{pictures = getSheetPictures03((HSSFSheet) sheet, (HSSFWorkbook) wb);}// 获取最后一个非空行的行下标,比如总行数为n,则返回的为n-1int rows = sheet.getLastRowNum();if (rows > 0){// 定义一个map用于存放excel列的序号和field.Map<String, Integer> cellMap = new HashMap<String, Integer>();// 获取表头Row heard = sheet.getRow(titleNum);for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++){Cell cell = heard.getCell(i);if (StringUtils.isNotNull(cell)){String value = this.getCellValue(heard, i).toString();//修改点1// 去除表头值前后空格,提高匹配容错性String trimmedValue = StringUtils.trim(value);cellMap.put(trimmedValue, i);}else{cellMap.put(null, i);}}// 有数据时才处理 得到类的所有field.List<Object[]> fields = this.getFields();Map<Integer, Object[]> fieldsMap = new HashMap<Integer, Object[]>();for (Object[] objects : fields){//修改点2Excel attr = (Excel) objects[1];String fieldName = attr.name();Integer column = cellMap.get(fieldName);// 如果直接匹配失败,尝试处理表头中的特殊情况if (column == null && cellMap.size() > 0){// 遍历cellMap查找可能匹配的表头(如包含空格的情况)for (Map.Entry<String, Integer> entry : cellMap.entrySet()){String headerName = entry.getKey();if (headerName != null && StringUtils.trim(headerName).equals(fieldName)){column = entry.getValue();break;}}}if (column != null){fieldsMap.put(column, objects);}}for (int i = titleNum + 1; i <= rows; i++){// 从第2行开始取数据,默认第一行是表头.Row row = sheet.getRow(i);// 判断当前行是否是空行if (isRowEmpty(row)){continue;}T entity = null;for (Map.Entry<Integer, Object[]> entry : fieldsMap.entrySet()){Object val = this.getCellValue(row, entry.getKey());// 如果不存在实例则新建.entity = (entity == null ? clazz.newInstance() : entity);// 从map中得到对应列的field.Field field = (Field) entry.getValue()[0];Excel attr = (Excel) entry.getValue()[1];// 取得类型,并根据对象类型设置值.Class<?> fieldType = field.getType();if (String.class == fieldType){String s = Convert.toStr(val);if (s.matches("^\\d+\\.0$")){val = StringUtils.substringBefore(s, ".0");}else{String dateFormat = field.getAnnotation(Excel.class).dateFormat();if (StringUtils.isNotEmpty(dateFormat)){val = parseDateToStr(dateFormat, 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) && StringUtils.isNumeric(Convert.toStr(val))){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)){String propertyName = field.getName();if (StringUtils.isNotEmpty(attr.targetAttr())){propertyName = field.getName() + "." + attr.targetAttr();}if (StringUtils.isNotEmpty(attr.readConverterExp())){val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());}else if (StringUtils.isNotEmpty(attr.dictType())){if (!sysDictMap.containsKey(attr.dictType() + val)){String dictValue = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());sysDictMap.put(attr.dictType() + val, dictValue);}val = sysDictMap.get(attr.dictType() + val);}else if (!attr.handler().equals(ExcelHandlerAdapter.class)){val = dataFormatHandlerAdapter(val, attr, null);}else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures)){StringBuilder propertyString = new StringBuilder();List<PictureData> images = pictures.get(row.getRowNum() + "_" + entry.getKey());for (PictureData picture : images){byte[] data = picture.getData();String fileName = FileUtils.writeImportBytes(data);propertyString.append(fileName).append(SEPARATOR);}val = StringUtils.stripEnd(propertyString.toString(), SEPARATOR);}ReflectUtils.invokeSetter(entity, propertyName, val);}}list.add(entity);}}return list;}

//修改点1
在获取Excel表头值并存入映射表时,增加了trim()操作,自动去除表头值前后的空格,确保表头名称标准化。

//修改点2
增强了字段映射逻辑,如果直接匹配失败,会遍历所有表头进行容错处理,通过trim()后比较表头名称,实现了对带空格表头的智能匹配。

这两处修改共同作用,使得即使Excel表格中的表头前后包含空格(如"工单编号 "),也能正确匹配到实体类中定义的@Excel(name = "工单编号")注解的字段,有效提高了Excel导入功能的健壮性和用户体验。

仓库地址
不清楚可以看仓库,dev分支下提交

http://www.dtcms.com/a/511509.html

相关文章:

  • C++ 分治 快排铺垫 三指针 力扣 75.颜色分类 题解 每日一题
  • 预测算法:股票数据分析预测系统 股票预测 股价预测 Arima预测算法(时间序列预测算法) Flask 框架 大数据(源码)✅
  • 门户网站需要多少空间如何引流被动加好友微信
  • 网站的 联系我们怎么做关键词优化难易
  • 【Java】基于 Tabula 的 PDF 合并单元格内容提取
  • Android 系统的进程模型
  • vue2实现pdf预览兼容低版本浏览器
  • Android Compose 状态的概念
  • spark组件-spark core(批处理)-rdd持久化机制
  • 安全驾驶 智在掌控|腾视科技ES06终端,为车辆运营赋能
  • el-table 表格嵌套表格
  • 云南网站建设首选才力东营注册公司
  • 非对称密码算法分析技术深度剖析及未来展望
  • Arduino IDE下载安装汉化教程(附安装包,图文并茂)
  • 本地转移新分支到新仓库
  • GaussDB慢sql信息收集和执行计划查看
  • AWS IoT Core 监控与告警优化实战报告
  • 我的第一个开源项目【IOT-Tree Server】
  • 如何选择合适的倾角传感器厂家的产品以满足物联网监测需求?
  • 基于物联网与云计算的园区能耗管理平台构建与实践
  • Markdown 用法要点
  • 网站搭建功能需求wordpress安装怎么填
  • 网络原理:TCP协议
  • timm教程翻译:(六)Data
  • VSCode + AI Agent实现直接编译调试:告别Visual Studio的原理与实践
  • 【设计模式】建造者模式(Builder)
  • DeepSeek-OCR:把长文本“挤进图片”的新思路
  • 计算机做网站开题报告网页的六个基本元素
  • AI服务器工作之整机部件(CPU+内存)
  • 【EE初阶 - 网络原理】网络层 + 数据链路层 + DNS