diff --git a/pom.xml b/pom.xml
index 7dad24da..e85d0449 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0com.alibabaeasyexcel
- 2.1.1
+ 2.1.3jareasyexcel
diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
index f3ef9505..eb4f1886 100644
--- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
+++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
@@ -176,7 +176,7 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
clearEncrypt03();
if (throwable != null) {
- throw new ExcelAnalysisException("Can not close IO", throwable);
+ throw new ExcelAnalysisException("Can not close IO.", throwable);
}
}
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 a30b4260..2862be2d 100644
--- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java
+++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java
@@ -34,6 +34,7 @@ import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.SheetUtils;
+import com.alibaba.excel.util.StringUtils;
/**
*
@@ -148,7 +149,13 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
private void parseXmlSource(InputStream inputStream, ContentHandler handler) {
InputSource inputSource = new InputSource(inputStream);
try {
- SAXParserFactory saxFactory = SAXParserFactory.newInstance();
+ SAXParserFactory saxFactory;
+ String xlsxSAXParserFactoryName = analysisContext.readWorkbookHolder().getXlsxSAXParserFactoryName();
+ if (StringUtils.isEmpty(xlsxSAXParserFactoryName)) {
+ saxFactory = SAXParserFactory.newInstance();
+ } else {
+ saxFactory = SAXParserFactory.newInstance(xlsxSAXParserFactoryName, null);
+ }
saxFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
saxFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
saxFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
diff --git a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java
index 84205024..a07ad4ce 100644
--- a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java
+++ b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java
@@ -169,7 +169,9 @@ public class WriteContextImpl implements WriteContext {
int newRowIndex = writeSheetHolder.getNewRowIndexAndStartDoWrite();
newRowIndex += currentWriteHolder.relativeHeadRowIndex();
// Combined head
- addMergedRegionToCurrentSheet(excelWriteHeadProperty, newRowIndex);
+ if (currentWriteHolder.automaticMergeHead()) {
+ addMergedRegionToCurrentSheet(excelWriteHeadProperty, newRowIndex);
+ }
for (int relativeRowIndex = 0, i = newRowIndex; i < excelWriteHeadProperty.getHeadRowNumber() + newRowIndex;
i++, relativeRowIndex++) {
WriteHandlerUtils.beforeRowCreate(this, newRowIndex, relativeRowIndex, Boolean.TRUE);
@@ -182,8 +184,9 @@ public class WriteContextImpl implements WriteContext {
private void addMergedRegionToCurrentSheet(ExcelWriteHeadProperty excelWriteHeadProperty, int rowIndex) {
for (com.alibaba.excel.metadata.CellRange cellRangeModel : excelWriteHeadProperty.headCellRangeList()) {
- writeSheetHolder.getSheet().addMergedRegion(new CellRangeAddress(cellRangeModel.getFirstRow() + rowIndex,
- cellRangeModel.getLastRow() + rowIndex, cellRangeModel.getFirstCol(), cellRangeModel.getLastCol()));
+ writeSheetHolder.getSheet()
+ .addMergedRegionUnsafe(new CellRangeAddress(cellRangeModel.getFirstRow() + rowIndex,
+ cellRangeModel.getLastRow() + rowIndex, cellRangeModel.getFirstCol(), cellRangeModel.getLastCol()));
}
}
@@ -325,7 +328,7 @@ public class WriteContextImpl implements WriteContext {
clearEncrypt03();
if (throwable != null) {
- throw new ExcelGenerateException("Can not close IO", throwable);
+ throw new ExcelGenerateException("Can not close IO.", throwable);
}
if (LOGGER.isDebugEnabled()) {
diff --git a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java
index a458acf5..0c637267 100644
--- a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java
+++ b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java
@@ -5,6 +5,8 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
+import javax.xml.parsers.SAXParserFactory;
+
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.cache.ReadCache;
import com.alibaba.excel.cache.selector.ReadCacheSelector;
@@ -234,6 +236,23 @@ public class ExcelReaderBuilder {
return this;
}
+ /**
+ * SAXParserFactory used when reading xlsx.
+ *
+ * The default will automatically find.
+ *
+ * Please pass in the name of a class ,like : "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"
+ *
+ * @see SAXParserFactory#newInstance()
+ * @see SAXParserFactory#newInstance(String, ClassLoader)
+ * @param xlsxSAXParserFactoryName
+ * @return
+ */
+ public ExcelReaderBuilder xlsxSAXParserFactoryName(String xlsxSAXParserFactoryName) {
+ readWorkbook.setXlsxSAXParserFactoryName(xlsxSAXParserFactoryName);
+ return this;
+ }
+
/**
* Whether to use the default listener, which is used by default.
*
diff --git a/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java b/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java
index 6392ca02..7ddab563 100644
--- a/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java
+++ b/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java
@@ -3,6 +3,8 @@ package com.alibaba.excel.read.metadata;
import java.io.File;
import java.io.InputStream;
+import javax.xml.parsers.SAXParserFactory;
+
import com.alibaba.excel.cache.ReadCache;
import com.alibaba.excel.cache.selector.ReadCacheSelector;
import com.alibaba.excel.context.AnalysisContext;
@@ -64,6 +66,17 @@ public class ReadWorkbook extends ReadBasicParameter {
* Whether the encryption
*/
private String password;
+ /**
+ * SAXParserFactory used when reading xlsx.
+ *
+ * The default will automatically find.
+ *
+ * Please pass in the name of a class ,like : "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"
+ *
+ * @see SAXParserFactory#newInstance()
+ * @see SAXParserFactory#newInstance(String, ClassLoader)
+ */
+ private String xlsxSAXParserFactoryName;
/**
* Whether to use the default listener, which is used by default.
*
@@ -184,6 +197,14 @@ public class ReadWorkbook extends ReadBasicParameter {
this.password = password;
}
+ public String getXlsxSAXParserFactoryName() {
+ return xlsxSAXParserFactoryName;
+ }
+
+ public void setXlsxSAXParserFactoryName(String xlsxSAXParserFactoryName) {
+ this.xlsxSAXParserFactoryName = xlsxSAXParserFactoryName;
+ }
+
public Boolean getUseDefaultListener() {
return useDefaultListener;
}
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 35b38592..cbda93fd 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
@@ -6,6 +6,8 @@ import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
+import javax.xml.parsers.SAXParserFactory;
+
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
@@ -83,6 +85,17 @@ public class ReadWorkbookHolder extends AbstractReadHolder {
* Whether the encryption
*/
private String password;
+ /**
+ * SAXParserFactory used when reading xlsx.
+ *
+ * The default will automatically find.
+ *
+ * Please pass in the name of a class ,like : "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"
+ *
+ * @see SAXParserFactory#newInstance()
+ * @see SAXParserFactory#newInstance(String, ClassLoader)
+ */
+ private String xlsxSAXParserFactoryName;
/**
* The default is all excel objects.if true , you can use {@link com.alibaba.excel.annotation.ExcelIgnore} ignore a
* field. if false , you must use {@link com.alibaba.excel.annotation.ExcelProperty} to use a filed.
@@ -172,6 +185,7 @@ public class ReadWorkbookHolder extends AbstractReadHolder {
} else {
this.defaultReturnMap = readWorkbook.getDefaultReturnMap();
}
+ this.xlsxSAXParserFactoryName = readWorkbook.getXlsxSAXParserFactoryName();
this.hasReadSheet = new HashSet();
this.ignoreRecord03 = Boolean.FALSE;
this.password = readWorkbook.getPassword();
@@ -321,6 +335,14 @@ public class ReadWorkbookHolder extends AbstractReadHolder {
this.password = password;
}
+ public String getXlsxSAXParserFactoryName() {
+ return xlsxSAXParserFactoryName;
+ }
+
+ public void setXlsxSAXParserFactoryName(String xlsxSAXParserFactoryName) {
+ this.xlsxSAXParserFactoryName = xlsxSAXParserFactoryName;
+ }
+
@Override
public HolderEnum holderType() {
return HolderEnum.WORKBOOK;
diff --git a/src/main/java/com/alibaba/excel/util/FileUtils.java b/src/main/java/com/alibaba/excel/util/FileUtils.java
index 34e68530..20b16bc6 100644
--- a/src/main/java/com/alibaba/excel/util/FileUtils.java
+++ b/src/main/java/com/alibaba/excel/util/FileUtils.java
@@ -9,24 +9,50 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
+import org.apache.poi.util.DefaultTempFileCreationStrategy;
+import org.apache.poi.util.TempFile;
+
import com.alibaba.excel.exception.ExcelAnalysisException;
-import com.alibaba.excel.exception.ExcelGenerateException;
+import com.alibaba.excel.exception.ExcelCommonException;
/**
*
* @author jipengfei
*/
public class FileUtils {
+ public static final String POI_FILES = "poifiles";
+ public static final String EX_CACHE = "excache";
+ /**
+ * If a server has multiple projects in use at the same time, a directory with the same name will be created under
+ * the temporary directory, but each project is run by a different user, so there is a permission problem, so each
+ * project creates a unique UUID as a separate Temporary Files.
+ */
+ private static String tempFilePrefix =
+ System.getProperty(TempFile.JAVA_IO_TMPDIR) + File.separator + UUID.randomUUID().toString() + File.separator;
+ /**
+ * Used to store poi temporary files.
+ */
+ private static String poiFilesPath = tempFilePrefix + POI_FILES + File.separator;
+ /**
+ * Used to store easy excel temporary files.
+ */
+ private static String cachePath = tempFilePrefix + EX_CACHE + File.separator;
- private static final String JAVA_IO_TMPDIR = "java.io.tmpdir";
-
- private static final String POIFILES = "poifiles";
-
- private static final String CACHE = "excache";
private static final int WRITE_BUFF_SIZE = 8192;
private FileUtils() {}
+ static {
+ // Create a temporary directory in advance
+ File tempFile = new File(tempFilePrefix);
+ createDirectory(tempFile);
+ tempFile.deleteOnExit();
+ // Initialize the cache directory
+ File cacheFile = new File(cachePath);
+ createDirectory(cacheFile);
+ cacheFile.deleteOnExit();
+ }
+
/**
* Reads the contents of a file into a byte array. * The file is always closed.
*
@@ -106,19 +132,31 @@ public class FileUtils {
}
}
- /**
- */
public static void createPoiFilesDirectory() {
- createTmpDirectory(POIFILES);
+ File poiFilesPathFile = new File(poiFilesPath);
+ createDirectory(poiFilesPathFile);
+ TempFile.setTempFileCreationStrategy(new DefaultTempFileCreationStrategy(poiFilesPathFile));
+ poiFilesPathFile.deleteOnExit();
}
public static File createCacheTmpFile() {
- File directory = createTmpDirectory(CACHE);
- File cache = new File(directory.getPath(), UUID.randomUUID().toString());
- if (!cache.mkdir()) {
- throw new ExcelGenerateException("Can not create temp file!");
+ return createDirectory(new File(cachePath + UUID.randomUUID().toString()));
+ }
+
+ public static File createTmpFile(String fileName) {
+ File directory = createDirectory(new File(tempFilePrefix));
+ return new File(directory, fileName);
+ }
+
+ /**
+ *
+ * @param directory
+ */
+ private static File createDirectory(File directory) {
+ if (!directory.exists() && !directory.mkdirs()) {
+ throw new ExcelCommonException("Cannot create directory:" + directory.getAbsolutePath());
}
- return cache;
+ return directory;
}
/**
@@ -144,35 +182,27 @@ public class FileUtils {
}
}
- public static File createTmpDirectory(String path) {
- String tmpDir = System.getProperty(JAVA_IO_TMPDIR);
- if (tmpDir == null) {
- throw new RuntimeException(
- "Systems temporary directory not defined - set the -D" + JAVA_IO_TMPDIR + " jvm property!");
- }
- File directory = new File(tmpDir, path);
- if (!directory.exists()) {
- syncCreatePoiFilesDirectory(directory);
- }
- return directory;
+ public static String getTempFilePrefix() {
+ return tempFilePrefix;
}
- public static File createTmpFile(String fileName) {
- String tmpDir = System.getProperty(JAVA_IO_TMPDIR);
- if (tmpDir == null) {
- throw new RuntimeException(
- "Systems temporary directory not defined - set the -D" + JAVA_IO_TMPDIR + " jvm property!");
- }
- return new File(tmpDir, fileName);
+ public static void setTempFilePrefix(String tempFilePrefix) {
+ FileUtils.tempFilePrefix = tempFilePrefix;
}
- /**
- *
- * @param directory
- */
- private static synchronized void syncCreatePoiFilesDirectory(File directory) {
- if (!directory.exists()) {
- directory.mkdirs();
- }
+ public static String getPoiFilesPath() {
+ return poiFilesPath;
+ }
+
+ public static void setPoiFilesPath(String poiFilesPath) {
+ FileUtils.poiFilesPath = poiFilesPath;
+ }
+
+ public static String getCachePath() {
+ return cachePath;
+ }
+
+ public static void setCachePath(String cachePath) {
+ FileUtils.cachePath = cachePath;
}
}
diff --git a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java
index 9658f553..59f78bfb 100644
--- a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java
+++ b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java
@@ -25,10 +25,13 @@ public class ExcelBuilderImpl implements ExcelBuilder {
private ExcelWriteFillExecutor excelWriteFillExecutor;
private ExcelWriteAddExecutor excelWriteAddExecutor;
+ static {
+ // Create temporary cache directory at initialization time to avoid POI concurrent write bugs
+ FileUtils.createPoiFilesDirectory();
+ }
+
public ExcelBuilderImpl(WriteWorkbook writeWorkbook) {
try {
- // Create temporary cache directory at initialization time to avoid POI concurrent write bugs
- FileUtils.createPoiFilesDirectory();
context = new WriteContextImpl(writeWorkbook);
} catch (RuntimeException e) {
finishOnException();
diff --git a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java
index f0d37ede..c1f2d949 100644
--- a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java
+++ b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java
@@ -91,6 +91,17 @@ public class ExcelWriterBuilder {
return this;
}
+ /**
+ * Whether to automatically merge headers.Default is true.
+ *
+ * @param automaticMergeHead
+ * @return
+ */
+ public ExcelWriterBuilder automaticMergeHead(Boolean automaticMergeHead) {
+ writeWorkbook.setAutomaticMergeHead(automaticMergeHead);
+ return this;
+ }
+
/**
* Whether the encryption.
*