Browse Source

Merge pull request #431 from clevertension/refactor

hudge refactor to support v2.0
pull/507/head
jipengfei-jpf 6 years ago committed by GitHub
parent
commit
0883bdf9f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      src/main/java/com/alibaba/excel/EasyExcelFactory.java
  2. 95
      src/main/java/com/alibaba/excel/ExcelReader.java
  3. 116
      src/main/java/com/alibaba/excel/ExcelWriter.java
  4. 110
      src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java
  5. 13
      src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java
  6. 49
      src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
  7. 27
      src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java
  8. 13
      src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java
  9. 275
      src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java
  10. 71
      src/main/java/com/alibaba/excel/analysis/v03/handlers/BOFRecordHandler.java
  11. 37
      src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java
  12. 71
      src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java
  13. 30
      src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java
  14. 30
      src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java
  15. 32
      src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java
  16. 36
      src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java
  17. 31
      src/main/java/com/alibaba/excel/analysis/v03/handlers/RKRecordHandler.java
  18. 39
      src/main/java/com/alibaba/excel/analysis/v03/handlers/SSTRecordHandler.java
  19. 11
      src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java
  20. 29
      src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java
  21. 128
      src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java
  22. 11
      src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java
  23. 36
      src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java
  24. 121
      src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java
  25. 37
      src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java
  26. 21
      src/main/java/com/alibaba/excel/context/AnalysisContext.java
  27. 37
      src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java
  28. 294
      src/main/java/com/alibaba/excel/context/WriteContext.java
  29. 311
      src/main/java/com/alibaba/excel/context/WriteContextImpl.java
  30. 33
      src/main/java/com/alibaba/excel/converters/BigDecimalConverter.java
  31. 42
      src/main/java/com/alibaba/excel/converters/BooleanConverter.java
  32. 13
      src/main/java/com/alibaba/excel/converters/Converter.java
  33. 8
      src/main/java/com/alibaba/excel/converters/ConverterRegistryCenter.java
  34. 55
      src/main/java/com/alibaba/excel/converters/DateConverter.java
  35. 33
      src/main/java/com/alibaba/excel/converters/DoubleConverter.java
  36. 31
      src/main/java/com/alibaba/excel/converters/FloatConverter.java
  37. 33
      src/main/java/com/alibaba/excel/converters/IntegerConverter.java
  38. 33
      src/main/java/com/alibaba/excel/converters/LongConverter.java
  39. 31
      src/main/java/com/alibaba/excel/converters/StringConverter.java
  40. 2
      src/main/java/com/alibaba/excel/event/AnalysisEventListener.java
  41. 12
      src/main/java/com/alibaba/excel/event/AnalysisEventRegistryCenter.java
  42. 5
      src/main/java/com/alibaba/excel/event/AnalysisFinishEvent.java
  43. 29
      src/main/java/com/alibaba/excel/event/EachRowAnalysisFinishEvent.java
  44. 42
      src/main/java/com/alibaba/excel/event/ModelBuildEventListener.java
  45. 34
      src/main/java/com/alibaba/excel/event/OneRowAnalysisFinishEvent.java
  46. 14
      src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java
  47. 10
      src/main/java/com/alibaba/excel/parameter/GenerateParam.java
  48. 120
      src/main/java/com/alibaba/excel/util/TypeUtil.java
  49. 18
      src/main/java/com/alibaba/excel/util/WorkBookUtil.java
  50. 13
      src/main/java/com/alibaba/excel/write/ExcelBuilder.java
  51. 85
      src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java
  52. 8
      src/main/java/com/alibaba/excel/write/MergeStrategy.java
  53. 78
      src/test/java/com/alibaba/easyexcel/test/WriteTest.java
  54. 2
      src/test/java/com/alibaba/easyexcel/test/model/WriteModel.java
  55. 4
      src/test/java/com/alibaba/easyexcel/test/util/FileUtil.java

14
src/main/java/com/alibaba/excel/EasyExcelFactory.java

@ -27,7 +27,7 @@ public class EasyExcelFactory {
*/ */
public static List<Object> read(InputStream in, Sheet sheet) { public static List<Object> read(InputStream in, Sheet sheet) {
final List<Object> rows = new ArrayList<Object>(); final List<Object> rows = new ArrayList<Object>();
new ExcelReader(in, null, new AnalysisEventListener() { new ExcelReader(in, null, new AnalysisEventListener<Object>() {
@Override @Override
public void invoke(Object object, AnalysisContext context) { public void invoke(Object object, AnalysisContext context) {
rows.add(object); rows.add(object);
@ -65,7 +65,7 @@ public class EasyExcelFactory {
/** /**
* Get ExcelWriter * Get ExcelWriter
* *
* @param outputStream the java OutputStream you wish to write the data to. * @param outputStream the java OutputStream you wish to write the value to.
* @return new ExcelWriter. * @return new ExcelWriter.
*/ */
public static ExcelWriter getWriter(OutputStream outputStream) { public static ExcelWriter getWriter(OutputStream outputStream) {
@ -75,7 +75,7 @@ public class EasyExcelFactory {
/** /**
* Get ExcelWriter * Get ExcelWriter
* *
* @param outputStream the java OutputStream you wish to write the data to. * @param outputStream the java OutputStream you wish to write the value to.
* @param typeEnum 03 or 07 * @param typeEnum 03 or 07
* @param needHead Do you need to write the header to the file? * @param needHead Do you need to write the header to the file?
* @return new ExcelWriter * @return new ExcelWriter
@ -87,9 +87,9 @@ public class EasyExcelFactory {
/** /**
* Get ExcelWriter with a template file * Get ExcelWriter with a template file
* *
* @param temp Append data after a POI file , Can be nullthe template POI filesystem that contains the * @param temp Append value after a POI file , Can be nullthe template POI filesystem that contains the
* Workbook stream) * Workbook stream)
* @param outputStream the java OutputStream you wish to write the data to * @param outputStream the java OutputStream you wish to write the value to
* @param typeEnum 03 or 07 * @param typeEnum 03 or 07
* @return new ExcelWriter * @return new ExcelWriter
*/ */
@ -101,9 +101,9 @@ public class EasyExcelFactory {
/** /**
* Get ExcelWriter with a template file * Get ExcelWriter with a template file
* *
* @param temp Append data after a POI file , Can be nullthe template POI filesystem that contains the * @param temp Append value after a POI file , Can be nullthe template POI filesystem that contains the
* Workbook stream) * Workbook stream)
* @param outputStream the java OutputStream you wish to write the data to * @param outputStream the java OutputStream you wish to write the value to
* @param typeEnum 03 or 07 * @param typeEnum 03 or 07
* @param needHead * @param needHead
* @param handler User-defined callback * @param handler User-defined callback

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

@ -1,17 +1,18 @@
package com.alibaba.excel; package com.alibaba.excel;
import java.io.InputStream;
import java.util.List;
import com.alibaba.excel.analysis.ExcelAnalyser; import com.alibaba.excel.analysis.ExcelAnalyser;
import com.alibaba.excel.analysis.ExcelAnalyserImpl; import com.alibaba.excel.analysis.ExcelAnalyserImpl;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.BaseRowModel; import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.parameter.AnalysisParam; import com.alibaba.excel.parameter.AnalysisParam;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import java.io.InputStream;
import java.util.List;
/** /**
* Excel readers are all read in event mode. * Excel readers are all read in event mode.
* *
@ -29,7 +30,8 @@ public class ExcelReader {
* *
* @param in the POI filesystem that contains the Workbook stream * @param in the POI filesystem that contains the Workbook stream
* @param excelTypeEnum 03 or 07 * @param excelTypeEnum 03 or 07
* @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext * @param customContent
* {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext
* @param eventListener Callback method after each row is parsed. * @param eventListener Callback method after each row is parsed.
*/ */
@Deprecated @Deprecated
@ -42,12 +44,25 @@ public class ExcelReader {
* Create new reader * Create new reader
* *
* @param in the POI filesystem that contains the Workbook stream * @param in the POI filesystem that contains the Workbook stream
* @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext * @param customContent
* {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext
* @param eventListener Callback method after each row is parsed * @param eventListener Callback method after each row is parsed
*/ */
public ExcelReader(InputStream in, Object customContent, public ExcelReader(InputStream in, Object customContent, AnalysisEventListener eventListener) {
AnalysisEventListener eventListener) { this(in, customContent, eventListener, null, true);
this(in, customContent, eventListener, true); }
/**
* Create new reader
*
* @param in the POI filesystem that contains the Workbook stream
* @param customContent
* {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext
* @param eventListener Callback method after each row is parsed
*/
public ExcelReader(InputStream in, Object customContent, AnalysisEventListener eventListener,
List<Converter> converters) {
this(in, customContent, eventListener, converters, true);
} }
/** /**
@ -66,41 +81,63 @@ public class ExcelReader {
* *
* @param in the POI filesystem that contains the Workbook stream * @param in the POI filesystem that contains the Workbook stream
* @param excelTypeEnum 03 or 07 * @param excelTypeEnum 03 or 07
* @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext * @param customContent
* {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext
* @param eventListener Callback method after each row is parsed. * @param eventListener Callback method after each row is parsed.
* @param trim The content of the form is empty and needs to be empty. The purpose is to be fault-tolerant, * @param trim The content of the form is empty and needs to be empty. The purpose is to be
* because there are often table contents with spaces that can not be converted into custom * fault-tolerant, because there are often table contents with spaces that can not be
* types. For example: '1234 ' contain a space cannot be converted to int. * converted into custom types. For example: '1234 ' contain a space cannot be converted
* to int.
*/ */
@Deprecated @Deprecated
public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent, public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent,
AnalysisEventListener eventListener, boolean trim) { AnalysisEventListener eventListener, boolean trim) {
validateParam(in, eventListener); this(in, excelTypeEnum, customContent, eventListener, null, trim);
analyser = new ExcelAnalyserImpl(in, excelTypeEnum, customContent, eventListener, trim);
} }
/** /**
* Create new reader * Create new reader
* *
* @param in * @param in
* @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext * @param customContent
* {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext
* @param eventListener * @param eventListener
* @param trim The content of the form is empty and needs to be empty. The purpose is to be fault-tolerant, * @param trim The content of the form is empty and needs to be empty. The purpose is to be
* because there are often table contents with spaces that can not be converted into custom * fault-tolerant, because there are often table contents with spaces that can not be
* types. For example: '1234 ' contain a space cannot be converted to int. * converted into custom types. For example: '1234 ' contain a space cannot be converted
* to int.
*/ */
public ExcelReader(InputStream in, Object customContent, public ExcelReader(InputStream in, Object customContent, AnalysisEventListener eventListener,
AnalysisEventListener eventListener, boolean trim) { List<Converter> converters, boolean trim) {
ExcelTypeEnum excelTypeEnum = ExcelTypeEnum.valueOf(in); this(in, ExcelTypeEnum.valueOf(in), customContent, eventListener, converters, trim);
}
public ExcelReader(InputStream in, Object excelTypeEnum, AnalysisEventListener<Object> eventListener,
boolean trim) {
this(in, ExcelTypeEnum.valueOf(in), null, eventListener, null, trim);
}
public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent,
AnalysisEventListener eventListener, List<Converter> converters, boolean trim) {
validateParam(in, eventListener); validateParam(in, eventListener);
analyser = new ExcelAnalyserImpl(in, excelTypeEnum, customContent, eventListener, trim); analyser = new ExcelAnalyserImpl(in, excelTypeEnum, customContent, eventListener, trim);
initConverters(analyser, converters);
}
private void initConverters(ExcelAnalyser analyser, List<Converter> converters) {
if (converters != null && converters.size() > 0) {
for (Converter c : converters) {
analyser.getAnalysisContext().getConverterRegistryCenter().register(c);
}
}
} }
/** /**
* Parse all sheet content by default * Parse all sheet content by default
*/ */
public void read() { public void read() {
analyser.analysis(); read(null, null);;
} }
/** /**
@ -109,19 +146,23 @@ public class ExcelReader {
* @param sheet Read sheet * @param sheet Read sheet
*/ */
public void read(Sheet sheet) { public void read(Sheet sheet) {
analyser.analysis(sheet); read(sheet, null);
} }
/** /**
* Parse the specified sheet * Parse the specified sheet
* *
* @param sheet Read sheet * @param sheet Read sheet
* @param clazz object parsed into each row of data * @param clazz object parsed into each row of value
*/ */
@Deprecated
public void read(Sheet sheet, Class<? extends BaseRowModel> clazz) { public void read(Sheet sheet, Class<? extends BaseRowModel> clazz) {
analyser.beforeAnalysis();
if (sheet != null) {
sheet.setClazz(clazz); sheet.setClazz(clazz);
analyser.analysis(sheet); analyser.analysis(sheet);
} else {
analyser.analysis();
}
} }
/** /**
@ -133,6 +174,10 @@ public class ExcelReader {
return analyser.getSheets(); return analyser.getSheets();
} }
public AnalysisContext getAnalysisContext() {
return analyser.getAnalysisContext();
}
/** /**
* validate param * validate param
* *

116
src/main/java/com/alibaba/excel/ExcelWriter.java

@ -1,5 +1,18 @@
package com.alibaba.excel; package com.alibaba.excel;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import com.alibaba.excel.converters.BooleanConverter;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ConverterRegistryCenter;
import com.alibaba.excel.converters.DateConverter;
import com.alibaba.excel.converters.DoubleConverter;
import com.alibaba.excel.converters.FloatConverter;
import com.alibaba.excel.converters.IntegerConverter;
import com.alibaba.excel.converters.LongConverter;
import com.alibaba.excel.converters.StringConverter;
import com.alibaba.excel.event.WriteHandler; import com.alibaba.excel.event.WriteHandler;
import com.alibaba.excel.metadata.BaseRowModel; import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
@ -8,18 +21,17 @@ import com.alibaba.excel.parameter.GenerateParam;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.ExcelBuilder; import com.alibaba.excel.write.ExcelBuilder;
import com.alibaba.excel.write.ExcelBuilderImpl; import com.alibaba.excel.write.ExcelBuilderImpl;
import com.alibaba.excel.write.MergeStrategy;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
/** /**
* Excel Writer This tool is used to write data out to Excel via POI. * Excel Writer This tool is used to write value out to Excel via POI. This object can perform the
* This object can perform the following two functions. * following two functions.
*
* <pre> * <pre>
* 1. Create a new empty Excel workbook, write the data to the stream after the data is filled. * 1. Create a new empty Excel workbook, write the value to the stream after the value is filled.
* 2. Edit existing Excel, write the original Excel file, or write it to other places.} * 2. Edit existing Excel, write the original Excel file, or write it to other places.}
* </pre> * </pre>
*
* @author jipengfei * @author jipengfei
*/ */
public class ExcelWriter { public class ExcelWriter {
@ -28,7 +40,8 @@ public class ExcelWriter {
/** /**
* Create new writer * Create new writer
* @param outputStream the java OutputStream you wish to write the data to *
* @param outputStream the java OutputStream you wish to write the value to
* @param typeEnum 03 or 07 * @param typeEnum 03 or 07
*/ */
public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum) { public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum) {
@ -43,46 +56,80 @@ public class ExcelWriter {
*/ */
@Deprecated @Deprecated
public ExcelWriter(GenerateParam generateParam) { public ExcelWriter(GenerateParam generateParam) {
this(generateParam.getOutputStream(), generateParam.getType(), true); this(generateParam.getOutputStream(), generateParam.getType(), generateParam.isNeedHead());
this.objectClass = generateParam.getClazz(); this.objectClass = generateParam.getClazz();
} }
/** /**
* *
* Create new writer * Create new writer
* @param outputStream the java OutputStream you wish to write the data to *
* @param outputStream the java OutputStream you wish to write the value to
* @param typeEnum 03 or 07 * @param typeEnum 03 or 07
* @param needHead Do you need to write the header to the file? * @param needHead Do you need to write the header to the file?
*/ */
public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum, boolean needHead) { public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum, boolean needHead) {
excelBuilder = new ExcelBuilderImpl(null, outputStream, typeEnum, needHead, null); this(null, outputStream, typeEnum, needHead, null, null);
} }
/** /**
* Create new writer * Create new writer
* @param templateInputStream Append data after a POI file ,Can be nullthe template POI filesystem that contains the Workbook stream) *
* @param outputStream the java OutputStream you wish to write the data to * @param templateInputStream Append value after a POI file ,Can be nullthe template POI
* filesystem that contains the Workbook stream)
* @param outputStream the java OutputStream you wish to write the value to
* @param typeEnum 03 or 07 * @param typeEnum 03 or 07
*/ */
public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum,Boolean needHead) { public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum,
excelBuilder = new ExcelBuilderImpl(templateInputStream,outputStream, typeEnum, needHead, null); Boolean needHead) {
this(templateInputStream, outputStream, typeEnum, needHead, null, null);
} }
/** /**
* Create new writer * Create new writer
* @param templateInputStream Append data after a POI file ,Can be nullthe template POI filesystem that contains the Workbook stream) *
* @param outputStream the java OutputStream you wish to write the data to * @param templateInputStream Append value after a POI file ,Can be nullthe template POI
* filesystem that contains the Workbook stream)
* @param outputStream the java OutputStream you wish to write the value to
* @param typeEnum 03 or 07 * @param typeEnum 03 or 07
* @param writeHandler User-defined callback * @param writeHandler User-defined callback
*/ */
public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum, Boolean needHead, public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum,
WriteHandler writeHandler) { Boolean needHead, WriteHandler writeHandler) {
excelBuilder = new ExcelBuilderImpl(templateInputStream,outputStream, typeEnum, needHead,writeHandler); this(templateInputStream, outputStream, typeEnum, needHead, writeHandler, null);
} }
public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum,
Boolean needHead, WriteHandler writeHandler, List<Converter> converters) {
excelBuilder = new ExcelBuilderImpl(templateInputStream, outputStream, typeEnum, needHead, writeHandler,
converters);
if (this.excelBuilder instanceof ConverterRegistryCenter) {
ConverterRegistryCenter registryCenter = (ConverterRegistryCenter)this.excelBuilder;
initConverters(registryCenter, converters);
}
}
private void initConverters(ConverterRegistryCenter registryCenter, List<Converter> converters) {
registerDefaultConverters(registryCenter);
if (converters != null && converters.size() > 0) {
for (Converter c : converters) {
registryCenter.register(c);
}
}
}
private void registerDefaultConverters(ConverterRegistryCenter registryCenter) {
registryCenter.register(new StringConverter());
registryCenter.register(new DateConverter(null));
registryCenter.register(new IntegerConverter());
registryCenter.register(new DoubleConverter());
registryCenter.register(new LongConverter());
registryCenter.register(new FloatConverter());
registryCenter.register(new BooleanConverter());
}
/** /**
* Write data to a sheet * Write value to a sheet
*
* @param data Data to be written * @param data Data to be written
* @param sheet Write to this sheet * @param sheet Write to this sheet
* @return this current writer * @return this current writer
@ -94,7 +141,8 @@ public class ExcelWriter {
/** /**
* Write data to a sheet * Write value to a sheet
*
* @param data Data to be written * @param data Data to be written
* @return this current writer * @return this current writer
*/ */
@ -110,7 +158,8 @@ public class ExcelWriter {
/** /**
* *
* Write data to a sheet * Write value to a sheet
*
* @param data Data to be written * @param data Data to be written
* @param sheet Write to this sheet * @param sheet Write to this sheet
* @return this * @return this
@ -121,7 +170,8 @@ public class ExcelWriter {
} }
/** /**
* Write data to a sheet * Write value to a sheet
*
* @param data Data to be written * @param data Data to be written
* @param sheet Write to this sheet * @param sheet Write to this sheet
* @return this * @return this
@ -132,7 +182,8 @@ public class ExcelWriter {
} }
/** /**
* Write data to a sheet * Write value to a sheet
*
* @param data Data to be written * @param data Data to be written
* @param sheet Write to this sheet * @param sheet Write to this sheet
* @param table Write to this table * @param table Write to this table
@ -144,7 +195,8 @@ public class ExcelWriter {
} }
/** /**
* Write data to a sheet * Write value to a sheet
*
* @param data Data to be written * @param data Data to be written
* @param sheet Write to this sheet * @param sheet Write to this sheet
* @param table Write to this table * @param table Write to this table
@ -158,18 +210,16 @@ public class ExcelWriter {
/** /**
* Merge CellsIndexes are zero-based. * Merge CellsIndexes are zero-based.
* *
* @param firstRow Index of first row * @param strategies the merge strategies.
* @param lastRow Index of last row (inclusive), must be equal to or larger than {@code firstRow}
* @param firstCol Index of first column
* @param lastCol Index of last column (inclusive), must be equal to or larger than {@code firstCol}
*/ */
public ExcelWriter merge(int firstRow, int lastRow, int firstCol, int lastCol){ public ExcelWriter merge(List<MergeStrategy> strategies) {
excelBuilder.merge(firstRow,lastRow,firstCol,lastCol); excelBuilder.merge(strategies);
return this; return this;
} }
/** /**
* Write data to a sheet * Write value to a sheet
*
* @param data Data to be written * @param data Data to be written
* @param sheet Write to this sheet * @param sheet Write to this sheet
* @param table Write to this table * @param table Write to this table

110
src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java

@ -1,41 +1,85 @@
package com.alibaba.excel.analysis; package com.alibaba.excel.analysis;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.event.AnalysisEventRegisterCenter;
import com.alibaba.excel.event.OneRowAnalysisFinishEvent;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.util.TypeUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map.Entry;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.converters.BooleanConverter;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ConverterRegistryCenter;
import com.alibaba.excel.converters.DateConverter;
import com.alibaba.excel.converters.DoubleConverter;
import com.alibaba.excel.converters.FloatConverter;
import com.alibaba.excel.converters.IntegerConverter;
import com.alibaba.excel.converters.LongConverter;
import com.alibaba.excel.converters.StringConverter;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.event.AnalysisEventRegistryCenter;
import com.alibaba.excel.event.AnalysisFinishEvent;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.ExcelHeadProperty;
import com.alibaba.excel.metadata.Sheet;
/** /**
* @author jipengfei * @author jipengfei
*/ */
public abstract class BaseSaxAnalyser implements AnalysisEventRegisterCenter, ExcelAnalyser { public abstract class BaseSaxAnalyser implements ConverterRegistryCenter, AnalysisEventRegistryCenter, ExcelAnalyser {
protected AnalysisContext analysisContext; protected AnalysisContext analysisContext;
private LinkedHashMap<String, AnalysisEventListener> listeners = new LinkedHashMap<String, AnalysisEventListener>(); private LinkedHashMap<String, AnalysisEventListener<Object>> listeners =
new LinkedHashMap<String, AnalysisEventListener<Object>>();
private LinkedHashMap<String, Converter> converters = new LinkedHashMap<String, Converter>();
/** /**
* execute method * execute method
*/ */
protected abstract void execute(); protected abstract void execute();
@Override @Override
public void appendLister(String name, AnalysisEventListener listener) { public void register(String name, AnalysisEventListener<Object> listener) {
if (!listeners.containsKey(name)) { if (!listeners.containsKey(name)) {
listeners.put(name, listener); listeners.put(name, listener);
} }
} }
@Override
public void register(Converter converter) {
converters.put(converter.getName(), converter);
}
@Override
public void beforeAnalysis() {
registerDefaultConverters();
}
private void registerDefaultConverters() {
StringConverter s = new StringConverter();
converters.put(s.getName(), s);
DateConverter d = new DateConverter(this.analysisContext);
converters.put(d.getName(), d);
IntegerConverter i = new IntegerConverter();
converters.put(i.getName(), i);
DoubleConverter dc = new DoubleConverter();
converters.put(dc.getName(), dc);
LongConverter l = new LongConverter();
converters.put(l.getName(), l);
FloatConverter f = new FloatConverter();
converters.put(f.getName(), f);
BooleanConverter b = new BooleanConverter();
converters.put(b.getName(), b);
}
@Override
public Collection<Converter> getConverters() {
return converters.values();
}
@Override @Override
public void analysis(Sheet sheetParam) { public void analysis(Sheet sheetParam) {
analysisContext.setCurrentSheet(sheetParam);
execute(); execute();
} }
@ -44,44 +88,42 @@ public abstract class BaseSaxAnalyser implements AnalysisEventRegisterCenter, Ex
execute(); execute();
} }
@Override
public AnalysisContext getAnalysisContext() {
return analysisContext;
}
/** /**
*/ */
@Override @Override
public void cleanAllListeners() { public void cleanAllListeners() {
listeners = new LinkedHashMap<String, AnalysisEventListener>(); listeners.clear();
} }
@Override @Override
public void notifyListeners(OneRowAnalysisFinishEvent event) { public void cleanListener(String name) {
analysisContext.setCurrentRowAnalysisResult(event.getData()); listeners.remove(name);
}
@SuppressWarnings("unchecked")
@Override
public void notify(AnalysisFinishEvent event) {
analysisContext.setCurrentRowAnalysisResult(event.getAnalysisResult());
/** Parsing header content **/ /** Parsing header content **/
if (analysisContext.getCurrentRowNum() < analysisContext.getCurrentSheet().getHeadLineMun()) { if (analysisContext.getCurrentRowNum() < analysisContext.getCurrentSheet().getHeadLineMun()) {
if (analysisContext.getCurrentRowNum() <= analysisContext.getCurrentSheet().getHeadLineMun() - 1) { if (analysisContext.getCurrentRowNum() <= analysisContext.getCurrentSheet().getHeadLineMun() - 1) {
analysisContext.buildExcelHeadProperty(null, buildExcelHeadProperty(null, (List<String>) analysisContext.getCurrentRowAnalysisResult());
(List<String>)analysisContext.getCurrentRowAnalysisResult());
} }
} else { } else {
List<String> content = converter((List<String>)event.getData()); for (Entry<String, AnalysisEventListener<Object>> entry : listeners.entrySet()) {
/** Parsing Analyze the body content **/
analysisContext.setCurrentRowAnalysisResult(content);
if (listeners.size() == 1) {
analysisContext.setCurrentRowAnalysisResult(content);
}
/** notify all event listeners **/
for (Map.Entry<String, AnalysisEventListener> entry : listeners.entrySet()) {
entry.getValue().invoke(analysisContext.getCurrentRowAnalysisResult(), analysisContext); entry.getValue().invoke(analysisContext.getCurrentRowAnalysisResult(), analysisContext);
} }
} }
} }
private List<String> converter(List<String> data) {
List<String> list = new ArrayList<String>();
if (data != null) {
for (String str : data) {
list.add(TypeUtil.formatFloat(str));
}
}
return list;
}
private void buildExcelHeadProperty(Class<? extends BaseRowModel> clazz, List<String> headOneRow) {
ExcelHeadProperty excelHeadProperty = ExcelHeadProperty
.buildExcelHeadProperty(this.analysisContext.getExcelHeadProperty(), clazz, headOneRow);
this.analysisContext.setExcelHeadProperty(excelHeadProperty);
}
} }

13
src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java

@ -1,9 +1,10 @@
package com.alibaba.excel.analysis; package com.alibaba.excel.analysis;
import com.alibaba.excel.metadata.Sheet;
import java.util.List; import java.util.List;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.Sheet;
/** /**
* Excel file analyser * Excel file analyser
* *
@ -11,6 +12,8 @@ import java.util.List;
*/ */
public interface ExcelAnalyser { public interface ExcelAnalyser {
void beforeAnalysis();
/** /**
* parse one sheet * parse one sheet
* *
@ -30,4 +33,10 @@ public interface ExcelAnalyser {
*/ */
List<Sheet> getSheets(); List<Sheet> getSheets();
/**
* get the analysis context.
* @return analysis context
*/
AnalysisContext getAnalysisContext();
} }

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

@ -1,18 +1,21 @@
package com.alibaba.excel.analysis; package com.alibaba.excel.analysis;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import com.alibaba.excel.analysis.v03.XlsSaxAnalyser; import com.alibaba.excel.analysis.v03.XlsSaxAnalyser;
import com.alibaba.excel.analysis.v07.XlsxSaxAnalyser; import com.alibaba.excel.analysis.v07.XlsxSaxAnalyser;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.context.AnalysisContextImpl; import com.alibaba.excel.context.AnalysisContextImpl;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ConverterRegistryCenter;
import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.modelbuild.ModelBuildEventListener; import com.alibaba.excel.event.ModelBuildEventListener;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import java.io.InputStream;
import java.util.List;
/** /**
* @author jipengfei * @author jipengfei
*/ */
@ -23,9 +26,21 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
private BaseSaxAnalyser saxAnalyser; private BaseSaxAnalyser saxAnalyser;
public ExcelAnalyserImpl(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom, public ExcelAnalyserImpl(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom,
AnalysisEventListener eventListener, boolean trim) { AnalysisEventListener<Object> eventListener, boolean trim) {
ConverterRegistryCenter center = new ConverterRegistryCenter() {
@Override
public void register(Converter converter) {
saxAnalyser.register(converter);
}
@Override
public Collection<Converter> getConverters() {
return saxAnalyser.getConverters();
}
};
analysisContext = new AnalysisContextImpl(inputStream, excelTypeEnum, custom, analysisContext = new AnalysisContextImpl(inputStream, excelTypeEnum, custom,
eventListener, trim); eventListener, center, trim);
this.saxAnalyser = getSaxAnalyser();
} }
private BaseSaxAnalyser getSaxAnalyser() { private BaseSaxAnalyser getSaxAnalyser() {
@ -66,30 +81,34 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
analysisContext.setCurrentSheet(sheetParam); analysisContext.setCurrentSheet(sheetParam);
analysis(); analysis();
} }
@Override
public AnalysisContext getAnalysisContext() {
return analysisContext;
}
@Override @Override
public void analysis() { public void analysis() {
BaseSaxAnalyser saxAnalyser = getSaxAnalyser();
appendListeners(saxAnalyser);
saxAnalyser.execute(); saxAnalyser.execute();
analysisContext.getEventListener().doAfterAllAnalysed(analysisContext); analysisContext.getEventListener().doAfterAllAnalysed(analysisContext);
} }
@Override @Override
public List<Sheet> getSheets() { public List<Sheet> getSheets() {
BaseSaxAnalyser saxAnalyser = getSaxAnalyser(); return this.saxAnalyser.getSheets();
saxAnalyser.cleanAllListeners();
return saxAnalyser.getSheets();
} }
private void appendListeners(BaseSaxAnalyser saxAnalyser) { private void registerListeners(BaseSaxAnalyser saxAnalyser) {
saxAnalyser.cleanAllListeners(); saxAnalyser.cleanAllListeners();
if (analysisContext.getCurrentSheet() != null && analysisContext.getCurrentSheet().getClazz() != null) { if (analysisContext.getCurrentSheet() != null && analysisContext.getCurrentSheet().getClazz() != null) {
saxAnalyser.appendLister("model_build_listener", new ModelBuildEventListener()); saxAnalyser.register("model_build_listener", new ModelBuildEventListener(this.saxAnalyser.getConverters()));
} }
if (analysisContext.getEventListener() != null) { if (analysisContext.getEventListener() != null) {
saxAnalyser.appendLister("user_define_listener", analysisContext.getEventListener()); saxAnalyser.register("user_define_listener", analysisContext.getEventListener());
} }
} }
@Override
public void beforeAnalysis() {
BaseSaxAnalyser saxAnalyser = getSaxAnalyser();
registerListeners(saxAnalyser);
}
} }

27
src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java

@ -0,0 +1,27 @@
package com.alibaba.excel.analysis.v03;
public abstract class AbstractXlsRecordHandler implements XlsRecordHandler {
protected int row = -1;
protected int column = -1;
protected String value = null;
@Override
public int getRow() {
return row;
}
@Override
public int getColumn() {
return column;
}
@Override
public String getValue() {
return value;
}
@Override
public int compareTo(XlsRecordHandler o) {
return this.getOrder() - o.getOrder();
}
}

13
src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java

@ -0,0 +1,13 @@
package com.alibaba.excel.analysis.v03;
import org.apache.poi.hssf.record.Record;
public interface XlsRecordHandler extends Comparable<XlsRecordHandler> {
boolean support(Record record);
void init();
void processRecord(Record record);
int getRow();
int getColumn();
String getValue();
int getOrder();
}

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

@ -1,20 +1,21 @@
package com.alibaba.excel.analysis.v03; package com.alibaba.excel.analysis.v03;
import com.alibaba.excel.analysis.BaseSaxAnalyser; import com.alibaba.excel.analysis.BaseSaxAnalyser;
import com.alibaba.excel.analysis.v03.handlers.*;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.OneRowAnalysisFinishEvent; import com.alibaba.excel.event.EachRowAnalysisFinishEvent;
import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.util.CollectionUtils;
import org.apache.poi.hssf.eventusermodel.*; import org.apache.poi.hssf.eventusermodel.*;
import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.*; import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
@ -26,15 +27,23 @@ import java.util.List;
* @author jipengfei * @author jipengfei
*/ */
public class XlsSaxAnalyser extends BaseSaxAnalyser implements HSSFListener { public class XlsSaxAnalyser extends BaseSaxAnalyser implements HSSFListener {
private boolean outputFormulaValues = true;
private boolean analyAllSheet = false; private POIFSFileSystem fs;
private int lastRowNumber;
private int lastColumnNumber;
/**
* For parsing Formulas
*/
private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener;
private FormatTrackingHSSFListener formatListener;
private List<String> records;
private boolean notAllEmpty = false;
private List<Sheet> sheets = new ArrayList<Sheet>();
private HSSFWorkbook stubWorkbook;
private List<XlsRecordHandler> recordHandlers = new ArrayList<XlsRecordHandler>();
public XlsSaxAnalyser(AnalysisContext context) throws IOException { public XlsSaxAnalyser(AnalysisContext context) throws IOException {
this.analysisContext = context; this.analysisContext = context;
this.records = new ArrayList<String>(); this.records = new ArrayList<String>();
if (analysisContext.getCurrentSheet() == null) {
this.analyAllSheet = true;
}
context.setCurrentRowNum(0); context.setCurrentRowNum(0);
this.fs = new POIFSFileSystem(analysisContext.getInputStream()); this.fs = new POIFSFileSystem(analysisContext.getInputStream());
@ -42,23 +51,25 @@ public class XlsSaxAnalyser extends BaseSaxAnalyser implements HSSFListener {
@Override @Override
public List<Sheet> getSheets() { public List<Sheet> getSheets() {
execute();
return sheets; return sheets;
} }
@Override @Override
public void execute() { public void execute() {
init();
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this); MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
formatListener = new FormatTrackingHSSFListener(listener); formatListener = new FormatTrackingHSSFListener(listener);
workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener);
if (workbookBuildingListener != null && stubWorkbook == null) {
stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();
}
init();
HSSFEventFactory factory = new HSSFEventFactory(); HSSFEventFactory factory = new HSSFEventFactory();
HSSFRequest request = new HSSFRequest(); HSSFRequest request = new HSSFRequest();
if (outputFormulaValues) { if (outputFormulaValues) {
request.addListenerForAllRecords(formatListener); request.addListenerForAllRecords(formatListener);
} else { } else {
workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener);
request.addListenerForAllRecords(workbookBuildingListener); request.addListenerForAllRecords(workbookBuildingListener);
} }
@ -72,223 +83,42 @@ public class XlsSaxAnalyser extends BaseSaxAnalyser implements HSSFListener {
private void init() { private void init() {
lastRowNumber = 0; lastRowNumber = 0;
lastColumnNumber = 0; lastColumnNumber = 0;
nextRow = 0;
nextColumn = 0;
sheetIndex = 0;
records = new ArrayList<String>(); records = new ArrayList<String>();
notAllEmpty = false; notAllEmpty = false;
orderedBSRs = null;
boundSheetRecords = new ArrayList<BoundSheetRecord>();
sheets = new ArrayList<Sheet>(); sheets = new ArrayList<Sheet>();
if (analysisContext.getCurrentSheet() == null) { buildXlsRecordHandlers();
this.analyAllSheet = true;
} else {
this.analyAllSheet = false;
} }
}
private POIFSFileSystem fs;
private int lastRowNumber;
private int lastColumnNumber;
/**
* Should we output the formula, or the value it has?
*/
private boolean outputFormulaValues = true;
/**
* For parsing Formulas
*/
private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener;
private HSSFWorkbook stubWorkbook;
private SSTRecord sstRecord;
private FormatTrackingHSSFListener formatListener;
/**
* So we known which sheet we're on
*/
private int nextRow;
private int nextColumn;
private boolean outputNextStringRecord;
/**
* Main HSSFListener method, processes events, and outputs the CSV as the file is processed.
*/
private int sheetIndex;
private List<String> records;
private boolean notAllEmpty = false;
private BoundSheetRecord[] orderedBSRs;
private List<BoundSheetRecord> boundSheetRecords = new ArrayList<BoundSheetRecord>();
private List<Sheet> sheets = new ArrayList<Sheet>();
public void processRecord(Record record) { public void processRecord(Record record) {
int thisRow = -1; int thisRow = -1;
int thisColumn = -1; int thisColumn = -1;
String thisStr = null; String thisStr = null;
for(XlsRecordHandler handler : this.recordHandlers) {
switch (record.getSid()) { if (handler.support(record)) {
case BoundSheetRecord.sid: handler.processRecord(record);
boundSheetRecords.add((BoundSheetRecord)record); thisRow = handler.getRow();
break; thisColumn = handler.getColumn();
case BOFRecord.sid: thisStr = handler.getValue();
BOFRecord br = (BOFRecord)record;
if (br.getType() == BOFRecord.TYPE_WORKSHEET) {
// Create sub workbook if required
if (workbookBuildingListener != null && stubWorkbook == null) {
stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();
}
if (orderedBSRs == null) {
orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords);
}
sheetIndex++;
Sheet sheet = new Sheet(sheetIndex, 0);
sheet.setSheetName(orderedBSRs[sheetIndex - 1].getSheetname());
sheets.add(sheet);
if (this.analyAllSheet) {
analysisContext.setCurrentSheet(sheet);
}
}
break;
case SSTRecord.sid:
sstRecord = (SSTRecord)record;
break;
case BlankRecord.sid:
BlankRecord brec = (BlankRecord)record;
thisRow = brec.getRow();
thisColumn = brec.getColumn();
thisStr = "";
break;
case BoolErrRecord.sid:
BoolErrRecord berec = (BoolErrRecord)record;
thisRow = berec.getRow();
thisColumn = berec.getColumn();
thisStr = "";
break;
case FormulaRecord.sid:
FormulaRecord frec = (FormulaRecord)record;
thisRow = frec.getRow();
thisColumn = frec.getColumn();
if (outputFormulaValues) {
if (Double.isNaN(frec.getValue())) {
// Formula result is a string
// This is stored in the next record
outputNextStringRecord = true;
nextRow = frec.getRow();
nextColumn = frec.getColumn();
} else {
thisStr = formatListener.formatNumberDateCell(frec);
}
} else {
thisStr = HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression());
}
break;
case StringRecord.sid:
if (outputNextStringRecord) {
// String for formula
StringRecord srec = (StringRecord)record;
thisStr = srec.getString();
thisRow = nextRow;
thisColumn = nextColumn;
outputNextStringRecord = false;
}
break;
case LabelRecord.sid:
LabelRecord lrec = (LabelRecord)record;
thisRow = lrec.getRow();
thisColumn = lrec.getColumn();
thisStr = lrec.getValue();
break; break;
case LabelSSTRecord.sid:
LabelSSTRecord lsrec = (LabelSSTRecord)record;
thisRow = lsrec.getRow();
thisColumn = lsrec.getColumn();
if (sstRecord == null) {
thisStr = "";
} else {
thisStr = sstRecord.getString(lsrec.getSSTIndex()).toString();
}
break;
case NoteRecord.sid:
NoteRecord nrec = (NoteRecord)record;
thisRow = nrec.getRow();
thisColumn = nrec.getColumn();
// TODO: Find object to match nrec.getShapeId()
thisStr = "(TODO)";
break;
case NumberRecord.sid:
NumberRecord numrec = (NumberRecord)record;
thisRow = numrec.getRow();
thisColumn = numrec.getColumn();
// Format
thisStr = formatListener.formatNumberDateCell(numrec);
break;
case RKRecord.sid:
RKRecord rkrec = (RKRecord)record;
thisRow = rkrec.getRow();
thisColumn = rkrec.getColumn();
thisStr = "";
break;
default:
break;
}
// Handle new row
if (thisRow != -1 && thisRow != lastRowNumber) {
lastColumnNumber = -1;
} }
// Handle missing column
if (record instanceof MissingCellDummyRecord) {
MissingCellDummyRecord mc = (MissingCellDummyRecord)record;
thisRow = mc.getRow();
thisColumn = mc.getColumn();
thisStr = "";
} }
// If we got something to print out, do so // If we got something to print out, do so
if (thisStr != null) { if (thisStr != null) {
if (analysisContext.trim()) { if (analysisContext.trim()) {
thisStr = thisStr.trim(); thisStr = thisStr.trim();
} }
if (!"".equals(thisStr)) { if (!"".equals(thisStr)) {
notAllEmpty = true; notAllEmpty = true;
} }
// }
records.add(thisStr); records.add(thisStr);
} }
// Handle new row
if (thisRow != -1 && thisRow != lastRowNumber) {
lastColumnNumber = -1;
}
// Update column and row count // Update column and row count
if (thisRow > -1) { if (thisRow > -1) {
lastRowNumber = thisRow; lastRowNumber = thisRow;
@ -297,22 +127,43 @@ public class XlsSaxAnalyser extends BaseSaxAnalyser implements HSSFListener {
lastColumnNumber = thisColumn; lastColumnNumber = thisColumn;
} }
processLastCellOfRow(record);
}
private void processLastCellOfRow(Record record) {
// Handle end of row // Handle end of row
if (record instanceof LastCellOfRowDummyRecord) { if (record instanceof LastCellOfRowDummyRecord) {
thisRow = ((LastCellOfRowDummyRecord)record).getRow(); int row = ((LastCellOfRowDummyRecord)record).getRow();
if (lastColumnNumber == -1) { if (lastColumnNumber == -1) {
lastColumnNumber = 0; lastColumnNumber = 0;
} }
analysisContext.setCurrentRowNum(thisRow); analysisContext.setCurrentRowNum(row);
Sheet sheet = analysisContext.getCurrentSheet(); if (notAllEmpty) {
notify(new EachRowAnalysisFinishEvent(new ArrayList<String>(records)));
if ((sheet == null || sheet.getSheetNo() == sheetIndex) && notAllEmpty) {
notifyListeners(new OneRowAnalysisFinishEvent(records));
} }
records.clear(); records.clear();
lastColumnNumber = -1; lastColumnNumber = -1;
notAllEmpty = false; notAllEmpty = false;
} }
} }
private void buildXlsRecordHandlers() {
if (CollectionUtils.isEmpty(recordHandlers)) {
recordHandlers.add(new BlankOrErrorRecordHandler());
recordHandlers.add(new BOFRecordHandler(workbookBuildingListener, analysisContext, sheets));
recordHandlers.add(new FormulaRecordHandler(stubWorkbook, formatListener));
recordHandlers.add(new LabelRecordHandler());
recordHandlers.add(new NoteRecordHandler());
recordHandlers.add(new NumberRecordHandler(formatListener));
recordHandlers.add(new RKRecordHandler());
recordHandlers.add(new SSTRecordHandler());
recordHandlers.add(new MissingCellDummyRecordHandler());
Collections.sort(recordHandlers);
}
for(XlsRecordHandler x : recordHandlers) {
x.init();
}
}
} }

71
src/main/java/com/alibaba/excel/analysis/v03/handlers/BOFRecordHandler.java

@ -0,0 +1,71 @@
package com.alibaba.excel.analysis.v03.handlers;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import com.alibaba.excel.analysis.v03.XlsRecordHandler;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.Sheet;
import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder;
import org.apache.poi.hssf.record.BOFRecord;
import org.apache.poi.hssf.record.BoundSheetRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import java.util.ArrayList;
import java.util.List;
public class BOFRecordHandler extends AbstractXlsRecordHandler {
private List<BoundSheetRecord> boundSheetRecords = new ArrayList<BoundSheetRecord>();
private BoundSheetRecord[] orderedBSRs;
private int sheetIndex;
private List<Sheet> sheets;
private AnalysisContext context;
private boolean analyAllSheet;
private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener;
public BOFRecordHandler(EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener, AnalysisContext context, List<Sheet> sheets) {
this.context = context;
this.workbookBuildingListener = workbookBuildingListener;
this.sheets = sheets;
}
@Override
public boolean support(Record record) {
return BoundSheetRecord.sid == record.getSid() || BOFRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
if (record.getSid() == BoundSheetRecord.sid) {
boundSheetRecords.add((BoundSheetRecord)record);
} else if (record.getSid() == BOFRecord.sid) {
BOFRecord br = (BOFRecord)record;
if (br.getType() == BOFRecord.TYPE_WORKSHEET) {
if (orderedBSRs == null) {
orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords);
}
sheetIndex++;
Sheet sheet = new Sheet(sheetIndex, 0);
sheet.setSheetName(orderedBSRs[sheetIndex - 1].getSheetname());
sheets.add(sheet);
if (this.analyAllSheet) {
context.setCurrentSheet(sheet);
}
}
}
}
@Override
public void init() {
if (context.getCurrentSheet() == null) {
this.analyAllSheet = true;
}
sheetIndex = 0;
orderedBSRs = null;
boundSheetRecords.clear();
sheets.clear();
}
@Override
public int getOrder() {
return 0;
}
}

37
src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java

@ -0,0 +1,37 @@
package com.alibaba.excel.analysis.v03.handlers;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import org.apache.poi.hssf.record.*;
public class BlankOrErrorRecordHandler extends AbstractXlsRecordHandler {
@Override
public boolean support(Record record) {
return BlankRecord.sid == record.getSid() || BoolErrRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
if (record.getSid() == BlankRecord.sid) {
BlankRecord br = (BlankRecord)record;
this.row = br.getRow();
this.column = br.getColumn();
this.value = "";
} else if (record.getSid() == BoolErrRecord.sid) {
BoolErrRecord ber = (BoolErrRecord)record;
this.row = ber.getRow();
this.column = ber.getColumn();
this.value = "";
}
}
@Override
public void init() {
}
@Override
public int getOrder() {
return 0;
}
}

71
src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java

@ -0,0 +1,71 @@
package com.alibaba.excel.analysis.v03.handlers;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
public class FormulaRecordHandler extends AbstractXlsRecordHandler {
private int nextRow;
private int nextColumn;
/**
* Should we output the formula, or the value it has?
*/
private boolean outputFormulaValues = true;
private boolean outputNextStringRecord;
private FormatTrackingHSSFListener formatListener;
private HSSFWorkbook stubWorkbook;
public FormulaRecordHandler(HSSFWorkbook stubWorkbook, FormatTrackingHSSFListener formatListener) {
this.stubWorkbook = stubWorkbook;
this.formatListener = formatListener;
}
@Override
public boolean support(Record record) {
return FormulaRecord.sid == record.getSid() || StringRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
if (record.getSid() == FormulaRecord.sid) {
FormulaRecord frec = (FormulaRecord)record;
this.row = frec.getRow();
this.column = frec.getColumn();
if (outputFormulaValues) {
if (Double.isNaN(frec.getValue())) {
// Formula result is a string
// This is stored in the next record
outputNextStringRecord = true;
nextRow = frec.getRow();
nextColumn = frec.getColumn();
} else {
this.value = formatListener.formatNumberDateCell(frec);
}
} else {
this.value = HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression());
}
} else if (record.getSid() == StringRecord.sid) {
if (outputNextStringRecord) {
// String for formula
StringRecord srec = (StringRecord)record;
this.value = srec.getString();
this.row = nextRow;
this.column = nextColumn;
outputNextStringRecord = false;
}
}
}
@Override
public void init() {
this.nextRow = 0;
this.nextColumn = 0;
}
@Override
public int getOrder() {
return 0;
}
}

30
src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java

@ -0,0 +1,30 @@
package com.alibaba.excel.analysis.v03.handlers;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import org.apache.poi.hssf.record.LabelRecord;
import org.apache.poi.hssf.record.Record;
public class LabelRecordHandler extends AbstractXlsRecordHandler {
@Override
public boolean support(Record record) {
return LabelRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
LabelRecord lrec = (LabelRecord)record;
this.row = lrec.getRow();
this.column = lrec.getColumn();
this.value = lrec.getValue();
}
@Override
public void init() {
}
@Override
public int getOrder() {
return 0;
}
}

30
src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java

@ -0,0 +1,30 @@
package com.alibaba.excel.analysis.v03.handlers;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
import org.apache.poi.hssf.record.Record;
public class MissingCellDummyRecordHandler extends AbstractXlsRecordHandler {
@Override
public boolean support(Record record) {
return record instanceof MissingCellDummyRecord;
}
@Override
public void init() {
}
@Override
public void processRecord(Record record) {
MissingCellDummyRecord mcdr = (MissingCellDummyRecord)record;
this.row = mcdr.getRow();
this.column = mcdr.getColumn();
this.value = "";
}
@Override
public int getOrder() {
return 1;
}
}

32
src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java

@ -0,0 +1,32 @@
package com.alibaba.excel.analysis.v03.handlers;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import org.apache.poi.hssf.record.NoteRecord;
import org.apache.poi.hssf.record.Record;
public class NoteRecordHandler extends AbstractXlsRecordHandler {
@Override
public boolean support(Record record) {
return NoteRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
NoteRecord nrec = (NoteRecord)record;
this.row = nrec.getRow();
this.column = nrec.getColumn();
// TODO: Find object to match nrec.getShapeId()
this.value = "(TODO)";
}
@Override
public void init() {
}
@Override
public int getOrder() {
return 0;
}
}

36
src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java

@ -0,0 +1,36 @@
package com.alibaba.excel.analysis.v03.handlers;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.Record;
public class NumberRecordHandler extends AbstractXlsRecordHandler {
private FormatTrackingHSSFListener formatListener;
public NumberRecordHandler(FormatTrackingHSSFListener formatListener) {
this.formatListener = formatListener;
}
@Override
public boolean support(Record record) {
return NumberRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
NumberRecord numrec = (NumberRecord)record;
this.row = numrec.getRow();
this.column = numrec.getColumn();
// Format
this.value = formatListener.formatNumberDateCell(numrec);
}
@Override
public void init() {
}
@Override
public int getOrder() {
return 0;
}
}

31
src/main/java/com/alibaba/excel/analysis/v03/handlers/RKRecordHandler.java

@ -0,0 +1,31 @@
package com.alibaba.excel.analysis.v03.handlers;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import org.apache.poi.hssf.record.RKRecord;
import org.apache.poi.hssf.record.Record;
public class RKRecordHandler extends AbstractXlsRecordHandler {
@Override
public boolean support(Record record) {
return RKRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
RKRecord rkrec = (RKRecord)record;
this.row = rkrec.getRow();
this.row = rkrec.getColumn();
this.value = "";
}
@Override
public void init() {
}
@Override
public int getOrder() {
return 0;
}
}

39
src/main/java/com/alibaba/excel/analysis/v03/handlers/SSTRecordHandler.java

@ -0,0 +1,39 @@
package com.alibaba.excel.analysis.v03.handlers;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import org.apache.poi.hssf.record.*;
public class SSTRecordHandler extends AbstractXlsRecordHandler {
private SSTRecord sstRecord;
@Override
public boolean support(Record record) {
return SSTRecord.sid == record.getSid() || LabelSSTRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
if (record.getSid() == SSTRecord.sid) {
sstRecord = (SSTRecord)record;
} else if (record.getSid() == LabelSSTRecord.sid) {
LabelSSTRecord lsrec = (LabelSSTRecord)record;
this.row = lsrec.getRow();
this.column = lsrec.getColumn();
if (sstRecord == null) {
this.value = "";
} else {
this.value = sstRecord.getString(lsrec.getSSTIndex()).toString();
}
}
}
@Override
public void init() {
}
@Override
public int getOrder() {
return 0;
}
}

11
src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java

@ -0,0 +1,11 @@
package com.alibaba.excel.analysis.v07;
import org.xml.sax.Attributes;
public interface XlsxCellHandler {
boolean support(String name);
void startHandle(String name, Attributes attributes);
void endHandle(String name);
}

29
src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java

@ -0,0 +1,29 @@
package com.alibaba.excel.analysis.v07;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.xssf.model.SharedStringsTable;
import com.alibaba.excel.analysis.v07.handlers.CountRowCellHandler;
import com.alibaba.excel.analysis.v07.handlers.DefaultCellHandler;
import com.alibaba.excel.analysis.v07.handlers.ProcessResultCellHandler;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventRegistryCenter;
public class XlsxHandlerFactory {
public static List<XlsxCellHandler> buildCellHandlers(AnalysisContext analysisContext,
AnalysisEventRegistryCenter registerCenter, SharedStringsTable sst) {
List<XlsxCellHandler> result = new ArrayList<XlsxCellHandler>();
result.add(new CountRowCellHandler(analysisContext));
DefaultCellHandler defaultCellHandler = buildXlsxRowResultHandler(analysisContext, registerCenter, sst);
result.add(defaultCellHandler);
result.add(new ProcessResultCellHandler(registerCenter, defaultCellHandler));
return result;
}
private static DefaultCellHandler buildXlsxRowResultHandler(AnalysisContext analysisContext,
AnalysisEventRegistryCenter registerCenter, SharedStringsTable sst) {
return new DefaultCellHandler(analysisContext, registerCenter, sst);
}
}

128
src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java

@ -1,20 +1,14 @@
package com.alibaba.excel.analysis.v07; package com.alibaba.excel.analysis.v07;
import com.alibaba.excel.annotation.FieldType; import java.util.List;
import com.alibaba.excel.constant.ExcelXmlConstants;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventRegisterCenter;
import com.alibaba.excel.event.OneRowAnalysisFinishEvent;
import com.alibaba.excel.util.PositionUtils;
import org.apache.poi.xssf.model.SharedStringsTable; import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
import java.util.Arrays; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventRegistryCenter;
import static com.alibaba.excel.constant.ExcelXmlConstants.*;
/** /**
* *
@ -22,117 +16,43 @@ import static com.alibaba.excel.constant.ExcelXmlConstants.*;
*/ */
public class XlsxRowHandler extends DefaultHandler { public class XlsxRowHandler extends DefaultHandler {
private String currentCellIndex; private List<XlsxCellHandler> cellHandlers;
private XlsxRowResultHolder rowResultHolder;
private FieldType currentCellType;
private int curRow;
private int curCol;
private String[] curRowContent = new String[20];
private String currentCellValue;
private SharedStringsTable sst;
private AnalysisContext analysisContext;
private AnalysisEventRegisterCenter registerCenter; public XlsxRowHandler(AnalysisEventRegistryCenter registerCenter, SharedStringsTable sst,
public XlsxRowHandler(AnalysisEventRegisterCenter registerCenter, SharedStringsTable sst,
AnalysisContext analysisContext) { AnalysisContext analysisContext) {
this.registerCenter = registerCenter; this.cellHandlers = XlsxHandlerFactory.buildCellHandlers(analysisContext, registerCenter, sst);
this.analysisContext = analysisContext; for (XlsxCellHandler cellHandler : cellHandlers) {
this.sst = sst; if (cellHandler instanceof XlsxRowResultHolder) {
this.rowResultHolder = (XlsxRowResultHolder) cellHandler;
} break;
@Override
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
setTotalRowCount(name, attributes);
startCell(name, attributes);
startCellValue(name);
}
private void startCellValue(String name) {
if (name.equals(CELL_VALUE_TAG) || name.equals(CELL_VALUE_TAG_1)) {
// initialize current cell value
currentCellValue = "";
}
}
private void startCell(String name, Attributes attributes) {
if (ExcelXmlConstants.CELL_TAG.equals(name)) {
currentCellIndex = attributes.getValue(ExcelXmlConstants.POSITION);
int nextRow = PositionUtils.getRow(currentCellIndex);
if (nextRow > curRow) {
curRow = nextRow;
// endRow(ROW_TAG);
}
analysisContext.setCurrentRowNum(curRow);
curCol = PositionUtils.getCol(currentCellIndex);
String cellType = attributes.getValue("t");
currentCellType = FieldType.EMPTY;
if (cellType != null && cellType.equals("s")) {
currentCellType = FieldType.STRING;
}
} }
} }
private void endCellValue(String name) throws SAXException {
// ensure size
if (curCol >= curRowContent.length) {
curRowContent = Arrays.copyOf(curRowContent, (int)(curCol * 1.5));
} }
if (CELL_VALUE_TAG.equals(name)) {
switch (currentCellType) { @Override
case STRING: public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
int idx = Integer.parseInt(currentCellValue); for (XlsxCellHandler cellHandler : cellHandlers) {
currentCellValue = new XSSFRichTextString(sst.getEntryAt(idx)).toString(); if (cellHandler.support(name)) {
currentCellType = FieldType.EMPTY; cellHandler.startHandle(name, attributes);
break;
} }
curRowContent[curCol] = currentCellValue;
} else if (CELL_VALUE_TAG_1.equals(name)) {
curRowContent[curCol] = currentCellValue;
} }
} }
@Override @Override
public void endElement(String uri, String localName, String name) throws SAXException { public void endElement(String uri, String localName, String name) throws SAXException {
endRow(name); for (XlsxCellHandler cellHandler : cellHandlers) {
endCellValue(name); if (cellHandler.support(name)) {
cellHandler.endHandle(name);
} }
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
currentCellValue += new String(ch, start, length);
} }
private void setTotalRowCount(String name, Attributes attributes) {
if (DIMENSION.equals(name)) {
String d = attributes.getValue(DIMENSION_REF);
String totalStr = d.substring(d.indexOf(":") + 1, d.length());
String c = totalStr.toUpperCase().replaceAll("[A-Z]", "");
analysisContext.setTotalCount(Integer.parseInt(c));
} }
} @Override
public void characters(char[] ch, int start, int length) throws SAXException {
private void endRow(String name) { if (rowResultHolder != null) {
if (name.equals(ROW_TAG)) { rowResultHolder.appendCurrentCellValue(new String(ch, start, length));
registerCenter.notifyListeners(new OneRowAnalysisFinishEvent(curRowContent,curCol));
curRowContent = new String[20];
} }
} }
} }

11
src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java

@ -0,0 +1,11 @@
package com.alibaba.excel.analysis.v07;
public interface XlsxRowResultHolder {
void clearResult();
void appendCurrentCellValue(String currentCellValue);
String[] getCurRowContent();
int getColumnSize();
}

36
src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java

@ -0,0 +1,36 @@
package com.alibaba.excel.analysis.v07.handlers;
import static com.alibaba.excel.constant.ExcelXmlConstants.DIMENSION;
import static com.alibaba.excel.constant.ExcelXmlConstants.DIMENSION_REF;
import org.xml.sax.Attributes;
import com.alibaba.excel.analysis.v07.XlsxCellHandler;
import com.alibaba.excel.context.AnalysisContext;
public class CountRowCellHandler implements XlsxCellHandler {
private final AnalysisContext analysisContext;
public CountRowCellHandler(AnalysisContext analysisContext) {
this.analysisContext = analysisContext;
}
@Override
public boolean support(String name) {
return DIMENSION.equals(name);
}
@Override
public void startHandle(String name, Attributes attributes) {
String d = attributes.getValue(DIMENSION_REF);
String totalStr = d.substring(d.indexOf(":") + 1, d.length());
String c = totalStr.toUpperCase().replaceAll("[A-Z]", "");
analysisContext.setTotalCount(Integer.parseInt(c));
}
@Override
public void endHandle(String name) {
}
}

121
src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java

@ -0,0 +1,121 @@
package com.alibaba.excel.analysis.v07.handlers;
import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_VALUE_TAG;
import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_TAG;
import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_VALUE_TAG_1;
import java.util.Arrays;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.Attributes;
import com.alibaba.excel.analysis.v07.XlsxCellHandler;
import com.alibaba.excel.analysis.v07.XlsxRowResultHolder;
import com.alibaba.excel.annotation.FieldType;
import com.alibaba.excel.constant.ExcelXmlConstants;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventRegistryCenter;
import com.alibaba.excel.util.PositionUtils;
public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder {
private String currentCellIndex;
private FieldType currentCellType;
private int curRow;
private int curCol;
private String[] curRowContent = new String[20];
private String currentCellValue;
private final AnalysisContext analysisContext;
private final AnalysisEventRegistryCenter registerCenter;
private final SharedStringsTable sst;
public DefaultCellHandler(AnalysisContext analysisContext, AnalysisEventRegistryCenter registerCenter, SharedStringsTable sst) {
this.analysisContext = analysisContext;
this.registerCenter = registerCenter;
this.sst = sst;
}
@Override
public void clearResult() {
curRowContent = new String[20];
}
@Override
public boolean support(String name) {
return CELL_VALUE_TAG.equals(name) || CELL_VALUE_TAG_1.equals(name) || CELL_TAG.equals(name);
}
@Override
public void startHandle(String name, Attributes attributes) {
if (CELL_TAG.equals(name)) {
currentCellIndex = attributes.getValue(ExcelXmlConstants.POSITION);
int nextRow = PositionUtils.getRow(currentCellIndex);
if (nextRow > curRow) {
curRow = nextRow;
// endRow(ROW_TAG);
}
analysisContext.setCurrentRowNum(curRow);
curCol = PositionUtils.getCol(currentCellIndex);
String cellType = attributes.getValue("t");
currentCellType = FieldType.EMPTY;
if (cellType != null && cellType.equals("s")) {
currentCellType = FieldType.STRING;
}
}
if (name.equals(CELL_VALUE_TAG) || name.equals(CELL_VALUE_TAG_1)) {
// initialize current cell value
currentCellValue = "";
}
}
@Override
public void endHandle(String name) {
ensureSize();
if (CELL_VALUE_TAG.equals(name)) {
switch (currentCellType) {
case STRING:
int idx = Integer.parseInt(currentCellValue);
currentCellValue = new XSSFRichTextString(sst.getEntryAt(idx)).toString();
currentCellType = FieldType.EMPTY;
break;
}
curRowContent[curCol] = currentCellValue;
} else if (CELL_VALUE_TAG_1.equals(name)) {
curRowContent[curCol] = currentCellValue;
}
}
private void ensureSize() {
// try to size
if (curCol >= curRowContent.length) {
curRowContent = Arrays.copyOf(curRowContent, (int) (curCol * 1.5));
}
}
@Override
public void appendCurrentCellValue(String currentCellValue) {
this.currentCellValue += currentCellValue;
}
@Override
public String[] getCurRowContent() {
return this.curRowContent;
}
@Override
public int getColumnSize() {
return this.curCol;
}
}

37
src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java

@ -0,0 +1,37 @@
package com.alibaba.excel.analysis.v07.handlers;
import org.xml.sax.Attributes;
import static com.alibaba.excel.constant.ExcelXmlConstants.ROW_TAG;
import com.alibaba.excel.analysis.v07.XlsxCellHandler;
import com.alibaba.excel.analysis.v07.XlsxRowResultHolder;
import com.alibaba.excel.event.AnalysisEventRegistryCenter;
import com.alibaba.excel.event.EachRowAnalysisFinishEvent;
public class ProcessResultCellHandler implements XlsxCellHandler {
private AnalysisEventRegistryCenter registerCenter;
private XlsxRowResultHolder rowResultHandler;
public ProcessResultCellHandler(AnalysisEventRegistryCenter registerCenter,
XlsxRowResultHolder rowResultHandler) {
this.registerCenter = registerCenter;
this.rowResultHandler = rowResultHandler;
}
@Override
public boolean support(String name) {
return ROW_TAG.equals(name);
}
@Override
public void startHandle(String name, Attributes attributes) {
}
@Override
public void endHandle(String name) {
registerCenter.notify(new EachRowAnalysisFinishEvent(rowResultHandler.getCurRowContent(),
rowResultHandler.getColumnSize()));
rowResultHandler.clearResult();
}
}

21
src/main/java/com/alibaba/excel/context/AnalysisContext.java

@ -1,14 +1,13 @@
package com.alibaba.excel.context; package com.alibaba.excel.context;
import java.io.InputStream;
import com.alibaba.excel.converters.ConverterRegistryCenter;
import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.ExcelHeadProperty; import com.alibaba.excel.metadata.ExcelHeadProperty;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import java.io.InputStream;
import java.util.List;
/** /**
* *
* A context is the main anchorage point of a excel reader. * A context is the main anchorage point of a excel reader.
@ -52,8 +51,13 @@ public interface AnalysisContext {
* custom listener * custom listener
* @return listener * @return listener
*/ */
AnalysisEventListener getEventListener(); AnalysisEventListener<Object> getEventListener();
/**
* get the converter registry center.
* @return converter registry center.
*/
ConverterRegistryCenter getConverterRegistryCenter();
/** /**
* get current row * get current row
* @return * @return
@ -87,11 +91,10 @@ public interface AnalysisContext {
ExcelHeadProperty getExcelHeadProperty(); ExcelHeadProperty getExcelHeadProperty();
/** /**
* * set the excel head property
* @param clazz * @param excelHeadProperty the excel property to set.
* @param headOneRow
*/ */
void buildExcelHeadProperty(Class<? extends BaseRowModel> clazz, List<String> headOneRow); void setExcelHeadProperty(ExcelHeadProperty excelHeadProperty);
/** /**
* *

37
src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java

@ -1,16 +1,14 @@
package com.alibaba.excel.context; package com.alibaba.excel.context;
import java.io.InputStream;
import com.alibaba.excel.converters.ConverterRegistryCenter;
import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.ExcelHeadProperty; import com.alibaba.excel.metadata.ExcelHeadProperty;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/** /**
* *
* @author jipengfei * @author jipengfei
@ -25,7 +23,7 @@ public class AnalysisContextImpl implements AnalysisContext {
private InputStream inputStream; private InputStream inputStream;
private AnalysisEventListener eventListener; private AnalysisEventListener<Object> eventListener;
private Integer currentRowNum; private Integer currentRowNum;
@ -37,6 +35,8 @@ public class AnalysisContextImpl implements AnalysisContext {
private boolean use1904WindowDate = false; private boolean use1904WindowDate = false;
private ConverterRegistryCenter converterRegistryCenter;
@Override @Override
public void setUse1904WindowDate(boolean use1904WindowDate) { public void setUse1904WindowDate(boolean use1904WindowDate) {
this.use1904WindowDate = use1904WindowDate; this.use1904WindowDate = use1904WindowDate;
@ -65,20 +65,22 @@ public class AnalysisContextImpl implements AnalysisContext {
private Object currentRowAnalysisResult; private Object currentRowAnalysisResult;
public AnalysisContextImpl(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom, public AnalysisContextImpl(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom,
AnalysisEventListener listener, boolean trim) { AnalysisEventListener<Object> listener, ConverterRegistryCenter converterRegistryCenter, boolean trim) {
this.custom = custom; this.custom = custom;
this.eventListener = listener; this.eventListener = listener;
this.inputStream = inputStream; this.inputStream = inputStream;
this.excelType = excelTypeEnum; this.excelType = excelTypeEnum;
this.trim = trim; this.trim = trim;
this.converterRegistryCenter = converterRegistryCenter;
} }
@Override @Override
public void setCurrentSheet(Sheet currentSheet) { public void setCurrentSheet(Sheet currentSheet) {
cleanCurrentSheet(); cleanCurrentSheet();
this.currentSheet = currentSheet; this.currentSheet = currentSheet;
if (currentSheet.getClazz() != null) { if (currentSheet.getClazz() != null) {
buildExcelHeadProperty(currentSheet.getClazz(), null); ExcelHeadProperty.buildExcelHeadProperty(this.excelHeadProperty, currentSheet.getClazz(), null);
} }
} }
@ -122,11 +124,11 @@ public class AnalysisContextImpl implements AnalysisContext {
} }
@Override @Override
public AnalysisEventListener getEventListener() { public AnalysisEventListener<Object> getEventListener() {
return eventListener; return eventListener;
} }
public void setEventListener(AnalysisEventListener eventListener) { public void setEventListener(AnalysisEventListener<Object> eventListener) {
this.eventListener = eventListener; this.eventListener = eventListener;
} }
@ -155,18 +157,19 @@ public class AnalysisContextImpl implements AnalysisContext {
return this.excelHeadProperty; return this.excelHeadProperty;
} }
@Override @Override
public void buildExcelHeadProperty(Class<? extends BaseRowModel> clazz, List<String> headOneRow) { public void setExcelHeadProperty(ExcelHeadProperty excelHeadProperty) {
if (this.excelHeadProperty == null && (clazz != null || headOneRow != null)) { this.excelHeadProperty = excelHeadProperty;
this.excelHeadProperty = new ExcelHeadProperty(clazz, new ArrayList<List<String>>());
}
if (this.excelHeadProperty.getHead() == null && headOneRow != null) {
this.excelHeadProperty.appendOneRow(headOneRow);
}
} }
@Override @Override
public boolean trim() { public boolean trim() {
return this.trim; return this.trim;
} }
@Override
public ConverterRegistryCenter getConverterRegistryCenter() {
return converterRegistryCenter;
}
} }

294
src/main/java/com/alibaba/excel/context/WriteContext.java

@ -1,293 +1,35 @@
package com.alibaba.excel.context; package com.alibaba.excel.context;
import com.alibaba.excel.event.WriteHandler;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.ExcelHeadProperty;
import com.alibaba.excel.metadata.Table;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.StyleUtil;
import com.alibaba.excel.util.WorkBookUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.alibaba.excel.util.StyleUtil.buildSheetStyle;
/**
* A context is the main anchorage point of a excel writer.
*
* @author jipengfei
*/
public class WriteContext {
/***
* The sheet currently written
*/
private Sheet currentSheet;
/**
* current param
*/
private com.alibaba.excel.metadata.Sheet currentSheetParam;
/**
* The sheet currently written's name
*/
private String currentSheetName;
/**
*
*/
private Table currentTable;
/**
* Excel type
*/
private ExcelTypeEnum excelType;
/**
* POI Workbook
*/
private Workbook workbook;
/**
* Final output stream
*/
private OutputStream outputStream;
/**
* Written form collection
*/
private Map<Integer, Table> tableMap = new ConcurrentHashMap<Integer, Table>();
/**
* Cell default style
*/
private CellStyle defaultCellStyle;
/**
* Current table head style
*/
private CellStyle currentHeadCellStyle;
/**
* Current table content style
*/
private CellStyle currentContentCellStyle;
/**
* the header attribute of excel
*/
private ExcelHeadProperty excelHeadProperty;
private boolean needHead = Boolean.TRUE;
private WriteHandler afterWriteHandler;
public WriteHandler getAfterWriteHandler() {
return afterWriteHandler;
}
public WriteContext(InputStream templateInputStream, OutputStream out, ExcelTypeEnum excelType,
boolean needHead, WriteHandler afterWriteHandler) throws IOException {
this.needHead = needHead;
this.outputStream = out;
this.afterWriteHandler = afterWriteHandler;
this.workbook = WorkBookUtil.createWorkBook(templateInputStream, excelType);
this.defaultCellStyle = StyleUtil.buildDefaultCellStyle(this.workbook);
}
/**
* @param sheet
*/
public void currentSheet(com.alibaba.excel.metadata.Sheet sheet) {
if (null == currentSheetParam || currentSheetParam.getSheetNo() != sheet.getSheetNo()) {
cleanCurrentSheet();
currentSheetParam = sheet;
try {
this.currentSheet = workbook.getSheetAt(sheet.getSheetNo() - 1);
} catch (Exception e) {
this.currentSheet = WorkBookUtil.createSheet(workbook, sheet);
if (null != afterWriteHandler) {
this.afterWriteHandler.sheet(sheet.getSheetNo(), currentSheet);
}
}
buildSheetStyle(currentSheet, sheet.getColumnWidthMap());
/** **/
this.initCurrentSheet(sheet);
}
}
private void initCurrentSheet(com.alibaba.excel.metadata.Sheet sheet) {
/** **/
initExcelHeadProperty(sheet.getHead(), sheet.getClazz());
initTableStyle(sheet.getTableStyle());
initTableHead();
}
private void cleanCurrentSheet() {
this.currentSheet = null;
this.currentSheetParam = null;
this.excelHeadProperty = null;
this.currentHeadCellStyle = null;
this.currentContentCellStyle = null;
this.currentTable = null;
}
/**
* init excel header
*
* @param head
* @param clazz
*/
private void initExcelHeadProperty(List<List<String>> head, Class<? extends BaseRowModel> clazz) {
if (head != null || clazz != null) { this.excelHeadProperty = new ExcelHeadProperty(clazz, head); }
}
public void initTableHead() {
if (needHead && null != excelHeadProperty && !CollectionUtils.isEmpty(excelHeadProperty.getHead())) {
int startRow = currentSheet.getLastRowNum();
if (startRow > 0) {
startRow += 4;
} else {
startRow = currentSheetParam.getStartRow();
}
addMergedRegionToCurrentSheet(startRow);
int i = startRow;
for (; i < this.excelHeadProperty.getRowNum() + startRow; i++) {
Row row = WorkBookUtil.createRow(currentSheet, i);
if (null != afterWriteHandler) {
this.afterWriteHandler.row(i, row);
}
addOneRowOfHeadDataToExcel(row, this.excelHeadProperty.getHeadByRowNum(i - startRow));
}
}
}
private void addMergedRegionToCurrentSheet(int startRow) {
for (com.alibaba.excel.metadata.CellRange cellRangeModel : excelHeadProperty.getCellRangeModels()) {
currentSheet.addMergedRegion(new CellRangeAddress(cellRangeModel.getFirstRow() + startRow,
cellRangeModel.getLastRow() + startRow,
cellRangeModel.getFirstCol(), cellRangeModel.getLastCol()));
}
}
private void addOneRowOfHeadDataToExcel(Row row, List<String> headByRowNum) { import org.apache.poi.ss.usermodel.CellStyle;
if (headByRowNum != null && headByRowNum.size() > 0) { import org.apache.poi.ss.usermodel.Sheet;
for (int i = 0; i < headByRowNum.size(); i++) { import org.apache.poi.ss.usermodel.Workbook;
Cell cell = WorkBookUtil.createCell(row, i, getCurrentHeadCellStyle(), headByRowNum.get(i));
if (null != afterWriteHandler) {
this.afterWriteHandler.cell(i, cell);
}
}
}
}
private void initTableStyle(com.alibaba.excel.metadata.TableStyle tableStyle) { import com.alibaba.excel.converters.ConverterRegistryCenter;
if (tableStyle != null) { import com.alibaba.excel.event.WriteHandler;
this.currentHeadCellStyle = StyleUtil.buildCellStyle(this.workbook, tableStyle.getTableHeadFont(), import com.alibaba.excel.metadata.ExcelHeadProperty;
tableStyle.getTableHeadBackGroundColor()); import com.alibaba.excel.metadata.Table;
this.currentContentCellStyle = StyleUtil.buildCellStyle(this.workbook, tableStyle.getTableContentFont(),
tableStyle.getTableContentBackGroundColor());
}
}
private void cleanCurrentTable() {
this.excelHeadProperty = null;
this.currentHeadCellStyle = null;
this.currentContentCellStyle = null;
this.currentTable = null;
}
public void currentTable(Table table) {
if (null == currentTable || currentTable.getTableNo() != table.getTableNo()) {
cleanCurrentTable();
this.currentTable = table;
this.initExcelHeadProperty(table.getHead(), table.getClazz());
this.initTableStyle(table.getTableStyle());
this.initTableHead();
}
}
public ExcelHeadProperty getExcelHeadProperty() {
return this.excelHeadProperty;
}
public boolean needHead() {
return this.needHead;
}
public Sheet getCurrentSheet() {
return currentSheet;
}
public void setCurrentSheet(Sheet currentSheet) {
this.currentSheet = currentSheet;
}
public String getCurrentSheetName() {
return currentSheetName;
}
public void setCurrentSheetName(String currentSheetName) { public interface WriteContext {
this.currentSheetName = currentSheetName;
}
public ExcelTypeEnum getExcelType() { Sheet getCurrentSheet();
return excelType;
}
public void setExcelType(ExcelTypeEnum excelType) { boolean needHead();
this.excelType = excelType;
}
public OutputStream getOutputStream() { ExcelHeadProperty getExcelHeadProperty();
return outputStream;
}
public CellStyle getCurrentHeadCellStyle() { void currentSheet(com.alibaba.excel.metadata.Sheet sheet);
return this.currentHeadCellStyle == null ? defaultCellStyle : this.currentHeadCellStyle;
}
public CellStyle getCurrentContentStyle() { void currentTable(Table table);
return this.currentContentCellStyle;
}
public Workbook getWorkbook() { OutputStream getOutputStream();
return workbook;
}
public com.alibaba.excel.metadata.Sheet getCurrentSheetParam() { Workbook getWorkbook();
return currentSheetParam;
}
public void setCurrentSheetParam(com.alibaba.excel.metadata.Sheet currentSheetParam) { WriteHandler getWriteHandler();
this.currentSheetParam = currentSheetParam;
}
public Table getCurrentTable() { CellStyle getCurrentContentStyle();
return currentTable;
}
public void setCurrentTable(Table currentTable) { ConverterRegistryCenter getConverterRegistryCenter();
this.currentTable = currentTable;
}
} }

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

@ -0,0 +1,311 @@
package com.alibaba.excel.context;
import static com.alibaba.excel.util.StyleUtil.buildSheetStyle;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import com.alibaba.excel.converters.ConverterRegistryCenter;
import com.alibaba.excel.event.WriteHandler;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.ExcelHeadProperty;
import com.alibaba.excel.metadata.Table;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.StyleUtil;
import com.alibaba.excel.util.WorkBookUtil;
/**
* A context is the main anchorage point of a excel writer.
*
* @author jipengfei
*/
public class WriteContextImpl implements WriteContext {
/***
* The sheet currently written
*/
private Sheet currentSheet;
/**
* current param
*/
private com.alibaba.excel.metadata.Sheet currentSheetParam;
/**
* The sheet currently written's name
*/
private String currentSheetName;
/**
*
*/
private Table currentTable;
/**
* Excel type
*/
private ExcelTypeEnum excelType;
/**
* POI Workbook
*/
private Workbook workbook;
/**
* Final output stream
*/
private OutputStream outputStream;
/**
* Written form collection
*/
private Map<Integer, Table> tableMap = new ConcurrentHashMap<Integer, Table>();
/**
* Cell default style
*/
private CellStyle defaultCellStyle;
/**
* Current table head style
*/
private CellStyle currentHeadCellStyle;
/**
* Current table content style
*/
private CellStyle currentContentCellStyle;
/**
* the header attribute of excel
*/
private ExcelHeadProperty excelHeadProperty;
private boolean needHead = true;
private WriteHandler writeHandler;
private ConverterRegistryCenter registryCenter;
public WriteHandler getWriteHandler() {
return writeHandler;
}
public WriteContextImpl(InputStream templateInputStream, OutputStream out, ExcelTypeEnum excelType,
boolean needHead, WriteHandler writeHandler, ConverterRegistryCenter registryCenter) throws IOException {
this.needHead = needHead;
this.outputStream = out;
this.writeHandler = writeHandler;
this.workbook = WorkBookUtil.createWorkBook(templateInputStream, excelType);
this.defaultCellStyle = StyleUtil.buildDefaultCellStyle(this.workbook);
this.registryCenter = registryCenter;
}
/**
* @param sheet
*/
@Override
public void currentSheet(com.alibaba.excel.metadata.Sheet sheet) {
if (null == currentSheetParam || currentSheetParam.getSheetNo() != sheet.getSheetNo()) {
cleanCurrentSheet();
currentSheetParam = sheet;
try {
this.currentSheet = workbook.getSheetAt(sheet.getSheetNo() - 1);
} catch (Exception e) {
this.currentSheet = WorkBookUtil.createSheet(workbook, sheet);
if (null != writeHandler) {
this.writeHandler.sheet(sheet.getSheetNo(), currentSheet);
}
}
buildSheetStyle(currentSheet, sheet.getColumnWidthMap());
/** **/
this.initCurrentSheet(sheet);
}
}
private void initCurrentSheet(com.alibaba.excel.metadata.Sheet sheet) {
/** **/
initExcelHeadProperty(sheet.getHead(), sheet.getClazz());
initTableStyle(sheet.getTableStyle());
initTableHead();
}
private void cleanCurrentSheet() {
this.currentSheet = null;
this.currentSheetParam = null;
this.excelHeadProperty = null;
this.currentHeadCellStyle = null;
this.currentContentCellStyle = null;
this.currentTable = null;
}
/**
* init excel header
*
* @param head
* @param clazz
*/
private void initExcelHeadProperty(List<List<String>> head, Class<? extends BaseRowModel> clazz) {
if (head != null || clazz != null) { this.excelHeadProperty = new ExcelHeadProperty(clazz, head); }
}
public void initTableHead() {
if (needHead && null != excelHeadProperty && !CollectionUtils.isEmpty(excelHeadProperty.getHead())) {
int startRow = currentSheet.getLastRowNum();
if (startRow > 0) {
startRow += 4;
} else {
startRow = currentSheetParam.getStartRow();
}
addMergedRegionToCurrentSheet(startRow);
int i = startRow;
for (; i < this.excelHeadProperty.getRowNum() + startRow; i++) {
Row row = WorkBookUtil.createRow(currentSheet, i);
if (null != writeHandler) {
this.writeHandler.row(i, row);
}
addOneRowOfHeadDataToExcel(row, this.excelHeadProperty.getHeadByRowNum(i - startRow));
}
}
}
private void addMergedRegionToCurrentSheet(int startRow) {
for (com.alibaba.excel.metadata.CellRange cellRangeModel : excelHeadProperty.getCellRangeModels()) {
currentSheet.addMergedRegion(new CellRangeAddress(cellRangeModel.getFirstRow() + startRow,
cellRangeModel.getLastRow() + startRow,
cellRangeModel.getFirstCol(), cellRangeModel.getLastCol()));
}
}
private void addOneRowOfHeadDataToExcel(Row row, List<String> headByRowNum) {
if (headByRowNum != null && headByRowNum.size() > 0) {
for (int i = 0; i < headByRowNum.size(); i++) {
Cell cell = WorkBookUtil.createCell(row, i, getCurrentHeadCellStyle(), headByRowNum.get(i));
if (null != writeHandler) {
this.writeHandler.cell(i, cell);
}
}
}
}
private void initTableStyle(com.alibaba.excel.metadata.TableStyle tableStyle) {
if (tableStyle != null) {
this.currentHeadCellStyle = StyleUtil.buildCellStyle(this.workbook, tableStyle.getTableHeadFont(),
tableStyle.getTableHeadBackGroundColor());
this.currentContentCellStyle = StyleUtil.buildCellStyle(this.workbook, tableStyle.getTableContentFont(),
tableStyle.getTableContentBackGroundColor());
}
}
private void cleanCurrentTable() {
this.excelHeadProperty = null;
this.currentHeadCellStyle = null;
this.currentContentCellStyle = null;
this.currentTable = null;
}
@Override
public void currentTable(Table table) {
if (null == currentTable || currentTable.getTableNo() != table.getTableNo()) {
cleanCurrentTable();
this.currentTable = table;
this.initExcelHeadProperty(table.getHead(), table.getClazz());
this.initTableStyle(table.getTableStyle());
this.initTableHead();
}
}
public ExcelHeadProperty getExcelHeadProperty() {
return this.excelHeadProperty;
}
public boolean needHead() {
return this.needHead;
}
@Override
public Sheet getCurrentSheet() {
return currentSheet;
}
public void setCurrentSheet(Sheet currentSheet) {
this.currentSheet = currentSheet;
}
public String getCurrentSheetName() {
return currentSheetName;
}
public void setCurrentSheetName(String currentSheetName) {
this.currentSheetName = currentSheetName;
}
public ExcelTypeEnum getExcelType() {
return excelType;
}
public void setExcelType(ExcelTypeEnum excelType) {
this.excelType = excelType;
}
@Override
public OutputStream getOutputStream() {
return outputStream;
}
public CellStyle getCurrentHeadCellStyle() {
return this.currentHeadCellStyle == null ? defaultCellStyle : this.currentHeadCellStyle;
}
public CellStyle getCurrentContentStyle() {
return this.currentContentCellStyle;
}
@Override
public Workbook getWorkbook() {
return workbook;
}
public com.alibaba.excel.metadata.Sheet getCurrentSheetParam() {
return currentSheetParam;
}
public void setCurrentSheetParam(com.alibaba.excel.metadata.Sheet currentSheetParam) {
this.currentSheetParam = currentSheetParam;
}
public Table getCurrentTable() {
return currentTable;
}
public void setCurrentTable(Table currentTable) {
this.currentTable = currentTable;
}
@Override
public ConverterRegistryCenter getConverterRegistryCenter() {
return registryCenter;
}
}

33
src/main/java/com/alibaba/excel/converters/BigDecimalConverter.java

@ -0,0 +1,33 @@
package com.alibaba.excel.converters;
import java.math.BigDecimal;
import org.apache.poi.ss.usermodel.Cell;
import com.alibaba.excel.metadata.ExcelColumnProperty;
public class BigDecimalConverter implements Converter {
@Override
public String getName() {
return "big-decimal-converter";
}
@Override
public boolean support(ExcelColumnProperty columnProperty) {
return BigDecimal.class.equals(columnProperty.getField().getType());
}
@Override
public Object convert(String value, ExcelColumnProperty columnProperty) {
return new BigDecimal(value);
}
@Override
public Cell convert(Cell cell, Object value, ExcelColumnProperty columnProperty) {
cell.setCellValue(Double.parseDouble(value.toString()));
return cell;
}
@Override
public boolean support(Object cellValue) {
return cellValue instanceof BigDecimal;
}
}

42
src/main/java/com/alibaba/excel/converters/BooleanConverter.java

@ -0,0 +1,42 @@
package com.alibaba.excel.converters;
import java.lang.reflect.Field;
import org.apache.poi.ss.usermodel.Cell;
import com.alibaba.excel.metadata.ExcelColumnProperty;
public class BooleanConverter implements Converter {
@Override
public String getName() {
return "boolean-converter";
}
@Override
public boolean support(ExcelColumnProperty columnProperty) {
Field field = columnProperty.getField();
return Boolean.class.equals(field.getType()) || boolean.class.equals(field.getType());
}
@Override
public Object convert(String value, ExcelColumnProperty columnProperty) {
String valueLower = value.toLowerCase();
if (valueLower.equals("true") || valueLower.equals("false")) {
return Boolean.parseBoolean(value.toLowerCase());
}
Integer integer = Integer.parseInt(value);
if (integer == 0) {
return false;
} else {
return true;
}
}
@Override
public Cell convert(Cell cell, Object value, ExcelColumnProperty columnProperty) {
cell.setCellValue(String.valueOf(value));
return cell;
}
@Override
public boolean support(Object cellValue) {
return cellValue instanceof Boolean || boolean.class.equals(cellValue.getClass());
}
}

13
src/main/java/com/alibaba/excel/converters/Converter.java

@ -0,0 +1,13 @@
package com.alibaba.excel.converters;
import org.apache.poi.ss.usermodel.Cell;
import com.alibaba.excel.metadata.ExcelColumnProperty;
public interface Converter {
String getName();
boolean support(ExcelColumnProperty columnProperty);
boolean support(Object cellValue);
Object convert(String value, ExcelColumnProperty columnProperty);
Cell convert(Cell cell, Object value, ExcelColumnProperty columnProperty);
}

8
src/main/java/com/alibaba/excel/converters/ConverterRegistryCenter.java

@ -0,0 +1,8 @@
package com.alibaba.excel.converters;
import java.util.Collection;
public interface ConverterRegistryCenter {
void register(Converter converter);
Collection<Converter> getConverters();
}

55
src/main/java/com/alibaba/excel/converters/DateConverter.java

@ -0,0 +1,55 @@
package com.alibaba.excel.converters;
import java.util.Date;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.Cell;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.ExcelColumnProperty;
import com.alibaba.excel.util.StringUtils;
import com.alibaba.excel.util.TypeUtil;
public class DateConverter implements Converter {
private final AnalysisContext context;
public DateConverter(AnalysisContext context) {
this.context = context;
}
@Override
public String getName() {
return "date-converter";
}
@Override
public boolean support(ExcelColumnProperty columnProperty) {
return Date.class.equals(columnProperty.getField().getType());
}
@Override
public Object convert(String value, ExcelColumnProperty columnProperty) {
if (value.contains("-") || value.contains("/") || value.contains(":")) {
return TypeUtil.getSimpleDateFormatDate(value, columnProperty.getFormat());
} else {
Double d = Double.parseDouble(value);
return HSSFDateUtil.getJavaDate(d, context != null ? context.use1904WindowDate() : false);
}
}
@Override
public Cell convert(Cell cell, Object value, ExcelColumnProperty columnProperty) {
Date d = (Date)value;
if (columnProperty != null && StringUtils.isEmpty(columnProperty.getFormat()) == false) {
cell.setCellValue(TypeUtil.formatDate(d, columnProperty.getFormat()));
} else {
cell.setCellValue(d);
}
return cell;
}
@Override
public boolean support(Object cellValue) {
return cellValue instanceof Date;
}
}

33
src/main/java/com/alibaba/excel/converters/DoubleConverter.java

@ -0,0 +1,33 @@
package com.alibaba.excel.converters;
import java.lang.reflect.Field;
import org.apache.poi.ss.usermodel.Cell;
import com.alibaba.excel.metadata.ExcelColumnProperty;
import com.alibaba.excel.util.TypeUtil;
public class DoubleConverter implements Converter {
@Override
public String getName() {
return "double-converter";
}
@Override
public boolean support(ExcelColumnProperty columnProperty) {
Field field = columnProperty.getField();
return Double.class.equals(field.getType()) || double.class.equals(field.getType());
}
@Override
public Object convert(String value, ExcelColumnProperty columnProperty) {
return TypeUtil.formatFloat(value);
}
@Override
public Cell convert(Cell cell, Object value, ExcelColumnProperty columnProperty) {
cell.setCellValue(Double.parseDouble(value.toString()));
return cell;
}
@Override
public boolean support(Object cellValue) {
return cellValue instanceof Double || double.class.equals(cellValue.getClass());
}
}

31
src/main/java/com/alibaba/excel/converters/FloatConverter.java

@ -0,0 +1,31 @@
package com.alibaba.excel.converters;
import org.apache.poi.ss.usermodel.Cell;
import com.alibaba.excel.metadata.ExcelColumnProperty;
import com.alibaba.excel.util.TypeUtil;
public class FloatConverter implements Converter {
@Override
public String getName() {
return "float-converter";
}
@Override
public boolean support(ExcelColumnProperty columnProperty) {
return Float.class.equals(columnProperty.getField().getType());
}
@Override
public Object convert(String value, ExcelColumnProperty columnProperty) {
return TypeUtil.formatFloat(value);
}
@Override
public Cell convert(Cell cell, Object value, ExcelColumnProperty columnProperty) {
cell.setCellValue(Double.parseDouble(value.toString()));
return cell;
}
@Override
public boolean support(Object cellValue) {
return cellValue instanceof Float || float.class.equals(cellValue.getClass());
}
}

33
src/main/java/com/alibaba/excel/converters/IntegerConverter.java

@ -0,0 +1,33 @@
package com.alibaba.excel.converters;
import java.lang.reflect.Field;
import org.apache.poi.ss.usermodel.Cell;
import com.alibaba.excel.metadata.ExcelColumnProperty;
public class IntegerConverter implements Converter {
@Override
public String getName() {
return "integer-converter";
}
@Override
public boolean support(ExcelColumnProperty columnProperty) {
Field field = columnProperty.getField();
return Integer.class.equals(field.getType()) || int.class.equals(field.getType());
}
@Override
public Object convert(String value, ExcelColumnProperty columnProperty) {
return Integer.parseInt(value);
}
@Override
public Cell convert(Cell cell, Object value, ExcelColumnProperty columnProperty) {
cell.setCellValue(Double.parseDouble(value.toString()));
return cell;
}
@Override
public boolean support(Object cellValue) {
return cellValue instanceof Integer || int.class.equals(cellValue.getClass());
}
}

33
src/main/java/com/alibaba/excel/converters/LongConverter.java

@ -0,0 +1,33 @@
package com.alibaba.excel.converters;
import java.lang.reflect.Field;
import org.apache.poi.ss.usermodel.Cell;
import com.alibaba.excel.metadata.ExcelColumnProperty;
public class LongConverter implements Converter {
@Override
public String getName() {
return "long-converter";
}
@Override
public boolean support(ExcelColumnProperty columnProperty) {
Field field = columnProperty.getField();
return Long.class.equals(field.getType()) || long.class.equals(field.getType());
}
@Override
public Object convert(String value, ExcelColumnProperty columnProperty) {
return Long.parseLong(value);
}
@Override
public Cell convert(Cell cell, Object value, ExcelColumnProperty columnProperty) {
cell.setCellValue(Double.parseDouble(value.toString()));
return cell;
}
@Override
public boolean support(Object cellValue) {
return cellValue instanceof Long || long.class.equals(cellValue.getClass());
}
}

31
src/main/java/com/alibaba/excel/converters/StringConverter.java

@ -0,0 +1,31 @@
package com.alibaba.excel.converters;
import org.apache.poi.ss.usermodel.Cell;
import com.alibaba.excel.metadata.ExcelColumnProperty;
import com.alibaba.excel.util.TypeUtil;
public class StringConverter implements Converter {
@Override
public String getName() {
return "string-converter";
}
@Override
public boolean support(ExcelColumnProperty columnProperty) {
return String.class.equals(columnProperty.getField().getType());
}
@Override
public Object convert(String value, ExcelColumnProperty columnProperty) {
return TypeUtil.formatFloat(value);
}
@Override
public Cell convert(Cell cell, Object value, ExcelColumnProperty columnProperty) {
cell.setCellValue(String.valueOf(value));
return cell;
}
@Override
public boolean support(Object cellValue) {
return cellValue instanceof String;
}
}

2
src/main/java/com/alibaba/excel/event/AnalysisEventListener.java

@ -12,7 +12,7 @@ public abstract class AnalysisEventListener<T> {
/** /**
* when analysis one row trigger invoke function * when analysis one row trigger invoke function
* *
* @param object one row data * @param object one row value
* @param context analysis context * @param context analysis context
*/ */
public abstract void invoke(T object, AnalysisContext context); public abstract void invoke(T object, AnalysisContext context);

12
src/main/java/com/alibaba/excel/event/AnalysisEventRegisterCenter.java → src/main/java/com/alibaba/excel/event/AnalysisEventRegistryCenter.java

@ -5,7 +5,7 @@ package com.alibaba.excel.event;
* *
* @author jipengfei * @author jipengfei
*/ */
public interface AnalysisEventRegisterCenter { public interface AnalysisEventRegistryCenter {
/** /**
* Append listener * Append listener
@ -13,17 +13,23 @@ public interface AnalysisEventRegisterCenter {
* @param name listener name. * @param name listener name.
* @param listener Callback method after each row is parsed. * @param listener Callback method after each row is parsed.
*/ */
void appendLister(String name, AnalysisEventListener listener); void register(String name, AnalysisEventListener<Object> listener);
/** /**
* Parse one row to notify all event listeners * Parse one row to notify all event listeners
* *
* @param event parse event * @param event parse event
*/ */
void notifyListeners(OneRowAnalysisFinishEvent event); void notify(AnalysisFinishEvent event);
/** /**
* Clean all listeners. * Clean all listeners.
*/ */
void cleanAllListeners(); void cleanAllListeners();
/**
* clean listener by name
* @param name the listener name
*/
void cleanListener(String name);
} }

5
src/main/java/com/alibaba/excel/event/AnalysisFinishEvent.java

@ -0,0 +1,5 @@
package com.alibaba.excel.event;
public interface AnalysisFinishEvent {
Object getAnalysisResult();
}

29
src/main/java/com/alibaba/excel/event/EachRowAnalysisFinishEvent.java

@ -0,0 +1,29 @@
package com.alibaba.excel.event;
import java.util.ArrayList;
import java.util.List;
/**
* @author jipengfei
*/
public class EachRowAnalysisFinishEvent implements AnalysisFinishEvent {
private Object result;
public EachRowAnalysisFinishEvent(Object content) {
this.result = content;
}
public EachRowAnalysisFinishEvent(String[] content, int length) {
if (content != null) {
List<String> ls = new ArrayList<String>(length);
for (int i = 0; i <= length; i++) {
ls.add(content[i]);
}
result = ls;
}
}
@Override
public Object getAnalysisResult() {
return result;
}
}

42
src/main/java/com/alibaba/excel/modelbuild/ModelBuildEventListener.java → src/main/java/com/alibaba/excel/event/ModelBuildEventListener.java

@ -1,23 +1,34 @@
package com.alibaba.excel.modelbuild; package com.alibaba.excel.event;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.exception.ExcelGenerateException;
import com.alibaba.excel.metadata.ExcelColumnProperty;
import com.alibaba.excel.metadata.ExcelHeadProperty; import com.alibaba.excel.metadata.ExcelHeadProperty;
import com.alibaba.excel.util.TypeUtil; import com.alibaba.excel.util.TypeUtil;
import net.sf.cglib.beans.BeanMap;
import java.util.List; import net.sf.cglib.beans.BeanMap;
/** /**
* @author jipengfei * @author jipengfei
*/ */
public class ModelBuildEventListener extends AnalysisEventListener { public class ModelBuildEventListener extends AnalysisEventListener<Object> {
private final Collection<Converter> converters;
public ModelBuildEventListener(Collection<Converter> converters) {
this.converters = converters;
}
@Override @Override
public void invoke(Object object, AnalysisContext context) { public void invoke(Object object, AnalysisContext context) {
if (context.getExcelHeadProperty() != null && context.getExcelHeadProperty().getHeadClazz() != null) { if (context.getExcelHeadProperty() != null && context.getExcelHeadProperty().getHeadClazz() != null) {
try { try {
@SuppressWarnings("unchecked")
Object resultModel = buildUserModel(context, (List<String>)object); Object resultModel = buildUserModel(context, (List<String>)object);
context.setCurrentRowAnalysisResult(resultModel); context.setCurrentRowAnalysisResult(resultModel);
} catch (Exception e) { } catch (Exception e) {
@ -26,17 +37,36 @@ public class ModelBuildEventListener extends AnalysisEventListener {
} }
} }
@SuppressWarnings({"rawtypes", "unchecked"})
private Object buildUserModel(AnalysisContext context, List<String> stringList) throws Exception { private Object buildUserModel(AnalysisContext context, List<String> stringList) throws Exception {
ExcelHeadProperty excelHeadProperty = context.getExcelHeadProperty(); ExcelHeadProperty excelHeadProperty = context.getExcelHeadProperty();
Object resultModel = excelHeadProperty.getHeadClazz().newInstance(); Object resultModel = excelHeadProperty.getHeadClazz().newInstance();
if (excelHeadProperty == null) { if (excelHeadProperty == null) {
return resultModel; return resultModel;
} }
BeanMap.create(resultModel).putAll( Map map = new HashMap();
TypeUtil.getFieldValues(stringList, excelHeadProperty, context.use1904WindowDate())); for (int i = 0; i < stringList.size(); i++) {
ExcelColumnProperty columnProperty = excelHeadProperty.getExcelColumnProperty(i);
if (columnProperty != null) {
Object value = convertValue(stringList.get(i), columnProperty);
if (value != null) {
map.put(columnProperty.getField().getName(), value);
}
}
}
BeanMap.create(resultModel).putAll(map);
return resultModel; return resultModel;
} }
private Object convertValue(String value, ExcelColumnProperty columnProperty) {
for (Converter c : converters) {
if (c.support(columnProperty)) {
return c.convert(value, columnProperty);
}
}
return null;
}
@Override @Override
public void doAfterAllAnalysed(AnalysisContext context) { public void doAfterAllAnalysed(AnalysisContext context) {

34
src/main/java/com/alibaba/excel/event/OneRowAnalysisFinishEvent.java

@ -1,34 +0,0 @@
package com.alibaba.excel.event;
import java.util.ArrayList;
import java.util.List;
/**
* @author jipengfei
*/
public class OneRowAnalysisFinishEvent {
public OneRowAnalysisFinishEvent(Object content) {
this.data = content;
}
public OneRowAnalysisFinishEvent(String[] content, int length) {
if (content != null) {
List<String> ls = new ArrayList<String>(length);
for (int i = 0; i <= length; i++) {
ls.add(content[i]);
}
data = ls;
}
}
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}

14
src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java

@ -123,11 +123,11 @@ public class ExcelHeadProperty {
return excelColumnPropertyMap1.get(columnNum); return excelColumnPropertyMap1.get(columnNum);
} }
public Class getHeadClazz() { public Class<? extends BaseRowModel> getHeadClazz() {
return headClazz; return headClazz;
} }
public void setHeadClazz(Class headClazz) { public void setHeadClazz(Class<? extends BaseRowModel> headClazz) {
this.headClazz = headClazz; this.headClazz = headClazz;
} }
@ -224,5 +224,13 @@ public class ExcelHeadProperty {
} }
return headRowNum; return headRowNum;
} }
public static ExcelHeadProperty buildExcelHeadProperty(ExcelHeadProperty excelHeadProperty, Class<? extends BaseRowModel> clazz, List<String> headOneRow) {
if (excelHeadProperty == null && (clazz != null || headOneRow != null)) {
excelHeadProperty = new ExcelHeadProperty(clazz, new ArrayList<List<String>>());
}
if (excelHeadProperty.getHead() == null && headOneRow != null) {
excelHeadProperty.appendOneRow(headOneRow);
}
return excelHeadProperty;
}
} }

10
src/main/java/com/alibaba/excel/parameter/GenerateParam.java

@ -17,6 +17,8 @@ public class GenerateParam {
private ExcelTypeEnum type; private ExcelTypeEnum type;
private boolean needHead = true;
public GenerateParam(String sheetName, Class clazz, OutputStream outputStream) { public GenerateParam(String sheetName, Class clazz, OutputStream outputStream) {
this.outputStream = outputStream; this.outputStream = outputStream;
this.sheetName = sheetName; this.sheetName = sheetName;
@ -55,4 +57,12 @@ public class GenerateParam {
public void setType(ExcelTypeEnum type) { public void setType(ExcelTypeEnum type) {
this.type = type; this.type = type;
} }
public boolean isNeedHead() {
return needHead;
}
public void setNeedHead(boolean needHead) {
this.needHead = needHead;
}
} }

120
src/main/java/com/alibaba/excel/util/TypeUtil.java

@ -1,18 +1,22 @@
package com.alibaba.excel.util; package com.alibaba.excel.util;
import com.alibaba.excel.metadata.ExcelColumnProperty;
import com.alibaba.excel.metadata.ExcelHeadProperty;
import net.sf.cglib.beans.BeanMap;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.metadata.ExcelColumnProperty;
import com.alibaba.excel.metadata.ExcelHeadProperty;
/** /**
* @author jipengfei * @author jipengfei
*/ */
@ -26,70 +30,6 @@ public class TypeUtil {
DATE_FORMAT_LIST.add("yyyyMMdd HH:mm:ss"); DATE_FORMAT_LIST.add("yyyyMMdd HH:mm:ss");
} }
private static int getCountOfChar(String value, char c) {
int n = 0;
if (value == null) {
return 0;
}
char[] chars = value.toCharArray();
for (char cc : chars) {
if (cc == c) {
n++;
}
}
return n;
}
public static Object convert(String value, Field field, String format, boolean us) {
if (!StringUtils.isEmpty(value)) {
if (Float.class.equals(field.getType())) {
return Float.parseFloat(value);
}
if (Integer.class.equals(field.getType()) || int.class.equals(field.getType())) {
return Integer.parseInt(value);
}
if (Double.class.equals(field.getType()) || double.class.equals(field.getType())) {
if (null != format && !"".equals(format)) {
int n = getCountOfChar(value, '0');
return Double.parseDouble(TypeUtil.formatFloat0(value, n));
} else {
return Double.parseDouble(TypeUtil.formatFloat(value));
}
}
if (Boolean.class.equals(field.getType()) || boolean.class.equals(field.getType())) {
String valueLower = value.toLowerCase();
if (valueLower.equals("true") || valueLower.equals("false")) {
return Boolean.parseBoolean(value.toLowerCase());
}
Integer integer = Integer.parseInt(value);
if (integer == 0) {
return false;
} else {
return true;
}
}
if (Long.class.equals(field.getType()) || long.class.equals(field.getType())) {
return Long.parseLong(value);
}
if (Date.class.equals(field.getType())) {
if (value.contains("-") || value.contains("/") || value.contains(":")) {
return getSimpleDateFormatDate(value, format);
} else {
Double d = Double.parseDouble(value);
return HSSFDateUtil.getJavaDate(d, us);
}
}
if (BigDecimal.class.equals(field.getType())) {
return new BigDecimal(value);
}
if(String.class.equals(field.getType())){
return formatFloat(value);
}
}
return null;
}
public static Boolean isNum(Field field) { public static Boolean isNum(Field field) {
if (field == null) { if (field == null) {
return false; return false;
@ -112,12 +52,8 @@ public class TypeUtil {
} }
public static Boolean isNum(Object cellValue) { public static Boolean isNum(Object cellValue) {
if (cellValue instanceof Integer if (cellValue instanceof Integer || cellValue instanceof Double || cellValue instanceof Short
|| cellValue instanceof Double || cellValue instanceof Long || cellValue instanceof Float || cellValue instanceof BigDecimal) {
|| cellValue instanceof Short
|| cellValue instanceof Long
|| cellValue instanceof Float
|| cellValue instanceof BigDecimal) {
return true; return true;
} }
return false; return false;
@ -164,7 +100,7 @@ public class TypeUtil {
if (isNumeric(value)) { if (isNumeric(value)) {
try { try {
BigDecimal decimal = new BigDecimal(value); BigDecimal decimal = new BigDecimal(value);
BigDecimal setScale = decimal.setScale(10, BigDecimal.ROUND_HALF_DOWN).stripTrailingZeros(); BigDecimal setScale = decimal.setScale(10, RoundingMode.HALF_DOWN).stripTrailingZeros();
return setScale.toPlainString(); return setScale.toPlainString();
} catch (Exception e) { } catch (Exception e) {
} }
@ -178,7 +114,7 @@ public class TypeUtil {
if (isNumeric(value)) { if (isNumeric(value)) {
try { try {
BigDecimal decimal = new BigDecimal(value); BigDecimal decimal = new BigDecimal(value);
BigDecimal setScale = decimal.setScale(n, BigDecimal.ROUND_HALF_DOWN); BigDecimal setScale = decimal.setScale(n, RoundingMode.HALF_DOWN);
return setScale.toPlainString(); return setScale.toPlainString();
} catch (Exception e) { } catch (Exception e) {
} }
@ -206,32 +142,4 @@ public class TypeUtil {
} }
return simpleDateFormat.format(cellValue); return simpleDateFormat.format(cellValue);
} }
public static String getFieldStringValue(BeanMap beanMap, String fieldName, String format) {
String cellValue = null;
Object value = beanMap.get(fieldName);
if (value != null) {
if (value instanceof Date) {
cellValue = TypeUtil.formatDate((Date)value, format);
} else {
cellValue = value.toString();
}
}
return cellValue;
}
public static Map getFieldValues(List<String> stringList, ExcelHeadProperty excelHeadProperty, Boolean use1904WindowDate) {
Map map = new HashMap();
for (int i = 0; i < stringList.size(); i++) {
ExcelColumnProperty columnProperty = excelHeadProperty.getExcelColumnProperty(i);
if (columnProperty != null) {
Object value = TypeUtil.convert(stringList.get(i), columnProperty.getField(),
columnProperty.getFormat(), use1904WindowDate);
if (value != null) {
map.put(columnProperty.getField().getName(),value);
}
}
}
return map;
}
} }

18
src/main/java/com/alibaba/excel/util/WorkBookUtil.java

@ -55,21 +55,15 @@ public class WorkBookUtil {
return sheet.createRow(rowNum); return sheet.createRow(rowNum);
} }
public static Cell createCell(Row row, int colNum, CellStyle cellStyle, String cellValue) { public static Cell createCell(Row row, int colNum, CellStyle cellStyle) {
return createCell(row, colNum, cellStyle, cellValue, false);
}
public static Cell createCell(Row row, int colNum, CellStyle cellStyle, Object cellValue, Boolean isNum) {
Cell cell = row.createCell(colNum); Cell cell = row.createCell(colNum);
cell.setCellStyle(cellStyle); cell.setCellStyle(cellStyle);
if (null != cellValue) {
if (isNum) {
cell.setCellValue(Double.parseDouble(cellValue.toString()));
} else {
cell.setCellValue(cellValue.toString());
}
}
return cell; return cell;
} }
public static Cell createCell(Row row, int colNum, CellStyle cellStyle, String cellValue) {
Cell cell = createCell(row, colNum, cellStyle);
cell.setCellValue(cellValue);
return cell;
}
} }

13
src/main/java/com/alibaba/excel/write/ExcelBuilder.java

@ -11,7 +11,7 @@ import java.util.List;
public interface ExcelBuilder { public interface ExcelBuilder {
/** /**
* workBook increase data * workBook increase value
* *
* @param data java basic type or java model extend BaseModel * @param data java basic type or java model extend BaseModel
* @param startRow Start row number * @param startRow Start row number
@ -19,7 +19,7 @@ public interface ExcelBuilder {
void addContent(List data, int startRow); void addContent(List data, int startRow);
/** /**
* WorkBook increase data * WorkBook increase value
* *
* @param data java basic type or java model extend BaseModel * @param data java basic type or java model extend BaseModel
* @param sheetParam Write the sheet * @param sheetParam Write the sheet
@ -27,7 +27,7 @@ public interface ExcelBuilder {
void addContent(List data, Sheet sheetParam); void addContent(List data, Sheet sheetParam);
/** /**
* WorkBook increase data * WorkBook increase value
* *
* @param data java basic type or java model extend BaseModel * @param data java basic type or java model extend BaseModel
* @param sheetParam Write the sheet * @param sheetParam Write the sheet
@ -38,12 +38,9 @@ public interface ExcelBuilder {
/** /**
* Creates new cell range. Indexes are zero-based. * Creates new cell range. Indexes are zero-based.
* *
* @param firstRow Index of first row * @param strategies the merge strategy
* @param lastRow Index of last row (inclusive), must be equal to or larger than {@code firstRow}
* @param firstCol Index of first column
* @param lastCol Index of last column (inclusive), must be equal to or larger than {@code firstCol}
*/ */
void merge(int firstRow, int lastRow, int firstCol, int lastCol); void merge(List<MergeStrategy> strategies);
/** /**
* Close io * Close io

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

@ -1,6 +1,20 @@
package com.alibaba.excel.write; package com.alibaba.excel.write;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import com.alibaba.excel.context.WriteContext; import com.alibaba.excel.context.WriteContext;
import com.alibaba.excel.context.WriteContextImpl;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ConverterRegistryCenter;
import com.alibaba.excel.event.WriteHandler; import com.alibaba.excel.event.WriteHandler;
import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.exception.ExcelGenerateException;
import com.alibaba.excel.metadata.BaseRowModel; import com.alibaba.excel.metadata.BaseRowModel;
@ -12,32 +26,28 @@ import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.POITempFile; import com.alibaba.excel.util.POITempFile;
import com.alibaba.excel.util.TypeUtil; import com.alibaba.excel.util.TypeUtil;
import com.alibaba.excel.util.WorkBookUtil; import com.alibaba.excel.util.WorkBookUtil;
import net.sf.cglib.beans.BeanMap;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.IOException; import net.sf.cglib.beans.BeanMap;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
/** /**
* @author jipengfei * @author jipengfei
*/ */
public class ExcelBuilderImpl implements ExcelBuilder { public class ExcelBuilderImpl implements ExcelBuilder, ConverterRegistryCenter {
private WriteContext context; private WriteContext context;
private final List<Converter> converters = new ArrayList<Converter>();
public ExcelBuilderImpl(InputStream templateInputStream, public ExcelBuilderImpl(InputStream templateInputStream,
OutputStream out, OutputStream out,
ExcelTypeEnum excelType, ExcelTypeEnum excelType,
boolean needHead, WriteHandler writeHandler) { boolean needHead, WriteHandler writeHandler, List<Converter> converters) {
try { try {
//初始化时候创建临时缓存目录,用于规避POI在并发写bug //初始化时候创建临时缓存目录,用于规避POI在并发写bug
POITempFile.createPOIFilesDirectory(); POITempFile.createPOIFilesDirectory();
context = new WriteContext(templateInputStream, out, excelType, needHead, writeHandler); if (converters != null) {
converters.addAll(converters);
}
context = new WriteContextImpl(templateInputStream, out, excelType, needHead, writeHandler, this);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -80,10 +90,14 @@ public class ExcelBuilderImpl implements ExcelBuilder {
} }
@Override @Override
public void merge(int firstRow, int lastRow, int firstCol, int lastCol) { public void merge(List<MergeStrategy> strategies) {
CellRangeAddress cra = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol); if (strategies != null) {
for (MergeStrategy ms : strategies) {
CellRangeAddress cra = new CellRangeAddress(ms.getFirstRow(), ms.getLastRow(), ms.getFirstCol(), ms.getLastCol());
context.getCurrentSheet().addMergedRegion(cra); context.getCurrentSheet().addMergedRegion(cra);
} }
}
}
@Override @Override
public void finish() { public void finish() {
@ -101,10 +115,10 @@ public class ExcelBuilderImpl implements ExcelBuilder {
} }
for (int i = 0; i < oneRowData.size(); i++) { for (int i = 0; i < oneRowData.size(); i++) {
Object cellValue = oneRowData.get(i); Object cellValue = oneRowData.get(i);
Cell cell = WorkBookUtil.createCell(row, i, context.getCurrentContentStyle(), cellValue, Cell cell = WorkBookUtil.createCell(row, i, context.getCurrentContentStyle());
TypeUtil.isNum(cellValue)); cell = convertValue(cell, cellValue, null);
if (null != context.getAfterWriteHandler()) { if (null != context.getWriteHandler()) {
context.getAfterWriteHandler().cell(i, cell); context.getWriteHandler().cell(i, cell);
} }
} }
} }
@ -114,24 +128,33 @@ public class ExcelBuilderImpl implements ExcelBuilder {
BeanMap beanMap = BeanMap.create(oneRowData); BeanMap beanMap = BeanMap.create(oneRowData);
for (ExcelColumnProperty excelHeadProperty : context.getExcelHeadProperty().getColumnPropertyList()) { for (ExcelColumnProperty excelHeadProperty : context.getExcelHeadProperty().getColumnPropertyList()) {
BaseRowModel baseRowModel = (BaseRowModel)oneRowData; BaseRowModel baseRowModel = (BaseRowModel)oneRowData;
String cellValue = TypeUtil.getFieldStringValue(beanMap, excelHeadProperty.getField().getName(),
excelHeadProperty.getFormat());
CellStyle cellStyle = baseRowModel.getStyle(i) != null ? baseRowModel.getStyle(i) CellStyle cellStyle = baseRowModel.getStyle(i) != null ? baseRowModel.getStyle(i)
: context.getCurrentContentStyle(); : context.getCurrentContentStyle();
Cell cell = WorkBookUtil.createCell(row, i, cellStyle, cellValue, Object value = beanMap.get(excelHeadProperty.getField().getName());
TypeUtil.isNum(excelHeadProperty.getField())); Cell cell = WorkBookUtil.createCell(row, i, cellStyle);
if (null != context.getAfterWriteHandler()) { cell = convertValue(cell, value, excelHeadProperty);
context.getAfterWriteHandler().cell(i, cell); if (null != context.getWriteHandler()) {
context.getWriteHandler().cell(i, cell);
} }
i++; i++;
} }
}
private Cell convertValue(Cell cell, Object value, ExcelColumnProperty excelHeadProperty) {
if (!CollectionUtils.isEmpty(this.converters)) {
for (Converter c : this.converters) {
if (value != null && c.support(value)) {
return c.convert(cell, value, excelHeadProperty);
}
}
}
return cell;
} }
private void addOneRowOfDataToExcel(Object oneRowData, int n) { private void addOneRowOfDataToExcel(Object oneRowData, int n) {
Row row = WorkBookUtil.createRow(context.getCurrentSheet(), n); Row row = WorkBookUtil.createRow(context.getCurrentSheet(), n);
if (null != context.getAfterWriteHandler()) { if (null != context.getWriteHandler()) {
context.getAfterWriteHandler().row(n, row); context.getWriteHandler().row(n, row);
} }
if (oneRowData instanceof List) { if (oneRowData instanceof List) {
addBasicTypeToExcel((List)oneRowData, row); addBasicTypeToExcel((List)oneRowData, row);
@ -139,4 +162,14 @@ public class ExcelBuilderImpl implements ExcelBuilder {
addJavaObjectToExcel(oneRowData, row); addJavaObjectToExcel(oneRowData, row);
} }
} }
@Override
public void register(Converter converter) {
this.converters.add(converter);
}
@Override
public List<Converter> getConverters() {
return this.converters;
}
} }

8
src/main/java/com/alibaba/excel/write/MergeStrategy.java

@ -0,0 +1,8 @@
package com.alibaba.excel.write;
public interface MergeStrategy {
int getFirstRow();
int getLastRow();
int getFirstCol();
int getLastCol();
}

78
src/test/java/com/alibaba/easyexcel/test/WriteTest.java

@ -1,5 +1,22 @@
package com.alibaba.easyexcel.test; package com.alibaba.easyexcel.test;
import static com.alibaba.easyexcel.test.util.DataUtil.createTableStyle;
import static com.alibaba.easyexcel.test.util.DataUtil.createTestListJavaMode;
import static com.alibaba.easyexcel.test.util.DataUtil.createTestListObject;
import static com.alibaba.easyexcel.test.util.DataUtil.createTestListStringHead;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import com.alibaba.easyexcel.test.listen.AfterWriteHandlerImpl; import com.alibaba.easyexcel.test.listen.AfterWriteHandlerImpl;
import com.alibaba.easyexcel.test.model.WriteModel; import com.alibaba.easyexcel.test.model.WriteModel;
import com.alibaba.easyexcel.test.util.FileUtil; import com.alibaba.easyexcel.test.util.FileUtil;
@ -8,19 +25,13 @@ import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table; import com.alibaba.excel.metadata.Table;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import org.junit.Test; import com.alibaba.excel.write.MergeStrategy;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import static com.alibaba.easyexcel.test.util.DataUtil.*;
public class WriteTest { public class WriteTest {
@Test @Test
public void writeV2007() throws IOException { public void writeV2007() throws IOException {
OutputStream out = new FileOutputStream("/Users/jipengfei/2007.xlsx"); OutputStream out = new FileOutputStream(new File(FileUtil.getPath(), "write_2007.xlsx"));
ExcelWriter writer = EasyExcelFactory.getWriter(out); ExcelWriter writer = EasyExcelFactory.getWriter(out);
// 写第一个sheet, sheet1 数据全是List<String> 无模型映射关系 // 写第一个sheet, sheet1 数据全是List<String> 无模型映射关系
Sheet sheet1 = new Sheet(1, 3); Sheet sheet1 = new Sheet(1, 3);
@ -28,7 +39,10 @@ public class WriteTest {
// 设置列宽 设置每列的宽度 // 设置列宽 设置每列的宽度
Map columnWidth = new HashMap(); Map columnWidth = new HashMap();
columnWidth.put(0,10000);columnWidth.put(1,40000);columnWidth.put(2,10000);columnWidth.put(3,10000); columnWidth.put(0, 10000);
columnWidth.put(1, 40000);
columnWidth.put(2, 10000);
columnWidth.put(3, 10000);
sheet1.setColumnWidthMap(columnWidth); sheet1.setColumnWidthMap(columnWidth);
sheet1.setHead(createTestListStringHead()); sheet1.setHead(createTestListStringHead());
// or 设置自适应宽度 // or 设置自适应宽度
@ -40,8 +54,31 @@ public class WriteTest {
sheet2.setTableStyle(createTableStyle()); sheet2.setTableStyle(createTableStyle());
// writer.write1(null, sheet2); // writer.write1(null, sheet2);
writer.write(createTestListJavaMode(), sheet2); writer.write(createTestListJavaMode(), sheet2);
List<MergeStrategy> strategies = new ArrayList<MergeStrategy>();
strategies.add(new MergeStrategy() {
@Override
public int getFirstRow() {
return 5;
}
@Override
public int getLastRow() {
return 20;
}
@Override
public int getFirstCol() {
return 1;
}
@Override
public int getLastCol() {
return 1;
}
});
// 需要合并单元格 // 需要合并单元格
writer.merge(5,20,1,1); writer.merge(strategies);
// 写第三个sheet包含多个table情况 // 写第三个sheet包含多个table情况
Sheet sheet3 = new Sheet(3, 0); Sheet sheet3 = new Sheet(3, 0);
@ -65,7 +102,7 @@ public class WriteTest {
@Test @Test
public void writeV2007WithTemplate() throws IOException { public void writeV2007WithTemplate() throws IOException {
InputStream inputStream = FileUtil.getResourcesFileInputStream("temp.xlsx"); InputStream inputStream = FileUtil.getResourcesFileInputStream("temp.xlsx");
OutputStream out = new FileOutputStream("/Users/jipengfei/2007.xlsx"); OutputStream out = new FileOutputStream(new File(FileUtil.getPath(), "write_2007_1.xlsx"));
ExcelWriter writer = EasyExcelFactory.getWriterWithTemp(inputStream, out, ExcelTypeEnum.XLSX, true); ExcelWriter writer = EasyExcelFactory.getWriterWithTemp(inputStream, out, ExcelTypeEnum.XLSX, true);
// 写第一个sheet, sheet1 数据全是List<String> 无模型映射关系 // 写第一个sheet, sheet1 数据全是List<String> 无模型映射关系
Sheet sheet1 = new Sheet(1, 3); Sheet sheet1 = new Sheet(1, 3);
@ -74,7 +111,10 @@ public class WriteTest {
// 设置列宽 设置每列的宽度 // 设置列宽 设置每列的宽度
Map columnWidth = new HashMap(); Map columnWidth = new HashMap();
columnWidth.put(0,10000);columnWidth.put(1,40000);columnWidth.put(2,10000);columnWidth.put(3,10000); columnWidth.put(0, 10000);
columnWidth.put(1, 40000);
columnWidth.put(2, 10000);
columnWidth.put(3, 10000);
sheet1.setColumnWidthMap(columnWidth); sheet1.setColumnWidthMap(columnWidth);
sheet1.setHead(createTestListStringHead()); sheet1.setHead(createTestListStringHead());
// or 设置自适应宽度 // or 设置自适应宽度
@ -109,7 +149,7 @@ public class WriteTest {
@Test @Test
public void writeV2007WithTemplateAndHandler() throws IOException { public void writeV2007WithTemplateAndHandler() throws IOException {
InputStream inputStream = FileUtil.getResourcesFileInputStream("temp.xlsx"); InputStream inputStream = FileUtil.getResourcesFileInputStream("temp.xlsx");
OutputStream out = new FileOutputStream("/Users/jipengfei/2007.xlsx"); OutputStream out = new FileOutputStream(new File(FileUtil.getPath(), "write_2007_2.xlsx"));
ExcelWriter writer = EasyExcelFactory.getWriterWithTempAndHandler(inputStream, out, ExcelTypeEnum.XLSX, true, ExcelWriter writer = EasyExcelFactory.getWriterWithTempAndHandler(inputStream, out, ExcelTypeEnum.XLSX, true,
new AfterWriteHandlerImpl()); new AfterWriteHandlerImpl());
// 写第一个sheet, sheet1 数据全是List<String> 无模型映射关系 // 写第一个sheet, sheet1 数据全是List<String> 无模型映射关系
@ -119,7 +159,10 @@ public class WriteTest {
// 设置列宽 设置每列的宽度 // 设置列宽 设置每列的宽度
Map columnWidth = new HashMap(); Map columnWidth = new HashMap();
columnWidth.put(0,10000);columnWidth.put(1,40000);columnWidth.put(2,10000);columnWidth.put(3,10000); columnWidth.put(0, 10000);
columnWidth.put(1, 40000);
columnWidth.put(2, 10000);
columnWidth.put(3, 10000);
sheet1.setColumnWidthMap(columnWidth); sheet1.setColumnWidthMap(columnWidth);
sheet1.setHead(createTestListStringHead()); sheet1.setHead(createTestListStringHead());
// or 设置自适应宽度 // or 设置自适应宽度
@ -155,7 +198,7 @@ public class WriteTest {
@Test @Test
public void writeV2003() throws IOException { public void writeV2003() throws IOException {
OutputStream out = new FileOutputStream("/Users/jipengfei/2003.xls"); OutputStream out = new FileOutputStream(new File(FileUtil.getPath(), "write_2003.xlsx"));
ExcelWriter writer = EasyExcelFactory.getWriter(out, ExcelTypeEnum.XLS, true); ExcelWriter writer = EasyExcelFactory.getWriter(out, ExcelTypeEnum.XLS, true);
// 写第一个sheet, sheet1 数据全是List<String> 无模型映射关系 // 写第一个sheet, sheet1 数据全是List<String> 无模型映射关系
Sheet sheet1 = new Sheet(1, 3); Sheet sheet1 = new Sheet(1, 3);
@ -163,7 +206,10 @@ public class WriteTest {
// 设置列宽 设置每列的宽度 // 设置列宽 设置每列的宽度
Map columnWidth = new HashMap(); Map columnWidth = new HashMap();
columnWidth.put(0,10000);columnWidth.put(1,40000);columnWidth.put(2,10000);columnWidth.put(3,10000); columnWidth.put(0, 10000);
columnWidth.put(1, 40000);
columnWidth.put(2, 10000);
columnWidth.put(3, 10000);
sheet1.setColumnWidthMap(columnWidth); sheet1.setColumnWidthMap(columnWidth);
sheet1.setHead(createTestListStringHead()); sheet1.setHead(createTestListStringHead());
// or 设置自适应宽度 // or 设置自适应宽度

2
src/test/java/com/alibaba/easyexcel/test/model/WriteModel.java

@ -25,7 +25,7 @@ public class WriteModel extends BaseWriteModel {
@ExcelProperty(value = {"表头6","表头61","表头612"},index = 6) @ExcelProperty(value = {"表头6","表头61","表头612"},index = 6)
private BigDecimal p7; private BigDecimal p7;
@ExcelProperty(value = {"表头6","表头62","表头621"},index = 7) @ExcelProperty(value = {"表头6","表头62","表头621"},index = 7, format = "yyyy-MM-dd")
private Date p8; private Date p8;
@ExcelProperty(value = {"表头6","表头62","表头622"},index = 8) @ExcelProperty(value = {"表头6","表头62","表头622"},index = 8)

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

@ -7,4 +7,8 @@ public class FileUtil {
public static InputStream getResourcesFileInputStream(String fileName) { public static InputStream getResourcesFileInputStream(String fileName) {
return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName);
} }
public static String getPath() {
return FileUtil.class.getResource("/").getPath();
}
} }

Loading…
Cancel
Save