Browse Source

Merge pull request #843 from alibaba/2.1.x

2.1.x
pull/854/head
Jiaju Zhuang 5 years ago committed by GitHub
parent
commit
e997a9efbd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      pom.xml
  2. 2
      src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
  3. 9
      src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java
  4. 7
      src/main/java/com/alibaba/excel/context/WriteContextImpl.java
  5. 19
      src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java
  6. 21
      src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java
  7. 22
      src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java
  8. 104
      src/main/java/com/alibaba/excel/util/FileUtils.java
  9. 11
      src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java
  10. 11
      src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java
  11. 12
      src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java
  12. 27
      src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java
  13. 2
      src/main/java/com/alibaba/excel/write/merge/AbstractMergeStrategy.java
  14. 22
      src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java
  15. 4
      src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java
  16. 13
      src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java
  17. 31
      src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java
  18. 7
      src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java
  19. 8
      src/main/java/com/alibaba/excel/write/style/column/AbstractHeadColumnWidthStyleStrategy.java
  20. 2
      src/main/java/com/alibaba/excel/write/style/column/SimpleColumnWidthStyleStrategy.java
  21. 2
      src/test/java/com/alibaba/easyexcel/test/core/fill/FillData.java
  22. 18
      src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java
  23. 20
      src/test/java/com/alibaba/easyexcel/test/core/head/ComplexHeadDataTest.java
  24. 2
      src/test/java/com/alibaba/easyexcel/test/temp/LockTest.java
  25. 9
      update.md

2
pom.xml

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId> <artifactId>easyexcel</artifactId>
<version>2.1.2</version> <version>2.1.3</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>easyexcel</name> <name>easyexcel</name>

2
src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java

@ -176,7 +176,7 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
clearEncrypt03(); clearEncrypt03();
if (throwable != null) { if (throwable != null) {
throw new ExcelAnalysisException("Can not close IO", throwable); throw new ExcelAnalysisException("Can not close IO.", throwable);
} }
} }

9
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.CollectionUtils;
import com.alibaba.excel.util.FileUtils; import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.SheetUtils; 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) { private void parseXmlSource(InputStream inputStream, ContentHandler handler) {
InputSource inputSource = new InputSource(inputStream); InputSource inputSource = new InputSource(inputStream);
try { 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://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-general-entities", false);
saxFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); saxFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

7
src/main/java/com/alibaba/excel/context/WriteContextImpl.java

@ -169,7 +169,9 @@ public class WriteContextImpl implements WriteContext {
int newRowIndex = writeSheetHolder.getNewRowIndexAndStartDoWrite(); int newRowIndex = writeSheetHolder.getNewRowIndexAndStartDoWrite();
newRowIndex += currentWriteHolder.relativeHeadRowIndex(); newRowIndex += currentWriteHolder.relativeHeadRowIndex();
// Combined head // Combined head
if (currentWriteHolder.automaticMergeHead()) {
addMergedRegionToCurrentSheet(excelWriteHeadProperty, newRowIndex); addMergedRegionToCurrentSheet(excelWriteHeadProperty, newRowIndex);
}
for (int relativeRowIndex = 0, i = newRowIndex; i < excelWriteHeadProperty.getHeadRowNumber() + newRowIndex; for (int relativeRowIndex = 0, i = newRowIndex; i < excelWriteHeadProperty.getHeadRowNumber() + newRowIndex;
i++, relativeRowIndex++) { i++, relativeRowIndex++) {
WriteHandlerUtils.beforeRowCreate(this, newRowIndex, relativeRowIndex, Boolean.TRUE); WriteHandlerUtils.beforeRowCreate(this, newRowIndex, relativeRowIndex, Boolean.TRUE);
@ -182,7 +184,8 @@ public class WriteContextImpl implements WriteContext {
private void addMergedRegionToCurrentSheet(ExcelWriteHeadProperty excelWriteHeadProperty, int rowIndex) { private void addMergedRegionToCurrentSheet(ExcelWriteHeadProperty excelWriteHeadProperty, int rowIndex) {
for (com.alibaba.excel.metadata.CellRange cellRangeModel : excelWriteHeadProperty.headCellRangeList()) { for (com.alibaba.excel.metadata.CellRange cellRangeModel : excelWriteHeadProperty.headCellRangeList()) {
writeSheetHolder.getSheet().addMergedRegion(new CellRangeAddress(cellRangeModel.getFirstRow() + rowIndex, writeSheetHolder.getSheet()
.addMergedRegionUnsafe(new CellRangeAddress(cellRangeModel.getFirstRow() + rowIndex,
cellRangeModel.getLastRow() + rowIndex, cellRangeModel.getFirstCol(), cellRangeModel.getLastCol())); cellRangeModel.getLastRow() + rowIndex, cellRangeModel.getFirstCol(), cellRangeModel.getLastCol()));
} }
} }
@ -325,7 +328,7 @@ public class WriteContextImpl implements WriteContext {
clearEncrypt03(); clearEncrypt03();
if (throwable != null) { if (throwable != null) {
throw new ExcelGenerateException("Can not close IO", throwable); throw new ExcelGenerateException("Can not close IO.", throwable);
} }
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {

19
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.ArrayList;
import java.util.List; import java.util.List;
import javax.xml.parsers.SAXParserFactory;
import com.alibaba.excel.ExcelReader; import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.cache.ReadCache; import com.alibaba.excel.cache.ReadCache;
import com.alibaba.excel.cache.selector.ReadCacheSelector; import com.alibaba.excel.cache.selector.ReadCacheSelector;
@ -233,6 +235,23 @@ public class ExcelReaderBuilder {
return this; return this;
} }
/**
* SAXParserFactory used when reading xlsx.
* <p>
* The default will automatically find.
* <p>
* 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;
}
public ExcelReader build() { public ExcelReader build() {
return new ExcelReader(readWorkbook); return new ExcelReader(readWorkbook);
} }

21
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.File;
import java.io.InputStream; import java.io.InputStream;
import javax.xml.parsers.SAXParserFactory;
import com.alibaba.excel.cache.ReadCache; import com.alibaba.excel.cache.ReadCache;
import com.alibaba.excel.cache.selector.ReadCacheSelector; import com.alibaba.excel.cache.selector.ReadCacheSelector;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
@ -63,6 +65,17 @@ public class ReadWorkbook extends ReadBasicParameter {
* Whether the encryption * Whether the encryption
*/ */
private String password; private String password;
/**
* SAXParserFactory used when reading xlsx.
* <p>
* The default will automatically find.
* <p>
* 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.Default is true. * The default is all excel objects.Default is true.
* <p> * <p>
@ -176,4 +189,12 @@ public class ReadWorkbook extends ReadBasicParameter {
public void setPassword(String password) { public void setPassword(String password) {
this.password = password; this.password = password;
} }
public String getXlsxSAXParserFactoryName() {
return xlsxSAXParserFactoryName;
}
public void setXlsxSAXParserFactoryName(String xlsxSAXParserFactoryName) {
this.xlsxSAXParserFactoryName = xlsxSAXParserFactoryName;
}
} }

22
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.HashSet;
import java.util.Set; import java.util.Set;
import javax.xml.parsers.SAXParserFactory;
import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
@ -83,6 +85,17 @@ public class ReadWorkbookHolder extends AbstractReadHolder {
* Whether the encryption * Whether the encryption
*/ */
private String password; private String password;
/**
* SAXParserFactory used when reading xlsx.
* <p>
* The default will automatically find.
* <p>
* 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 * 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. * 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 { } else {
this.defaultReturnMap = readWorkbook.getDefaultReturnMap(); this.defaultReturnMap = readWorkbook.getDefaultReturnMap();
} }
this.xlsxSAXParserFactoryName = readWorkbook.getXlsxSAXParserFactoryName();
this.hasReadSheet = new HashSet<Integer>(); this.hasReadSheet = new HashSet<Integer>();
this.ignoreRecord03 = Boolean.FALSE; this.ignoreRecord03 = Boolean.FALSE;
this.password = readWorkbook.getPassword(); this.password = readWorkbook.getPassword();
@ -321,6 +335,14 @@ public class ReadWorkbookHolder extends AbstractReadHolder {
this.password = password; this.password = password;
} }
public String getXlsxSAXParserFactoryName() {
return xlsxSAXParserFactoryName;
}
public void setXlsxSAXParserFactoryName(String xlsxSAXParserFactoryName) {
this.xlsxSAXParserFactoryName = xlsxSAXParserFactoryName;
}
@Override @Override
public HolderEnum holderType() { public HolderEnum holderType() {
return HolderEnum.WORKBOOK; return HolderEnum.WORKBOOK;

104
src/main/java/com/alibaba/excel/util/FileUtils.java

@ -9,24 +9,50 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.UUID; 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.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.exception.ExcelCommonException;
/** /**
* *
* @author jipengfei * @author jipengfei
*/ */
public class FileUtils { 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 static final int WRITE_BUFF_SIZE = 8192;
private FileUtils() {} 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. * 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() { public static void createPoiFilesDirectory() {
createTmpDirectory(POIFILES); File poiFilesPathFile = new File(poiFilesPath);
createDirectory(poiFilesPathFile);
TempFile.setTempFileCreationStrategy(new DefaultTempFileCreationStrategy(poiFilesPathFile));
poiFilesPathFile.deleteOnExit();
} }
public static File createCacheTmpFile() { public static File createCacheTmpFile() {
File directory = createTmpDirectory(CACHE); return createDirectory(new File(cachePath + 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;
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 directory;
} }
/** /**
@ -144,35 +182,27 @@ public class FileUtils {
} }
} }
public static File createTmpDirectory(String path) { public static String getTempFilePrefix() {
String tmpDir = System.getProperty(JAVA_IO_TMPDIR); return tempFilePrefix;
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()) { public static void setTempFilePrefix(String tempFilePrefix) {
syncCreatePoiFilesDirectory(directory); FileUtils.tempFilePrefix = tempFilePrefix;
}
return directory;
} }
public static File createTmpFile(String fileName) { public static String getPoiFilesPath() {
String tmpDir = System.getProperty(JAVA_IO_TMPDIR); return poiFilesPath;
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 setPoiFilesPath(String poiFilesPath) {
FileUtils.poiFilesPath = poiFilesPath;
} }
/** public static String getCachePath() {
* return cachePath;
* @param directory
*/
private static synchronized void syncCreatePoiFilesDirectory(File directory) {
if (!directory.exists()) {
directory.mkdirs();
} }
public static void setCachePath(String cachePath) {
FileUtils.cachePath = cachePath;
} }
} }

11
src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java

@ -91,6 +91,17 @@ public class ExcelWriterBuilder {
return this; 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. * Whether the encryption.
* <p> * <p>

11
src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java

@ -86,6 +86,17 @@ public class ExcelWriterSheetBuilder {
return this; return this;
} }
/**
* Whether to automatically merge headers.Default is true.
*
* @param automaticMergeHead
* @return
*/
public ExcelWriterSheetBuilder automaticMergeHead(Boolean automaticMergeHead) {
writeSheet.setAutomaticMergeHead(automaticMergeHead);
return this;
}
/** /**
* Custom type conversions override the default. * Custom type conversions override the default.
* *

12
src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java

@ -90,6 +90,17 @@ public class ExcelWriterTableBuilder {
return this; return this;
} }
/**
* Whether to automatically merge headers.Default is true.
*
* @param automaticMergeHead
* @return
*/
public ExcelWriterTableBuilder automaticMergeHead(Boolean automaticMergeHead) {
writeTable.setAutomaticMergeHead(automaticMergeHead);
return this;
}
/** /**
* Custom type conversions override the default. * Custom type conversions override the default.
* *
@ -129,7 +140,6 @@ public class ExcelWriterTableBuilder {
return this; return this;
} }
/** /**
* Ignore the custom columns. * Ignore the custom columns.
*/ */

27
src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java

@ -21,7 +21,6 @@ import com.alibaba.excel.enums.WriteDirectionEnum;
import com.alibaba.excel.enums.WriteTemplateAnalysisCellTypeEnum; import com.alibaba.excel.enums.WriteTemplateAnalysisCellTypeEnum;
import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.exception.ExcelGenerateException;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.CollectionUtils; import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.util.StringUtils;
@ -69,6 +68,8 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
private Map<Integer, Map<AnalysisCell, Integer>> collectionLastIndexCache = private Map<Integer, Map<AnalysisCell, Integer>> collectionLastIndexCache =
new HashMap<Integer, Map<AnalysisCell, Integer>>(8); new HashMap<Integer, Map<AnalysisCell, Integer>>(8);
private Map<Integer, Integer> relativeRowIndexMap = new HashMap<Integer, Integer>(8);
public ExcelWriteFillExecutor(WriteContext writeContext) { public ExcelWriteFillExecutor(WriteContext writeContext) {
super(writeContext); super(writeContext);
} }
@ -89,10 +90,10 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
shiftRows(collectionData.size(), analysisCellList); shiftRows(collectionData.size(), analysisCellList);
} }
while (iterator.hasNext()) { while (iterator.hasNext()) {
doFill(analysisCellList, iterator.next(), fillConfig); doFill(analysisCellList, iterator.next(), fillConfig, getRelativeRowIndex());
} }
} else { } else {
doFill(readTemplateData(templateAnalysisCache), data, fillConfig); doFill(readTemplateData(templateAnalysisCache), data, fillConfig, null);
} }
} }
@ -138,7 +139,8 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
} }
} }
private void doFill(List<AnalysisCell> analysisCellList, Object oneRowData, FillConfig fillConfig) { private void doFill(List<AnalysisCell> analysisCellList, Object oneRowData, FillConfig fillConfig,
Integer relativeRowIndex) {
Map dataMap; Map dataMap;
if (oneRowData instanceof Map) { if (oneRowData instanceof Map) {
dataMap = (Map)oneRowData; dataMap = (Map)oneRowData;
@ -161,7 +163,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
Object value = dataMap.get(variable); Object value = dataMap.get(variable);
CellData cellData = converterAndSet(writeSheetHolder, value == null ? null : value.getClass(), cell, CellData cellData = converterAndSet(writeSheetHolder, value == null ? null : value.getClass(), cell,
value, fieldNameContentPropertyMap.get(variable)); value, fieldNameContentPropertyMap.get(variable));
WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, null, null, Boolean.FALSE); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, null, relativeRowIndex, Boolean.FALSE);
} else { } else {
StringBuilder cellValueBuild = new StringBuilder(); StringBuilder cellValueBuild = new StringBuilder();
int index = 0; int index = 0;
@ -197,9 +199,22 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
} }
cellValueBuild.append(analysisCell.getPrepareDataList().get(index)); cellValueBuild.append(analysisCell.getPrepareDataList().get(index));
cell.setCellValue(cellValueBuild.toString()); cell.setCellValue(cellValueBuild.toString());
WriteHandlerUtils.afterCellDispose(writeContext, cellDataList, cell, null, null, Boolean.FALSE); WriteHandlerUtils.afterCellDispose(writeContext, cellDataList, cell, null, relativeRowIndex,
Boolean.FALSE);
}
}
} }
private Integer getRelativeRowIndex() {
Integer sheetNo = writeContext.writeSheetHolder().getSheetNo();
Integer relativeRowIndex = relativeRowIndexMap.get(sheetNo);
if (relativeRowIndex == null) {
relativeRowIndex = 0;
} else {
relativeRowIndex++;
} }
relativeRowIndexMap.put(sheetNo, relativeRowIndex);
return relativeRowIndex;
} }
private Cell getOneCell(AnalysisCell analysisCell, FillConfig fillConfig) { private Cell getOneCell(AnalysisCell analysisCell, FillConfig fillConfig) {

2
src/main/java/com/alibaba/excel/write/merge/AbstractMergeStrategy.java

@ -45,5 +45,5 @@ public abstract class AbstractMergeStrategy implements CellWriteHandler {
* @param head * @param head
* @param relativeRowIndex * @param relativeRowIndex
*/ */
protected abstract void merge(Sheet sheet, Cell cell, Head head, int relativeRowIndex); protected abstract void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex);
} }

22
src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java

@ -39,14 +39,20 @@ public class LoopMergeStrategy extends AbstractMergeStrategy {
} }
@Override @Override
protected void merge(Sheet sheet, Cell cell, Head head, int relativeRowIndex) { protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
if (head.getColumnIndex() == columnIndex && relativeRowIndex % eachRow == 0) { if (relativeRowIndex == null) {
CellRangeAddress cellRangeAddress = new CellRangeAddress( return;
cell.getRowIndex(), }
cell.getRowIndex() + eachRow - 1, Integer currentColumnIndex;
cell.getColumnIndex(), if (head != null) {
cell.getColumnIndex() + columnCount - 1); currentColumnIndex = head.getColumnIndex();
sheet.addMergedRegion(cellRangeAddress); } else {
currentColumnIndex = cell.getColumnIndex();
}
if (currentColumnIndex == columnIndex && relativeRowIndex % eachRow == 0) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(cell.getRowIndex(),
cell.getRowIndex() + eachRow - 1, cell.getColumnIndex(), cell.getColumnIndex() + columnCount - 1);
sheet.addMergedRegionUnsafe(cellRangeAddress);
} }
} }
} }

4
src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java

@ -29,11 +29,11 @@ public class OnceAbsoluteMergeStrategy extends AbstractMergeStrategy {
} }
@Override @Override
protected void merge(Sheet sheet, Cell cell, Head head, int relativeRowIndex) { protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
if (cell.getRowIndex() == firstRowIndex && cell.getColumnIndex() == firstColumnIndex) { if (cell.getRowIndex() == firstRowIndex && cell.getColumnIndex() == firstColumnIndex) {
CellRangeAddress cellRangeAddress = CellRangeAddress cellRangeAddress =
new CellRangeAddress(firstRowIndex, lastRowIndex, firstColumnIndex, lastColumnIndex); new CellRangeAddress(firstRowIndex, lastRowIndex, firstColumnIndex, lastColumnIndex);
sheet.addMergedRegion(cellRangeAddress); sheet.addMergedRegionUnsafe(cellRangeAddress);
} }
} }
} }

13
src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java

@ -29,6 +29,10 @@ public class WriteBasicParameter extends BasicParameter {
* Use the default style.Default is true. * Use the default style.Default is true.
*/ */
private Boolean useDefaultStyle; private Boolean useDefaultStyle;
/**
* Whether to automatically merge headers.Default is true.
*/
private Boolean automaticMergeHead;
/** /**
* Ignore the custom columns. * Ignore the custom columns.
*/ */
@ -78,6 +82,14 @@ public class WriteBasicParameter extends BasicParameter {
this.useDefaultStyle = useDefaultStyle; this.useDefaultStyle = useDefaultStyle;
} }
public Boolean getAutomaticMergeHead() {
return automaticMergeHead;
}
public void setAutomaticMergeHead(Boolean automaticMergeHead) {
this.automaticMergeHead = automaticMergeHead;
}
public Collection<Integer> getExcludeColumnIndexes() { public Collection<Integer> getExcludeColumnIndexes() {
return excludeColumnIndexes; return excludeColumnIndexes;
} }
@ -109,4 +121,5 @@ public class WriteBasicParameter extends BasicParameter {
public void setIncludeColumnFiledNames(Collection<String> includeColumnFiledNames) { public void setIncludeColumnFiledNames(Collection<String> includeColumnFiledNames) {
this.includeColumnFiledNames = includeColumnFiledNames; this.includeColumnFiledNames = includeColumnFiledNames;
} }
} }

31
src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java

@ -66,6 +66,10 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
* Use the default style.Default is true. * Use the default style.Default is true.
*/ */
private Boolean useDefaultStyle; private Boolean useDefaultStyle;
/**
* Whether to automatically merge headers.Default is true.
*/
private Boolean automaticMergeHead;
/** /**
* Ignore the custom columns. * Ignore the custom columns.
*/ */
@ -127,6 +131,16 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
this.useDefaultStyle = writeBasicParameter.getUseDefaultStyle(); this.useDefaultStyle = writeBasicParameter.getUseDefaultStyle();
} }
if (writeBasicParameter.getAutomaticMergeHead() == null) {
if (parentAbstractWriteHolder == null) {
this.automaticMergeHead = Boolean.TRUE;
} else {
this.automaticMergeHead = parentAbstractWriteHolder.getAutomaticMergeHead();
}
} else {
this.automaticMergeHead = writeBasicParameter.getAutomaticMergeHead();
}
if (writeBasicParameter.getExcludeColumnFiledNames() == null && parentAbstractWriteHolder != null) { if (writeBasicParameter.getExcludeColumnFiledNames() == null && parentAbstractWriteHolder != null) {
this.excludeColumnFiledNames = parentAbstractWriteHolder.getExcludeColumnFiledNames(); this.excludeColumnFiledNames = parentAbstractWriteHolder.getExcludeColumnFiledNames();
} else { } else {
@ -251,7 +265,7 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
} }
writeBasicParameter.getCustomWriteHandlerList().add(new AbstractHeadColumnWidthStyleStrategy() { writeBasicParameter.getCustomWriteHandlerList().add(new AbstractHeadColumnWidthStyleStrategy() {
@Override @Override
protected Integer columnWidth(Head head) { protected Integer columnWidth(Head head, Integer columnIndex) {
if (columnWidthMap.containsKey(head.getColumnIndex())) { if (columnWidthMap.containsKey(head.getColumnIndex())) {
return columnWidthMap.get(head.getColumnIndex()) / 256; return columnWidthMap.get(head.getColumnIndex()) / 256;
} }
@ -300,7 +314,7 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
private void dealColumnWidth(List<WriteHandler> handlerList) { private void dealColumnWidth(List<WriteHandler> handlerList) {
WriteHandler columnWidthStyleStrategy = new AbstractHeadColumnWidthStyleStrategy() { WriteHandler columnWidthStyleStrategy = new AbstractHeadColumnWidthStyleStrategy() {
@Override @Override
protected Integer columnWidth(Head head) { protected Integer columnWidth(Head head, Integer columnIndex) {
if (head == null) { if (head == null) {
return null; return null;
} }
@ -441,6 +455,14 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
this.useDefaultStyle = useDefaultStyle; this.useDefaultStyle = useDefaultStyle;
} }
public Boolean getAutomaticMergeHead() {
return automaticMergeHead;
}
public void setAutomaticMergeHead(Boolean automaticMergeHead) {
this.automaticMergeHead = automaticMergeHead;
}
public Collection<Integer> getExcludeColumnIndexes() { public Collection<Integer> getExcludeColumnIndexes() {
return excludeColumnIndexes; return excludeColumnIndexes;
} }
@ -492,4 +514,9 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
public int relativeHeadRowIndex() { public int relativeHeadRowIndex() {
return getRelativeHeadRowIndex(); return getRelativeHeadRowIndex();
} }
@Override
public boolean automaticMergeHead() {
return getAutomaticMergeHead();
}
} }

7
src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java

@ -44,6 +44,13 @@ public interface WriteHolder extends ConfigurationHolder {
*/ */
boolean needHead(); boolean needHead();
/**
* Whether need automatic merge headers.
*
* @return
*/
boolean automaticMergeHead();
/** /**
* Writes the head relative to the existing contents of the sheet. Indexes are zero-based. * Writes the head relative to the existing contents of the sheet. Indexes are zero-based.
* *

8
src/main/java/com/alibaba/excel/write/style/column/AbstractHeadColumnWidthStyleStrategy.java

@ -22,7 +22,7 @@ public abstract class AbstractHeadColumnWidthStyleStrategy extends AbstractColum
if (!needSetWidth) { if (!needSetWidth) {
return; return;
} }
Integer width = columnWidth(head); Integer width = columnWidth(head, cell.getColumnIndex());
if (width != null) { if (width != null) {
width = width * 256; width = width * 256;
writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), width); writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), width);
@ -36,9 +36,11 @@ public abstract class AbstractHeadColumnWidthStyleStrategy extends AbstractColum
* if return null,ignore * if return null,ignore
* *
* @param head * @param head
* Nullable * Nullable.
* @param columnIndex
* Not null.
* @return * @return
*/ */
protected abstract Integer columnWidth(Head head); protected abstract Integer columnWidth(Head head, Integer columnIndex);
} }

2
src/main/java/com/alibaba/excel/write/style/column/SimpleColumnWidthStyleStrategy.java

@ -19,7 +19,7 @@ public class SimpleColumnWidthStyleStrategy extends AbstractHeadColumnWidthStyle
} }
@Override @Override
protected Integer columnWidth(Head head) { protected Integer columnWidth(Head head, Integer columnIndex) {
return columnWidth; return columnWidth;
} }
} }

2
src/test/java/com/alibaba/easyexcel/test/core/fill/FillData.java

@ -14,6 +14,6 @@ public class FillData {
private String name; private String name;
@NumberFormat("#") @NumberFormat("#")
@ExcelProperty(converter = DoubleStringConverter.class) @ExcelProperty(converter = DoubleStringConverter.class)
private double number; private Double number;
private String empty; private String empty;
} }

18
src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java

@ -6,35 +6,19 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.FixMethodOrder; import org.junit.FixMethodOrder;
import org.junit.Test; import org.junit.Test;
import org.junit.runners.MethodSorters; import org.junit.runners.MethodSorters;
import com.alibaba.easyexcel.test.core.style.StyleData;
import com.alibaba.easyexcel.test.core.style.StyleDataListener;
import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.easyexcel.test.util.TestFileUtil;
import com.alibaba.excel.EasyExcel; import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.enums.WriteDirectionEnum; import com.alibaba.excel.enums.WriteDirectionEnum;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.merge.LoopMergeStrategy; import com.alibaba.excel.write.merge.LoopMergeStrategy;
import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy;
import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig; import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.AbstractVerticalCellStyleStrategy;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
/** /**
* *
@ -121,7 +105,7 @@ public class FillDataTest {
private void complexFill(File file, File template) { private void complexFill(File file, File template) {
ExcelWriter excelWriter = EasyExcel.write(file).withTemplate(template).build(); ExcelWriter excelWriter = EasyExcel.write(file).withTemplate(template).build();
WriteSheet writeSheet = EasyExcel.writerSheet().build(); WriteSheet writeSheet = EasyExcel.writerSheet().registerWriteHandler(new LoopMergeStrategy(2, 0)).build();
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
excelWriter.fill(data(), fillConfig, writeSheet); excelWriter.fill(data(), fillConfig, writeSheet);
excelWriter.fill(data(), fillConfig, writeSheet); excelWriter.fill(data(), fillConfig, writeSheet);

20
src/test/java/com/alibaba/easyexcel/test/core/head/ComplexHeadDataTest.java

@ -18,11 +18,15 @@ public class ComplexHeadDataTest {
private static File file07; private static File file07;
private static File file03; private static File file03;
private static File file07AutomaticMergeHead;
private static File file03AutomaticMergeHead;
@BeforeClass @BeforeClass
public static void init() { public static void init() {
file07 = TestFileUtil.createNewFile("complexHead07.xlsx"); file07 = TestFileUtil.createNewFile("complexHead07.xlsx");
file03 = TestFileUtil.createNewFile("complexHead03.xls"); file03 = TestFileUtil.createNewFile("complexHead03.xls");
file07AutomaticMergeHead = TestFileUtil.createNewFile("complexHeadAutomaticMergeHead07.xlsx");
file03AutomaticMergeHead = TestFileUtil.createNewFile("complexHeadAutomaticMergeHead03.xls");
} }
@Test @Test
@ -37,6 +41,22 @@ public class ComplexHeadDataTest {
private void readAndWrite(File file) { private void readAndWrite(File file) {
EasyExcel.write(file, ComplexHeadData.class).sheet().doWrite(data()); EasyExcel.write(file, ComplexHeadData.class).sheet().doWrite(data());
EasyExcel.read(file, ComplexHeadData.class, new ComplexDataListener())
.xlsxSAXParserFactoryName("com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl").sheet().doRead();
}
@Test
public void t03ReadAndWriteAutomaticMergeHead07() {
readAndWriteAutomaticMergeHead07(file07AutomaticMergeHead);
}
@Test
public void t04ReadAndWriteAutomaticMergeHead0703() {
readAndWriteAutomaticMergeHead07(file03AutomaticMergeHead);
}
private void readAndWriteAutomaticMergeHead07(File file) {
EasyExcel.write(file, ComplexHeadData.class).automaticMergeHead(Boolean.FALSE).sheet().doWrite(data());
EasyExcel.read(file, ComplexHeadData.class, new ComplexDataListener()).sheet().doRead(); EasyExcel.read(file, ComplexHeadData.class, new ComplexDataListener()).sheet().doRead();
} }

2
src/test/java/com/alibaba/easyexcel/test/temp/LockTest.java

@ -39,7 +39,7 @@ public class LockTest {
@Test @Test
public void test2() throws Exception { public void test2() throws Exception {
List<Object> list = List<Object> list =
EasyExcel.read(new FileInputStream("D:\\test\\null.xlsx")).sheet().headRowNumber(0).doReadSync(); EasyExcel.read(new FileInputStream("D:\\test\\开发部.xls")).sheet().headRowNumber(0).doReadSync();
for (Object data : list) { for (Object data : list) {
LOGGER.info("返回数据:{}", ((Map)data).size()); LOGGER.info("返回数据:{}", ((Map)data).size());
LOGGER.info("返回数据:{}", JSON.toJSONString(data)); LOGGER.info("返回数据:{}", JSON.toJSONString(data));

9
update.md

@ -1,3 +1,12 @@
# 2.1.3
* 每个java进程单独创建一个缓存目录 [Issue #813](https://github.com/alibaba/easyexcel/issues/813)
* 统一修改合并为unsafe,提高大量数据导出的合并的效率
* 修改merge返回参数`relativeRowIndex`为`Integer`
* 新增参数`automaticMergeHead` 可以设置不自动合并头 [Issue #822](https://github.com/alibaba/easyexcel/issues/822)
* 新增参数`xlsxSAXParserFactoryName` 可以指定`SAXParserFactory`
* 修复合并策略 空指针的问题
* `SimpleColumnWidthStyleStrategy` 新增 参数`columnIndex` [Issue #806](https://github.com/alibaba/easyexcel/issues/806)
# 2.1.2 # 2.1.2
* 修复强制创建新行填充,只有一行数据会未填充的bug * 修复强制创建新行填充,只有一行数据会未填充的bug

Loading…
Cancel
Save