Browse Source

Merge branch 'master' into 2.1.fix

# Conflicts:
#	src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java
#	src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java
bugfix
Jiaju Zhuang 5 years ago
parent
commit
49694970c6
  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. 7
      src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java
  10. 11
      src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java
  11. 11
      src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java
  12. 12
      src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java
  13. 30
      src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java
  14. 2
      src/main/java/com/alibaba/excel/write/merge/AbstractMergeStrategy.java
  15. 22
      src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java
  16. 4
      src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java
  17. 13
      src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java
  18. 31
      src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java
  19. 7
      src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java
  20. 8
      src/main/java/com/alibaba/excel/write/style/column/AbstractHeadColumnWidthStyleStrategy.java
  21. 2
      src/main/java/com/alibaba/excel/write/style/column/SimpleColumnWidthStyleStrategy.java
  22. 2
      src/test/java/com/alibaba/easyexcel/test/core/fill/FillData.java
  23. 18
      src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java
  24. 20
      src/test/java/com/alibaba/easyexcel/test/core/head/ComplexHeadDataTest.java
  25. 2
      src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java
  26. 17
      src/test/java/com/alibaba/easyexcel/test/temp/FillTempTest.java
  27. 2
      src/test/java/com/alibaba/easyexcel/test/temp/LockTest.java
  28. 11
      src/test/java/com/alibaba/easyexcel/test/temp/fill/FillData2.java
  29. 12
      src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadTest.java
  30. 14
      update.md

2
pom.xml

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

2
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);
}
}

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.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);

7
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
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,7 +184,8 @@ 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,
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()) {

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.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.
* <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;
}
/**
* Whether to use the default listener, which is used by default.
* <p>

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.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.
* <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;
/**
* Whether to use the default listener, which is used by default.
* <p>
@ -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;
}

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.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.
* <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
* 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<Integer>();
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;

104
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()));
}
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) {
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!");
public static String getTempFilePrefix() {
return tempFilePrefix;
}
File directory = new File(tmpDir, path);
if (!directory.exists()) {
syncCreatePoiFilesDirectory(directory);
}
return directory;
public static void setTempFilePrefix(String tempFilePrefix) {
FileUtils.tempFilePrefix = 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!");
public static String getPoiFilesPath() {
return poiFilesPath;
}
return new File(tmpDir, fileName);
public static void setPoiFilesPath(String poiFilesPath) {
FileUtils.poiFilesPath = poiFilesPath;
}
/**
*
* @param directory
*/
private static synchronized void syncCreatePoiFilesDirectory(File directory) {
if (!directory.exists()) {
directory.mkdirs();
public static String getCachePath() {
return cachePath;
}
public static void setCachePath(String cachePath) {
FileUtils.cachePath = cachePath;
}
}

7
src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java

@ -25,10 +25,13 @@ public class ExcelBuilderImpl implements ExcelBuilder {
private ExcelWriteFillExecutor excelWriteFillExecutor;
private ExcelWriteAddExecutor excelWriteAddExecutor;
public ExcelBuilderImpl(WriteWorkbook writeWorkbook) {
try {
static {
// Create temporary cache directory at initialization time to avoid POI concurrent write bugs
FileUtils.createPoiFilesDirectory();
}
public ExcelBuilderImpl(WriteWorkbook writeWorkbook) {
try {
context = new WriteContextImpl(writeWorkbook);
} catch (RuntimeException e) {
finishOnException();

11
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.
* <p>

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

@ -86,6 +86,17 @@ public class ExcelWriterSheetBuilder {
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.
*

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

@ -90,6 +90,17 @@ public class ExcelWriterTableBuilder {
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.
*
@ -129,7 +140,6 @@ public class ExcelWriterTableBuilder {
return this;
}
/**
* Ignore the custom columns.
*/

30
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.exception.ExcelGenerateException;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.StringUtils;
@ -69,6 +68,8 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
private Map<Integer, Map<AnalysisCell, Integer>> collectionLastIndexCache =
new HashMap<Integer, Map<AnalysisCell, Integer>>(8);
private Map<Integer, Integer> relativeRowIndexMap = new HashMap<Integer, Integer>(8);
public ExcelWriteFillExecutor(WriteContext writeContext) {
super(writeContext);
}
@ -89,10 +90,10 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
shiftRows(collectionData.size(), analysisCellList);
}
while (iterator.hasNext()) {
doFill(analysisCellList, iterator.next(), fillConfig);
doFill(analysisCellList, iterator.next(), fillConfig, getRelativeRowIndex());
}
} else {
doFill(readTemplateData(templateAnalysisCache), data, fillConfig);
doFill(readTemplateData(templateAnalysisCache), data, fillConfig, null);
}
}
@ -127,6 +128,9 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
if (collectionLastIndexMap == null) {
number--;
}
if (number <= 0) {
return;
}
sheet.shiftRows(maxRowIndex + 1, lastRowIndex, number, true, false);
for (AnalysisCell analysisCell : templateAnalysisCache.get(writeContext.writeSheetHolder().getSheetNo())) {
if (analysisCell.getRowIndex() > maxRowIndex) {
@ -135,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;
if (oneRowData instanceof Map) {
dataMap = (Map)oneRowData;
@ -158,7 +163,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
Object value = dataMap.get(variable);
CellData cellData = converterAndSet(writeSheetHolder, value == null ? null : value.getClass(), cell,
value, fieldNameContentPropertyMap.get(variable));
WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, null, null, Boolean.FALSE);
WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, null, relativeRowIndex, Boolean.FALSE);
} else {
StringBuilder cellValueBuild = new StringBuilder();
int index = 0;
@ -194,9 +199,22 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
}
cellValueBuild.append(analysisCell.getPrepareDataList().get(index));
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) {

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

@ -45,5 +45,5 @@ public abstract class AbstractMergeStrategy implements CellWriteHandler {
* @param head
* @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
protected void merge(Sheet sheet, Cell cell, Head head, int relativeRowIndex) {
if (head.getColumnIndex() == columnIndex && relativeRowIndex % eachRow == 0) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(
cell.getRowIndex(),
cell.getRowIndex() + eachRow - 1,
cell.getColumnIndex(),
cell.getColumnIndex() + columnCount - 1);
sheet.addMergedRegion(cellRangeAddress);
protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
if (relativeRowIndex == null) {
return;
}
Integer currentColumnIndex;
if (head != null) {
currentColumnIndex = head.getColumnIndex();
} 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
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) {
CellRangeAddress cellRangeAddress =
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.
*/
private Boolean useDefaultStyle;
/**
* Whether to automatically merge headers.Default is true.
*/
private Boolean automaticMergeHead;
/**
* Ignore the custom columns.
*/
@ -78,6 +82,14 @@ public class WriteBasicParameter extends BasicParameter {
this.useDefaultStyle = useDefaultStyle;
}
public Boolean getAutomaticMergeHead() {
return automaticMergeHead;
}
public void setAutomaticMergeHead(Boolean automaticMergeHead) {
this.automaticMergeHead = automaticMergeHead;
}
public Collection<Integer> getExcludeColumnIndexes() {
return excludeColumnIndexes;
}
@ -109,4 +121,5 @@ public class WriteBasicParameter extends BasicParameter {
public void setIncludeColumnFiledNames(Collection<String> 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.
*/
private Boolean useDefaultStyle;
/**
* Whether to automatically merge headers.Default is true.
*/
private Boolean automaticMergeHead;
/**
* Ignore the custom columns.
*/
@ -127,6 +131,16 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
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) {
this.excludeColumnFiledNames = parentAbstractWriteHolder.getExcludeColumnFiledNames();
} else {
@ -251,7 +265,7 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
}
writeBasicParameter.getCustomWriteHandlerList().add(new AbstractHeadColumnWidthStyleStrategy() {
@Override
protected Integer columnWidth(Head head) {
protected Integer columnWidth(Head head, Integer columnIndex) {
if (columnWidthMap.containsKey(head.getColumnIndex())) {
return columnWidthMap.get(head.getColumnIndex()) / 256;
}
@ -300,7 +314,7 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
private void dealColumnWidth(List<WriteHandler> handlerList) {
WriteHandler columnWidthStyleStrategy = new AbstractHeadColumnWidthStyleStrategy() {
@Override
protected Integer columnWidth(Head head) {
protected Integer columnWidth(Head head, Integer columnIndex) {
if (head == null) {
return null;
}
@ -441,6 +455,14 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
this.useDefaultStyle = useDefaultStyle;
}
public Boolean getAutomaticMergeHead() {
return automaticMergeHead;
}
public void setAutomaticMergeHead(Boolean automaticMergeHead) {
this.automaticMergeHead = automaticMergeHead;
}
public Collection<Integer> getExcludeColumnIndexes() {
return excludeColumnIndexes;
}
@ -492,4 +514,9 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
public int relativeHeadRowIndex() {
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();
/**
* Whether need automatic merge headers.
*
* @return
*/
boolean automaticMergeHead();
/**
* 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) {
return;
}
Integer width = columnWidth(head);
Integer width = columnWidth(head, cell.getColumnIndex());
if (width != null) {
width = width * 256;
writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), width);
@ -36,9 +36,11 @@ public abstract class AbstractHeadColumnWidthStyleStrategy extends AbstractColum
* if return null,ignore
*
* @param head
* Nullable
* Nullable.
* @param columnIndex
* Not null.
* @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
protected Integer columnWidth(Head head) {
protected Integer columnWidth(Head head, Integer columnIndex) {
return columnWidth;
}
}

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

@ -14,6 +14,6 @@ public class FillData {
private String name;
@NumberFormat("#")
@ExcelProperty(converter = DoubleStringConverter.class)
private double number;
private Double number;
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.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.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Test;
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.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
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.OnceAbsoluteMergeStrategy;
import com.alibaba.excel.write.metadata.WriteSheet;
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) {
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();
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 file03;
private static File file07AutomaticMergeHead;
private static File file03AutomaticMergeHead;
@BeforeClass
public static void init() {
file07 = TestFileUtil.createNewFile("complexHead07.xlsx");
file03 = TestFileUtil.createNewFile("complexHead03.xls");
file07AutomaticMergeHead = TestFileUtil.createNewFile("complexHeadAutomaticMergeHead07.xlsx");
file03AutomaticMergeHead = TestFileUtil.createNewFile("complexHeadAutomaticMergeHead03.xls");
}
@Test
@ -37,6 +41,22 @@ public class ComplexHeadDataTest {
private void readAndWrite(File file) {
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();
}

2
src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java

@ -73,6 +73,8 @@ public class WriteTest {
* 2. 根据自己或者排除自己需要的列
* <p>
* 3. 直接写即可
*
* @since 2.1.1
*/
@Test
public void excludeOrIncludeWrite() {

17
src/test/java/com/alibaba/easyexcel/test/temp/FillTempTest.java

@ -1,6 +1,5 @@
package com.alibaba.easyexcel.test.temp;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -10,12 +9,12 @@ import org.junit.Ignore;
import org.junit.Test;
import com.alibaba.easyexcel.test.demo.fill.FillData;
import com.alibaba.easyexcel.test.temp.fill.FillData2;
import com.alibaba.easyexcel.test.util.TestFileUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
/**
* 写的填充写法
@ -46,7 +45,7 @@ public class FillTempTest {
// 如果数据量大 list不是最后一行 参照下一个
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
excelWriter.fill(data(), fillConfig, writeSheet);
excelWriter.fill(data(), fillConfig, writeSheet);
// excelWriter.fill(data2(), fillConfig, writeSheet);
Map<String, Object> map = new HashMap<String, Object>();
map.put("date", "2019年10月9日13:28:28");
map.put("total", 1000);
@ -73,7 +72,7 @@ public class FillTempTest {
WriteSheet writeSheet = EasyExcel.writerSheet().build();
// 直接写入数据
excelWriter.fill(data(), writeSheet);
excelWriter.fill(data(), writeSheet);
excelWriter.fill(data2(), writeSheet);
// 写入list之前的数据
Map<String, Object> map = new HashMap<String, Object>();
@ -97,6 +96,16 @@ public class FillTempTest {
// 新建一个 然后一点点复制过来的方案,最后导致list需要新增行的时候,后面的列的数据没法后移,后续会继续想想解决方案
}
private List<FillData2> data2() {
List<FillData2> list = new ArrayList<FillData2>();
for (int i = 0; i < 10; i++) {
FillData2 fillData = new FillData2();
list.add(fillData);
fillData.setTest("ttttttt" + i);
}
return list;
}
private List<FillData> data() {
List<FillData> list = new ArrayList<FillData>();
for (int i = 0; i < 10; i++) {

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

@ -39,7 +39,7 @@ public class LockTest {
@Test
public void test2() throws Exception {
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) {
LOGGER.info("返回数据:{}", ((Map)data).size());
LOGGER.info("返回数据:{}", JSON.toJSONString(data));

11
src/test/java/com/alibaba/easyexcel/test/temp/fill/FillData2.java

@ -0,0 +1,11 @@
package com.alibaba.easyexcel.test.temp.fill;
import lombok.Data;
/**
* @author Jiaju Zhuang
*/
@Data
public class FillData2 {
private String test;
}

12
src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadTest.java

@ -8,6 +8,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.cache.Ehcache;
/**
* 临时测试
@ -25,4 +26,15 @@ public class HeadReadTest {
}
@Test
public void testCache() throws Exception {
File file = new File("D:\\test\\headt1.xls");
EasyExcel.read(file, HeadReadData.class, new HDListener()).readCache(new Ehcache(20)).sheet(0).doRead();
LOGGER.info("------------------");
EasyExcel.read(file, HeadReadData.class, new HDListener()).readCache(new Ehcache(20)).sheet(0).doRead();
LOGGER.info("------------------");
EasyExcel.read(file, HeadReadData.class, new HDListener()).readCache(new Ehcache(20)).sheet(0).doRead();
}
}

14
update.md

@ -1,3 +1,15 @@
# 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
* 修复强制创建新行填充,只有一行数据会未填充的bug
# 2.1.1
* 发布正式版
* 修改map返回为LinkedHashMap
@ -61,7 +73,7 @@
* 修复监听器转换异常会重复提示的bug
# 2.0.1
* 降级poi为3.1.7 兼容jdk6
* 降级poi为3.17 兼容jdk6
# 2.0.0
* 修复当cell为空可能会抛出空指针的bug

Loading…
Cancel
Save