赞
踩
现场运维反馈,甲方爸爸有业务导入excel表单发生“系统异常”,但是不是每个人都有这种问题,个别用户导入的excel存在异常,由于网络隔离和生产日志管理原因,一直无法拿到error日志,只能请求到家里协助定位问题。
但是家里不管怎么导入excel文件就是无法复现,故怀疑是文件问题,让现场人员把业务的excel表数据拷贝到新建的excel里面试试,结果导入成功,所以只能说临时解决了问题。
通过各种申请,层层审批,终于拿到了导入出错的原始文件,开始进行分析解决问题之路。
文件问题:拿到原始文件后,通过office打开,发现打开文件标题上出现了“兼容模式”字样,如下图:
此时可以确认文件应该是第三方应用系统中导出的文件,而非通过excel进行制作的表格数据。
导入程序报错信息:通过把此文件导入测试,发现错误很明显
- org.apache.poi.hssf.record.RecordInputStream$LeftoverDataException: Initialisation of record 0x31(FontRecord) left 4 bytes remaining still to be read.
- at org.apache.poi.hssf.record.RecordInputStream.hasNextRecord(RecordInputStream.java:188)
- at org.apache.poi.hssf.record.RecordFactoryInputStream.nextRecord(RecordFactoryInputStream.java:234)
- at org.apache.poi.hssf.record.RecordFactory.createRecords(RecordFactory.java:488)
- at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:343)
- at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:306)
- at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:258)
- at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:241)
- ... ...
通过异常关键字进行检索,很多解决方案都是文件另存未就能解决问题,而没有进行具体解决。本着能不改就不改的理念,让PM跟甲方爸爸进行了沟通,得到的答复是:凭什么要另存为,下载下来的数据都是都是核心数据,另存为如果改动了这个责任谁来担当,你们必须解决。好吧,都是“甩锅”。
通过异常报错位置,在IDEAL里面找到反编译后的代码位置,发现发生问题的位置原逻辑如下:
- public boolean hasNextRecord() throws LeftoverDataException {
- if (this._currentDataLength != -1 && this._currentDataLength != this._currentDataOffset) {
- throw new LeftoverDataException(this._currentSid, this.remaining());
- }
- if (this._currentDataLength != DATA_LEN_NEEDS_TO_BE_READ) {
- this._nextSid = this.readNextSid();
- }
- return this._nextSid != INVALID_SID_VALUE;
- }
此处由于 this._currentDataLength != this._currentDataOffset 导致抛出异常。
此篇文章中的方法,进行了处理之路。
很多都说需要对源码重新打包,此种做法在我们项目中是无法实施的,按照合同协议要求,第三方包,必须使用原生,不允许引用项目中的第三方包,所有包都是maven仓库中的包。所以只能选择另外的一个解决方案:重写jar包中的类,通过JVM的编译输出优先使用项目src中的类原理来实现覆盖jar包中的类的方法进行处理。
首先,新建包:org.apache.poi.hssf.record,然后新建类RecordInputStream,保持跟poi包中一致,再进行代码修改。
- public boolean hasNextRecord() throws LeftoverDataException {
- if (this._currentDataLength != -1 && this._currentDataLength != this._currentDataOffset) {
- // throw new LeftoverDataException(this._currentSid, this.remaining());
- readToEndOfRecord();
- }
- if (this._currentDataLength != DATA_LEN_NEEDS_TO_BE_READ) {
- this._nextSid = this.readNextSid();
- }
- return this._nextSid != INVALID_SID_VALUE;
- }
- private void readToEndOfRecord() {
- while (this._currentDataOffset < this._currentDataLength)
- readByte();
- }
(此处代码参考网上方法进行处理) ,再结合刚刚参考的文档说明规避“Found EOFRecord before WindowTwoRecord was encountered”异常,故还要重新建类RecordOrderer以此来覆盖poi.jar里面的此类,此类的包路径为:org.apache.poi.hssf.model。修改代码如下:
- public static boolean isEndOfRowBlock(int sid) {
- switch (sid) {
- case EOFRecord.sid:
- //为了解决其他非标准excel生成的文件进行导入
- // throw new RuntimeException("Found EOFRecord before WindowTwoRecord was encountered");
- case DrawingRecord.sid:
- case DrawingSelectionRecord.sid:
- case ObjRecord.sid:
- case TextObjectRecord.sid:
- case ColumnInfoRecord.sid: // See Bugzilla 53984
- case GutsRecord.sid: // see Bugzilla 50426
- case WindowOneRecord.sid:
- // should really be part of workbook stream, but some apps seem to put this before WINDOW2
- case WindowTwoRecord.sid:
- return true;
- case DVALRecord.sid:
- return true;
- default:
- return PageSettingsBlock.isComponentRecord(sid);
- }
- }
让其EOFRecord.sid的数据不抛出异常,直接注释掉。
本以为一切顺利,结果调试中出现以下异常:
- java.lang.RuntimeException: Unexpected record type (org.apache.poi.hssf.record.PaneRecord)
- at org.apache.poi.hssf.record.aggregates.RowRecordsAggregate.<init>(RowRecordsAggregate.java:97)
- at org.apache.poi.hssf.model.InternalSheet.<init>(InternalSheet.java:183)
- at org.apache.poi.hssf.model.InternalSheet.createSheet(InternalSheet.java:122)
- at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:354)
- at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:306)
- at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:258)
- at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:241)
好吧,继续处理RowRecordsAggregate类吧,还是按照覆盖模式进行处理。
修改代码如下:
- public RowRecordsAggregate(RecordStream rs, SharedValueManager svm) {
- this(svm);
-
- while(true) {
- while(rs.hasNext()) {
- Record rec = rs.getNext();
- switch (rec.getSid()) {
- case DConRefRecord.sid:
- this.addUnknownRecord(rec);
- case DBCellRecord.sid:
- break;
- case RowRecord.sid:
- this.insertRow((RowRecord)rec);
- break;
- default:
- if (rec instanceof UnknownRecord) {
- this.addUnknownRecord(rec);
-
- while(rs.peekNextSid() == 60) {
- this.addUnknownRecord(rs.getNext());
- }
- } else if (rec instanceof MulBlankRecord) {
- this._valuesAgg.addMultipleBlanks((MulBlankRecord)rec);
- } else {
- //此处为了解决非标excel文件导入而重新进行处理
- // if (!(rec instanceof CellValueRecordInterface)) {
- // throw new RuntimeException("Unexpected record type (" + rec.getClass().getName() + ")");
- // }
- //
- // this._valuesAgg.construct((CellValueRecordInterface)rec, rs, svm);
- if (rec instanceof CellValueRecordInterface) {
- this._valuesAgg.construct((CellValueRecordInterface) rec, rs, svm);
- }
- }
- }
- }
-
- return;
- }
- }
好了,现在导入提供的原始文件,终于不报错了。
PS:发现阿里的easyExcel的github上也有人遇到此问题,但是由于是底层Poi问题,所以上面建议也是修改poi.jar源码模式进行处理。使用poi.jar版本为4.1.0 ,后续升级POI还要看此三个类是有有变更,一旦变更还要跟着进行处理(o(╥﹏╥)o)。
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。