diff --git a/src/main/java/com/alibaba/excel/EasyExcelFactory.java b/src/main/java/com/alibaba/excel/EasyExcelFactory.java index 5327dc9..758d465 100644 --- a/src/main/java/com/alibaba/excel/EasyExcelFactory.java +++ b/src/main/java/com/alibaba/excel/EasyExcelFactory.java @@ -27,7 +27,7 @@ public class EasyExcelFactory { */ public static List read(InputStream in, Sheet sheet) { final List rows = new ArrayList(); - new ExcelReader(in, null, new AnalysisEventListener() { + new ExcelReader(in, null, new AnalysisEventListener() { @Override public void invoke(Object object, AnalysisContext context) { rows.add(object); @@ -65,7 +65,7 @@ public class EasyExcelFactory { /** * 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. */ public static ExcelWriter getWriter(OutputStream outputStream) { @@ -75,7 +75,7 @@ public class EasyExcelFactory { /** * 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 needHead Do you need to write the header to the file? * @return new ExcelWriter @@ -87,9 +87,9 @@ public class EasyExcelFactory { /** * Get ExcelWriter with a template file * - * @param temp Append data after a POI file , Can be null(the template POI filesystem that contains the + * @param temp Append value after a POI file , Can be null(the template POI filesystem that contains the * 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 * @return new ExcelWriter */ @@ -101,9 +101,9 @@ public class EasyExcelFactory { /** * Get ExcelWriter with a template file * - * @param temp Append data after a POI file , Can be null(the template POI filesystem that contains the + * @param temp Append value after a POI file , Can be null(the template POI filesystem that contains the * 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 needHead * @param handler User-defined callback diff --git a/src/main/java/com/alibaba/excel/ExcelReader.java b/src/main/java/com/alibaba/excel/ExcelReader.java index 9ed5892..cefe92f 100644 --- a/src/main/java/com/alibaba/excel/ExcelReader.java +++ b/src/main/java/com/alibaba/excel/ExcelReader.java @@ -1,17 +1,18 @@ package com.alibaba.excel; +import java.io.InputStream; +import java.util.List; + import com.alibaba.excel.analysis.ExcelAnalyser; import com.alibaba.excel.analysis.ExcelAnalyserImpl; import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.converters.Converter; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.BaseRowModel; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.parameter.AnalysisParam; import com.alibaba.excel.support.ExcelTypeEnum; -import java.io.InputStream; -import java.util.List; - /** * Excel readers are all read in event mode. * @@ -22,38 +23,52 @@ public class ExcelReader { /** * Analyser */ - private ExcelAnalyser analyser ; + private ExcelAnalyser analyser; /** * Create new reader * - * @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 customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext + * @param customContent + * {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext * @param eventListener Callback method after each row is parsed. */ @Deprecated public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent, - AnalysisEventListener eventListener) { + AnalysisEventListener eventListener) { this(in, excelTypeEnum, 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 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) { - this(in, customContent, eventListener, true); + public ExcelReader(InputStream in, Object customContent, AnalysisEventListener eventListener) { + this(in, customContent, eventListener, null, true); } /** * Create new reader * - * @param param old param Deprecated + * @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 converters) { + this(in, customContent, eventListener, converters, true); + } + + /** + * Create new reader + * + * @param param old param Deprecated * @param eventListener Callback method after each row is parsed. */ @Deprecated @@ -64,43 +79,65 @@ public class ExcelReader { /** * Create new reader * - * @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 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 trim The content of the form is empty and needs to be empty. The purpose is to be fault-tolerant, - * because there are often table contents with spaces that can not be converted into custom - * types. For example: '1234 ' contain a space cannot be converted to int. + * @param trim The content of the form is empty and needs to be empty. The purpose is to be + * fault-tolerant, because there are often table contents with spaces that can not be + * converted into custom types. For example: '1234 ' contain a space cannot be converted + * to int. */ @Deprecated public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent, - AnalysisEventListener eventListener, boolean trim) { - validateParam(in, eventListener); - analyser = new ExcelAnalyserImpl(in, excelTypeEnum, customContent, eventListener, trim); + AnalysisEventListener eventListener, boolean trim) { + this(in, excelTypeEnum, customContent, eventListener, null, trim); } /** * Create new reader * * @param in - * @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext + * @param customContent + * {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext * @param eventListener - * @param trim The content of the form is empty and needs to be empty. The purpose is to be fault-tolerant, - * because there are often table contents with spaces that can not be converted into custom - * types. For example: '1234 ' contain a space cannot be converted to int. + * @param trim The content of the form is empty and needs to be empty. The purpose is to be + * fault-tolerant, because there are often table contents with spaces that can not be + * converted into custom types. For example: '1234 ' contain a space cannot be converted + * to int. */ - public ExcelReader(InputStream in, Object customContent, - AnalysisEventListener eventListener, boolean trim) { - ExcelTypeEnum excelTypeEnum = ExcelTypeEnum.valueOf(in); + public ExcelReader(InputStream in, Object customContent, AnalysisEventListener eventListener, + List converters, boolean trim) { + this(in, ExcelTypeEnum.valueOf(in), customContent, eventListener, converters, trim); + } + + public ExcelReader(InputStream in, Object excelTypeEnum, AnalysisEventListener eventListener, + boolean trim) { + this(in, ExcelTypeEnum.valueOf(in), null, eventListener, null, trim); + } + + public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent, + AnalysisEventListener eventListener, List converters, boolean trim) { 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 converters) { + if (converters != null && converters.size() > 0) { + for (Converter c : converters) { + analyser.getAnalysisContext().getConverterRegistryCenter().register(c); + } + } } /** * Parse all sheet content by default */ public void read() { - analyser.analysis(); + read(null, null);; } /** @@ -109,19 +146,23 @@ public class ExcelReader { * @param sheet Read sheet */ public void read(Sheet sheet) { - analyser.analysis(sheet); + read(sheet, null); } /** * Parse the specified sheet * - * @param sheet Read sheet - * @param clazz object parsed into each row of data + * @param sheet Read sheet + * @param clazz object parsed into each row of value */ - @Deprecated public void read(Sheet sheet, Class clazz) { - sheet.setClazz(clazz); - analyser.analysis(sheet); + analyser.beforeAnalysis(); + if (sheet != null) { + sheet.setClazz(clazz); + analyser.analysis(sheet); + } else { + analyser.analysis(); + } } /** @@ -133,13 +174,17 @@ public class ExcelReader { return analyser.getSheets(); } + public AnalysisContext getAnalysisContext() { + return analyser.getAnalysisContext(); + } + /** * validate param * * @param in * @param eventListener */ - private void validateParam(InputStream in, AnalysisEventListener eventListener) { + private void validateParam(InputStream in, AnalysisEventListener eventListener) { if (eventListener == null) { throw new IllegalArgumentException("AnalysisEventListener can not null"); } else if (in == null) { diff --git a/src/main/java/com/alibaba/excel/ExcelWriter.java b/src/main/java/com/alibaba/excel/ExcelWriter.java index e3c5e0e..8e1c011 100644 --- a/src/main/java/com/alibaba/excel/ExcelWriter.java +++ b/src/main/java/com/alibaba/excel/ExcelWriter.java @@ -1,5 +1,18 @@ 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.metadata.BaseRowModel; 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.write.ExcelBuilder; import com.alibaba.excel.write.ExcelBuilderImpl; - -import java.io.InputStream; -import java.io.OutputStream; -import java.util.List; +import com.alibaba.excel.write.MergeStrategy; /** - * Excel Writer This tool is used to write data out to Excel via POI. - * This object can perform the following two functions. + * Excel Writer This tool is used to write value out to Excel via POI. This object can perform the + * following two functions. + * *
- *    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.}
  * 
+ * * @author jipengfei */ public class ExcelWriter { @@ -28,7 +40,8 @@ public class ExcelWriter { /** * 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 */ public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum) { @@ -43,46 +56,80 @@ public class ExcelWriter { */ @Deprecated public ExcelWriter(GenerateParam generateParam) { - this(generateParam.getOutputStream(), generateParam.getType(), true); + this(generateParam.getOutputStream(), generateParam.getType(), generateParam.isNeedHead()); this.objectClass = generateParam.getClazz(); } /** * * 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 needHead Do you need to write the header to the file? */ 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 - * @param templateInputStream Append data after a POI file ,Can be null(the template POI filesystem that contains the Workbook stream) - * @param outputStream the java OutputStream you wish to write the data to + * Create new writer + * + * @param templateInputStream Append value after a POI file ,Can be null(the 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 */ - public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum,Boolean needHead) { - excelBuilder = new ExcelBuilderImpl(templateInputStream,outputStream, typeEnum, needHead, null); + public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum, + Boolean needHead) { + this(templateInputStream, outputStream, typeEnum, needHead, null, null); } /** - * Create new writer - * @param templateInputStream Append data after a POI file ,Can be null(the template POI filesystem that contains the Workbook stream) - * @param outputStream the java OutputStream you wish to write the data to + * Create new writer + * + * @param templateInputStream Append value after a POI file ,Can be null(the 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 writeHandler User-defined callback */ - public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum, Boolean needHead, - WriteHandler writeHandler) { - excelBuilder = new ExcelBuilderImpl(templateInputStream,outputStream, typeEnum, needHead,writeHandler); + public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum, + Boolean needHead, WriteHandler writeHandler) { + this(templateInputStream, outputStream, typeEnum, needHead, writeHandler, null); } + public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum, + Boolean needHead, WriteHandler writeHandler, List 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 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 sheet Write to this sheet * @return this current writer @@ -94,23 +141,25 @@ public class ExcelWriter { /** - * Write data to a sheet + * Write value to a sheet + * * @param data Data to be written * @return this current writer */ @Deprecated public ExcelWriter write(List data) { if (objectClass != null) { - return this.write(data,new Sheet(1,0,objectClass)); - }else { - return this.write0(data,new Sheet(1,0,objectClass)); + return this.write(data, new Sheet(1, 0, objectClass)); + } else { + return this.write0(data, new Sheet(1, 0, objectClass)); } } /** * - * Write data to a sheet + * Write value to a sheet + * * @param data Data to be written * @param sheet Write to this sheet * @return this @@ -121,8 +170,9 @@ public class ExcelWriter { } /** - * Write data to a sheet - * @param data Data to be written + * Write value to a sheet + * + * @param data Data to be written * @param sheet Write to this sheet * @return this */ @@ -132,8 +182,9 @@ public class ExcelWriter { } /** - * Write data to a sheet - * @param data Data to be written + * Write value to a sheet + * + * @param data Data to be written * @param sheet Write to this sheet * @param table Write to this table * @return this @@ -144,8 +195,9 @@ public class ExcelWriter { } /** - * Write data to a sheet - * @param data Data to be written + * Write value to a sheet + * + * @param data Data to be written * @param sheet Write to this sheet * @param table Write to this table * @return this @@ -158,19 +210,17 @@ public class ExcelWriter { /** * Merge Cells,Indexes are zero-based. * - * @param firstRow Index of first row - * @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} + * @param strategies the merge strategies. */ - public ExcelWriter merge(int firstRow, int lastRow, int firstCol, int lastCol){ - excelBuilder.merge(firstRow,lastRow,firstCol,lastCol); + public ExcelWriter merge(List strategies) { + excelBuilder.merge(strategies); return this; } /** - * Write data to a sheet - * @param data Data to be written + * Write value to a sheet + * + * @param data Data to be written * @param sheet Write to this sheet * @param table Write to this table * @return diff --git a/src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java index 45c0d9b..f4decde 100644 --- a/src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java @@ -1,41 +1,85 @@ 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.Collection; import java.util.LinkedHashMap; 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 */ -public abstract class BaseSaxAnalyser implements AnalysisEventRegisterCenter, ExcelAnalyser { +public abstract class BaseSaxAnalyser implements ConverterRegistryCenter, AnalysisEventRegistryCenter, ExcelAnalyser { protected AnalysisContext analysisContext; - private LinkedHashMap listeners = new LinkedHashMap(); + private LinkedHashMap> listeners = + new LinkedHashMap>(); + private LinkedHashMap converters = new LinkedHashMap(); /** * execute method */ protected abstract void execute(); - @Override - public void appendLister(String name, AnalysisEventListener listener) { + public void register(String name, AnalysisEventListener listener) { if (!listeners.containsKey(name)) { 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 getConverters() { + return converters.values(); + } @Override public void analysis(Sheet sheetParam) { + analysisContext.setCurrentSheet(sheetParam); execute(); } @@ -44,44 +88,42 @@ public abstract class BaseSaxAnalyser implements AnalysisEventRegisterCenter, Ex execute(); } + @Override + public AnalysisContext getAnalysisContext() { + return analysisContext; + } /** */ @Override public void cleanAllListeners() { - listeners = new LinkedHashMap(); + listeners.clear(); } @Override - public void notifyListeners(OneRowAnalysisFinishEvent event) { - analysisContext.setCurrentRowAnalysisResult(event.getData()); + public void cleanListener(String name) { + listeners.remove(name); + } + + @SuppressWarnings("unchecked") + @Override + public void notify(AnalysisFinishEvent event) { + analysisContext.setCurrentRowAnalysisResult(event.getAnalysisResult()); /** Parsing header content **/ if (analysisContext.getCurrentRowNum() < analysisContext.getCurrentSheet().getHeadLineMun()) { if (analysisContext.getCurrentRowNum() <= analysisContext.getCurrentSheet().getHeadLineMun() - 1) { - analysisContext.buildExcelHeadProperty(null, - (List)analysisContext.getCurrentRowAnalysisResult()); + buildExcelHeadProperty(null, (List) analysisContext.getCurrentRowAnalysisResult()); } } else { - List content = converter((List)event.getData()); - /** Parsing Analyze the body content **/ - analysisContext.setCurrentRowAnalysisResult(content); - if (listeners.size() == 1) { - analysisContext.setCurrentRowAnalysisResult(content); - } - /** notify all event listeners **/ - for (Map.Entry entry : listeners.entrySet()) { + for (Entry> entry : listeners.entrySet()) { entry.getValue().invoke(analysisContext.getCurrentRowAnalysisResult(), analysisContext); } } } - private List converter(List data) { - List list = new ArrayList(); - if (data != null) { - for (String str : data) { - list.add(TypeUtil.formatFloat(str)); - } - } - return list; - } + private void buildExcelHeadProperty(Class clazz, List headOneRow) { + ExcelHeadProperty excelHeadProperty = ExcelHeadProperty + .buildExcelHeadProperty(this.analysisContext.getExcelHeadProperty(), clazz, headOneRow); + this.analysisContext.setExcelHeadProperty(excelHeadProperty); + } } diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java index b5aef4d..01f8f85 100644 --- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java @@ -1,16 +1,19 @@ package com.alibaba.excel.analysis; -import com.alibaba.excel.metadata.Sheet; - import java.util.List; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.metadata.Sheet; + /** * Excel file analyser * * @author jipengfei */ public interface ExcelAnalyser { - + + void beforeAnalysis(); + /** * parse one sheet * @@ -29,5 +32,11 @@ public interface ExcelAnalyser { * @return all sheets */ List getSheets(); + + /** + * get the analysis context. + * @return analysis context + */ + AnalysisContext getAnalysisContext(); } diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java index b8dd376..42e40a0 100644 --- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java @@ -1,18 +1,21 @@ 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.v07.XlsxSaxAnalyser; import com.alibaba.excel.context.AnalysisContext; 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.exception.ExcelAnalysisException; 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 java.io.InputStream; -import java.util.List; - /** * @author jipengfei */ @@ -23,9 +26,21 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { private BaseSaxAnalyser saxAnalyser; public ExcelAnalyserImpl(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom, - AnalysisEventListener eventListener, boolean trim) { + AnalysisEventListener eventListener, boolean trim) { + ConverterRegistryCenter center = new ConverterRegistryCenter() { + @Override + public void register(Converter converter) { + saxAnalyser.register(converter); + } + + @Override + public Collection getConverters() { + return saxAnalyser.getConverters(); + } + }; analysisContext = new AnalysisContextImpl(inputStream, excelTypeEnum, custom, - eventListener, trim); + eventListener, center, trim); + this.saxAnalyser = getSaxAnalyser(); } private BaseSaxAnalyser getSaxAnalyser() { @@ -60,36 +75,40 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { } return this.saxAnalyser; } - + @Override public void analysis(Sheet sheetParam) { analysisContext.setCurrentSheet(sheetParam); analysis(); } - + @Override + public AnalysisContext getAnalysisContext() { + return analysisContext; + } @Override public void analysis() { - BaseSaxAnalyser saxAnalyser = getSaxAnalyser(); - appendListeners(saxAnalyser); saxAnalyser.execute(); analysisContext.getEventListener().doAfterAllAnalysed(analysisContext); } @Override public List getSheets() { - BaseSaxAnalyser saxAnalyser = getSaxAnalyser(); - saxAnalyser.cleanAllListeners(); - return saxAnalyser.getSheets(); + return this.saxAnalyser.getSheets(); } - private void appendListeners(BaseSaxAnalyser saxAnalyser) { + private void registerListeners(BaseSaxAnalyser saxAnalyser) { saxAnalyser.cleanAllListeners(); 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) { - saxAnalyser.appendLister("user_define_listener", analysisContext.getEventListener()); + saxAnalyser.register("user_define_listener", analysisContext.getEventListener()); } } + @Override + public void beforeAnalysis() { + BaseSaxAnalyser saxAnalyser = getSaxAnalyser(); + registerListeners(saxAnalyser); + } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java new file mode 100644 index 0000000..0aa1335 --- /dev/null +++ b/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(); + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java new file mode 100644 index 0000000..818ab01 --- /dev/null +++ b/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 { + boolean support(Record record); + void init(); + void processRecord(Record record); + int getRow(); + int getColumn(); + String getValue(); + int getOrder(); +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java index 0154625..b832a3c 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java @@ -1,20 +1,21 @@ package com.alibaba.excel.analysis.v03; import com.alibaba.excel.analysis.BaseSaxAnalyser; +import com.alibaba.excel.analysis.v03.handlers.*; 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.metadata.Sheet; +import com.alibaba.excel.util.CollectionUtils; import org.apache.poi.hssf.eventusermodel.*; 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.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -26,15 +27,23 @@ import java.util.List; * @author jipengfei */ public class XlsSaxAnalyser extends BaseSaxAnalyser implements HSSFListener { - - private boolean analyAllSheet = false; - + private boolean outputFormulaValues = true; + private POIFSFileSystem fs; + private int lastRowNumber; + private int lastColumnNumber; + /** + * For parsing Formulas + */ + private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener; + private FormatTrackingHSSFListener formatListener; + private List records; + private boolean notAllEmpty = false; + private List sheets = new ArrayList(); + private HSSFWorkbook stubWorkbook; + private List recordHandlers = new ArrayList(); public XlsSaxAnalyser(AnalysisContext context) throws IOException { this.analysisContext = context; this.records = new ArrayList(); - if (analysisContext.getCurrentSheet() == null) { - this.analyAllSheet = true; - } context.setCurrentRowNum(0); this.fs = new POIFSFileSystem(analysisContext.getInputStream()); @@ -42,23 +51,25 @@ public class XlsSaxAnalyser extends BaseSaxAnalyser implements HSSFListener { @Override public List getSheets() { - execute(); return sheets; } @Override public void execute() { - init(); MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this); formatListener = new FormatTrackingHSSFListener(listener); + workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener); + if (workbookBuildingListener != null && stubWorkbook == null) { + stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook(); + } + + init(); HSSFEventFactory factory = new HSSFEventFactory(); HSSFRequest request = new HSSFRequest(); - if (outputFormulaValues) { request.addListenerForAllRecords(formatListener); } else { - workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener); request.addListenerForAllRecords(workbookBuildingListener); } @@ -72,223 +83,42 @@ public class XlsSaxAnalyser extends BaseSaxAnalyser implements HSSFListener { private void init() { lastRowNumber = 0; lastColumnNumber = 0; - nextRow = 0; - - nextColumn = 0; - - sheetIndex = 0; - records = new ArrayList(); - notAllEmpty = false; - - orderedBSRs = null; - - boundSheetRecords = new ArrayList(); - sheets = new ArrayList(); - if (analysisContext.getCurrentSheet() == null) { - this.analyAllSheet = true; - } else { - this.analyAllSheet = false; - } + buildXlsRecordHandlers(); } - 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 records; - - private boolean notAllEmpty = false; - - private BoundSheetRecord[] orderedBSRs; - - private List boundSheetRecords = new ArrayList(); - - private List sheets = new ArrayList(); - public void processRecord(Record record) { int thisRow = -1; int thisColumn = -1; String thisStr = null; - - switch (record.getSid()) { - case BoundSheetRecord.sid: - boundSheetRecords.add((BoundSheetRecord)record); - break; - case BOFRecord.sid: - 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; - 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)"; + for(XlsRecordHandler handler : this.recordHandlers) { + if (handler.support(record)) { + handler.processRecord(record); + thisRow = handler.getRow(); + thisColumn = handler.getColumn(); + thisStr = handler.getValue(); 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 (thisStr != null) { - if (analysisContext.trim()) { thisStr = thisStr.trim(); } if (!"".equals(thisStr)) { notAllEmpty = true; } - // } records.add(thisStr); } + // Handle new row + if (thisRow != -1 && thisRow != lastRowNumber) { + lastColumnNumber = -1; + } + // Update column and row count if (thisRow > -1) { lastRowNumber = thisRow; @@ -297,22 +127,43 @@ public class XlsSaxAnalyser extends BaseSaxAnalyser implements HSSFListener { lastColumnNumber = thisColumn; } + processLastCellOfRow(record); + } + + private void processLastCellOfRow(Record record) { // Handle end of row if (record instanceof LastCellOfRowDummyRecord) { - thisRow = ((LastCellOfRowDummyRecord)record).getRow(); + int row = ((LastCellOfRowDummyRecord)record).getRow(); if (lastColumnNumber == -1) { lastColumnNumber = 0; } - analysisContext.setCurrentRowNum(thisRow); - Sheet sheet = analysisContext.getCurrentSheet(); - - if ((sheet == null || sheet.getSheetNo() == sheetIndex) && notAllEmpty) { - notifyListeners(new OneRowAnalysisFinishEvent(records)); + analysisContext.setCurrentRowNum(row); + if (notAllEmpty) { + notify(new EachRowAnalysisFinishEvent(new ArrayList(records))); } records.clear(); lastColumnNumber = -1; 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(); + } + } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BOFRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BOFRecordHandler.java new file mode 100644 index 0000000..fb41807 --- /dev/null +++ b/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 boundSheetRecords = new ArrayList(); + private BoundSheetRecord[] orderedBSRs; + private int sheetIndex; + private List sheets; + private AnalysisContext context; + private boolean analyAllSheet; + private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener; + public BOFRecordHandler(EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener, AnalysisContext context, List 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; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java new file mode 100644 index 0000000..5f52655 --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java new file mode 100644 index 0000000..fddfd64 --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java new file mode 100644 index 0000000..c342e40 --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java new file mode 100644 index 0000000..ad97aba --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java new file mode 100644 index 0000000..8704f4b --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java new file mode 100644 index 0000000..a87a56b --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/RKRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RKRecordHandler.java new file mode 100644 index 0000000..5f4b9ce --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/SSTRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SSTRecordHandler.java new file mode 100644 index 0000000..841686b --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java new file mode 100644 index 0000000..dfc0fe8 --- /dev/null +++ b/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); +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java new file mode 100644 index 0000000..6d866a5 --- /dev/null +++ b/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 buildCellHandlers(AnalysisContext analysisContext, + AnalysisEventRegistryCenter registerCenter, SharedStringsTable sst) { + List result = new ArrayList(); + 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); + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java index 2431e9a..5a02735 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java @@ -1,20 +1,14 @@ package com.alibaba.excel.analysis.v07; -import com.alibaba.excel.annotation.FieldType; -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 java.util.List; + import org.apache.poi.xssf.model.SharedStringsTable; -import org.apache.poi.xssf.usermodel.XSSFRichTextString; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; -import java.util.Arrays; - -import static com.alibaba.excel.constant.ExcelXmlConstants.*; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventRegistryCenter; /** * @@ -22,117 +16,43 @@ import static com.alibaba.excel.constant.ExcelXmlConstants.*; */ public class XlsxRowHandler extends DefaultHandler { - private String currentCellIndex; - - 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(AnalysisEventRegisterCenter registerCenter, SharedStringsTable sst, - AnalysisContext analysisContext) { - this.registerCenter = registerCenter; - this.analysisContext = analysisContext; - this.sst = sst; - - } - - @Override - public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { - - setTotalRowCount(name, attributes); - - startCell(name, attributes); - - startCellValue(name); + private List cellHandlers; + private XlsxRowResultHolder rowResultHolder; - } - - 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; + public XlsxRowHandler(AnalysisEventRegistryCenter registerCenter, SharedStringsTable sst, + AnalysisContext analysisContext) { + this.cellHandlers = XlsxHandlerFactory.buildCellHandlers(analysisContext, registerCenter, sst); + for (XlsxCellHandler cellHandler : cellHandlers) { + if (cellHandler instanceof XlsxRowResultHolder) { + this.rowResultHolder = (XlsxRowResultHolder) cellHandler; + break; } } } - 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) { - case STRING: - int idx = Integer.parseInt(currentCellValue); - currentCellValue = new XSSFRichTextString(sst.getEntryAt(idx)).toString(); - currentCellType = FieldType.EMPTY; - break; + @Override + public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { + for (XlsxCellHandler cellHandler : cellHandlers) { + if (cellHandler.support(name)) { + cellHandler.startHandle(name, attributes); } - curRowContent[curCol] = currentCellValue; - } else if (CELL_VALUE_TAG_1.equals(name)) { - curRowContent[curCol] = currentCellValue; } } @Override public void endElement(String uri, String localName, String name) throws SAXException { - endRow(name); - endCellValue(name); + for (XlsxCellHandler cellHandler : cellHandlers) { + 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)); + if (rowResultHolder != null) { + rowResultHolder.appendCurrentCellValue(new String(ch, start, length)); } - } - - private void endRow(String name) { - if (name.equals(ROW_TAG)) { - registerCenter.notifyListeners(new OneRowAnalysisFinishEvent(curRowContent,curCol)); - curRowContent = new String[20]; - } - } - } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java new file mode 100644 index 0000000..6320618 --- /dev/null +++ b/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(); +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java new file mode 100644 index 0000000..a697570 --- /dev/null +++ b/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) { + + } + +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java new file mode 100644 index 0000000..abce458 --- /dev/null +++ b/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; + } + +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java new file mode 100644 index 0000000..a0b8c92 --- /dev/null +++ b/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(); + } + +} diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContext.java b/src/main/java/com/alibaba/excel/context/AnalysisContext.java index 23c846f..74e3782 100644 --- a/src/main/java/com/alibaba/excel/context/AnalysisContext.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContext.java @@ -1,14 +1,13 @@ 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.metadata.BaseRowModel; import com.alibaba.excel.metadata.ExcelHeadProperty; import com.alibaba.excel.metadata.Sheet; 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. @@ -52,8 +51,13 @@ public interface AnalysisContext { * custom listener * @return listener */ - AnalysisEventListener getEventListener(); + AnalysisEventListener getEventListener(); + /** + * get the converter registry center. + * @return converter registry center. + */ + ConverterRegistryCenter getConverterRegistryCenter(); /** * get current row * @return @@ -87,11 +91,10 @@ public interface AnalysisContext { ExcelHeadProperty getExcelHeadProperty(); /** - * - * @param clazz - * @param headOneRow + * set the excel head property + * @param excelHeadProperty the excel property to set. */ - void buildExcelHeadProperty(Class clazz, List headOneRow); + void setExcelHeadProperty(ExcelHeadProperty excelHeadProperty); /** * diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java index fff5055..84bccb0 100644 --- a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java @@ -1,16 +1,14 @@ 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.exception.ExcelAnalysisException; -import com.alibaba.excel.metadata.BaseRowModel; import com.alibaba.excel.metadata.ExcelHeadProperty; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.support.ExcelTypeEnum; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - /** * * @author jipengfei @@ -25,7 +23,7 @@ public class AnalysisContextImpl implements AnalysisContext { private InputStream inputStream; - private AnalysisEventListener eventListener; + private AnalysisEventListener eventListener; private Integer currentRowNum; @@ -36,6 +34,8 @@ public class AnalysisContextImpl implements AnalysisContext { private boolean trim; private boolean use1904WindowDate = false; + + private ConverterRegistryCenter converterRegistryCenter; @Override public void setUse1904WindowDate(boolean use1904WindowDate) { @@ -65,20 +65,22 @@ public class AnalysisContextImpl implements AnalysisContext { private Object currentRowAnalysisResult; public AnalysisContextImpl(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom, - AnalysisEventListener listener, boolean trim) { + AnalysisEventListener listener, ConverterRegistryCenter converterRegistryCenter, boolean trim) { this.custom = custom; this.eventListener = listener; this.inputStream = inputStream; this.excelType = excelTypeEnum; this.trim = trim; + this.converterRegistryCenter = converterRegistryCenter; } + @Override public void setCurrentSheet(Sheet currentSheet) { cleanCurrentSheet(); this.currentSheet = currentSheet; 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 - public AnalysisEventListener getEventListener() { + public AnalysisEventListener getEventListener() { return eventListener; } - public void setEventListener(AnalysisEventListener eventListener) { + public void setEventListener(AnalysisEventListener eventListener) { this.eventListener = eventListener; } @@ -154,19 +156,20 @@ public class AnalysisContextImpl implements AnalysisContext { public ExcelHeadProperty getExcelHeadProperty() { return this.excelHeadProperty; } + @Override - public void buildExcelHeadProperty(Class clazz, List headOneRow) { - if (this.excelHeadProperty == null && (clazz != null || headOneRow != null)) { - this.excelHeadProperty = new ExcelHeadProperty(clazz, new ArrayList>()); - } - if (this.excelHeadProperty.getHead() == null && headOneRow != null) { - this.excelHeadProperty.appendOneRow(headOneRow); - } + public void setExcelHeadProperty(ExcelHeadProperty excelHeadProperty) { + this.excelHeadProperty = excelHeadProperty; } @Override public boolean trim() { return this.trim; } + + @Override + public ConverterRegistryCenter getConverterRegistryCenter() { + return converterRegistryCenter; + } } diff --git a/src/main/java/com/alibaba/excel/context/WriteContext.java b/src/main/java/com/alibaba/excel/context/WriteContext.java index b1aee59..92b936e 100644 --- a/src/main/java/com/alibaba/excel/context/WriteContext.java +++ b/src/main/java/com/alibaba/excel/context/WriteContext.java @@ -1,293 +1,35 @@ 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.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 tableMap = new ConcurrentHashMap(); - - /** - * 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()); +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; - 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> head, Class 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 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 != afterWriteHandler) { - this.afterWriteHandler.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; - - } - - 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) { - this.currentSheetName = currentSheetName; - } - - public ExcelTypeEnum getExcelType() { - return excelType; - } - - public void setExcelType(ExcelTypeEnum excelType) { - this.excelType = excelType; - } +import com.alibaba.excel.converters.ConverterRegistryCenter; +import com.alibaba.excel.event.WriteHandler; +import com.alibaba.excel.metadata.ExcelHeadProperty; +import com.alibaba.excel.metadata.Table; - public OutputStream getOutputStream() { - return outputStream; - } +public interface WriteContext { - public CellStyle getCurrentHeadCellStyle() { - return this.currentHeadCellStyle == null ? defaultCellStyle : this.currentHeadCellStyle; - } + Sheet getCurrentSheet(); - public CellStyle getCurrentContentStyle() { - return this.currentContentCellStyle; - } + boolean needHead(); - public Workbook getWorkbook() { - return workbook; - } + ExcelHeadProperty getExcelHeadProperty(); - public com.alibaba.excel.metadata.Sheet getCurrentSheetParam() { - return currentSheetParam; - } + void currentSheet(com.alibaba.excel.metadata.Sheet sheet); + + void currentTable(Table table); - public void setCurrentSheetParam(com.alibaba.excel.metadata.Sheet currentSheetParam) { - this.currentSheetParam = currentSheetParam; - } + OutputStream getOutputStream(); - public Table getCurrentTable() { - return currentTable; - } + Workbook getWorkbook(); + + WriteHandler getWriteHandler(); - public void setCurrentTable(Table currentTable) { - this.currentTable = currentTable; - } + CellStyle getCurrentContentStyle(); + + ConverterRegistryCenter getConverterRegistryCenter(); } - - diff --git a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java new file mode 100644 index 0000000..434f67d --- /dev/null +++ b/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 tableMap = new ConcurrentHashMap(); + + /** + * 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> head, Class 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 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; + } +} + + diff --git a/src/main/java/com/alibaba/excel/converters/BigDecimalConverter.java b/src/main/java/com/alibaba/excel/converters/BigDecimalConverter.java new file mode 100644 index 0000000..feee369 --- /dev/null +++ b/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; + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/BooleanConverter.java b/src/main/java/com/alibaba/excel/converters/BooleanConverter.java new file mode 100644 index 0000000..bca16d7 --- /dev/null +++ b/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()); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/Converter.java b/src/main/java/com/alibaba/excel/converters/Converter.java new file mode 100644 index 0000000..11bbcdb --- /dev/null +++ b/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); +} diff --git a/src/main/java/com/alibaba/excel/converters/ConverterRegistryCenter.java b/src/main/java/com/alibaba/excel/converters/ConverterRegistryCenter.java new file mode 100644 index 0000000..7020ba7 --- /dev/null +++ b/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 getConverters(); +} diff --git a/src/main/java/com/alibaba/excel/converters/DateConverter.java b/src/main/java/com/alibaba/excel/converters/DateConverter.java new file mode 100644 index 0000000..40f9abe --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/alibaba/excel/converters/DoubleConverter.java b/src/main/java/com/alibaba/excel/converters/DoubleConverter.java new file mode 100644 index 0000000..27efbb6 --- /dev/null +++ b/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()); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/FloatConverter.java b/src/main/java/com/alibaba/excel/converters/FloatConverter.java new file mode 100644 index 0000000..5c17c62 --- /dev/null +++ b/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()); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/IntegerConverter.java b/src/main/java/com/alibaba/excel/converters/IntegerConverter.java new file mode 100644 index 0000000..6433992 --- /dev/null +++ b/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()); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/LongConverter.java b/src/main/java/com/alibaba/excel/converters/LongConverter.java new file mode 100644 index 0000000..36245a1 --- /dev/null +++ b/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()); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/StringConverter.java b/src/main/java/com/alibaba/excel/converters/StringConverter.java new file mode 100644 index 0000000..281ffaf --- /dev/null +++ b/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; + } +} diff --git a/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java b/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java index 2a30da4..cc0d877 100644 --- a/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java +++ b/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java @@ -12,7 +12,7 @@ public abstract class AnalysisEventListener { /** * when analysis one row trigger invoke function * - * @param object one row data + * @param object one row value * @param context analysis context */ public abstract void invoke(T object, AnalysisContext context); diff --git a/src/main/java/com/alibaba/excel/event/AnalysisEventRegisterCenter.java b/src/main/java/com/alibaba/excel/event/AnalysisEventRegistryCenter.java similarity index 59% rename from src/main/java/com/alibaba/excel/event/AnalysisEventRegisterCenter.java rename to src/main/java/com/alibaba/excel/event/AnalysisEventRegistryCenter.java index 7969f77..d3f0095 100644 --- a/src/main/java/com/alibaba/excel/event/AnalysisEventRegisterCenter.java +++ b/src/main/java/com/alibaba/excel/event/AnalysisEventRegistryCenter.java @@ -5,7 +5,7 @@ package com.alibaba.excel.event; * * @author jipengfei */ -public interface AnalysisEventRegisterCenter { +public interface AnalysisEventRegistryCenter { /** * Append listener @@ -13,17 +13,23 @@ public interface AnalysisEventRegisterCenter { * @param name listener name. * @param listener Callback method after each row is parsed. */ - void appendLister(String name, AnalysisEventListener listener); + void register(String name, AnalysisEventListener listener); /** * Parse one row to notify all event listeners * * @param event parse event */ - void notifyListeners(OneRowAnalysisFinishEvent event); + void notify(AnalysisFinishEvent event); /** * Clean all listeners. */ void cleanAllListeners(); + + /** + * clean listener by name + * @param name the listener name + */ + void cleanListener(String name); } diff --git a/src/main/java/com/alibaba/excel/event/AnalysisFinishEvent.java b/src/main/java/com/alibaba/excel/event/AnalysisFinishEvent.java new file mode 100644 index 0000000..4da100c --- /dev/null +++ b/src/main/java/com/alibaba/excel/event/AnalysisFinishEvent.java @@ -0,0 +1,5 @@ +package com.alibaba.excel.event; + +public interface AnalysisFinishEvent { + Object getAnalysisResult(); +} diff --git a/src/main/java/com/alibaba/excel/event/EachRowAnalysisFinishEvent.java b/src/main/java/com/alibaba/excel/event/EachRowAnalysisFinishEvent.java new file mode 100644 index 0000000..9a31ef4 --- /dev/null +++ b/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 ls = new ArrayList(length); + for (int i = 0; i <= length; i++) { + ls.add(content[i]); + } + result = ls; + } + } + + @Override + public Object getAnalysisResult() { + return result; + } +} diff --git a/src/main/java/com/alibaba/excel/modelbuild/ModelBuildEventListener.java b/src/main/java/com/alibaba/excel/event/ModelBuildEventListener.java similarity index 51% rename from src/main/java/com/alibaba/excel/modelbuild/ModelBuildEventListener.java rename to src/main/java/com/alibaba/excel/event/ModelBuildEventListener.java index bea35c7..82f7708 100644 --- a/src/main/java/com/alibaba/excel/modelbuild/ModelBuildEventListener.java +++ b/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.converters.Converter; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.exception.ExcelGenerateException; +import com.alibaba.excel.metadata.ExcelColumnProperty; import com.alibaba.excel.metadata.ExcelHeadProperty; import com.alibaba.excel.util.TypeUtil; -import net.sf.cglib.beans.BeanMap; -import java.util.List; +import net.sf.cglib.beans.BeanMap; /** * @author jipengfei */ -public class ModelBuildEventListener extends AnalysisEventListener { - +public class ModelBuildEventListener extends AnalysisEventListener { + private final Collection converters; + public ModelBuildEventListener(Collection converters) { + this.converters = converters; + } + @Override public void invoke(Object object, AnalysisContext context) { if (context.getExcelHeadProperty() != null && context.getExcelHeadProperty().getHeadClazz() != null) { try { + @SuppressWarnings("unchecked") Object resultModel = buildUserModel(context, (List)object); context.setCurrentRowAnalysisResult(resultModel); } catch (Exception e) { @@ -26,17 +37,36 @@ public class ModelBuildEventListener extends AnalysisEventListener { } } + @SuppressWarnings({"rawtypes", "unchecked"}) private Object buildUserModel(AnalysisContext context, List stringList) throws Exception { ExcelHeadProperty excelHeadProperty = context.getExcelHeadProperty(); Object resultModel = excelHeadProperty.getHeadClazz().newInstance(); if (excelHeadProperty == null) { return resultModel; } - BeanMap.create(resultModel).putAll( - TypeUtil.getFieldValues(stringList, excelHeadProperty, context.use1904WindowDate())); + Map map = new HashMap(); + 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; } + private Object convertValue(String value, ExcelColumnProperty columnProperty) { + for (Converter c : converters) { + if (c.support(columnProperty)) { + return c.convert(value, columnProperty); + } + } + return null; + } + @Override public void doAfterAllAnalysed(AnalysisContext context) { diff --git a/src/main/java/com/alibaba/excel/event/OneRowAnalysisFinishEvent.java b/src/main/java/com/alibaba/excel/event/OneRowAnalysisFinishEvent.java deleted file mode 100644 index 048e9d6..0000000 --- a/src/main/java/com/alibaba/excel/event/OneRowAnalysisFinishEvent.java +++ /dev/null @@ -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 ls = new ArrayList(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; - } -} diff --git a/src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java b/src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java index 95ff9fd..7486a72 100644 --- a/src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java +++ b/src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java @@ -123,11 +123,11 @@ public class ExcelHeadProperty { return excelColumnPropertyMap1.get(columnNum); } - public Class getHeadClazz() { + public Class getHeadClazz() { return headClazz; } - public void setHeadClazz(Class headClazz) { + public void setHeadClazz(Class headClazz) { this.headClazz = headClazz; } @@ -224,5 +224,13 @@ public class ExcelHeadProperty { } return headRowNum; } - + public static ExcelHeadProperty buildExcelHeadProperty(ExcelHeadProperty excelHeadProperty, Class clazz, List headOneRow) { + if (excelHeadProperty == null && (clazz != null || headOneRow != null)) { + excelHeadProperty = new ExcelHeadProperty(clazz, new ArrayList>()); + } + if (excelHeadProperty.getHead() == null && headOneRow != null) { + excelHeadProperty.appendOneRow(headOneRow); + } + return excelHeadProperty; + } } diff --git a/src/main/java/com/alibaba/excel/parameter/GenerateParam.java b/src/main/java/com/alibaba/excel/parameter/GenerateParam.java index 9dfccc5..a98ad71 100644 --- a/src/main/java/com/alibaba/excel/parameter/GenerateParam.java +++ b/src/main/java/com/alibaba/excel/parameter/GenerateParam.java @@ -17,6 +17,8 @@ public class GenerateParam { private ExcelTypeEnum type; + private boolean needHead = true; + public GenerateParam(String sheetName, Class clazz, OutputStream outputStream) { this.outputStream = outputStream; this.sheetName = sheetName; @@ -55,4 +57,12 @@ public class GenerateParam { public void setType(ExcelTypeEnum type) { this.type = type; } + + public boolean isNeedHead() { + return needHead; + } + + public void setNeedHead(boolean needHead) { + this.needHead = needHead; + } } diff --git a/src/main/java/com/alibaba/excel/util/TypeUtil.java b/src/main/java/com/alibaba/excel/util/TypeUtil.java index b79d623..185b331 100644 --- a/src/main/java/com/alibaba/excel/util/TypeUtil.java +++ b/src/main/java/com/alibaba/excel/util/TypeUtil.java @@ -1,18 +1,22 @@ 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.math.BigDecimal; +import java.math.RoundingMode; import java.text.ParseException; 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.Pattern; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.metadata.ExcelColumnProperty; +import com.alibaba.excel.metadata.ExcelHeadProperty; + /** * @author jipengfei */ @@ -26,70 +30,6 @@ public class TypeUtil { 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) { if (field == null) { return false; @@ -112,12 +52,8 @@ public class TypeUtil { } public static Boolean isNum(Object cellValue) { - if (cellValue instanceof Integer - || cellValue instanceof Double - || cellValue instanceof Short - || cellValue instanceof Long - || cellValue instanceof Float - || cellValue instanceof BigDecimal) { + if (cellValue instanceof Integer || cellValue instanceof Double || cellValue instanceof Short + || cellValue instanceof Long || cellValue instanceof Float || cellValue instanceof BigDecimal) { return true; } return false; @@ -164,7 +100,7 @@ public class TypeUtil { if (isNumeric(value)) { try { 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(); } catch (Exception e) { } @@ -178,7 +114,7 @@ public class TypeUtil { if (isNumeric(value)) { try { 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(); } catch (Exception e) { } @@ -199,39 +135,11 @@ public class TypeUtil { public static String formatDate(Date cellValue, String format) { SimpleDateFormat simpleDateFormat; - if(!StringUtils.isEmpty(format)) { - simpleDateFormat = new SimpleDateFormat(format); - }else { + if (!StringUtils.isEmpty(format)) { + simpleDateFormat = new SimpleDateFormat(format); + } else { simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } 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 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; - } } diff --git a/src/main/java/com/alibaba/excel/util/WorkBookUtil.java b/src/main/java/com/alibaba/excel/util/WorkBookUtil.java index 5536929..ed9716a 100644 --- a/src/main/java/com/alibaba/excel/util/WorkBookUtil.java +++ b/src/main/java/com/alibaba/excel/util/WorkBookUtil.java @@ -54,22 +54,16 @@ public class WorkBookUtil { public static Row createRow(Sheet sheet, int rowNum) { return sheet.createRow(rowNum); } - - public static Cell createCell(Row row, int colNum, CellStyle cellStyle, String cellValue) { - return createCell(row, colNum, cellStyle, cellValue, false); - } - - public static Cell createCell(Row row, int colNum, CellStyle cellStyle, Object cellValue, Boolean isNum) { + + public static Cell createCell(Row row, int colNum, CellStyle cellStyle) { Cell cell = row.createCell(colNum); cell.setCellStyle(cellStyle); - if (null != cellValue) { - if (isNum) { - cell.setCellValue(Double.parseDouble(cellValue.toString())); - } else { - cell.setCellValue(cellValue.toString()); - } - } 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; + } } diff --git a/src/main/java/com/alibaba/excel/write/ExcelBuilder.java b/src/main/java/com/alibaba/excel/write/ExcelBuilder.java index c016018..62d47ee 100644 --- a/src/main/java/com/alibaba/excel/write/ExcelBuilder.java +++ b/src/main/java/com/alibaba/excel/write/ExcelBuilder.java @@ -11,7 +11,7 @@ import java.util.List; public interface ExcelBuilder { /** - * workBook increase data + * workBook increase value * * @param data java basic type or java model extend BaseModel * @param startRow Start row number @@ -19,7 +19,7 @@ public interface ExcelBuilder { void addContent(List data, int startRow); /** - * WorkBook increase data + * WorkBook increase value * * @param data java basic type or java model extend BaseModel * @param sheetParam Write the sheet @@ -27,7 +27,7 @@ public interface ExcelBuilder { void addContent(List data, Sheet sheetParam); /** - * WorkBook increase data + * WorkBook increase value * * @param data java basic type or java model extend BaseModel * @param sheetParam Write the sheet @@ -38,12 +38,9 @@ public interface ExcelBuilder { /** * Creates new cell range. Indexes are zero-based. * - * @param firstRow Index of first row - * @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} + * @param strategies the merge strategy */ - void merge(int firstRow, int lastRow, int firstCol, int lastCol); + void merge(List strategies); /** * Close io diff --git a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java index 02b37cb..3655bb5 100644 --- a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java +++ b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java @@ -1,6 +1,20 @@ 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.WriteContextImpl; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.converters.ConverterRegistryCenter; import com.alibaba.excel.event.WriteHandler; import com.alibaba.excel.exception.ExcelGenerateException; 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.TypeUtil; 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 java.io.InputStream; -import java.io.OutputStream; -import java.util.List; +import net.sf.cglib.beans.BeanMap; /** * @author jipengfei */ -public class ExcelBuilderImpl implements ExcelBuilder { +public class ExcelBuilderImpl implements ExcelBuilder, ConverterRegistryCenter { private WriteContext context; + private final List converters = new ArrayList(); public ExcelBuilderImpl(InputStream templateInputStream, OutputStream out, ExcelTypeEnum excelType, - boolean needHead, WriteHandler writeHandler) { + boolean needHead, WriteHandler writeHandler, List converters) { try { //初始化时候创建临时缓存目录,用于规避POI在并发写bug 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) { throw new RuntimeException(e); } @@ -80,9 +90,13 @@ public class ExcelBuilderImpl implements ExcelBuilder { } @Override - public void merge(int firstRow, int lastRow, int firstCol, int lastCol) { - CellRangeAddress cra = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol); - context.getCurrentSheet().addMergedRegion(cra); + public void merge(List strategies) { + if (strategies != null) { + for (MergeStrategy ms : strategies) { + CellRangeAddress cra = new CellRangeAddress(ms.getFirstRow(), ms.getLastRow(), ms.getFirstCol(), ms.getLastCol()); + context.getCurrentSheet().addMergedRegion(cra); + } + } } @Override @@ -101,10 +115,10 @@ public class ExcelBuilderImpl implements ExcelBuilder { } for (int i = 0; i < oneRowData.size(); i++) { Object cellValue = oneRowData.get(i); - Cell cell = WorkBookUtil.createCell(row, i, context.getCurrentContentStyle(), cellValue, - TypeUtil.isNum(cellValue)); - if (null != context.getAfterWriteHandler()) { - context.getAfterWriteHandler().cell(i, cell); + Cell cell = WorkBookUtil.createCell(row, i, context.getCurrentContentStyle()); + cell = convertValue(cell, cellValue, null); + if (null != context.getWriteHandler()) { + context.getWriteHandler().cell(i, cell); } } } @@ -114,24 +128,33 @@ public class ExcelBuilderImpl implements ExcelBuilder { BeanMap beanMap = BeanMap.create(oneRowData); for (ExcelColumnProperty excelHeadProperty : context.getExcelHeadProperty().getColumnPropertyList()) { BaseRowModel baseRowModel = (BaseRowModel)oneRowData; - String cellValue = TypeUtil.getFieldStringValue(beanMap, excelHeadProperty.getField().getName(), - excelHeadProperty.getFormat()); CellStyle cellStyle = baseRowModel.getStyle(i) != null ? baseRowModel.getStyle(i) - : context.getCurrentContentStyle(); - Cell cell = WorkBookUtil.createCell(row, i, cellStyle, cellValue, - TypeUtil.isNum(excelHeadProperty.getField())); - if (null != context.getAfterWriteHandler()) { - context.getAfterWriteHandler().cell(i, cell); + : context.getCurrentContentStyle(); + Object value = beanMap.get(excelHeadProperty.getField().getName()); + Cell cell = WorkBookUtil.createCell(row, i, cellStyle); + cell = convertValue(cell, value, excelHeadProperty); + if (null != context.getWriteHandler()) { + context.getWriteHandler().cell(i, cell); } 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) { Row row = WorkBookUtil.createRow(context.getCurrentSheet(), n); - if (null != context.getAfterWriteHandler()) { - context.getAfterWriteHandler().row(n, row); + if (null != context.getWriteHandler()) { + context.getWriteHandler().row(n, row); } if (oneRowData instanceof List) { addBasicTypeToExcel((List)oneRowData, row); @@ -139,4 +162,14 @@ public class ExcelBuilderImpl implements ExcelBuilder { addJavaObjectToExcel(oneRowData, row); } } + + @Override + public void register(Converter converter) { + this.converters.add(converter); + } + + @Override + public List getConverters() { + return this.converters; + } } diff --git a/src/main/java/com/alibaba/excel/write/MergeStrategy.java b/src/main/java/com/alibaba/excel/write/MergeStrategy.java new file mode 100644 index 0000000..a585d0e --- /dev/null +++ b/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(); +} diff --git a/src/test/java/com/alibaba/easyexcel/test/ReadTest.java b/src/test/java/com/alibaba/easyexcel/test/ReadTest.java index f92fede..e229328 100644 --- a/src/test/java/com/alibaba/easyexcel/test/ReadTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/ReadTest.java @@ -161,13 +161,13 @@ public class ReadTest { public void saxReadSheetsV2003() throws IOException { InputStream inputStream = FileUtil.getResourcesFileInputStream("2003.xls"); ExcelListener excelListener = new ExcelListener(); - ExcelReader excelReader = EasyExcelFactory.getReader(inputStream,excelListener); + ExcelReader excelReader = EasyExcelFactory.getReader(inputStream, excelListener); List sheets = excelReader.getSheets(); System.out.println(); - for (Sheet sheet:sheets) { - if(sheet.getSheetNo() == 1) { + for (Sheet sheet : sheets) { + if (sheet.getSheetNo() == 1) { excelReader.read(sheet); - }else { + } else { sheet.setHeadLineMun(2); sheet.setClazz(ReadModel.class); excelReader.read(sheet); diff --git a/src/test/java/com/alibaba/easyexcel/test/WriteTest.java b/src/test/java/com/alibaba/easyexcel/test/WriteTest.java index 6b481b6..5acc49e 100644 --- a/src/test/java/com/alibaba/easyexcel/test/WriteTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/WriteTest.java @@ -1,5 +1,22 @@ 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.model.WriteModel; import com.alibaba.easyexcel.test.util.FileUtil; @@ -8,49 +25,69 @@ import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Table; import com.alibaba.excel.support.ExcelTypeEnum; -import org.junit.Test; - -import java.io.*; -import java.util.HashMap; -import java.util.Map; - -import static com.alibaba.easyexcel.test.util.DataUtil.*; +import com.alibaba.excel.write.MergeStrategy; public class WriteTest { @Test 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); - //写第一个sheet, sheet1 数据全是List 无模型映射关系 + // 写第一个sheet, sheet1 数据全是List 无模型映射关系 Sheet sheet1 = new Sheet(1, 3); sheet1.setSheetName("第一个sheet"); - //设置列宽 设置每列的宽度 + // 设置列宽 设置每列的宽度 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.setHead(createTestListStringHead()); - //or 设置自适应宽度 - //sheet1.setAutoWidth(Boolean.TRUE); + // or 设置自适应宽度 + // sheet1.setAutoWidth(Boolean.TRUE); writer.write1(createTestListObject(), sheet1); - //写第二个sheet sheet2 模型上打有表头的注解,合并单元格 + // 写第二个sheet sheet2 模型上打有表头的注解,合并单元格 Sheet sheet2 = new Sheet(2, 3, WriteModel.class, "第二个sheet", null); sheet2.setTableStyle(createTableStyle()); - //writer.write1(null, sheet2); + // writer.write1(null, sheet2); writer.write(createTestListJavaMode(), sheet2); - //需要合并单元格 - writer.merge(5,20,1,1); - - //写第三个sheet包含多个table情况 + List strategies = new ArrayList(); + 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(strategies); + + // 写第三个sheet包含多个table情况 Sheet sheet3 = new Sheet(3, 0); sheet3.setSheetName("第三个sheet"); Table table1 = new Table(1); table1.setHead(createTestListStringHead()); writer.write1(createTestListObject(), sheet3, table1); - //写sheet2 模型上打有表头的注解 + // 写sheet2 模型上打有表头的注解 Table table2 = new Table(2); table2.setTableStyle(createTableStyle()); table2.setClazz(WriteModel.class); @@ -65,29 +102,32 @@ public class WriteTest { @Test public void writeV2007WithTemplate() throws IOException { InputStream inputStream = FileUtil.getResourcesFileInputStream("temp.xlsx"); - OutputStream out = new FileOutputStream("/Users/jipengfei/2007.xlsx"); - ExcelWriter writer = EasyExcelFactory.getWriterWithTemp(inputStream,out,ExcelTypeEnum.XLSX,true); - //写第一个sheet, sheet1 数据全是List 无模型映射关系 + OutputStream out = new FileOutputStream(new File(FileUtil.getPath(), "write_2007_1.xlsx")); + ExcelWriter writer = EasyExcelFactory.getWriterWithTemp(inputStream, out, ExcelTypeEnum.XLSX, true); + // 写第一个sheet, sheet1 数据全是List 无模型映射关系 Sheet sheet1 = new Sheet(1, 3); sheet1.setSheetName("第一个sheet"); sheet1.setStartRow(20); - //设置列宽 设置每列的宽度 + // 设置列宽 设置每列的宽度 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.setHead(createTestListStringHead()); - //or 设置自适应宽度 - //sheet1.setAutoWidth(Boolean.TRUE); + // or 设置自适应宽度 + // sheet1.setAutoWidth(Boolean.TRUE); writer.write1(createTestListObject(), sheet1); - //写第二个sheet sheet2 模型上打有表头的注解,合并单元格 + // 写第二个sheet sheet2 模型上打有表头的注解,合并单元格 Sheet sheet2 = new Sheet(2, 3, WriteModel.class, "第二个sheet", null); sheet2.setTableStyle(createTableStyle()); sheet2.setStartRow(20); writer.write(createTestListJavaMode(), sheet2); - //写第三个sheet包含多个table情况 + // 写第三个sheet包含多个table情况 Sheet sheet3 = new Sheet(3, 0); sheet3.setSheetName("第三个sheet"); sheet3.setStartRow(30); @@ -95,7 +135,7 @@ public class WriteTest { table1.setHead(createTestListStringHead()); writer.write1(createTestListObject(), sheet3, table1); - //写sheet2 模型上打有表头的注解 + // 写sheet2 模型上打有表头的注解 Table table2 = new Table(2); table2.setTableStyle(createTableStyle()); table2.setClazz(WriteModel.class); @@ -109,30 +149,33 @@ public class WriteTest { @Test public void writeV2007WithTemplateAndHandler() throws IOException { InputStream inputStream = FileUtil.getResourcesFileInputStream("temp.xlsx"); - OutputStream out = new FileOutputStream("/Users/jipengfei/2007.xlsx"); - ExcelWriter writer = EasyExcelFactory.getWriterWithTempAndHandler(inputStream,out,ExcelTypeEnum.XLSX,true, - new AfterWriteHandlerImpl()); - //写第一个sheet, sheet1 数据全是List 无模型映射关系 + OutputStream out = new FileOutputStream(new File(FileUtil.getPath(), "write_2007_2.xlsx")); + ExcelWriter writer = EasyExcelFactory.getWriterWithTempAndHandler(inputStream, out, ExcelTypeEnum.XLSX, true, + new AfterWriteHandlerImpl()); + // 写第一个sheet, sheet1 数据全是List 无模型映射关系 Sheet sheet1 = new Sheet(1, 3); sheet1.setSheetName("第一个sheet"); sheet1.setStartRow(20); - //设置列宽 设置每列的宽度 + // 设置列宽 设置每列的宽度 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.setHead(createTestListStringHead()); - //or 设置自适应宽度 - //sheet1.setAutoWidth(Boolean.TRUE); + // or 设置自适应宽度 + // sheet1.setAutoWidth(Boolean.TRUE); writer.write1(createTestListObject(), sheet1); - //写第二个sheet sheet2 模型上打有表头的注解,合并单元格 + // 写第二个sheet sheet2 模型上打有表头的注解,合并单元格 Sheet sheet2 = new Sheet(2, 3, WriteModel.class, "第二个sheet", null); sheet2.setTableStyle(createTableStyle()); sheet2.setStartRow(20); writer.write(createTestListJavaMode(), sheet2); - //写第三个sheet包含多个table情况 + // 写第三个sheet包含多个table情况 Sheet sheet3 = new Sheet(3, 0); sheet3.setSheetName("第三个sheet"); sheet3.setStartRow(30); @@ -140,7 +183,7 @@ public class WriteTest { table1.setHead(createTestListStringHead()); writer.write1(createTestListObject(), sheet3, table1); - //写sheet2 模型上打有表头的注解 + // 写sheet2 模型上打有表头的注解 Table table2 = new Table(2); table2.setTableStyle(createTableStyle()); table2.setClazz(WriteModel.class); @@ -155,34 +198,37 @@ public class WriteTest { @Test public void writeV2003() throws IOException { - OutputStream out = new FileOutputStream("/Users/jipengfei/2003.xls"); - ExcelWriter writer = EasyExcelFactory.getWriter(out, ExcelTypeEnum.XLS,true); - //写第一个sheet, sheet1 数据全是List 无模型映射关系 + OutputStream out = new FileOutputStream(new File(FileUtil.getPath(), "write_2003.xlsx")); + ExcelWriter writer = EasyExcelFactory.getWriter(out, ExcelTypeEnum.XLS, true); + // 写第一个sheet, sheet1 数据全是List 无模型映射关系 Sheet sheet1 = new Sheet(1, 3); sheet1.setSheetName("第一个sheet"); - //设置列宽 设置每列的宽度 + // 设置列宽 设置每列的宽度 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.setHead(createTestListStringHead()); - //or 设置自适应宽度 - //sheet1.setAutoWidth(Boolean.TRUE); + // or 设置自适应宽度 + // sheet1.setAutoWidth(Boolean.TRUE); writer.write1(createTestListObject(), sheet1); - //写第二个sheet sheet2 模型上打有表头的注解,合并单元格 + // 写第二个sheet sheet2 模型上打有表头的注解,合并单元格 Sheet sheet2 = new Sheet(2, 3, WriteModel.class, "第二个sheet", null); sheet2.setTableStyle(createTableStyle()); writer.write(createTestListJavaMode(), sheet2); - //写第三个sheet包含多个table情况 + // 写第三个sheet包含多个table情况 Sheet sheet3 = new Sheet(3, 0); sheet3.setSheetName("第三个sheet"); Table table1 = new Table(1); table1.setHead(createTestListStringHead()); writer.write1(createTestListObject(), sheet3, table1); - //写sheet2 模型上打有表头的注解 + // 写sheet2 模型上打有表头的注解 Table table2 = new Table(2); table2.setTableStyle(createTableStyle()); table2.setClazz(WriteModel.class); diff --git a/src/test/java/com/alibaba/easyexcel/test/model/WriteModel.java b/src/test/java/com/alibaba/easyexcel/test/model/WriteModel.java index acb17c1..8fa493e 100644 --- a/src/test/java/com/alibaba/easyexcel/test/model/WriteModel.java +++ b/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) private BigDecimal p7; - @ExcelProperty(value = {"表头6","表头62","表头621"},index = 7) + @ExcelProperty(value = {"表头6","表头62","表头621"},index = 7, format = "yyyy-MM-dd") private Date p8; @ExcelProperty(value = {"表头6","表头62","表头622"},index = 8) diff --git a/src/test/java/com/alibaba/easyexcel/test/util/FileUtil.java b/src/test/java/com/alibaba/easyexcel/test/util/FileUtil.java index 60cea7a..0307821 100644 --- a/src/test/java/com/alibaba/easyexcel/test/util/FileUtil.java +++ b/src/test/java/com/alibaba/easyexcel/test/util/FileUtil.java @@ -7,4 +7,8 @@ public class FileUtil { public static InputStream getResourcesFileInputStream(String fileName) { return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); } + + public static String getPath() { + return FileUtil.class.getResource("/").getPath(); + } }