问题总是会有了。遇到问题时,如果先把问题归结到自己能够Cover的范围,是有助于找到解决问题的办法。 “夫人心豫怯则智勇并竭,智勇并竭而强使之,适所以为敌禽耳。”
先假设问题可能出在自己,后面才可能集中精力去排查。排查之后,如果的确不是自己的,再给出解决方向也ok。俗称“先接锅,再甩锅”
业务反馈:Excel导入时很慢,1000多条数据导了5分钟都没处理完。 让排查下原因
手上正忙别的需求,被打断后就有点烦。梳理下这个功能的数据流,逻辑很清楚,没有明显的耗时点,唯一的可能的瓶颈就是下游的接口。但下游并没有批量接口可用,只能这样了。
所以,让业务再等等。过一会就操作完成了
又过了几分钟,业务反馈:页面上报错了
功能不可用了,这个要快查。
找了最近导入日志:
根据traceId在日志平台搜一下,摸摸情况
这不对啊。invoke打头的日志行,应该是excel表格一行记录。但此时却是空。
并且解析也失败了。
更离谱的是,本次导入的日志打印了882页,每页100条。 这明显不对! 1000行的记录,最多2000条日志。多出来的6000多条日志是怎么回事?
上面是不是讲的云里雾里了,来看下代码就清楚问题在哪了 解析excel用的是alibaba easyexcel,代码就这几行
@Override
public List<GbbExcelAlipayDTO> importExcel(InputStream inputStream) {
StatementExcelListener readListener = new StatementExcelListener(startMonth);
EasyExcel.read(inputStream, AlipayStatementExcelBO.class, readListener)
.headRowNumber(3) // 指定前两行作为标题行
.sheet(0)
.doRead();
return readListener.getResult();
}
读取上传Excel的第一个sheet, 前两行是Head, 从第三行开始是业务数据。
/**
* Count the number of added heads when read sheet.
*
* <p>
* 0 - This Sheet has no head ,since the first row are the data
* <p>
* 1 - This Sheet has one row head , this is the default
* <p>
* 2 - This Sheet has two row head ,since the third row is the data
*
* @param headRowNumber
* @return
*/
public T headRowNumber(Integer headRowNumber) {
parameter().setHeadRowNumber(headRowNumber);
return self();
}
com.alibaba.excel.read.builder.AbstractExcelReaderParameterBuilder#headRowNumber
采用了,报错后仍然继续解析数据的策略
并且,还有一个异常的地方:日志中的表头信息与Excel上传模板中是不同的
模板中是这样的:
查看了业务的Excel,肉眼可见的地方都是Ok的 但,
自己拿这个Excel上传下,出现的问题和业务报的一样,日志中也类似
查看了这个Excel,格式与模板相同。但与系统日志中打印的内容不同!!难道系统接收到的是一个假的Excel?
系统上线有3-4个月了,之前都是正常的。
难道这个Excel有隐藏彩蛋?
拿POI解析一下,看看sheet0中到底有啥
使用poi遍历所有sheet 并读取第一行内容的代码如下:
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @Auther: cheng.tang
* @Date: 2024/11/11
*/
public class Test {
public static void main(String[] args) {
String excelFilePath = "/Users/cheng.tang/Documents/facai@chaojihao.com-模板.xlsx"; // 替换为你的Excel文件路径
try (FileInputStream fis = new FileInputStream(new File(excelFilePath));
Workbook workbook = WorkbookFactory.create(fis)) {
// 遍历所有工作表
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
Sheet sheet = workbook.getSheetAt(i);
System.out.println("Sheet " + (i + 1) + ": " + sheet.getSheetName());
// 读取每个工作表的第一行
Row firstRow = sheet.getRow(0);
if (firstRow != null) {
DataFormatter formatter = new DataFormatter(); // 用于格式化单元格内容
for (int j = 0; j < firstRow.getLastCellNum(); j++) {
Cell cell = firstRow.getCell(j);
String cellValue = formatter.formatCellValue(cell);
System.out.print(cellValue + "\t");
}
System.out.println(); // 换行
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
看到解析结果,一下子就明白Gap在哪了:
肉眼看到的sheet其实是第5个, 前面的4个Sheet为什么看不到呢?
原来这个Excel使用了隐藏Sheet的功能!!!
系统解析的是sheet0中的内容。
在WPS中显示隐藏的Sheet,可以通过以下几种方法操作:
虽然没有直接的快捷键来显示工作表,但可以使用Ctrl + 9
快捷键来隐藏或取消隐藏当前选中的工作表。
让业务重新下载导入模板,把需要导入的内容贴到第一个sheet中,重新导入。
出现异常时,肯定是有原因的。
意识到这是一个异常,并找到原因。
回头看时,是不是觉得特别Easy,然后也很Happy。
生活就是这个样子,总是有一些不如意。
作为一个平凡的个体就是一直在识别异常、发现问题、解决问题的过程中不知不觉地过完这一生。