|
|
|
package com.alibaba.excel.analysis;
|
|
|
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
|
|
|
|
import org.apache.poi.poifs.crypt.Decryptor;
|
|
|
|
import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
|
|
|
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
|
|
|
import org.apache.poi.util.IOUtils;
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
import com.alibaba.excel.analysis.v03.XlsSaxAnalyser;
|
|
|
|
import com.alibaba.excel.analysis.v07.XlsxSaxAnalyser;
|
|
|
|
import com.alibaba.excel.context.AnalysisContext;
|
|
|
|
import com.alibaba.excel.context.AnalysisContextImpl;
|
|
|
|
import com.alibaba.excel.exception.ExcelAnalysisException;
|
|
|
|
import com.alibaba.excel.exception.ExcelAnalysisStopException;
|
|
|
|
import com.alibaba.excel.read.metadata.ReadSheet;
|
|
|
|
import com.alibaba.excel.read.metadata.ReadWorkbook;
|
|
|
|
import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
|
|
|
|
import com.alibaba.excel.support.ExcelTypeEnum;
|
|
|
|
import com.alibaba.excel.util.CollectionUtils;
|
|
|
|
import com.alibaba.excel.util.DateUtils;
|
|
|
|
import com.alibaba.excel.util.FileUtils;
|
|
|
|
import com.alibaba.excel.util.NumberDataFormatterUtils;
|
|
|
|
import com.alibaba.excel.util.StringUtils;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @author jipengfei
|
|
|
|
*/
|
|
|
|
public class ExcelAnalyserImpl implements ExcelAnalyser {
|
|
|
|
private static final Logger LOGGER = LoggerFactory.getLogger(ExcelAnalyserImpl.class);
|
|
|
|
|
|
|
|
private AnalysisContext analysisContext;
|
|
|
|
|
|
|
|
private ExcelReadExecutor excelReadExecutor;
|
|
|
|
/**
|
|
|
|
* Prevent multiple shutdowns
|
|
|
|
*/
|
|
|
|
private boolean finished = false;
|
|
|
|
|
|
|
|
public ExcelAnalyserImpl(ReadWorkbook readWorkbook) {
|
|
|
|
try {
|
|
|
|
analysisContext = new AnalysisContextImpl(readWorkbook);
|
|
|
|
choiceExcelExecutor();
|
|
|
|
} catch (RuntimeException e) {
|
|
|
|
finish();
|
|
|
|
throw e;
|
|
|
|
} catch (Throwable e) {
|
|
|
|
finish();
|
|
|
|
throw new ExcelAnalysisException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void choiceExcelExecutor() throws Exception {
|
|
|
|
ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder();
|
|
|
|
ExcelTypeEnum excelType = readWorkbookHolder.getExcelType();
|
|
|
|
if (excelType == null) {
|
|
|
|
excelReadExecutor = new XlsxSaxAnalyser(analysisContext, null);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (excelType) {
|
|
|
|
case XLS:
|
|
|
|
POIFSFileSystem poifsFileSystem;
|
|
|
|
if (readWorkbookHolder.getFile() != null) {
|
|
|
|
poifsFileSystem = new POIFSFileSystem(readWorkbookHolder.getFile());
|
|
|
|
} else {
|
|
|
|
poifsFileSystem = new POIFSFileSystem(readWorkbookHolder.getInputStream());
|
|
|
|
}
|
|
|
|
// So in encrypted excel, it looks like XLS but it's actually XLSX
|
|
|
|
if (poifsFileSystem.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
|
|
|
|
InputStream decryptedStream = null;
|
|
|
|
try {
|
|
|
|
decryptedStream =
|
|
|
|
DocumentFactoryHelper.getDecryptedStream(poifsFileSystem.getRoot().getFileSystem(),
|
|
|
|
analysisContext.readWorkbookHolder().getPassword());
|
|
|
|
excelReadExecutor = new XlsxSaxAnalyser(analysisContext, decryptedStream);
|
|
|
|
return;
|
|
|
|
} finally {
|
|
|
|
IOUtils.closeQuietly(decryptedStream);
|
|
|
|
// as we processed the full stream already, we can close the filesystem here
|
|
|
|
// otherwise file handles are leaked
|
|
|
|
poifsFileSystem.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (analysisContext.readWorkbookHolder().getPassword() != null) {
|
|
|
|
Biff8EncryptionKey.setCurrentUserPassword(analysisContext.readWorkbookHolder().getPassword());
|
|
|
|
}
|
|
|
|
excelReadExecutor = new XlsSaxAnalyser(analysisContext, poifsFileSystem);
|
|
|
|
break;
|
|
|
|
case XLSX:
|
|
|
|
excelReadExecutor = new XlsxSaxAnalyser(analysisContext, null);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void analysis(List<ReadSheet> readSheetList, Boolean readAll) {
|
|
|
|
try {
|
|
|
|
if (!readAll && CollectionUtils.isEmpty(readSheetList)) {
|
|
|
|
throw new IllegalArgumentException("Specify at least one read sheet.");
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
excelReadExecutor.execute(readSheetList, readAll);
|
|
|
|
} catch (ExcelAnalysisStopException e) {
|
|
|
|
if (LOGGER.isDebugEnabled()) {
|
|
|
|
LOGGER.debug("Custom stop!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// The last sheet is read
|
|
|
|
if (excelReadExecutor instanceof XlsSaxAnalyser) {
|
|
|
|
if (analysisContext.readSheetHolder() != null) {
|
|
|
|
analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (RuntimeException e) {
|
|
|
|
finish();
|
|
|
|
throw e;
|
|
|
|
} catch (Throwable e) {
|
|
|
|
finish();
|
|
|
|
throw new ExcelAnalysisException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void finish() {
|
|
|
|
if (finished) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
finished = true;
|
|
|
|
if (analysisContext == null || analysisContext.readWorkbookHolder() == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder();
|
|
|
|
|
|
|
|
Throwable throwable = null;
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (readWorkbookHolder.getReadCache() != null) {
|
|
|
|
readWorkbookHolder.getReadCache().destroy();
|
|
|
|
}
|
|
|
|
} catch (Throwable t) {
|
|
|
|
throwable = t;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
if (readWorkbookHolder.getOpcPackage() != null) {
|
|
|
|
readWorkbookHolder.getOpcPackage().revert();
|
|
|
|
}
|
|
|
|
} catch (Throwable t) {
|
|
|
|
throwable = t;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
if (readWorkbookHolder.getPoifsFileSystem() != null) {
|
|
|
|
readWorkbookHolder.getPoifsFileSystem().close();
|
|
|
|
}
|
|
|
|
} catch (Throwable t) {
|
|
|
|
throwable = t;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
if (analysisContext.readWorkbookHolder().getAutoCloseStream()
|
|
|
|
&& readWorkbookHolder.getInputStream() != null) {
|
|
|
|
readWorkbookHolder.getInputStream().close();
|
|
|
|
}
|
|
|
|
} catch (Throwable t) {
|
|
|
|
throwable = t;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
if (readWorkbookHolder.getTempFile() != null) {
|
|
|
|
FileUtils.delete(readWorkbookHolder.getTempFile());
|
|
|
|
}
|
|
|
|
} catch (Throwable t) {
|
|
|
|
throwable = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
clearEncrypt03();
|
|
|
|
|
|
|
|
removeThreadLocalCache();
|
|
|
|
|
|
|
|
if (throwable != null) {
|
|
|
|
throw new ExcelAnalysisException("Can not close IO.", throwable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void removeThreadLocalCache() {
|
|
|
|
NumberDataFormatterUtils.removeThreadLocalCache();
|
|
|
|
DateUtils.removeThreadLocalCache();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void clearEncrypt03() {
|
|
|
|
if (StringUtils.isEmpty(analysisContext.readWorkbookHolder().getPassword())
|
|
|
|
|| !ExcelTypeEnum.XLS.equals(analysisContext.readWorkbookHolder().getExcelType())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Biff8EncryptionKey.setCurrentUserPassword(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ExcelReadExecutor excelExecutor() {
|
|
|
|
return excelReadExecutor;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public AnalysisContext analysisContext() {
|
|
|
|
return analysisContext;
|
|
|
|
}
|
|
|
|
}
|