Browse Source

Merge pull request #1265 from alibaba/developing

Developing
developing
Jiaju Zhuang 5 years ago committed by GitHub
parent
commit
245be48ef8
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/ExcelReader.java
  3. 5
      src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java
  4. 24
      src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java
  5. 2
      src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java
  6. 19
      src/main/java/com/alibaba/excel/context/WriteContextImpl.java
  7. 11
      src/main/java/com/alibaba/excel/converters/NullableObjectConverter.java
  8. 2
      src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java
  9. 5
      src/main/java/com/alibaba/excel/util/ClassUtils.java
  10. 42
      src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java
  11. 14
      src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java
  12. 35
      src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java
  13. 42
      src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java
  14. 7
      src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java
  15. 12
      src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java
  16. 2
      src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java
  17. 42
      src/test/java/com/alibaba/easyexcel/test/temp/read/HeadListener.java
  18. 5
      src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadData.java
  19. 15
      src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadTest.java
  20. 27
      src/test/java/com/alibaba/easyexcel/test/temp/read/TestListener.java
  21. 27
      src/test/java/com/alibaba/easyexcel/test/temp/simple/DemoData1.java
  22. 27
      src/test/java/com/alibaba/easyexcel/test/temp/simple/DemoData2.java
  23. 22
      src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java
  24. 3
      src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteData.java
  25. 21
      src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteHandler.java
  26. 4
      src/test/java/com/alibaba/easyexcel/test/util/TestFileUtil.java
  27. 12
      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.2.0-beta2</version> <version>2.2.1</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>easyexcel</name> <name>easyexcel</name>

2
src/main/java/com/alibaba/excel/ExcelReader.java

@ -136,6 +136,8 @@ public class ExcelReader {
readWorkbook.setReadCache(new MapCache()); readWorkbook.setReadCache(new MapCache());
readWorkbook.setConvertAllFiled(Boolean.FALSE); readWorkbook.setConvertAllFiled(Boolean.FALSE);
readWorkbook.setDefaultReturnMap(Boolean.FALSE); readWorkbook.setDefaultReturnMap(Boolean.FALSE);
// The previous logic was that Article 0 started reading
readWorkbook.setHeadRowNumber(0);
excelAnalyser = new ExcelAnalyserImpl(readWorkbook); excelAnalyser = new ExcelAnalyserImpl(readWorkbook);
} }

5
src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java

@ -138,11 +138,6 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor {
} catch (IOException e) { } catch (IOException e) {
throw new ExcelAnalysisException(e); throw new ExcelAnalysisException(e);
} }
// Sometimes tables lack the end record of the last column
if (!xlsReadContext.xlsReadSheetHolder().getCellMap().isEmpty()) {
// Forge a termination data
processRecord(new LastCellOfRowDummyRecord(xlsReadContext.xlsReadSheetHolder().getRowIndex() + 1, -1));
}
} }
@Override @Override

24
src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java

@ -1,9 +1,16 @@
package com.alibaba.excel.analysis.v03.handlers; package com.alibaba.excel.analysis.v03.handlers;
import java.util.LinkedHashMap;
import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.Record;
import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler;
import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.context.xls.XlsReadContext;
import com.alibaba.excel.enums.RowTypeEnum;
import com.alibaba.excel.metadata.Cell;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder;
/** /**
* Record handler * Record handler
@ -14,8 +21,21 @@ public class EofRecordHandler extends AbstractXlsRecordHandler implements Ignora
@Override @Override
public void processRecord(XlsReadContext xlsReadContext, Record record) { public void processRecord(XlsReadContext xlsReadContext, Record record) {
if (xlsReadContext.readSheetHolder() != null) { if (xlsReadContext.readSheetHolder() == null) {
xlsReadContext.analysisEventProcessor().endSheet(xlsReadContext); return;
}
// Sometimes tables lack the end record of the last column
if (!xlsReadContext.xlsReadSheetHolder().getCellMap().isEmpty()) {
XlsReadSheetHolder xlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder();
// Forge a termination data
xlsReadContext.readRowHolder(new ReadRowHolder(xlsReadContext.xlsReadSheetHolder().getRowIndex() + 1,
xlsReadSheetHolder.getTempRowType(),
xlsReadContext.readSheetHolder().getGlobalConfiguration(), xlsReadSheetHolder.getCellMap()));
xlsReadContext.analysisEventProcessor().endRow(xlsReadContext);
xlsReadSheetHolder.setCellMap(new LinkedHashMap<Integer, Cell>());
xlsReadSheetHolder.setTempRowType(RowTypeEnum.EMPTY);
} }
xlsReadContext.analysisEventProcessor().endSheet(xlsReadContext);
} }
} }

2
src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java

@ -25,7 +25,6 @@ public class RowTagHandler extends AbstractXlsxTagHandler {
int rowIndex = PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R), int rowIndex = PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R),
xlsxReadSheetHolder.getRowIndex()); xlsxReadSheetHolder.getRowIndex());
Integer lastRowIndex = xlsxReadContext.readSheetHolder().getRowIndex(); Integer lastRowIndex = xlsxReadContext.readSheetHolder().getRowIndex();
if (lastRowIndex != null) {
while (lastRowIndex + 1 < rowIndex) { while (lastRowIndex + 1 < rowIndex) {
xlsxReadContext.readRowHolder(new ReadRowHolder(lastRowIndex + 1, RowTypeEnum.EMPTY, xlsxReadContext.readRowHolder(new ReadRowHolder(lastRowIndex + 1, RowTypeEnum.EMPTY,
xlsxReadSheetHolder.getGlobalConfiguration(), new LinkedHashMap<Integer, Cell>())); xlsxReadSheetHolder.getGlobalConfiguration(), new LinkedHashMap<Integer, Cell>()));
@ -34,7 +33,6 @@ public class RowTagHandler extends AbstractXlsxTagHandler {
xlsxReadSheetHolder.setCellMap(new LinkedHashMap<Integer, Cell>()); xlsxReadSheetHolder.setCellMap(new LinkedHashMap<Integer, Cell>());
lastRowIndex++; lastRowIndex++;
} }
}
xlsxReadSheetHolder.setRowIndex(rowIndex); xlsxReadSheetHolder.setRowIndex(rowIndex);
} }

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

@ -111,7 +111,14 @@ public class WriteContextImpl implements WriteContext {
if (selectSheetFromCache(writeSheet)) { if (selectSheetFromCache(writeSheet)) {
return; return;
} }
initCurrentSheetHolder(writeSheet); initCurrentSheetHolder(writeSheet);
// Workbook handler need to supplementary execution
WriteHandlerUtils.beforeWorkbookCreate(this, true);
WriteHandlerUtils.afterWorkbookCreate(this, true);
// Initialization current sheet // Initialization current sheet
initSheet(writeType); initSheet(writeType);
} }
@ -201,8 +208,8 @@ public class WriteContextImpl implements WriteContext {
if (currentWriteHolder.automaticMergeHead()) { 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()
i++, relativeRowIndex++) { + newRowIndex; i++, relativeRowIndex++) {
WriteHandlerUtils.beforeRowCreate(this, newRowIndex, relativeRowIndex, Boolean.TRUE); WriteHandlerUtils.beforeRowCreate(this, newRowIndex, relativeRowIndex, Boolean.TRUE);
Row row = WorkBookUtil.createRow(writeSheetHolder.getSheet(), i); Row row = WorkBookUtil.createRow(writeSheetHolder.getSheet(), i);
WriteHandlerUtils.afterRowCreate(this, row, relativeRowIndex, Boolean.TRUE); WriteHandlerUtils.afterRowCreate(this, row, relativeRowIndex, Boolean.TRUE);
@ -251,7 +258,15 @@ public class WriteContextImpl implements WriteContext {
} }
return; return;
} }
initCurrentTableHolder(writeTable); initCurrentTableHolder(writeTable);
// Workbook and sheet handler need to supplementary execution
WriteHandlerUtils.beforeWorkbookCreate(this, true);
WriteHandlerUtils.afterWorkbookCreate(this, true);
WriteHandlerUtils.beforeSheetCreate(this, true);
WriteHandlerUtils.afterSheetCreate(this, true);
initHead(writeTableHolder.excelWriteHeadProperty()); initHead(writeTableHolder.excelWriteHeadProperty());
} }

11
src/main/java/com/alibaba/excel/converters/NullableObjectConverter.java

@ -0,0 +1,11 @@
package com.alibaba.excel.converters;
/**
* When implementing <code>convertToExcelData</code> method, pay attention to the reference <code>value</code> may be
* null
*
* @author JiaJu Zhuang
**/
public interface NullableObjectConverter<T> extends Converter<T> {
}

2
src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java

@ -15,6 +15,7 @@ import com.alibaba.excel.read.metadata.ReadSheet;
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
public class ReadSheetHolder extends AbstractReadHolder { public class ReadSheetHolder extends AbstractReadHolder {
/** /**
* current param * current param
*/ */
@ -59,6 +60,7 @@ public class ReadSheetHolder extends AbstractReadHolder {
this.sheetNo = readSheet.getSheetNo(); this.sheetNo = readSheet.getSheetNo();
this.sheetName = readSheet.getSheetName(); this.sheetName = readSheet.getSheetName();
this.cellMap = new LinkedHashMap<Integer, Cell>(); this.cellMap = new LinkedHashMap<Integer, Cell>();
this.rowIndex = -1;
} }
public ReadSheet getReadSheet() { public ReadSheet getReadSheet() {

5
src/main/java/com/alibaba/excel/util/ClassUtils.java

@ -109,11 +109,12 @@ public class ClassUtils {
+ "' and '" + field.getName() + "' must be inconsistent"); + "' and '" + field.getName() + "' must be inconsistent");
} }
customFiledMap.put(excelProperty.index(), field); customFiledMap.put(excelProperty.index(), field);
allFieldList.add(field);
} }
List<Field> allWriteFieldList = new ArrayList<Field>(customFiledMap.values());
allWriteFieldList.addAll(allFieldList);
FIELD_CACHE.put(clazz, FIELD_CACHE.put(clazz,
new SoftReference<FieldCache>(new FieldCache(defaultFieldList, customFiledMap, allFieldList, ignoreMap))); new SoftReference<FieldCache>(new FieldCache(defaultFieldList, customFiledMap, allWriteFieldList, ignoreMap)));
} }
private static class FieldCache { private static class FieldCache {

42
src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java

@ -2,6 +2,7 @@ package com.alibaba.excel.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Row;
@ -24,9 +25,13 @@ public class WriteHandlerUtils {
private WriteHandlerUtils() {} private WriteHandlerUtils() {}
public static void beforeWorkbookCreate(WriteContext writeContext) { public static void beforeWorkbookCreate(WriteContext writeContext) {
List<WriteHandler> handlerList = beforeWorkbookCreate(writeContext, false);
writeContext.writeWorkbookHolder().writeHandlerMap().get(WorkbookWriteHandler.class); }
public static void beforeWorkbookCreate(WriteContext writeContext, boolean runOwn) {
List<WriteHandler> handlerList = getHandlerList(writeContext, WorkbookWriteHandler.class, runOwn);
if (handlerList == null || handlerList.isEmpty()) { if (handlerList == null || handlerList.isEmpty()) {
return; return;
} }
@ -38,8 +43,11 @@ public class WriteHandlerUtils {
} }
public static void afterWorkbookCreate(WriteContext writeContext) { public static void afterWorkbookCreate(WriteContext writeContext) {
List<WriteHandler> handlerList = afterWorkbookCreate(writeContext, false);
writeContext.writeWorkbookHolder().writeHandlerMap().get(WorkbookWriteHandler.class); }
public static void afterWorkbookCreate(WriteContext writeContext, boolean runOwn) {
List<WriteHandler> handlerList = getHandlerList(writeContext, WorkbookWriteHandler.class, runOwn);
if (handlerList == null || handlerList.isEmpty()) { if (handlerList == null || handlerList.isEmpty()) {
return; return;
} }
@ -52,7 +60,7 @@ public class WriteHandlerUtils {
public static void afterWorkbookDispose(WriteContext writeContext) { public static void afterWorkbookDispose(WriteContext writeContext) {
List<WriteHandler> handlerList = List<WriteHandler> handlerList =
writeContext.writeWorkbookHolder().writeHandlerMap().get(WorkbookWriteHandler.class); writeContext.currentWriteHolder().writeHandlerMap().get(WorkbookWriteHandler.class);
if (handlerList == null || handlerList.isEmpty()) { if (handlerList == null || handlerList.isEmpty()) {
return; return;
} }
@ -64,7 +72,11 @@ public class WriteHandlerUtils {
} }
public static void beforeSheetCreate(WriteContext writeContext) { public static void beforeSheetCreate(WriteContext writeContext) {
List<WriteHandler> handlerList = writeContext.writeSheetHolder().writeHandlerMap().get(SheetWriteHandler.class); beforeSheetCreate(writeContext, false);
}
public static void beforeSheetCreate(WriteContext writeContext, boolean runOwn) {
List<WriteHandler> handlerList = getHandlerList(writeContext, SheetWriteHandler.class, runOwn);
if (handlerList == null || handlerList.isEmpty()) { if (handlerList == null || handlerList.isEmpty()) {
return; return;
} }
@ -76,8 +88,13 @@ public class WriteHandlerUtils {
} }
} }
public static void afterSheetCreate(WriteContext writeContext) { public static void afterSheetCreate(WriteContext writeContext) {
List<WriteHandler> handlerList = writeContext.writeSheetHolder().writeHandlerMap().get(SheetWriteHandler.class); afterSheetCreate(writeContext, false);
}
public static void afterSheetCreate(WriteContext writeContext, boolean runOwn) {
List<WriteHandler> handlerList = getHandlerList(writeContext, SheetWriteHandler.class, runOwn);
if (handlerList == null || handlerList.isEmpty()) { if (handlerList == null || handlerList.isEmpty()) {
return; return;
} }
@ -208,4 +225,15 @@ public class WriteHandlerUtils {
writeContext.writeWorkbookHolder().getWriteWorkbook().getWriteHandler().row(row.getRowNum(), row); writeContext.writeWorkbookHolder().getWriteWorkbook().getWriteHandler().row(row.getRowNum(), row);
} }
} }
private static List<WriteHandler> getHandlerList(WriteContext writeContext, Class<? extends WriteHandler> clazz,
boolean runOwn) {
Map<Class<? extends WriteHandler>, List<WriteHandler>> writeHandlerMap;
if (runOwn) {
writeHandlerMap = writeContext.currentWriteHolder().ownWriteHandlerMap();
} else {
writeHandlerMap = writeContext.currentWriteHolder().writeHandlerMap();
}
return writeHandlerMap.get(WorkbookWriteHandler.class);
}
} }

14
src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java

@ -10,6 +10,7 @@ import org.apache.poi.ss.usermodel.Sheet;
import com.alibaba.excel.context.WriteContext; import com.alibaba.excel.context.WriteContext;
import com.alibaba.excel.converters.Converter; import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ConverterKeyBuild; import com.alibaba.excel.converters.ConverterKeyBuild;
import com.alibaba.excel.converters.NullableObjectConverter;
import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.CellData;
@ -32,10 +33,9 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor {
protected CellData converterAndSet(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value, protected CellData converterAndSet(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value,
ExcelContentProperty excelContentProperty, Head head, Integer relativeRowIndex) { ExcelContentProperty excelContentProperty, Head head, Integer relativeRowIndex) {
if (value == null) { boolean needTrim =
return new CellData(CellDataTypeEnum.EMPTY); value != null && (value instanceof String && currentWriteHolder.globalConfiguration().getAutoTrim());
} if (needTrim) {
if (value instanceof String && currentWriteHolder.globalConfiguration().getAutoTrim()) {
value = ((String) value).trim(); value = ((String) value).trim();
} }
CellData cellData = convert(currentWriteHolder, clazz, cell, value, excelContentProperty); CellData cellData = convert(currentWriteHolder, clazz, cell, value, excelContentProperty);
@ -70,9 +70,6 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor {
protected CellData convert(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value, protected CellData convert(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value,
ExcelContentProperty excelContentProperty) { ExcelContentProperty excelContentProperty) {
if (value == null) {
return new CellData(CellDataTypeEnum.EMPTY);
}
// This means that the user has defined the data. // This means that the user has defined the data.
if (value instanceof CellData) { if (value instanceof CellData) {
CellData cellDataValue = (CellData)value; CellData cellDataValue = (CellData)value;
@ -110,6 +107,9 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor {
new CellData(CellDataTypeEnum.EMPTY), excelContentProperty, new CellData(CellDataTypeEnum.EMPTY), excelContentProperty,
"Can not find 'Converter' support class " + clazz.getSimpleName() + "."); "Can not find 'Converter' support class " + clazz.getSimpleName() + ".");
} }
if (value == null && !(converter instanceof NullableObjectConverter)) {
return new CellData(CellDataTypeEnum.EMPTY);
}
CellData cellData; CellData cellData;
try { try {
cellData = cellData =

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

@ -48,28 +48,28 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
/** /**
* Fields to replace in the template * Fields to replace in the template
*/ */
private Map<String, List<AnalysisCell>> templateAnalysisCache = new HashMap<String, List<AnalysisCell>>(8); private final Map<String, List<AnalysisCell>> templateAnalysisCache = new HashMap<String, List<AnalysisCell>>(8);
/** /**
* Collection fields to replace in the template * Collection fields to replace in the template
*/ */
private Map<String, List<AnalysisCell>> templateCollectionAnalysisCache = private final Map<String, List<AnalysisCell>> templateCollectionAnalysisCache =
new HashMap<String, List<AnalysisCell>>(8); new HashMap<String, List<AnalysisCell>>(8);
/** /**
* Style cache for collection fields * Style cache for collection fields
*/ */
private Map<String, Map<AnalysisCell, CellStyle>> collectionFieldStyleCache = private final Map<String, Map<AnalysisCell, CellStyle>> collectionFieldStyleCache =
new HashMap<String, Map<AnalysisCell, CellStyle>>(8); new HashMap<String, Map<AnalysisCell, CellStyle>>(8);
/** /**
* Row height cache for collection * Row height cache for collection
*/ */
private Map<String, Short> collectionRowHeightCache = new HashMap<String, Short>(8); private final Map<String, Short> collectionRowHeightCache = new HashMap<String, Short>(8);
/** /**
* Last index cache for collection fields * Last index cache for collection fields
*/ */
private Map<String, Map<AnalysisCell, Integer>> collectionLastIndexCache = private final Map<String, Map<AnalysisCell, Integer>> collectionLastIndexCache =
new HashMap<String, Map<AnalysisCell, Integer>>(8); new HashMap<String, Map<AnalysisCell, Integer>>(8);
private Map<String, Integer> relativeRowIndexMap = new HashMap<String, Integer>(8); private final Map<String, Integer> relativeRowIndexMap = new HashMap<String, Integer>(8);
/** /**
* The data prefix that is populated this time * The data prefix that is populated this time
*/ */
@ -156,12 +156,26 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
return; return;
} }
sheet.shiftRows(maxRowIndex + 1, lastRowIndex, number, true, false); sheet.shiftRows(maxRowIndex + 1, lastRowIndex, number, true, false);
for (AnalysisCell analysisCell : templateAnalysisCache.get(currentUniqueDataFlag)) {
// The current data is greater than unity rowindex increase
String tablePrefix = tablePrefix(currentUniqueDataFlag);
increaseRowIndex(templateAnalysisCache, number, maxRowIndex, tablePrefix);
increaseRowIndex(templateCollectionAnalysisCache, number, maxRowIndex, tablePrefix);
}
private void increaseRowIndex(Map<String, List<AnalysisCell>> templateAnalysisCache, int number, int maxRowIndex,
String tablePrefix) {
for (Map.Entry<String, List<AnalysisCell>> entry : templateAnalysisCache.entrySet()) {
if (!tablePrefix.equals(tablePrefix(entry.getKey()))) {
continue;
}
for (AnalysisCell analysisCell : entry.getValue()) {
if (analysisCell.getRowIndex() > maxRowIndex) { if (analysisCell.getRowIndex() > maxRowIndex) {
analysisCell.setRowIndex(analysisCell.getRowIndex() + number); analysisCell.setRowIndex(analysisCell.getRowIndex() + number);
} }
} }
} }
}
private void doFill(List<AnalysisCell> analysisCellList, Object oneRowData, FillConfig fillConfig, private void doFill(List<AnalysisCell> analysisCellList, Object oneRowData, FillConfig fillConfig,
Integer relativeRowIndex) { Integer relativeRowIndex) {
@ -384,8 +398,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
int startIndex = 0; int startIndex = 0;
int length = value.length(); int length = value.length();
int lastPrepareDataIndex = 0; int lastPrepareDataIndex = 0;
out: out: while (startIndex < length) {
while (startIndex < length) {
int prefixIndex = value.indexOf(FILL_PREFIX, startIndex); int prefixIndex = value.indexOf(FILL_PREFIX, startIndex);
if (prefixIndex < 0) { if (prefixIndex < 0) {
break out; break out;
@ -515,4 +528,8 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
return prefix + "-" + wrapperName; return prefix + "-" + wrapperName;
} }
private String tablePrefix(String uniqueDataFlag) {
return uniqueDataFlag.substring(0, uniqueDataFlag.indexOf("-") + 1);
}
} }

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

@ -64,9 +64,14 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
*/ */
private ExcelWriteHeadProperty excelWriteHeadProperty; private ExcelWriteHeadProperty excelWriteHeadProperty;
/** /**
* Write handler for workbook * Write handler
*/ */
private Map<Class<? extends WriteHandler>, List<WriteHandler>> writeHandlerMap; private Map<Class<? extends WriteHandler>, List<WriteHandler>> writeHandlerMap;
/**
* Own write handler.Created in the sheet in the workbook interceptors will not be executed because the workbook to
* create an event long past. So when initializing sheet, supplementary workbook event.
*/
private Map<Class<? extends WriteHandler>, List<WriteHandler>> ownWriteHandlerMap;
/** /**
* Use the default style.Default is true. * Use the default style.Default is true.
*/ */
@ -177,21 +182,22 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
List<WriteHandler> handlerList = new ArrayList<WriteHandler>(); List<WriteHandler> handlerList = new ArrayList<WriteHandler>();
// Initialization Annotation // Initialization Annotation
initAnnotationConfig(handlerList); initAnnotationConfig(handlerList, writeBasicParameter);
if (writeBasicParameter.getCustomWriteHandlerList() != null if (writeBasicParameter.getCustomWriteHandlerList() != null
&& !writeBasicParameter.getCustomWriteHandlerList().isEmpty()) { && !writeBasicParameter.getCustomWriteHandlerList().isEmpty()) {
handlerList.addAll(writeBasicParameter.getCustomWriteHandlerList()); handlerList.addAll(writeBasicParameter.getCustomWriteHandlerList());
} }
this.ownWriteHandlerMap = sortAndClearUpHandler(handlerList);
Map<Class<? extends WriteHandler>, List<WriteHandler>> parentWriteHandlerMap = null; Map<Class<? extends WriteHandler>, List<WriteHandler>> parentWriteHandlerMap = null;
if (parentAbstractWriteHolder != null) { if (parentAbstractWriteHolder != null) {
parentWriteHandlerMap = parentAbstractWriteHolder.getWriteHandlerMap(); parentWriteHandlerMap = parentAbstractWriteHolder.getWriteHandlerMap();
} else { } else {
handlerList.addAll(DefaultWriteHandlerLoader.loadDefaultHandler(useDefaultStyle)); handlerList.addAll(DefaultWriteHandlerLoader.loadDefaultHandler(useDefaultStyle));
} }
this.writeHandlerMap = sortAndClearUpAllHandler(handlerList, parentWriteHandlerMap);
this.writeHandlerMap = sortAndClearUpHandler(handlerList, parentWriteHandlerMap);
// Set converterMap // Set converterMap
if (parentAbstractWriteHolder == null) { if (parentAbstractWriteHolder == null) {
@ -279,10 +285,13 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
}); });
} }
protected void initAnnotationConfig(List<WriteHandler> handlerList) { protected void initAnnotationConfig(List<WriteHandler> handlerList, WriteBasicParameter writeBasicParameter) {
if (!HeadKindEnum.CLASS.equals(getExcelWriteHeadProperty().getHeadKind())) { if (!HeadKindEnum.CLASS.equals(getExcelWriteHeadProperty().getHeadKind())) {
return; return;
} }
if (writeBasicParameter.getClazz() == null) {
return;
}
Map<Integer, Head> headMap = getExcelWriteHeadProperty().getHeadMap(); Map<Integer, Head> headMap = getExcelWriteHeadProperty().getHeadMap();
boolean hasColumnWidth = false; boolean hasColumnWidth = false;
boolean hasStyle = false; boolean hasStyle = false;
@ -308,7 +317,6 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
dealRowHigh(handlerList); dealRowHigh(handlerList);
dealOnceAbsoluteMerge(handlerList); dealOnceAbsoluteMerge(handlerList);
} }
private void dealStyle(List<WriteHandler> handlerList) { private void dealStyle(List<WriteHandler> handlerList) {
@ -376,9 +384,9 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
handlerList.add(columnWidthStyleStrategy); handlerList.add(columnWidthStyleStrategy);
} }
protected Map<Class<? extends WriteHandler>, List<WriteHandler>> sortAndClearUpHandler(
List<WriteHandler> handlerList, Map<Class<? extends WriteHandler>, List<WriteHandler>> parentHandlerMap) {
protected Map<Class<? extends WriteHandler>, List<WriteHandler>> sortAndClearUpAllHandler(
List<WriteHandler> handlerList, Map<Class<? extends WriteHandler>, List<WriteHandler>> parentHandlerMap) {
// add // add
if (parentHandlerMap != null) { if (parentHandlerMap != null) {
List<WriteHandler> parentWriteHandler = parentHandlerMap.get(WriteHandler.class); List<WriteHandler> parentWriteHandler = parentHandlerMap.get(WriteHandler.class);
@ -386,7 +394,11 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
handlerList.addAll(parentWriteHandler); handlerList.addAll(parentWriteHandler);
} }
} }
return sortAndClearUpHandler(handlerList);
}
protected Map<Class<? extends WriteHandler>, List<WriteHandler>> sortAndClearUpHandler(
List<WriteHandler> handlerList) {
// sort // sort
Map<Integer, List<WriteHandler>> orderExcelWriteHandlerMap = new TreeMap<Integer, List<WriteHandler>>(); Map<Integer, List<WriteHandler>> orderExcelWriteHandlerMap = new TreeMap<Integer, List<WriteHandler>>();
for (WriteHandler handler : handlerList) { for (WriteHandler handler : handlerList) {
@ -480,6 +492,15 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
this.writeHandlerMap = writeHandlerMap; this.writeHandlerMap = writeHandlerMap;
} }
public Map<Class<? extends WriteHandler>, List<WriteHandler>> getOwnWriteHandlerMap() {
return ownWriteHandlerMap;
}
public void setOwnWriteHandlerMap(
Map<Class<? extends WriteHandler>, List<WriteHandler>> ownWriteHandlerMap) {
this.ownWriteHandlerMap = ownWriteHandlerMap;
}
public ExcelWriteHeadProperty getExcelWriteHeadProperty() { public ExcelWriteHeadProperty getExcelWriteHeadProperty() {
return excelWriteHeadProperty; return excelWriteHeadProperty;
} }
@ -554,6 +575,11 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
return getWriteHandlerMap(); return getWriteHandlerMap();
} }
@Override
public Map<Class<? extends WriteHandler>, List<WriteHandler>> ownWriteHandlerMap() {
return getOwnWriteHandlerMap();
}
@Override @Override
public boolean needHead() { public boolean needHead() {
return getNeedHead(); return getNeedHead();

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

@ -28,6 +28,13 @@ public interface WriteHolder extends ConfigurationHolder {
*/ */
Map<Class<? extends WriteHandler>, List<WriteHandler>> writeHandlerMap(); Map<Class<? extends WriteHandler>, List<WriteHandler>> writeHandlerMap();
/**
* create your own write handler.
*
* @return
*/
Map<Class<? extends WriteHandler>, List<WriteHandler>> ownWriteHandlerMap();
/** /**
* Is to determine if a field needs to be ignored * Is to determine if a field needs to be ignored
* *

12
src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java

@ -11,6 +11,7 @@ import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.SheetWriteHandler; import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.handler.WorkbookWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
@ -20,7 +21,7 @@ import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
* *
* @author Jiaju Zhuang * @author Jiaju Zhuang
*/ */
public abstract class AbstractCellStyleStrategy implements CellWriteHandler, SheetWriteHandler, NotRepeatExecutor { public abstract class AbstractCellStyleStrategy implements CellWriteHandler, WorkbookWriteHandler, NotRepeatExecutor {
boolean hasInitialized = false; boolean hasInitialized = false;
@Override @Override
@ -60,16 +61,21 @@ public abstract class AbstractCellStyleStrategy implements CellWriteHandler, She
} }
@Override @Override
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { public void beforeWorkbookCreate() {
} }
@Override @Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { public void afterWorkbookCreate(WriteWorkbookHolder writeWorkbookHolder) {
initCellStyle(writeWorkbookHolder.getWorkbook()); initCellStyle(writeWorkbookHolder.getWorkbook());
hasInitialized = true; hasInitialized = true;
} }
@Override
public void afterWorkbookDispose(WriteWorkbookHolder writeWorkbookHolder) {
}
/** /**
* Initialization cell style * Initialization cell style
* *

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

@ -32,7 +32,7 @@ public class Lock2Test {
@Test @Test
public void test() throws Exception { public void test() throws Exception {
File file = new File("D:\\test\\headt1.xlsx"); File file = TestFileUtil.readUserHomeFile("test/t3.xls");
List<Object> list = EasyExcel.read(file).sheet().headRowNumber(0).doReadSync(); List<Object> list = EasyExcel.read(file).sheet().headRowNumber(0).doReadSync();
LOGGER.info("数据:{}", list.size()); LOGGER.info("数据:{}", list.size());

42
src/test/java/com/alibaba/easyexcel/test/temp/read/HeadListener.java

@ -0,0 +1,42 @@
package com.alibaba.easyexcel.test.temp.read;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
/**
* 模板的读取类
*
* @author Jiaju Zhuang
*/
public class HeadListener extends AnalysisEventListener<HeadReadData> {
private static final Logger LOGGER = LoggerFactory.getLogger(HeadListener.class);
/**
* 每隔5条存储数据库实际使用中可以3000条然后清理list 方便内存回收
*/
private static final int BATCH_COUNT = 5;
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
LOGGER.info("HEAD:{}", JSON.toJSONString(headMap));
LOGGER.info("total:{}", context.readSheetHolder().getTotal());
}
@Override
public void invoke(HeadReadData data, AnalysisContext context) {
LOGGER.info("index:{}", context.readRowHolder().getRowIndex());
LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
LOGGER.info("所有数据解析完成!");
}
}

5
src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadData.java

@ -11,10 +11,9 @@ import lombok.experimental.Accessors;
* @author Jiaju Zhuang * @author Jiaju Zhuang
**/ **/
@Data @Data
@Accessors(chain = true)
public class HeadReadData { public class HeadReadData {
@ExcelProperty("头1") @ExcelProperty({"主标题","数据1"})
private String h1; private String h1;
@ExcelProperty({"头", "头2"}) @ExcelProperty({"主标题", "数据2"})
private String h2; private String h2;
} }

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

@ -1,14 +1,18 @@
package com.alibaba.easyexcel.test.temp.read; package com.alibaba.easyexcel.test.temp.read;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.alibaba.easyexcel.test.util.TestFileUtil;
import com.alibaba.excel.EasyExcel; import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.cache.Ehcache; import com.alibaba.excel.cache.Ehcache;
import com.alibaba.excel.support.ExcelTypeEnum;
/** /**
* 临时测试 * 临时测试
@ -18,11 +22,18 @@ import com.alibaba.excel.cache.Ehcache;
@Ignore @Ignore
public class HeadReadTest { public class HeadReadTest {
private static final Logger LOGGER = LoggerFactory.getLogger(HeadReadTest.class); private static final Logger LOGGER = LoggerFactory.getLogger(HeadReadTest.class);
@Test
public void testread() throws Exception {
FileInputStream fileInputStream = new FileInputStream("D://test/t1.xlsx");
ExcelReader excelReader = new ExcelReader(fileInputStream, ExcelTypeEnum.XLSX, null, new TestListener());
excelReader.read();
}
@Test @Test
public void test() throws Exception { public void test() throws Exception {
File file = new File("D:\\test\\headt1.xls"); File file = TestFileUtil.readUserHomeFile("test/t2.xlsx");
EasyExcel.read(file, HeadReadData.class, new HDListener()).sheet(0).doRead(); EasyExcel.read(file, HeadReadData.class, new HeadListener()).ignoreEmptyRow(false).sheet(0).doRead();
} }

27
src/test/java/com/alibaba/easyexcel/test/temp/read/TestListener.java

@ -0,0 +1,27 @@
package com.alibaba.easyexcel.test.temp.read;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
/**
* TODO
*
* @author JiaJu Zhuang
* @date 2020/4/9 16:33
**/
@Slf4j
public class TestListener extends AnalysisEventListener {
@Override
public void invoke(Object o, AnalysisContext analysisContext) {
log.info("解析一条:{}", JSON.toJSONString(o));
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}

27
src/test/java/com/alibaba/easyexcel/test/temp/simple/DemoData1.java

@ -0,0 +1,27 @@
package com.alibaba.easyexcel.test.temp.simple;
import java.util.Date;
import org.apache.poi.ss.usermodel.FillPatternType;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.HeadStyle;
import lombok.Data;
@Data
public class DemoData1 {
@ExcelProperty("字符串标题")
@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 42)
private String string;
@ExcelProperty("日期标题")
private Date date;
@ExcelProperty("数字标题")
private Double doubleData;
/**
* 忽略这个字段
*/
@ExcelIgnore
private String ignore;
}

27
src/test/java/com/alibaba/easyexcel/test/temp/simple/DemoData2.java

@ -0,0 +1,27 @@
package com.alibaba.easyexcel.test.temp.simple;
import java.util.Date;
import org.apache.poi.ss.usermodel.FillPatternType;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.HeadStyle;
import lombok.Data;
@Data
public class DemoData2 {
@ExcelProperty("字符串标题")
@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 42)
private String string;
@ExcelProperty("日期标题")
private Date date;
@ExcelProperty("数字标题")
private Double doubleData;
/**
* 忽略这个字段
*/
@ExcelIgnore
private String ignore;
}

22
src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java

@ -14,6 +14,9 @@ import com.alibaba.easyexcel.test.core.large.LargeData;
import com.alibaba.easyexcel.test.demo.write.DemoData; import com.alibaba.easyexcel.test.demo.write.DemoData;
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.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import net.sf.cglib.beans.BeanMap; import net.sf.cglib.beans.BeanMap;
@ -53,7 +56,7 @@ public class Wirte {
String fileName = TestFileUtil.getPath() + "t22" + System.currentTimeMillis() + ".xlsx"; String fileName = TestFileUtil.getPath() + "t22" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
// 如果这里想使用03 则 传入excelType参数即可 // 如果这里想使用03 则 传入excelType参数即可
EasyExcel.write(fileName, WriteData.class).sheet("模板").doWrite(data1()); EasyExcel.write(fileName, WriteData.class).sheet("模板").registerWriteHandler(new WriteHandler()).doWrite(data1());
} }
@Test @Test
@ -75,6 +78,23 @@ public class Wirte {
} }
@Test
public void tableWrite() {
String fileName = TestFileUtil.getPath() + "tableWrite" + System.currentTimeMillis() + ".xlsx";
// 这里直接写多个table的案例了,如果只有一个 也可以直一行代码搞定,参照其他案例
// 这里 需要指定写用哪个class去写
ExcelWriter excelWriter = EasyExcel.write(fileName).build();
// 把sheet设置为不需要头 不然会输出sheet的头 这样看起来第一个table 就有2个头了
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
// 这里必须指定需要头,table 会继承sheet的配置,sheet配置了不需要,table 默认也是不需要
WriteTable writeTable0 = EasyExcel.writerTable(0).head(DemoData1.class).build();
// 第一次写入会创建头
excelWriter.write(data(), writeSheet, writeTable0);
// 第二次写如也会创建头,然后在第一次的后面写入数据
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
}
private List<List<String>> head() { private List<List<String>> head() {
List<List<String>> list = new ArrayList<List<String>>(); List<List<String>> list = new ArrayList<List<String>>();
List<String> head0 = new ArrayList<String>(); List<String> head0 = new ArrayList<String>();

3
src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteData.java

@ -1,5 +1,7 @@
package com.alibaba.easyexcel.test.temp.simple; package com.alibaba.easyexcel.test.temp.simple;
import com.alibaba.excel.annotation.write.style.ContentStyle;
import lombok.Data; import lombok.Data;
/** /**
@ -9,5 +11,6 @@ import lombok.Data;
**/ **/
@Data @Data
public class WriteData { public class WriteData {
@ContentStyle(locked = true)
private float f; private float f;
} }

21
src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteHandler.java

@ -0,0 +1,21 @@
package com.alibaba.easyexcel.test.temp.simple;
import com.alibaba.excel.write.handler.AbstractSheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import lombok.extern.slf4j.Slf4j;
/**
* @author Jiaju Zhuang
*/
@Slf4j
public class WriteHandler extends AbstractSheetWriteHandler {
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder,
WriteSheetHolder writeSheetHolder) {
log.info("锁住");
writeSheetHolder.getSheet().protectSheet("edit");
}
}

4
src/test/java/com/alibaba/easyexcel/test/util/TestFileUtil.java

@ -5,6 +5,7 @@ import java.io.InputStream;
public class TestFileUtil { public class TestFileUtil {
public static InputStream getResourcesFileInputStream(String fileName) { public static InputStream getResourcesFileInputStream(String fileName) {
return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName);
} }
@ -29,4 +30,7 @@ public class TestFileUtil {
return new File(getPath() + pathName); return new File(getPath() + pathName);
} }
public static File readUserHomeFile(String pathName) {
return new File(System.getProperty("user.home") + File.separator + pathName);
}
} }

12
update.md

@ -1,3 +1,12 @@
# 2.2.1
* 发布正式版
* 修复第一行为空不会调用`invokeHeadMap`的bug [Issue #993](https://github.com/alibaba/easyexcel/issues/993)
* 当类的属性没有按照ExcelProperty的属性index顺序排序的时候,写数据出现错乱 [Issue #1046](https://github.com/alibaba/easyexcel/issues/1046)
* 新增支持自定义转换器 入参可以为空 实现`NullableObjectConverter` 即可 [Issue #1084](https://github.com/alibaba/easyexcel/issues/1084)
* 修复xls丢失结束标记的情况下 会漏读最后一行
* 修复填充的时候 多次`forceNewRow` 空指针的bug [Issue #1201](https://github.com/alibaba/easyexcel/issues/1201)
* 修复`table`、`sheet`中创建的拦截器不执行`workbook`事件的bug [Issue #1202](https://github.com/alibaba/easyexcel/issues/1202)
# 2.2.0-beta2 # 2.2.0-beta2
* 修复最长匹配策略不同表格会有影响的bug [Issue #1010](https://github.com/alibaba/easyexcel/issues/1010) * 修复最长匹配策略不同表格会有影响的bug [Issue #1010](https://github.com/alibaba/easyexcel/issues/1010)
* `LinkedList`写入的性能问题 #1121 * `LinkedList`写入的性能问题 #1121
@ -20,6 +29,9 @@
* 修复读取转换器的并发问题 * 修复读取转换器的并发问题
* 填充支持多个List对象 * 填充支持多个List对象
# 2.1.7
* 修复使用1+版本的写法,第1条开始读修改为第0条开始读
# 2.1.6 # 2.1.6
* 修复写入只有`sheetName`会抛异常 * 修复写入只有`sheetName`会抛异常

Loading…
Cancel
Save