From c8a14f3da4d725e2ca76ffbfdee7346698da2ab1 Mon Sep 17 00:00:00 2001 From: zhuangjiaju Date: Thu, 1 Aug 2019 16:11:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=BB=E5=86=99=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/analysis/ExcelAnalyserImpl.java | 31 ++++------ .../v03/handlers/FormulaRecordHandler.java | 61 ++++++++++++++++--- .../excel/analysis/v07/XlsxSaxAnalyser.java | 42 ++++++++++--- .../com/alibaba/excel/metadata/CellData.java | 10 +++ .../listener/ModelBuildEventListener.java | 2 +- .../metadata/holder/ReadWorkbookHolder.java | 11 ++++ .../com/alibaba/excel/util/FileUtils.java | 11 +++- .../core/converter/ReadAllConverterData.java | 12 ++-- .../ReadAllConverterDataListener.java | 53 +++++++++++----- 9 files changed, 173 insertions(+), 60 deletions(-) diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java index f5d4b695..31362d32 100644 --- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java @@ -35,25 +35,20 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { } } - private void choiceExcelExecutor() { - try { - ExcelTypeEnum excelType = analysisContext.readWorkbookHolder().getExcelType(); - if (excelType == null) { + private void choiceExcelExecutor() throws Exception { + ExcelTypeEnum excelType = analysisContext.readWorkbookHolder().getExcelType(); + if (excelType == null) { + excelExecutor = new XlsxSaxAnalyser(analysisContext); + return; + } + switch (excelType) { + case XLS: + excelExecutor = new XlsSaxAnalyser(analysisContext); + break; + case XLSX: excelExecutor = new XlsxSaxAnalyser(analysisContext); - return; - } - switch (excelType) { - case XLS: - excelExecutor = new XlsSaxAnalyser(analysisContext); - break; - case XLSX: - excelExecutor = new XlsxSaxAnalyser(analysisContext); - break; - default: - } - } catch (Exception e) { - throw new ExcelAnalysisException("File type error,io must be available markSupported,you can do like " - + "this new BufferedInputStream(new FileInputStream(\\\"/xxxx\\\")) \"", e); + break; + default: } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java index 40793df2..f8899c03 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java @@ -1,12 +1,17 @@ package com.alibaba.excel.analysis.v03.handlers; import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; +import org.apache.poi.hssf.model.HSSFFormulaParser; import org.apache.poi.hssf.record.FormulaRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.StringRecord; import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.CellType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; /** @@ -15,9 +20,13 @@ import com.alibaba.excel.metadata.CellData; * @author Dan Zheng */ public class FormulaRecordHandler extends AbstractXlsRecordHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(FormulaRecordHandler.class); + + private static final String ERROR = "#VALUE!"; private int nextRow; private int nextColumn; private boolean outputNextStringRecord; + private CellData tempCellData; private FormatTrackingHSSFListener formatListener; private HSSFWorkbook stubWorkbook; @@ -38,24 +47,56 @@ public class FormulaRecordHandler extends AbstractXlsRecordHandler { this.row = frec.getRow(); this.column = frec.getColumn(); - - if (Double.isNaN(frec.getValue())) { - // Formula result is a string - // This is stored in the next record - outputNextStringRecord = true; - nextRow = frec.getRow(); - nextColumn = frec.getColumn(); - } else { - this.cellData = new CellData(frec.getValue()); + CellType cellType = CellType.forInt(frec.getCachedResultType()); + String formulaValue = null; + try { + formulaValue = HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()); + } catch (Exception e) { + LOGGER.warn("Get formula value error.{}", e.getMessage()); + } + switch (cellType) { + case STRING: + // Formula result is a string + // This is stored in the next record + outputNextStringRecord = true; + nextRow = frec.getRow(); + nextColumn = frec.getColumn(); + tempCellData = new CellData(CellDataTypeEnum.STRING); + tempCellData.setFormula(Boolean.TRUE); + tempCellData.setFormulaValue(formulaValue); + break; + case NUMERIC: + this.cellData = new CellData(frec.getValue()); + this.cellData.setFormula(Boolean.TRUE); + this.cellData.setFormulaValue(formulaValue); + break; + case ERROR: + this.cellData = new CellData(CellDataTypeEnum.ERROR); + this.cellData.setStringValue(ERROR); + this.cellData.setFormula(Boolean.TRUE); + this.cellData.setFormulaValue(formulaValue); + break; + case BOOLEAN: + this.cellData = new CellData(frec.getCachedBooleanValue()); + this.cellData.setFormula(Boolean.TRUE); + this.cellData.setFormulaValue(formulaValue); + break; + default: + this.cellData = new CellData(CellDataTypeEnum.EMPTY); + this.cellData.setFormula(Boolean.TRUE); + this.cellData.setFormulaValue(formulaValue); + break; } } else if (record.getSid() == StringRecord.sid) { if (outputNextStringRecord) { // String for formula StringRecord srec = (StringRecord)record; - this.cellData = new CellData(srec.getString()); + this.cellData = tempCellData; + this.cellData.setStringValue(srec.getString()); this.row = nextRow; this.column = nextColumn; outputNextStringRecord = false; + tempCellData = null; } } } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java index a59060f3..a4802760 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java @@ -13,17 +13,21 @@ import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.xssf.eventusermodel.XSSFReader; import org.apache.poi.xssf.usermodel.XSSFRelation; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr; import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import com.alibaba.excel.analysis.ExcelExecutor; import com.alibaba.excel.cache.Ehcache; +import com.alibaba.excel.cache.MapCache; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.read.metadata.ReadSheet; @@ -35,6 +39,11 @@ import com.alibaba.excel.util.FileUtils; * @author jipengfei */ public class XlsxSaxAnalyser implements ExcelExecutor { + private static final Logger LOGGER = LoggerFactory.getLogger(XlsxSaxAnalyser.class); + /** + * If it's less than 5M, use map cache, or use ehcache. + */ + private static final long USE_MAP_CACHE_SIZE = 5 * 1000 * 1000L; private AnalysisContext analysisContext; private List sheetList; private Map sheetMap; @@ -43,15 +52,32 @@ public class XlsxSaxAnalyser implements ExcelExecutor { this.analysisContext = analysisContext; // Initialize cache ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder(); + + OPCPackage pkg = readOpcPackage(readWorkbookHolder); + + PackagePart sharedStringsTablePackagePart = + pkg.getPartsByContentType(XSSFRelation.SHARED_STRINGS.getContentType()).get(0); if (readWorkbookHolder.getReadCache() == null) { - readWorkbookHolder.setReadCache(new Ehcache()); + long size = sharedStringsTablePackagePart.getSize(); + if (size < 0) { + size = sharedStringsTablePackagePart.getInputStream().available(); + } + if (size < USE_MAP_CACHE_SIZE) { + if (LOGGER.isDebugEnabled()) { + LOGGER.info("Use map cache.size:{}", size); + } + readWorkbookHolder.setReadCache(new MapCache()); + } else { + if (LOGGER.isDebugEnabled()) { + LOGGER.info("Use ehcache.size:{}", size); + } + readWorkbookHolder.setReadCache(new Ehcache()); + } } readWorkbookHolder.getReadCache().init(analysisContext); - OPCPackage pkg = readOpcPackage(readWorkbookHolder); - // Analysis sharedStringsTable.xml - analysisSharedStringsTable(pkg, readWorkbookHolder); + analysisSharedStringsTable(sharedStringsTablePackagePart.getInputStream(), readWorkbookHolder); XSSFReader xssfReader = new XSSFReader(pkg); @@ -88,10 +114,10 @@ public class XlsxSaxAnalyser implements ExcelExecutor { } } - private void analysisSharedStringsTable(OPCPackage pkg, ReadWorkbookHolder readWorkbookHolder) throws Exception { + private void analysisSharedStringsTable(InputStream sharedStringsTableInputStream, + ReadWorkbookHolder readWorkbookHolder) throws Exception { ContentHandler handler = new SharedStringsTableHandler(readWorkbookHolder.getReadCache()); - parseXmlSource(pkg.getPartsByContentType(XSSFRelation.SHARED_STRINGS.getContentType()).get(0).getInputStream(), - handler); + parseXmlSource(sharedStringsTableInputStream, handler); readWorkbookHolder.getReadCache().putFinished(); } @@ -105,7 +131,7 @@ public class XlsxSaxAnalyser implements ExcelExecutor { File readTempFile = FileUtils.createCacheTmpFile(); readWorkbookHolder.setTempFile(readTempFile); File tempFile = new File(readTempFile.getPath(), UUID.randomUUID().toString() + ".xlsx"); - FileUtils.writeToFile(readTempFile, readWorkbookHolder.getInputStream()); + FileUtils.writeToFile(tempFile, readWorkbookHolder.getInputStream()); return OPCPackage.open(tempFile); } diff --git a/src/main/java/com/alibaba/excel/metadata/CellData.java b/src/main/java/com/alibaba/excel/metadata/CellData.java index 5f9ced79..dfef257c 100644 --- a/src/main/java/com/alibaba/excel/metadata/CellData.java +++ b/src/main/java/com/alibaba/excel/metadata/CellData.java @@ -24,6 +24,15 @@ public class CellData { private Boolean formula; private String formulaValue; + public CellData(CellData other) { + this.type = other.type; + this.doubleValue = other.doubleValue; + this.stringValue = other.stringValue; + this.booleanValue = other.booleanValue; + this.formula = other.formula; + this.formulaValue = other.formulaValue; + } + public CellData(String stringValue) { this(CellDataTypeEnum.STRING, stringValue); } @@ -128,4 +137,5 @@ public class CellData { return "empty"; } } + } diff --git a/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java b/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java index 7285808f..80deec44 100644 --- a/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java +++ b/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java @@ -82,7 +82,7 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener private Object convertValue(CellData cellData, Class clazz, ExcelContentProperty contentProperty, Map converterMap, GlobalConfiguration globalConfiguration) { if (clazz == CellData.class) { - return cellData; + return new CellData(cellData); } Converter converter = null; if (contentProperty != null) { diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java index 0962edf7..c2a9407a 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java @@ -3,6 +3,9 @@ package com.alibaba.excel.read.metadata.holder; import java.io.File; import java.io.InputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.alibaba.excel.cache.ReadCache; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.enums.HolderEnum; @@ -17,6 +20,8 @@ import com.alibaba.excel.support.ExcelTypeEnum; * @author zhuangjiaju */ public class ReadWorkbookHolder extends AbstractReadHolder { + private static final Logger LOGGER = LoggerFactory.getLogger(ReadWorkbookHolder.class); + /** * current param */ @@ -94,8 +99,14 @@ public class ReadWorkbookHolder extends AbstractReadHolder { } else { this.excelType = readWorkbook.getExcelType(); } + if (ExcelTypeEnum.XLS == excelType && getGlobalConfiguration().getUse1904windowing() == null) { + getGlobalConfiguration().setUse1904windowing(Boolean.FALSE); + } this.customObject = readWorkbook.getCustomObject(); this.readCache = readWorkbook.getReadCache(); + if (readCache != null && ExcelTypeEnum.XLS == excelType) { + LOGGER.warn("Xls not support 'readCache'!"); + } } public ReadWorkbook getReadWorkbook() { diff --git a/src/main/java/com/alibaba/excel/util/FileUtils.java b/src/main/java/com/alibaba/excel/util/FileUtils.java index 52353d17..0a76a659 100644 --- a/src/main/java/com/alibaba/excel/util/FileUtils.java +++ b/src/main/java/com/alibaba/excel/util/FileUtils.java @@ -8,6 +8,7 @@ import java.io.OutputStream; import java.util.UUID; import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.exception.ExcelGenerateException; /** * @@ -24,7 +25,7 @@ public class FileUtils { /** * Write inputStream to file - * + * * @param file * @param inputStream */ @@ -65,12 +66,16 @@ public class FileUtils { public static File createCacheTmpFile() { File directory = createTmpDirectory(CACHE); - return new File(directory.getPath(), UUID.randomUUID().toString()); + File cache = new File(directory.getPath(), UUID.randomUUID().toString()); + if (!cache.mkdir()) { + throw new ExcelGenerateException("Can not create temp file!"); + } + return cache; } /** * delete file - * + * * @param file */ public static void delete(File file) { diff --git a/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterData.java b/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterData.java index 19e4b283..ae797bfb 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterData.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterData.java @@ -36,10 +36,10 @@ public class ReadAllConverterData { private Short shortBoolean; private Short shortNumber; private Short shortString; - private String StringBoolean; - private String StringNumber; - private String StringString; - private String StringError; - private String StringFormulaNumber; - private String StringFormulaString; + private String stringBoolean; + private String stringNumber; + private String stringString; + private String stringError; + private String stringFormulaNumber; + private String stringFormulaString; } diff --git a/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterDataListener.java index 63352467..0bc7da99 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterDataListener.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterDataListener.java @@ -1,5 +1,7 @@ package com.alibaba.easyexcel.test.core.converter; +import java.math.BigDecimal; +import java.text.ParseException; import java.util.ArrayList; import java.util.List; @@ -9,6 +11,8 @@ import org.slf4j.LoggerFactory; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelCommonException; +import com.alibaba.excel.util.DateUtils; import com.alibaba.fastjson.JSON; /** @@ -27,20 +31,41 @@ public class ReadAllConverterDataListener extends AnalysisEventListener