From fb5ef154d44d4df9886e98202ff53e605bfbaaab Mon Sep 17 00:00:00 2001 From: "jipengfei.jpf" Date: Mon, 15 Oct 2018 15:14:23 +0800 Subject: [PATCH] =?UTF-8?q?=E9=98=BF=E9=87=8C=E5=85=A7=E9=83=A8=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=89=88=E6=9C=AC=E5=BC=80=E6=BA=90=EF=BC=8C=E4=B8=BA?= =?UTF-8?q?=E4=BA=86=E7=A8=B3=E5=AE=9A=E6=80=A707=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E4=BF=AE=E6=94=B9=E4=B8=BA=E5=BA=95=E5=B1=82?= =?UTF-8?q?=E4=BD=BF=E7=94=A8POI=E8=A7=A3=E6=9E=90=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 15 +- .../java/com/alibaba/excel/ExcelReader.java | 73 ++-- .../java/com/alibaba/excel/ExcelWriter.java | 112 ++++-- .../{read => analysis}/BaseSaxAnalyser.java | 36 +- .../alibaba/excel/analysis/ExcelAnalyser.java | 30 ++ .../{read => analysis}/ExcelAnalyserImpl.java | 42 +-- .../v03/XlsSaxAnalyser.java} | 55 +-- .../v07/XlsxRowHandler.java} | 40 +-- .../excel/analysis/v07/XlsxSaxAnalyser.java | 144 ++++++++ .../excel/annotation/ExcelColumnNum.java | 14 +- .../excel/annotation/ExcelProperty.java | 16 +- .../alibaba/excel/annotation/FieldType.java | 2 +- .../{util => constant}/ExcelXmlConstants.java | 4 +- .../{read => }/context/AnalysisContext.java | 57 ++- .../context/AnalysisContextImpl.java | 15 +- .../{write => }/context/GenerateContext.java | 29 +- .../context/GenerateContextImpl.java | 66 ++-- .../excel/event/AnalysisEventListener.java | 26 ++ .../event/AnalysisEventRegisterCenter.java | 12 +- .../event/OneRowAnalysisFinishEvent.java | 3 +- .../exception/ExcelAnalysisException.java | 3 +- .../exception/ExcelGenerateException.java | 4 +- .../alibaba/excel/metadata/BaseRowModel.java | 25 ++ .../com/alibaba/excel/metadata/CellRange.java | 1 + .../excel/metadata/ExcelColumnProperty.java | 5 +- .../excel/metadata/ExcelHeadProperty.java | 38 +- .../java/com/alibaba/excel/metadata/Font.java | 5 +- .../com/alibaba/excel/metadata/Sheet.java | 51 ++- .../com/alibaba/excel/metadata/Table.java | 5 +- .../alibaba/excel/metadata/TableStyle.java | 1 + .../modelbuild/ModelBuildEventListener.java | 16 +- .../excel/parameter/AnalysisParam.java | 58 +++ .../excel/parameter/ExcelWriteParam.java | 45 +++ .../excel/parameter/GenerateParam.java | 58 +++ .../com/alibaba/excel/read/ExcelAnalyser.java | 54 --- .../alibaba/excel/read/SaxAnalyserV07.java | 331 ------------------ .../read/event/AnalysisEventListener.java | 30 -- .../alibaba/excel/read/v07/XMLTempFile.java | 48 --- .../excel/read/v07/XmlParserFactory.java | 42 --- .../alibaba/excel/support/ExcelTypeEnum.java | 1 - .../alibaba/excel/util/EasyExcelTempFile.java | 62 ---- .../java/com/alibaba/excel/util/FileUtil.java | 122 ------- .../excel/util/IndexValueConverter.java | 145 ++++---- .../com/alibaba/excel/util/POITempFile.java | 41 +++ .../com/alibaba/excel/util/PositionUtils.java | 1 + .../java/com/alibaba/excel/util/TypeUtil.java | 77 +++- .../com/alibaba/excel/write/ExcelBuilder.java | 49 +-- .../alibaba/excel/write/ExcelBuilderImpl.java | 95 +++-- .../java/function/listener/ExcelListener.java | 16 +- .../function/read/ExelAllDataTypeTest.java | 9 +- src/test/java/function/read/NumTest3.java | 9 +- src/test/java/function/read/ReadSheets.java | 13 +- .../function/read/XLSX2007FunctionTest.java | 9 +- .../java/function/write/ExcelWriteTest1.java | 15 +- .../java/javamodel/IdentificationExcel.java | 48 +++ .../java/read/v03/XLS2003FunctionTest.java | 9 +- .../java/read/v07/Read2007MeanWhileWrite.java | 11 +- src/test/java/read/v07/Read2007Xlsx.java | 56 +-- .../Excel2007NoJavaModelAnalysisListener.java | 10 +- ...xcel2007WithJavaModelAnalysisListener.java | 11 +- src/test/resources/1.xlsx | Bin 42803 -> 0 bytes 61 files changed, 1137 insertions(+), 1283 deletions(-) rename src/main/java/com/alibaba/excel/{read => analysis}/BaseSaxAnalyser.java (72%) create mode 100644 src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java rename src/main/java/com/alibaba/excel/{read => analysis}/ExcelAnalyserImpl.java (67%) rename src/main/java/com/alibaba/excel/{read/SaxAnalyserV03.java => analysis/v03/XlsSaxAnalyser.java} (86%) rename src/main/java/com/alibaba/excel/{read/v07/RowHandler.java => analysis/v07/XlsxRowHandler.java} (77%) create mode 100644 src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java rename src/main/java/com/alibaba/excel/{util => constant}/ExcelXmlConstants.java (88%) rename src/main/java/com/alibaba/excel/{read => }/context/AnalysisContext.java (58%) rename src/main/java/com/alibaba/excel/{read => }/context/AnalysisContextImpl.java (94%) rename src/main/java/com/alibaba/excel/{write => }/context/GenerateContext.java (65%) rename src/main/java/com/alibaba/excel/{write => }/context/GenerateContextImpl.java (82%) create mode 100644 src/main/java/com/alibaba/excel/event/AnalysisEventListener.java rename src/main/java/com/alibaba/excel/{read => }/event/AnalysisEventRegisterCenter.java (55%) rename src/main/java/com/alibaba/excel/{read => }/event/OneRowAnalysisFinishEvent.java (85%) rename src/main/java/com/alibaba/excel/{read => }/exception/ExcelAnalysisException.java (84%) rename src/main/java/com/alibaba/excel/{write => }/exception/ExcelGenerateException.java (83%) rename src/main/java/com/alibaba/excel/{read => }/modelbuild/ModelBuildEventListener.java (87%) create mode 100644 src/main/java/com/alibaba/excel/parameter/AnalysisParam.java create mode 100644 src/main/java/com/alibaba/excel/parameter/ExcelWriteParam.java create mode 100644 src/main/java/com/alibaba/excel/parameter/GenerateParam.java delete mode 100644 src/main/java/com/alibaba/excel/read/ExcelAnalyser.java delete mode 100644 src/main/java/com/alibaba/excel/read/SaxAnalyserV07.java delete mode 100644 src/main/java/com/alibaba/excel/read/event/AnalysisEventListener.java delete mode 100644 src/main/java/com/alibaba/excel/read/v07/XMLTempFile.java delete mode 100644 src/main/java/com/alibaba/excel/read/v07/XmlParserFactory.java delete mode 100644 src/main/java/com/alibaba/excel/util/EasyExcelTempFile.java delete mode 100644 src/main/java/com/alibaba/excel/util/FileUtil.java create mode 100644 src/main/java/com/alibaba/excel/util/POITempFile.java create mode 100755 src/test/java/javamodel/IdentificationExcel.java delete mode 100644 src/test/resources/1.xlsx diff --git a/pom.xml b/pom.xml index e004b36..462d5f9 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.alibaba easyexcel - 1.0.4-SNAPSHOT + 1.0.4 jar easyexcel easyexcel is a excel handle tools written in Java @@ -118,18 +118,7 @@ - - - - - - - - - - - - + org.apache.maven.plugins maven-gpg-plugin diff --git a/src/main/java/com/alibaba/excel/ExcelReader.java b/src/main/java/com/alibaba/excel/ExcelReader.java index e5dfe6f..a15c74d 100644 --- a/src/main/java/com/alibaba/excel/ExcelReader.java +++ b/src/main/java/com/alibaba/excel/ExcelReader.java @@ -1,33 +1,35 @@ package com.alibaba.excel; -import java.io.InputStream; -import java.util.List; - -import com.alibaba.excel.read.ExcelAnalyser; -import com.alibaba.excel.read.ExcelAnalyserImpl; -import com.alibaba.excel.read.context.AnalysisContext; -import com.alibaba.excel.read.event.AnalysisEventListener; +import com.alibaba.excel.analysis.ExcelAnalyser; +import com.alibaba.excel.analysis.ExcelAnalyserImpl; +import com.alibaba.excel.context.AnalysisContext; +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解析,thread unsafe + * Excel thread unsafe * * @author jipengfei */ public class ExcelReader { /** - * 解析器 + * analyser */ private ExcelAnalyser analyser = new ExcelAnalyserImpl(); /** - * @param in 文件输入流 - * @param excelTypeEnum excel类型03、07 - * @param customContent 自定义模型可以在{@link AnalysisEventListener#invoke(Object, AnalysisContext) - * }AnalysisContext中获取用于监听者回调使用 - * @param eventListener 用户监听 + * @param in + * @param excelTypeEnum 0307 + * @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) + * }AnalysisContext + * @param eventListener */ public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent, AnalysisEventListener eventListener) { @@ -35,12 +37,22 @@ public class ExcelReader { } /** - * @param in 文件输入流 - * @param excelTypeEnum excel类型03、07 - * @param customContent 自定义模型可以在{@link AnalysisEventListener#invoke(Object, AnalysisContext) - * }AnalysisContext中获取用于监听者回调使用 - * @param eventListener 用户监听 - * @param trim 是否对解析的String做trim()默认true,用于防止 excel中空格引起的装换报错。 + * old 1.1.0 + * @param param + * @param eventListener + */ + @Deprecated + public ExcelReader(AnalysisParam param, AnalysisEventListener eventListener) { + this(param.getIn(), param.getExcelTypeEnum(), param.getCustomContent(), eventListener, true); + } + + /** + * @param in + * @param excelTypeEnum 03 07 + * @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) + * }AnalysisContext + * @param eventListener + * @param trim */ public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent, AnalysisEventListener eventListener, boolean trim) { @@ -49,39 +61,34 @@ public class ExcelReader { } /** - * 读一个sheet,且没有模型映射 */ public void read() { analyser.analysis(); } /** - * 读指定个sheet,没有模型映射 * - * @param sheet 需要解析的sheet + * @param sheet */ public void read(Sheet sheet) { analyser.analysis(sheet); } + @Deprecated + public void read(Sheet sheet,Class clazz){ + sheet.setClazz(clazz); + analyser.analysis(sheet); + } + /** - * 读取excel中包含哪些sheet * - * @return Sheets + * @return */ public List getSheets() { return analyser.getSheets(); } /** - * 关闭流,删除临时目录文件 - */ - public void finish(){ - analyser.stop(); - } - - /** - * 校验入参 * * @param in * @param excelTypeEnum diff --git a/src/main/java/com/alibaba/excel/ExcelWriter.java b/src/main/java/com/alibaba/excel/ExcelWriter.java index 7ead088..c526e99 100644 --- a/src/main/java/com/alibaba/excel/ExcelWriter.java +++ b/src/main/java/com/alibaba/excel/ExcelWriter.java @@ -1,17 +1,18 @@ package com.alibaba.excel; -import java.io.OutputStream; -import java.util.List; - import com.alibaba.excel.metadata.BaseRowModel; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Table; +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; + /** - * 生成excel,thread unsafe * * @author jipengfei */ @@ -19,80 +20,119 @@ public class ExcelWriter { private ExcelBuilder excelBuilder; - - /** - * 生成EXCEL * - * @param outputStream 文件输出流 - * @param typeEnum 输出文件类型03或07,强烈建议使用07版(可以输出超大excel而不内存溢出) + * */ public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum) { this(outputStream, typeEnum, true); } + private Class objectClass; + + private String sheetName; + + public ExcelWriter(GenerateParam generateParam) { + + this(generateParam.getOutputStream(), generateParam.getType(), true); + this.objectClass = generateParam.getClazz(); + this.sheetName = generateParam.getSheetName(); + } + /** - * 生成EXCEL * - * @param outputStream 文件输出流 - * @param typeEnum 输出文件类型03或07,强烈建议使用07版(可以输出超大excel而不内存溢出) - * @param needHead 是否需要表头 + * + * @param outputStream + * @param typeEnum */ public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum, boolean needHead) { excelBuilder = new ExcelBuilderImpl(); - excelBuilder.init(outputStream, typeEnum, needHead); + excelBuilder.init(null, outputStream, typeEnum, needHead); } /** - * 生成多sheet,每个sheet一张表 * - * @param data 一行数据是一个BaseRowModel子类的模型 - * @param sheet data写入某个sheet - * @return this(当前引用) + * @param templateInputStream + * @param outputStream + * @param typeEnum + */ + public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum, boolean needHead) { + excelBuilder = new ExcelBuilderImpl(); + excelBuilder.init(templateInputStream,outputStream, typeEnum, needHead); + } + + /** + * + * @param data + * @param sheet + * @return this */ public ExcelWriter write(List data, Sheet sheet) { excelBuilder.addContent(data, sheet); return this; } + //public Sheet(int sheetNo, int headLineMun, Class clazz, String sheetName, + // List> head) { + // this.sheetNo = sheetNo; + // this.clazz = clazz; + // this.headLineMun = headLineMun; + // this.sheetName = sheetName; + // this.head = head; + //} + + @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)); + + } + } + /** - * 生成多sheet,每个sheet一张表 * - * @param data List代表一行数据 - * @param sheet data写入某个sheet - * @return this(当前引用) + * + * @param data + * @param sheet + * @return this */ - public ExcelWriter write0(List> data, Sheet sheet) { + public ExcelWriter write1(List> data, Sheet sheet) { excelBuilder.addContent(data, sheet); return this; } /** - * 可生成多sheet,每个sheet多张表 * - * @param data type 一个java模型一行数据 - * @param sheet data写入某个sheet - * @param table data写入某个table - * @return this(当前引用) + * @param data + * @param sheet + * @return this */ + public ExcelWriter write0(List> data, Sheet sheet) { + excelBuilder.addContent(data, sheet); + return this; + } + + + public ExcelWriter write(List data, Sheet sheet, Table table) { excelBuilder.addContent(data, sheet, table); return this; } - /** - * 可生成多sheet,每个sheet多张表 - * - * @param data List 代表一行数据 - * @param sheet data写入某个sheet - * @param table data写入某个table - * @return this(当前引用) - */ + public ExcelWriter write0(List> data, Sheet sheet, Table table) { excelBuilder.addContent(data, sheet, table); return this; } + + public ExcelWriter write1(List> data, Sheet sheet, Table table) { + excelBuilder.addContent(data, sheet, table); + return this; + } + public void finish() { excelBuilder.finish(); } diff --git a/src/main/java/com/alibaba/excel/read/BaseSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java similarity index 72% rename from src/main/java/com/alibaba/excel/read/BaseSaxAnalyser.java rename to src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java index e596543..55e906c 100644 --- a/src/main/java/com/alibaba/excel/read/BaseSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java @@ -1,19 +1,20 @@ -package com.alibaba.excel.read; +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.support.ExcelTypeEnum; +import com.alibaba.excel.util.TypeUtil; import java.io.InputStream; +import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import com.alibaba.excel.read.context.AnalysisContext; -import com.alibaba.excel.read.event.AnalysisEventListener; -import com.alibaba.excel.read.event.AnalysisEventRegisterCenter; -import com.alibaba.excel.read.event.OneRowAnalysisFinishEvent; -import com.alibaba.excel.metadata.Sheet; -import com.alibaba.excel.support.ExcelTypeEnum; - /** - * 抽象sax模式 excel 解析类 * * @author jipengfei */ @@ -24,7 +25,6 @@ public abstract class BaseSaxAnalyser implements AnalysisEventRegisterCenter, Ex private LinkedHashMap listeners = new LinkedHashMap(); /** - * 开始执行解析 */ protected abstract void execute(); @@ -47,7 +47,6 @@ public abstract class BaseSaxAnalyser implements AnalysisEventRegisterCenter, Ex } /** - * 清空所有监听者 */ public void cleanAllListeners() { listeners = new LinkedHashMap(); @@ -56,7 +55,6 @@ public abstract class BaseSaxAnalyser implements AnalysisEventRegisterCenter, Ex public void notifyListeners(OneRowAnalysisFinishEvent event) { analysisContext.setCurrentRowAnalysisResult(event.getData()); - //表头数据 if (analysisContext.getCurrentRowNum() < analysisContext.getCurrentSheet().getHeadLineMun()) { if (analysisContext.getCurrentRowNum() <= analysisContext.getCurrentSheet().getHeadLineMun() - 1) { analysisContext.buildExcelHeadProperty(null, @@ -64,9 +62,23 @@ public abstract class BaseSaxAnalyser implements AnalysisEventRegisterCenter, Ex } } else { analysisContext.setCurrentRowAnalysisResult(event.getData()); + if (listeners.size() == 1) { + analysisContext.setCurrentRowAnalysisResult(converter((List)event.getData())); + } for (Map.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; + } + } diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java new file mode 100644 index 0000000..aef773d --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java @@ -0,0 +1,30 @@ +package com.alibaba.excel.analysis; + +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +import java.io.InputStream; +import java.util.List; + +/** + * + * @author jipengfei + */ +public interface ExcelAnalyser { + + void init(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom, AnalysisEventListener eventListener, + boolean trim); + + void analysis(Sheet sheetParam); + + + + void analysis(); + + + List getSheets(); + + + +} diff --git a/src/main/java/com/alibaba/excel/read/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java similarity index 67% rename from src/main/java/com/alibaba/excel/read/ExcelAnalyserImpl.java rename to src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java index 9afed07..3283698 100644 --- a/src/main/java/com/alibaba/excel/read/ExcelAnalyserImpl.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java @@ -1,15 +1,18 @@ -package com.alibaba.excel.read; +package com.alibaba.excel.analysis; -import java.io.InputStream; -import java.util.List; - -import com.alibaba.excel.read.context.AnalysisContext; -import com.alibaba.excel.read.context.AnalysisContextImpl; -import com.alibaba.excel.read.event.AnalysisEventListener; +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.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.metadata.Sheet; -import com.alibaba.excel.read.modelbuild.ModelBuildEventListener; +import com.alibaba.excel.modelbuild.ModelBuildEventListener; import com.alibaba.excel.support.ExcelTypeEnum; +import java.io.InputStream; +import java.util.List; + /** * @author jipengfei */ @@ -21,14 +24,15 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { private BaseSaxAnalyser getSaxAnalyser() { if (saxAnalyser == null) { - if (ExcelTypeEnum.XLS.equals(analysisContext.getExcelType())) { - this.saxAnalyser = new SaxAnalyserV03(analysisContext); - } else { - try { - this.saxAnalyser = new SaxAnalyserV07(analysisContext); - } catch (Exception e) { - e.printStackTrace(); + try { + if (ExcelTypeEnum.XLS.equals(analysisContext.getExcelType())) { + this.saxAnalyser = new XlsSaxAnalyser(analysisContext); + } else { + this.saxAnalyser = new XlsxSaxAnalyser(analysisContext); } + } catch (Exception e) { + throw new ExcelAnalysisException("Analyse excel occur file error fileType " + analysisContext.getExcelType(), + e); } } return this.saxAnalyser; @@ -59,10 +63,6 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { return saxAnalyser.getSheets(); } - public void stop() { - saxAnalyser.stop(); - } - private void appendListeners(BaseSaxAnalyser saxAnalyser) { if (analysisContext.getCurrentSheet() != null && analysisContext.getCurrentSheet().getClazz() != null) { saxAnalyser.appendLister("model_build_listener", new ModelBuildEventListener()); @@ -72,8 +72,4 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { } } - protected void finalize() throws Throwable { - stop(); - } - } diff --git a/src/main/java/com/alibaba/excel/read/SaxAnalyserV03.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java similarity index 86% rename from src/main/java/com/alibaba/excel/read/SaxAnalyserV03.java rename to src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java index bc86fe6..bfaa3e9 100644 --- a/src/main/java/com/alibaba/excel/read/SaxAnalyserV03.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java @@ -1,60 +1,39 @@ -package com.alibaba.excel.read; +package com.alibaba.excel.analysis.v03; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import com.alibaba.excel.read.context.AnalysisContext; -import com.alibaba.excel.read.event.OneRowAnalysisFinishEvent; -import com.alibaba.excel.read.exception.ExcelAnalysisException; +import com.alibaba.excel.analysis.BaseSaxAnalyser; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.OneRowAnalysisFinishEvent; +import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.metadata.Sheet; - -import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder; -import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; -import org.apache.poi.hssf.eventusermodel.HSSFEventFactory; -import org.apache.poi.hssf.eventusermodel.HSSFListener; -import org.apache.poi.hssf.eventusermodel.HSSFRequest; -import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener; +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.BOFRecord; -import org.apache.poi.hssf.record.BlankRecord; -import org.apache.poi.hssf.record.BoolErrRecord; -import org.apache.poi.hssf.record.BoundSheetRecord; -import org.apache.poi.hssf.record.FormulaRecord; -import org.apache.poi.hssf.record.LabelRecord; -import org.apache.poi.hssf.record.LabelSSTRecord; -import org.apache.poi.hssf.record.NoteRecord; -import org.apache.poi.hssf.record.NumberRecord; -import org.apache.poi.hssf.record.RKRecord; -import org.apache.poi.hssf.record.Record; -import org.apache.poi.hssf.record.SSTRecord; -import org.apache.poi.hssf.record.StringRecord; +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.List; + /** - * 2003版Excel解析器 * * @author jipengfei */ -public class SaxAnalyserV03 extends BaseSaxAnalyser implements HSSFListener { +public class XlsSaxAnalyser extends BaseSaxAnalyser implements HSSFListener { private boolean analyAllSheet = false; - public SaxAnalyserV03(AnalysisContext context) { + public XlsSaxAnalyser(AnalysisContext context) throws IOException { this.analysisContext = context; this.records = new ArrayList(); if (analysisContext.getCurrentSheet() == null) { this.analyAllSheet = true; } context.setCurrentRowNum(0); - try { - this.fs = new POIFSFileSystem(analysisContext.getInputStream()); - } catch (IOException e) { - throw new ExcelAnalysisException(e); - } + this.fs = new POIFSFileSystem(analysisContext.getInputStream()); + } public List getSheets() { @@ -62,10 +41,6 @@ public class SaxAnalyserV03 extends BaseSaxAnalyser implements HSSFListener { return sheets; } - public void stop() { - - } - @Override public void execute() { init(); diff --git a/src/main/java/com/alibaba/excel/read/v07/RowHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java similarity index 77% rename from src/main/java/com/alibaba/excel/read/v07/RowHandler.java rename to src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java index 7aaf6c9..12be50f 100644 --- a/src/main/java/com/alibaba/excel/read/v07/RowHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java @@ -1,30 +1,26 @@ -package com.alibaba.excel.read.v07; - -import java.util.Arrays; -import java.util.List; +package com.alibaba.excel.analysis.v07; import com.alibaba.excel.annotation.FieldType; -import com.alibaba.excel.util.ExcelXmlConstants; -import com.alibaba.excel.read.context.AnalysisContext; -import com.alibaba.excel.read.event.AnalysisEventRegisterCenter; -import com.alibaba.excel.read.event.OneRowAnalysisFinishEvent; +import com.alibaba.excel.constant.ExcelXmlConstants; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventRegisterCenter; +import com.alibaba.excel.event.OneRowAnalysisFinishEvent; import com.alibaba.excel.util.PositionUtils; - import org.apache.poi.xssf.model.SharedStringsTable; +import org.apache.poi.xssf.usermodel.XSSFRichTextString; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; -import static com.alibaba.excel.util.ExcelXmlConstants.CELL_VALUE_TAG; -import static com.alibaba.excel.util.ExcelXmlConstants.CELL_VALUE_TAG_1; -import static com.alibaba.excel.util.ExcelXmlConstants.DIMENSION; -import static com.alibaba.excel.util.ExcelXmlConstants.DIMENSION_REF; -import static com.alibaba.excel.util.ExcelXmlConstants.ROW_TAG; +import java.util.Arrays; + +import static com.alibaba.excel.constant.ExcelXmlConstants.*; /** * @author jipengfei + * @date 2017/08/23 */ -public class RowHandler extends DefaultHandler { +public class XlsxRowHandler extends DefaultHandler { private String currentCellIndex; @@ -44,14 +40,11 @@ public class RowHandler extends DefaultHandler { private AnalysisEventRegisterCenter registerCenter; - private List sharedStringList; - - public RowHandler(AnalysisEventRegisterCenter registerCenter, SharedStringsTable sst, - AnalysisContext analysisContext, List sharedStringList) { + public XlsxRowHandler(AnalysisEventRegisterCenter registerCenter, SharedStringsTable sst, + AnalysisContext analysisContext) { this.registerCenter = registerCenter; this.analysisContext = analysisContext; this.sst = sst; - this.sharedStringList = sharedStringList; } @@ -107,11 +100,7 @@ public class RowHandler extends DefaultHandler { switch (currentCellType) { case STRING: int idx = Integer.parseInt(currentCellValue); - if (idx < sharedStringList.size()) { - currentCellValue = sharedStringList.get(idx); - } else { - currentCellValue = ""; - } + currentCellValue = new XSSFRichTextString(sst.getEntryAt(idx)).toString(); currentCellType = FieldType.EMPTY; break; //case DATE: @@ -141,6 +130,7 @@ public class RowHandler extends DefaultHandler { } + private void setTotalRowCount(String name, Attributes attributes) { if (DIMENSION.equals(name)) { String d = attributes.getValue(DIMENSION_REF); diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java new file mode 100644 index 0000000..5d761f4 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java @@ -0,0 +1,144 @@ +package com.alibaba.excel.analysis.v07; + +import com.alibaba.excel.analysis.BaseSaxAnalyser; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.metadata.Sheet; +import org.apache.poi.openxml4j.exceptions.OpenXML4JException; +import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.xssf.eventusermodel.XSSFReader; +import org.apache.poi.xssf.model.SharedStringsTable; +import org.apache.xmlbeans.XmlException; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * @author jipengfei + * @date 2017/08/27 + */ +public class XlsxSaxAnalyser extends BaseSaxAnalyser { + + private XSSFReader xssfReader; + + private SharedStringsTable sharedStringsTable; + + private List sheetSourceList = new ArrayList(); + + private boolean use1904WindowDate = false; + + public XlsxSaxAnalyser(AnalysisContext analysisContext) throws IOException, OpenXML4JException, XmlException { + this.analysisContext = analysisContext; + + analysisContext.setCurrentRowNum(0); + this.xssfReader = new XSSFReader(OPCPackage.open(analysisContext.getInputStream())); + this.sharedStringsTable = this.xssfReader.getSharedStringsTable(); + + InputStream workbookXml = xssfReader.getWorkbookData(); + WorkbookDocument ctWorkbook = WorkbookDocument.Factory.parse(workbookXml); + CTWorkbook wb = ctWorkbook.getWorkbook(); + CTWorkbookPr prefix = wb.getWorkbookPr(); + if (prefix != null) { + this.use1904WindowDate = prefix.getDate1904(); + } + this.analysisContext.setUse1904WindowDate(use1904WindowDate); + + + XSSFReader.SheetIterator ite; + sheetSourceList = new ArrayList(); + ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData(); + while (ite.hasNext()) { + InputStream inputStream = ite.next(); + String sheetName = ite.getSheetName(); + SheetSource sheetSource = new SheetSource(sheetName, inputStream); + sheetSourceList.add(sheetSource); + } + + } + + protected void execute() { + Sheet sheetParam = analysisContext.getCurrentSheet(); + if (sheetParam != null && sheetParam.getSheetNo() > 0 && sheetSourceList.size() >= sheetParam.getSheetNo()) { + InputStream sheetInputStream = sheetSourceList.get(sheetParam.getSheetNo() - 1).getInputStream(); + parseXmlSource(sheetInputStream); + + } else { + int i = 0; + for (SheetSource sheetSource : sheetSourceList) { + i++; + analysisContext.setCurrentSheet(new Sheet(i)); + parseXmlSource(sheetSource.getInputStream()); + } + } + } + + private void parseXmlSource(InputStream inputStream) { + InputSource sheetSource = new InputSource(inputStream); + try { + SAXParserFactory saxFactory = SAXParserFactory.newInstance(); + saxFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + saxFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); + saxFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + SAXParser saxParser = saxFactory.newSAXParser(); + XMLReader xmlReader = saxParser.getXMLReader(); + + ContentHandler handler = new XlsxRowHandler(this, sharedStringsTable, analysisContext); + xmlReader.setContentHandler(handler); + xmlReader.parse(sheetSource); + inputStream.close(); + } catch (Exception e) { + throw new ExcelAnalysisException(e); + } + } + + public List getSheets() { + List sheets = new ArrayList(); + int i = 1; + for (SheetSource sheetSource : sheetSourceList) { + Sheet sheet = new Sheet(i, 0); + sheet.setSheetName(sheetSource.getSheetName()); + i++; + sheets.add(sheet); + } + + return sheets; + } + + class SheetSource { + + private String sheetName; + + private InputStream inputStream; + + public SheetSource(String sheetName, InputStream inputStream) { + this.sheetName = sheetName; + this.inputStream = inputStream; + } + + public String getSheetName() { + return sheetName; + } + + public void setSheetName(String sheetName) { + this.sheetName = sheetName; + } + + public InputStream getInputStream() { + return inputStream; + } + + public void setInputStream(InputStream inputStream) { + this.inputStream = inputStream; + } + } +} diff --git a/src/main/java/com/alibaba/excel/annotation/ExcelColumnNum.java b/src/main/java/com/alibaba/excel/annotation/ExcelColumnNum.java index 3b3ee81..6a53efa 100644 --- a/src/main/java/com/alibaba/excel/annotation/ExcelColumnNum.java +++ b/src/main/java/com/alibaba/excel/annotation/ExcelColumnNum.java @@ -1,17 +1,13 @@ package com.alibaba.excel.annotation; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import java.lang.annotation.*; /** * Created by jipengfei on 17/3/19. * Field column num at excel head * * @author jipengfei - * + * @date 2017/03/19 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @@ -20,16 +16,16 @@ public @interface ExcelColumnNum { /** * col num - * @return col num + * @return */ int value(); /** * - * Default @see com.alibaba.TypeUtil + * Default @see com.alibaba.excel.util.TypeUtil * if default is not meet you can set format * - * @return format + * @return */ String format() default ""; } diff --git a/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java b/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java index 2d2d355..cc3afc8 100644 --- a/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java +++ b/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java @@ -1,10 +1,6 @@ package com.alibaba.excel.annotation; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import java.lang.annotation.*; /** * @author jipengfei @@ -15,24 +11,22 @@ import java.lang.annotation.Target; public @interface ExcelProperty { /** - * 某列表头值 - * @return 表头值 + * @return */ String[] value() default {""}; /** - * 列顺序,越小越靠前 - * @return 列顺序 + * @return */ int index() default 99999; /** * - * default @see com.alibaba.TypeUtil + * default @see com.alibaba.excel.util.TypeUtil * if default is not meet you can set format * - * @return 日期格式化 + * @return */ String format() default ""; } diff --git a/src/main/java/com/alibaba/excel/annotation/FieldType.java b/src/main/java/com/alibaba/excel/annotation/FieldType.java index 8d2e57b..e5dc48d 100644 --- a/src/main/java/com/alibaba/excel/annotation/FieldType.java +++ b/src/main/java/com/alibaba/excel/annotation/FieldType.java @@ -3,7 +3,7 @@ package com.alibaba.excel.annotation; /** * * @author jipengfei - * + * @date 2017/03/15 */ public enum FieldType { diff --git a/src/main/java/com/alibaba/excel/util/ExcelXmlConstants.java b/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java similarity index 88% rename from src/main/java/com/alibaba/excel/util/ExcelXmlConstants.java rename to src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java index b9c42af..8403f9e 100644 --- a/src/main/java/com/alibaba/excel/util/ExcelXmlConstants.java +++ b/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java @@ -1,8 +1,8 @@ -package com.alibaba.excel.util; +package com.alibaba.excel.constant; /** * @author jipengfei - * + * @date 2017/08/24 */ public class ExcelXmlConstants { public static final String DIMENSION = "dimension"; diff --git a/src/main/java/com/alibaba/excel/read/context/AnalysisContext.java b/src/main/java/com/alibaba/excel/context/AnalysisContext.java similarity index 58% rename from src/main/java/com/alibaba/excel/read/context/AnalysisContext.java rename to src/main/java/com/alibaba/excel/context/AnalysisContext.java index 49b1bee..2f6b8ac 100644 --- a/src/main/java/com/alibaba/excel/read/context/AnalysisContext.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContext.java @@ -1,140 +1,123 @@ -package com.alibaba.excel.read.context; +package com.alibaba.excel.context; -import java.io.InputStream; -import java.util.List; - -import com.alibaba.excel.read.event.AnalysisEventListener; +import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.BaseRowModel; import com.alibaba.excel.metadata.ExcelHeadProperty; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.support.ExcelTypeEnum; +import java.io.InputStream; +import java.util.List; + /** - * 解析文件上下文 * * @author jipengfei */ public interface AnalysisContext { /** - * 返回用户自定义数据 * - * @return 返回用户自定义数据 */ Object getCustom(); /** - * 返回当前Sheet * - * @return current read sheet + * @return current analysis sheet */ Sheet getCurrentSheet(); /** - * 设置当前解析的Sheet * - * @param sheet 入参 + * @param sheet */ void setCurrentSheet(Sheet sheet); /** - * 返回解析的Excel类型 * * @return excel type */ ExcelTypeEnum getExcelType(); /** - * 返回输入IO * * @return file io */ InputStream getInputStream(); /** - * 获取当前监听者 * - * @return listener + * @return */ AnalysisEventListener getEventListener(); /** - * 获取当前行数 * - * @return 当前行 + * @return */ Integer getCurrentRowNum(); /** - * 设置当前行数 * - * @param row 设置行号 + * @param row */ void setCurrentRowNum(Integer row); /** - * 返回当前sheet共有多少行数据,仅限07版excel * - * @return 总行数 + * @return */ - @Deprecated Integer getTotalCount(); /** - * 设置总条数 * - * @param totalCount 总行数 + * @param totalCount */ void setTotalCount(Integer totalCount); /** - * 返回表头信息 * - * @return 表头信息 + * @return */ ExcelHeadProperty getExcelHeadProperty(); /** - * 构建 ExcelHeadProperty * - * @param clazz 自定义model - * @param headOneRow 表头内容 + * @param clazz + * @param headOneRow */ void buildExcelHeadProperty(Class clazz, List headOneRow); /** - * 是否trim() * - * @return 是否trim + * @return */ boolean trim(); /** * - * @param result 解析结果 */ void setCurrentRowAnalysisResult(Object result); + /** * - * @return 当前行解析结果 */ Object getCurrentRowAnalysisResult(); /** - * 中断 + * */ void interrupt(); /** * - * @return 是否use1904WindowDate + * @return */ boolean use1904WindowDate(); /** * - * @param use1904WindowDate 是否use1904WindowDate + * @param use1904WindowDate */ void setUse1904WindowDate(boolean use1904WindowDate); } diff --git a/src/main/java/com/alibaba/excel/read/context/AnalysisContextImpl.java b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java similarity index 94% rename from src/main/java/com/alibaba/excel/read/context/AnalysisContextImpl.java rename to src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java index 7da12e5..43dae67 100644 --- a/src/main/java/com/alibaba/excel/read/context/AnalysisContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java @@ -1,18 +1,17 @@ -package com.alibaba.excel.read.context; +package com.alibaba.excel.context; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -import com.alibaba.excel.read.event.AnalysisEventListener; -import com.alibaba.excel.read.exception.ExcelAnalysisException; +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; + /** - * 解析Excel上线文默认实现 * * @author jipengfei */ diff --git a/src/main/java/com/alibaba/excel/write/context/GenerateContext.java b/src/main/java/com/alibaba/excel/context/GenerateContext.java similarity index 65% rename from src/main/java/com/alibaba/excel/write/context/GenerateContext.java rename to src/main/java/com/alibaba/excel/context/GenerateContext.java index 3ac0759..5d74b2d 100644 --- a/src/main/java/com/alibaba/excel/write/context/GenerateContext.java +++ b/src/main/java/com/alibaba/excel/context/GenerateContext.java @@ -1,14 +1,13 @@ -package com.alibaba.excel.write.context; - -import java.io.OutputStream; +package com.alibaba.excel.context; import com.alibaba.excel.metadata.ExcelHeadProperty; import com.alibaba.excel.metadata.Table; - import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; +import java.io.OutputStream; + /** * @author jipengfei */ @@ -16,58 +15,50 @@ public interface GenerateContext { /** - * 返回当前sheet - * @return current read sheet + * @return current analysis sheet */ Sheet getCurrentSheet(); /** * - * 获取表头样式 - * @return 当前行表头样式 + * @return */ CellStyle getCurrentHeadCellStyle(); /** - * 获取内容样式 - * @return 当前行内容样式 + * @return */ CellStyle getCurrentContentStyle(); /** - * 返回WorkBook - * @return 返回文件book + * @return */ Workbook getWorkbook(); /** - * 返回Io流 - * @return 返回out流 + * @return */ OutputStream getOutputStream(); /** - * 构建一个sheet * @param sheet */ void buildCurrentSheet(com.alibaba.excel.metadata.Sheet sheet); /** - * 构建一个Table * @param table */ void buildTable(Table table); /** - * 返回表头信息 - * @return 返回表头信息 + * @return */ ExcelHeadProperty getExcelHeadProperty(); /** * - * @return 是否需要表头 + * @return */ boolean needHead(); } diff --git a/src/main/java/com/alibaba/excel/write/context/GenerateContextImpl.java b/src/main/java/com/alibaba/excel/context/GenerateContextImpl.java similarity index 82% rename from src/main/java/com/alibaba/excel/write/context/GenerateContextImpl.java rename to src/main/java/com/alibaba/excel/context/GenerateContextImpl.java index 9e0ab62..9c2f171 100644 --- a/src/main/java/com/alibaba/excel/write/context/GenerateContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/GenerateContextImpl.java @@ -1,34 +1,26 @@ -package com.alibaba.excel.write.context; +package com.alibaba.excel.context; -import java.io.OutputStream; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import com.alibaba.excel.metadata.BaseRowModel; +import com.alibaba.excel.metadata.*; import com.alibaba.excel.metadata.CellRange; -import com.alibaba.excel.metadata.ExcelHeadProperty; import com.alibaba.excel.metadata.Table; -import com.alibaba.excel.metadata.TableStyle; import com.alibaba.excel.support.ExcelTypeEnum; - import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.BorderStyle; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.Font; -import org.apache.poi.ss.usermodel.HorizontalAlignment; -import org.apache.poi.ss.usermodel.IndexedColors; -import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.VerticalAlignment; -import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +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; /** - * 生成Excel上下文 * * @author jipengfei */ @@ -58,11 +50,20 @@ public class GenerateContextImpl implements GenerateContext { private boolean needHead = true; - public GenerateContextImpl(OutputStream out, ExcelTypeEnum excelType, boolean needHead) { + public GenerateContextImpl(InputStream templateInputStream, OutputStream out, ExcelTypeEnum excelType, + boolean needHead) throws IOException { if (ExcelTypeEnum.XLS.equals(excelType)) { - this.workbook = new HSSFWorkbook(); + if(templateInputStream == null) { + this.workbook = new HSSFWorkbook(); + }else { + this.workbook = new HSSFWorkbook(new POIFSFileSystem(templateInputStream)); + } } else { - this.workbook = new SXSSFWorkbook(500); + if(templateInputStream == null) { + this.workbook = new SXSSFWorkbook(500); + }else { + this.workbook = new SXSSFWorkbook(new XSSFWorkbook(templateInputStream)); + } } this.outputStream = out; this.defaultCellStyle = buildDefaultCellStyle(); @@ -91,9 +92,22 @@ public class GenerateContextImpl implements GenerateContext { if (sheetMap.containsKey(sheet.getSheetNo())) { this.currentSheet = sheetMap.get(sheet.getSheetNo()); } else { - this.currentSheet = workbook.createSheet( - sheet.getSheetName() != null ? sheet.getSheetName() : sheet.getSheetNo() + ""); - this.currentSheet.setDefaultColumnWidth(20); + Sheet sheet1 = null; + try { + sheet1 = workbook.getSheetAt(sheet.getSheetNo()); + }catch (Exception e){ + + } + if(sheet1 == null) { + this.currentSheet = workbook.createSheet( + sheet.getSheetName() != null ? sheet.getSheetName() : sheet.getSheetNo() + ""); + this.currentSheet.setDefaultColumnWidth(20); + for (Map.Entry entry : sheet.getColumnWidthMap().entrySet()) { + currentSheet.setColumnWidth(entry.getKey(), entry.getValue()); + } + }else { + this.currentSheet = sheet1; + } sheetMap.put(sheet.getSheetNo(), this.currentSheet); buildHead(sheet.getHead(), sheet.getClazz()); buildTableStyle(sheet.getTableStyle()); diff --git a/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java b/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java new file mode 100644 index 0000000..2a30da4 --- /dev/null +++ b/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java @@ -0,0 +1,26 @@ +package com.alibaba.excel.event; + +import com.alibaba.excel.context.AnalysisContext; + +/** + * + * + * @author jipengfei + */ +public abstract class AnalysisEventListener { + + /** + * when analysis one row trigger invoke function + * + * @param object one row data + * @param context analysis context + */ + public abstract void invoke(T object, AnalysisContext context); + + /** + * if have something to do after all analysis + * + * @param context + */ + public abstract void doAfterAllAnalysed(AnalysisContext context); +} diff --git a/src/main/java/com/alibaba/excel/read/event/AnalysisEventRegisterCenter.java b/src/main/java/com/alibaba/excel/event/AnalysisEventRegisterCenter.java similarity index 55% rename from src/main/java/com/alibaba/excel/read/event/AnalysisEventRegisterCenter.java rename to src/main/java/com/alibaba/excel/event/AnalysisEventRegisterCenter.java index cfa10ae..5c557ec 100644 --- a/src/main/java/com/alibaba/excel/read/event/AnalysisEventRegisterCenter.java +++ b/src/main/java/com/alibaba/excel/event/AnalysisEventRegisterCenter.java @@ -1,29 +1,25 @@ -package com.alibaba.excel.read.event; +package com.alibaba.excel.event; /** - * 管理每个监听者 * * @author jipengfei */ public interface AnalysisEventRegisterCenter { /** - * 增加监听者 - * @param name 名称 - * @param listener 监听器 + * @param name + * @param listener */ void appendLister(String name, AnalysisEventListener listener); /** - * 通知所有监听者 - * @param event 事件 + * @param event */ void notifyListeners(OneRowAnalysisFinishEvent event); /** - * 清空所有监听者 */ void cleanAllListeners(); } diff --git a/src/main/java/com/alibaba/excel/read/event/OneRowAnalysisFinishEvent.java b/src/main/java/com/alibaba/excel/event/OneRowAnalysisFinishEvent.java similarity index 85% rename from src/main/java/com/alibaba/excel/read/event/OneRowAnalysisFinishEvent.java rename to src/main/java/com/alibaba/excel/event/OneRowAnalysisFinishEvent.java index 277472b..a9e9966 100644 --- a/src/main/java/com/alibaba/excel/read/event/OneRowAnalysisFinishEvent.java +++ b/src/main/java/com/alibaba/excel/event/OneRowAnalysisFinishEvent.java @@ -1,7 +1,8 @@ -package com.alibaba.excel.read.event; +package com.alibaba.excel.event; /** * @author jipengfei + * @date 2017/07/21 */ public class OneRowAnalysisFinishEvent { diff --git a/src/main/java/com/alibaba/excel/read/exception/ExcelAnalysisException.java b/src/main/java/com/alibaba/excel/exception/ExcelAnalysisException.java similarity index 84% rename from src/main/java/com/alibaba/excel/read/exception/ExcelAnalysisException.java rename to src/main/java/com/alibaba/excel/exception/ExcelAnalysisException.java index f5150eb..80d7a25 100644 --- a/src/main/java/com/alibaba/excel/read/exception/ExcelAnalysisException.java +++ b/src/main/java/com/alibaba/excel/exception/ExcelAnalysisException.java @@ -1,7 +1,6 @@ -package com.alibaba.excel.read.exception; +package com.alibaba.excel.exception; /** - * Excel解析时候封装的异常 * * @author jipengfei */ diff --git a/src/main/java/com/alibaba/excel/write/exception/ExcelGenerateException.java b/src/main/java/com/alibaba/excel/exception/ExcelGenerateException.java similarity index 83% rename from src/main/java/com/alibaba/excel/write/exception/ExcelGenerateException.java rename to src/main/java/com/alibaba/excel/exception/ExcelGenerateException.java index 69eea6b..b2a4900 100644 --- a/src/main/java/com/alibaba/excel/write/exception/ExcelGenerateException.java +++ b/src/main/java/com/alibaba/excel/exception/ExcelGenerateException.java @@ -1,7 +1,6 @@ -package com.alibaba.excel.write.exception; +package com.alibaba.excel.exception; /** - * 生成Excel封装的异常 * @author jipengfei */ public class ExcelGenerateException extends RuntimeException { @@ -18,4 +17,5 @@ public class ExcelGenerateException extends RuntimeException { public ExcelGenerateException(Throwable cause) { super(cause); } + } diff --git a/src/main/java/com/alibaba/excel/metadata/BaseRowModel.java b/src/main/java/com/alibaba/excel/metadata/BaseRowModel.java index 744bc0a..963b9da 100644 --- a/src/main/java/com/alibaba/excel/metadata/BaseRowModel.java +++ b/src/main/java/com/alibaba/excel/metadata/BaseRowModel.java @@ -1,9 +1,34 @@ package com.alibaba.excel.metadata; +import org.apache.poi.ss.usermodel.CellStyle; + +import java.util.HashMap; +import java.util.Map; + /** * Excel基础模型 * @author jipengfei */ public class BaseRowModel { + /** + * 每列样式 + */ + private Map cellStyleMap = new HashMap(); + + public void addStyle(Integer row, CellStyle cellStyle){ + cellStyleMap.put(row,cellStyle); + } + + public CellStyle getStyle(Integer row){ + return cellStyleMap.get(row); + } + + public Map getCellStyleMap() { + return cellStyleMap; + } + + public void setCellStyleMap(Map cellStyleMap) { + this.cellStyleMap = cellStyleMap; + } } diff --git a/src/main/java/com/alibaba/excel/metadata/CellRange.java b/src/main/java/com/alibaba/excel/metadata/CellRange.java index 6805526..7fac539 100644 --- a/src/main/java/com/alibaba/excel/metadata/CellRange.java +++ b/src/main/java/com/alibaba/excel/metadata/CellRange.java @@ -2,6 +2,7 @@ package com.alibaba.excel.metadata; /** * @author jipengfei + * @date 2017/06/02 */ public class CellRange { diff --git a/src/main/java/com/alibaba/excel/metadata/ExcelColumnProperty.java b/src/main/java/com/alibaba/excel/metadata/ExcelColumnProperty.java index d8ece78..8b3ed71 100644 --- a/src/main/java/com/alibaba/excel/metadata/ExcelColumnProperty.java +++ b/src/main/java/com/alibaba/excel/metadata/ExcelColumnProperty.java @@ -6,26 +6,23 @@ import java.util.List; /** * @author jipengfei + * @date 2017/05/31 */ public class ExcelColumnProperty implements Comparable { /** - * 列对应的Class field字段 */ private Field field; /** - * 列顺序 默认很大 */ private int index = 99999; /** - * 该列对应的表头 */ private List head = new ArrayList(); /** - * 日期类型format 如:"yyyy-MM-dd HH:mm:ss" */ private String format; diff --git a/src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java b/src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java index 9a8508e..675c1a4 100644 --- a/src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java +++ b/src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java @@ -1,40 +1,31 @@ package com.alibaba.excel.metadata; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.alibaba.excel.annotation.ExcelColumnNum; import com.alibaba.excel.annotation.ExcelProperty; +import java.lang.reflect.Field; +import java.util.*; + /** - * 表头信息 * * @author jipengfei + * @date 2017/05/31 */ public class ExcelHeadProperty { /** - * 表头数据对应的Class */ private Class headClazz; /** - * 表头名称 */ private List> head = new ArrayList>(); /** - * Excel每列表头数据 */ private List columnPropertyList = new ArrayList(); /** - * key:Excel列号,value:表头数据 */ private Map excelColumnPropertyMap1 = new HashMap(); @@ -45,7 +36,6 @@ public class ExcelHeadProperty { } /** - * 初始化每列 */ private void initColumnProperties() { if (this.headClazz != null) { @@ -66,7 +56,6 @@ public class ExcelHeadProperty { } /** - * 初始化一列 * * @param f */ @@ -97,9 +86,7 @@ public class ExcelHeadProperty { } /** - * 将表头的一行数据,转换为一列一列形式,组成表头 * - * @param row 表头中的一行数据 */ public void appendOneRow(List row) { @@ -117,10 +104,9 @@ public class ExcelHeadProperty { } /** - * 根据Excel中的列号,获取Excel的表头信息 * - * @param columnNum 列号 - * @return ExcelColumnProperty + * @param columnNum + * @return */ public ExcelColumnProperty getExcelColumnProperty(int columnNum) { ExcelColumnProperty excelColumnProperty = excelColumnPropertyMap1.get(columnNum); @@ -138,18 +124,6 @@ public class ExcelHeadProperty { } /** - * 根据Excel中的列号,获取Excel的表头信息 - * - * @param columnNum 列号 - * @return ExcelColumnProperty - */ - public ExcelColumnProperty getExcelColumnProperty1(int columnNum) { - return excelColumnPropertyMap1.get(columnNum); - - } - - /** - * 判断表头是否相同 * * @param columnHead * @param head diff --git a/src/main/java/com/alibaba/excel/metadata/Font.java b/src/main/java/com/alibaba/excel/metadata/Font.java index f5453e1..3eea50b 100644 --- a/src/main/java/com/alibaba/excel/metadata/Font.java +++ b/src/main/java/com/alibaba/excel/metadata/Font.java @@ -1,24 +1,21 @@ package com.alibaba.excel.metadata; /** - * 字体样式 * * @author jipengfei + * @date 2017/05/24 */ public class Font { /** - * 字体名称,如:宋体、黑体 */ private String fontName; /** - * 字体大小 */ private short fontHeightInPoints; /** - * 是否加粗 */ private boolean bold; diff --git a/src/main/java/com/alibaba/excel/metadata/Sheet.java b/src/main/java/com/alibaba/excel/metadata/Sheet.java index 2db84a0..f282800 100644 --- a/src/main/java/com/alibaba/excel/metadata/Sheet.java +++ b/src/main/java/com/alibaba/excel/metadata/Sheet.java @@ -1,36 +1,32 @@ package com.alibaba.excel.metadata; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** - * Sheet参数 * * @author jipengfei */ public class Sheet { /** - * 表头行数 */ private int headLineMun; /** - * sheet序号 从0开始 */ private int sheetNo; /** - * 名称 可不填 */ private String sheetName; /** - * 对用的表头模型 */ private Class clazz; /** - * 对用的表头层级树,用于clazz不确定时候,动态生成表头 */ private List> head; @@ -39,6 +35,22 @@ public class Sheet { */ private TableStyle tableStyle; + /** + * column with + */ + private Map columnWidthMap = new HashMap(); + + /** + * + */ + private Boolean autoWidth = Boolean.FALSE; + + /** + * + */ + private int startRow = -1; + + public Sheet(int sheetNo) { this.sheetNo = sheetNo; } @@ -114,6 +126,16 @@ public class Sheet { this.tableStyle = tableStyle; } + + + public Map getColumnWidthMap() { + return columnWidthMap; + } + + public void setColumnWidthMap(Map columnWidthMap) { + this.columnWidthMap = columnWidthMap; + } + @Override public String toString() { return "Sheet{" + @@ -123,6 +145,23 @@ public class Sheet { ", clazz=" + clazz + ", head=" + head + ", tableStyle=" + tableStyle + + ", columnWidthMap=" + columnWidthMap + '}'; } + + public Boolean getAutoWidth() { + return autoWidth; + } + + public void setAutoWidth(Boolean autoWidth) { + this.autoWidth = autoWidth; + } + + public int getStartRow() { + return startRow; + } + + public void setStartRow(int startRow) { + this.startRow = startRow; + } } diff --git a/src/main/java/com/alibaba/excel/metadata/Table.java b/src/main/java/com/alibaba/excel/metadata/Table.java index a2f9290..c4b3a8e 100644 --- a/src/main/java/com/alibaba/excel/metadata/Table.java +++ b/src/main/java/com/alibaba/excel/metadata/Table.java @@ -4,25 +4,22 @@ import java.util.List; /** * @author jipengfei + * @date 2017/05/16 */ public class Table { /** - * 对用的表头模型 */ private Class clazz; /** - * 对用的表头层级树,用于clazz不确定时候,动态生成表头 */ private List> head; /** - * 第几个table,用于和其他table区分 */ private Integer tableNo; /** - * 支持表格简单样式自定义 */ private TableStyle tableStyle; diff --git a/src/main/java/com/alibaba/excel/metadata/TableStyle.java b/src/main/java/com/alibaba/excel/metadata/TableStyle.java index 228019c..6618197 100644 --- a/src/main/java/com/alibaba/excel/metadata/TableStyle.java +++ b/src/main/java/com/alibaba/excel/metadata/TableStyle.java @@ -4,6 +4,7 @@ import org.apache.poi.ss.usermodel.IndexedColors; /** * @author jipengfei + * @date 2017/05/24 */ public class TableStyle { diff --git a/src/main/java/com/alibaba/excel/read/modelbuild/ModelBuildEventListener.java b/src/main/java/com/alibaba/excel/modelbuild/ModelBuildEventListener.java similarity index 87% rename from src/main/java/com/alibaba/excel/read/modelbuild/ModelBuildEventListener.java rename to src/main/java/com/alibaba/excel/modelbuild/ModelBuildEventListener.java index 3a4b8dc..b998603 100644 --- a/src/main/java/com/alibaba/excel/read/modelbuild/ModelBuildEventListener.java +++ b/src/main/java/com/alibaba/excel/modelbuild/ModelBuildEventListener.java @@ -1,18 +1,16 @@ -package com.alibaba.excel.read.modelbuild; +package com.alibaba.excel.modelbuild; -import java.util.List; - -import com.alibaba.excel.read.context.AnalysisContext; -import com.alibaba.excel.read.event.AnalysisEventListener; -import com.alibaba.excel.write.exception.ExcelGenerateException; +import com.alibaba.excel.context.AnalysisContext; +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 org.apache.commons.beanutils.BeanUtils; +import java.util.List; + /** - * 监听POI Sax解析的每行结果 * * @author jipengfei */ @@ -43,7 +41,7 @@ public class ModelBuildEventListener extends AnalysisEventListener { } if (excelHeadProperty != null) { for (int i = 0; i < stringList.size(); i++) { - ExcelColumnProperty columnProperty = excelHeadProperty.getExcelColumnProperty1(i); + ExcelColumnProperty columnProperty = excelHeadProperty.getExcelColumnProperty(i); if (columnProperty != null) { Object value = TypeUtil.convert(stringList.get(i), columnProperty.getField(), columnProperty.getFormat(),context.use1904WindowDate()); diff --git a/src/main/java/com/alibaba/excel/parameter/AnalysisParam.java b/src/main/java/com/alibaba/excel/parameter/AnalysisParam.java new file mode 100644 index 0000000..2f0cc59 --- /dev/null +++ b/src/main/java/com/alibaba/excel/parameter/AnalysisParam.java @@ -0,0 +1,58 @@ +package com.alibaba.excel.parameter; + +import com.alibaba.excel.support.ExcelTypeEnum; + +import java.io.InputStream; + +/** + * + * @author jipengfei + */ +@Deprecated +public class AnalysisParam { + + /** + * @see ExcelTypeEnum + */ + private ExcelTypeEnum excelTypeEnum; + + /** + * file in + */ + private InputStream in; + + /** + * user defined param to listener use + */ + private Object customContent; + + public AnalysisParam(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent) { + this.in = in; + this.excelTypeEnum = excelTypeEnum; + this.customContent = customContent; + } + + public ExcelTypeEnum getExcelTypeEnum() { + return excelTypeEnum; + } + + public void setExcelTypeEnum(ExcelTypeEnum excelTypeEnum) { + this.excelTypeEnum = excelTypeEnum; + } + + public Object getCustomContent() { + return customContent; + } + + public void setCustomContent(Object customContent) { + this.customContent = customContent; + } + + public InputStream getIn() { + return in; + } + + public void setIn(InputStream in) { + this.in = in; + } +} diff --git a/src/main/java/com/alibaba/excel/parameter/ExcelWriteParam.java b/src/main/java/com/alibaba/excel/parameter/ExcelWriteParam.java new file mode 100644 index 0000000..53e5d50 --- /dev/null +++ b/src/main/java/com/alibaba/excel/parameter/ExcelWriteParam.java @@ -0,0 +1,45 @@ +package com.alibaba.excel.parameter; + +import com.alibaba.excel.support.ExcelTypeEnum; + +import java.io.OutputStream; + +/** + * {@link com.alibaba.excel.ExcelWriter} + * + * @author jipengfei + * @date 2017/05/15 + */ +@Deprecated +public class ExcelWriteParam { + + /** + */ + private OutputStream outputStream; + + /** + */ + private ExcelTypeEnum type; + + public ExcelWriteParam(OutputStream outputStream, ExcelTypeEnum type) { + this.outputStream = outputStream; + this.type = type; + + } + + public OutputStream getOutputStream() { + return outputStream; + } + + public void setOutputStream(OutputStream outputStream) { + this.outputStream = outputStream; + } + + public ExcelTypeEnum getType() { + return type; + } + + public void setType(ExcelTypeEnum type) { + this.type = type; + } +} diff --git a/src/main/java/com/alibaba/excel/parameter/GenerateParam.java b/src/main/java/com/alibaba/excel/parameter/GenerateParam.java new file mode 100644 index 0000000..00910e6 --- /dev/null +++ b/src/main/java/com/alibaba/excel/parameter/GenerateParam.java @@ -0,0 +1,58 @@ +package com.alibaba.excel.parameter; + +import com.alibaba.excel.support.ExcelTypeEnum; + +import java.io.OutputStream; + +/** + * Created by jipengfei on 17/2/19. + */ +public class GenerateParam { + + private OutputStream outputStream; + + private String sheetName; + + private Class clazz; + + private ExcelTypeEnum type; + + public GenerateParam(String sheetName, Class clazz, OutputStream outputStream) { + this.outputStream = outputStream; + this.sheetName = sheetName; + this.clazz = clazz; + } + + public OutputStream getOutputStream() { + return outputStream; + } + + public void setOutputStream(OutputStream outputStream) { + this.outputStream = outputStream; + } + + + public String getSheetName() { + return sheetName; + } + + public void setSheetName(String sheetName) { + this.sheetName = sheetName; + } + + public Class getClazz() { + return clazz; + } + + public void setClazz(Class clazz) { + this.clazz = clazz; + } + + public ExcelTypeEnum getType() { + return type; + } + + public void setType(ExcelTypeEnum type) { + this.type = type; + } +} diff --git a/src/main/java/com/alibaba/excel/read/ExcelAnalyser.java b/src/main/java/com/alibaba/excel/read/ExcelAnalyser.java deleted file mode 100644 index 0f7f17a..0000000 --- a/src/main/java/com/alibaba/excel/read/ExcelAnalyser.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.alibaba.excel.read; - -import java.io.InputStream; -import java.util.List; - -import com.alibaba.excel.read.event.AnalysisEventListener; -import com.alibaba.excel.metadata.Sheet; -import com.alibaba.excel.support.ExcelTypeEnum; - -/** - * Excel解析器 - * - * @author jipengfei - */ -public interface ExcelAnalyser { - - /** - * Excel解析初始化 - * - * @param inputStream 解析为文件流 - * @param excelTypeEnum 解析文件类型 - * @param custom 用户自定义参数用户回调时候可以获取到 - * @param eventListener 解析器需要的监听器 - * @param trim 是否去空格 - */ - void init(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom, AnalysisEventListener eventListener, - boolean trim); - - /** - * 解析指定sheet,{@link AnalysisEventListener}监听中使用 - * - * @param sheetParam 入参 - */ - void analysis(Sheet sheetParam); - - - /** - * - * 默认解析第一个sheet,解析结果在 {@link AnalysisEventListener}监听中使用 - */ - void analysis(); - - /** - * 返回excel中包含哪些sheet - * - * @return 返回所有sheet - */ - List getSheets(); - - /** - * 关闭流 - */ - void stop(); -} diff --git a/src/main/java/com/alibaba/excel/read/SaxAnalyserV07.java b/src/main/java/com/alibaba/excel/read/SaxAnalyserV07.java deleted file mode 100644 index f3251d2..0000000 --- a/src/main/java/com/alibaba/excel/read/SaxAnalyserV07.java +++ /dev/null @@ -1,331 +0,0 @@ -package com.alibaba.excel.read; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; - -import javax.xml.parsers.ParserConfigurationException; - -import com.alibaba.excel.read.v07.RowHandler; -import com.alibaba.excel.read.v07.XmlParserFactory; -import com.alibaba.excel.read.v07.XMLTempFile; -import com.alibaba.excel.read.context.AnalysisContext; -import com.alibaba.excel.read.exception.ExcelAnalysisException; -import com.alibaba.excel.metadata.Sheet; -import com.alibaba.excel.util.FileUtil; - -import org.apache.poi.xssf.model.SharedStringsTable; -import org.apache.xmlbeans.XmlException; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr; -import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument; -import org.xml.sax.Attributes; -import org.xml.sax.ContentHandler; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -/** - * @author jipengfei - */ -public class SaxAnalyserV07 extends BaseSaxAnalyser { - - private SharedStringsTable sharedStringsTable; - - private List sharedStringList = new LinkedList(); - - private List sheetSourceList = new ArrayList(); - - private boolean use1904WindowDate = false; - - private final String path; - - private File tmpFile; - - private String workBookXMLFilePath; - - private String sharedStringXMLFilePath; - - public SaxAnalyserV07(AnalysisContext analysisContext) throws Exception { - this.analysisContext = analysisContext; - this.path = XMLTempFile.createPath(); - this.tmpFile = new File(XMLTempFile.getTmpFilePath(path)); - this.workBookXMLFilePath = XMLTempFile.getWorkBookFilePath(path); - this.sharedStringXMLFilePath = XMLTempFile.getSharedStringFilePath(path); - start(); - } - - @Override - protected void execute() { - try { - Sheet sheet = analysisContext.getCurrentSheet(); - if (!isAnalysisAllSheets(sheet)) { - if (this.sheetSourceList.size() < sheet.getSheetNo() || sheet.getSheetNo() == 0) { - return; - } - InputStream sheetInputStream = this.sheetSourceList.get(sheet.getSheetNo() - 1).getInputStream(); - parseXmlSource(sheetInputStream); - return; - } - int i = 0; - for (SheetSource sheetSource : this.sheetSourceList) { - i++; - this.analysisContext.setCurrentSheet(new Sheet(i)); - parseXmlSource(sheetSource.getInputStream()); - } - - } catch (Exception e) { - stop(); - throw new ExcelAnalysisException(e); - } finally { - - } - - } - - private boolean isAnalysisAllSheets(Sheet sheet) { - if (sheet == null) { - return true; - } - if (sheet.getSheetNo() < 0) { - return true; - } - return false; - } - - public void stop() { - for (SheetSource sheet : sheetSourceList) { - if (sheet.getInputStream() != null) { - try { - sheet.getInputStream().close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - FileUtil.deletefile(path); - } - - private void parseXmlSource(InputStream inputStream) { - try { - ContentHandler handler = new RowHandler(this, this.sharedStringsTable, this.analysisContext, - sharedStringList); - XmlParserFactory.parse(inputStream, handler); - inputStream.close(); - } catch (Exception e) { - try { - inputStream.close(); - } catch (IOException e1) { - e1.printStackTrace(); - } - throw new ExcelAnalysisException(e); - } - } - - public List getSheets() { - List sheets = new ArrayList(); - try { - int i = 1; - for (SheetSource sheetSource : this.sheetSourceList) { - Sheet sheet = new Sheet(i, 0); - sheet.setSheetName(sheetSource.getSheetName()); - i++; - sheets.add(sheet); - } - } catch (Exception e) { - stop(); - throw new ExcelAnalysisException(e); - } finally { - - } - - return sheets; - } - - private void start() throws IOException, XmlException, ParserConfigurationException, SAXException { - - createTmpFile(); - - unZipTempFile(); - - initSharedStringsTable(); - - initUse1904WindowDate(); - - initSheetSourceList(); - - } - - private void createTmpFile() throws FileNotFoundException { - FileUtil.writeFile(tmpFile, analysisContext.getInputStream()); - } - - private void unZipTempFile() throws IOException { - FileUtil.doUnZip(path, tmpFile); - } - - private void initSheetSourceList() throws IOException, ParserConfigurationException, SAXException { - this.sheetSourceList = new ArrayList(); - InputStream workbookXml = new FileInputStream(this.workBookXMLFilePath); - XmlParserFactory.parse(workbookXml, new DefaultHandler() { - - private int id = 0; - - @Override - public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException { - if (qName.toLowerCase(Locale.US).equals("sheet")) { - String name = null; - id++; - for (int i = 0; i < attrs.getLength(); i++) { - if (attrs.getLocalName(i).toLowerCase(Locale.US).equals("name")) { - name = attrs.getValue(i); - } else if (attrs.getLocalName(i).toLowerCase(Locale.US).equals("r:id")) { - //id = Integer.parseInt(attrs.getValue(i).replaceAll("rId", "")); - try { - InputStream inputStream = new FileInputStream(XMLTempFile.getSheetFilePath(path, id)); - sheetSourceList.add(new SheetSource(id, name, inputStream)); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } - } - - } - } - - }); - workbookXml.close(); - Collections.sort(sheetSourceList); - } - - private void initUse1904WindowDate() throws IOException, XmlException { - InputStream workbookXml = new FileInputStream(workBookXMLFilePath); - WorkbookDocument ctWorkbook = WorkbookDocument.Factory.parse(workbookXml); - CTWorkbook wb = ctWorkbook.getWorkbook(); - CTWorkbookPr prefix = wb.getWorkbookPr(); - if (prefix != null) { - this.use1904WindowDate = prefix.getDate1904(); - } - this.analysisContext.setUse1904WindowDate(use1904WindowDate); - workbookXml.close(); - } - - private void initSharedStringsTable() throws IOException, ParserConfigurationException, SAXException { - - InputStream inputStream = new FileInputStream(this.sharedStringXMLFilePath); - //this.sharedStringsTable = new SharedStringsTable(); - //this.sharedStringsTable.readFrom(inputStream); - - XmlParserFactory.parse(inputStream, new DefaultHandler() { - //int lastElementPosition = -1; - // - //int lastHandledElementPosition = -1; - - String beforeQName = ""; - - String currentQName = ""; - - @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) { - //if (hasSkippedEmptySharedString()) { - // sharedStringList.add(""); - //} - //if ("t".equals(qName)) { - // lastElementPosition++; - //} - if ("si".equals(qName) || "t".equals(qName)) { - beforeQName = currentQName; - currentQName = qName; - } - - } - //@Override - //public void endElement (String uri, String localName, String qName) - // throws SAXException - //{ - // if ("si".equals(qName) || "t".equals(qName)) { - // beforeQName = qName; - // currentQName = ""; - // } - //} - - //private boolean hasSkippedEmptySharedString() { - // return lastElementPosition > lastHandledElementPosition; - //} - - @Override - public void characters(char[] ch, int start, int length) { - if ("t".equals(currentQName) && ("t".equals(beforeQName))) { - String pre = sharedStringList.get(sharedStringList.size() - 1); - String str = pre + new String(ch, start, length); - sharedStringList.remove(sharedStringList.size() - 1); - sharedStringList.add(str); - }else if ("t".equals(currentQName) && ("si".equals(beforeQName))){ - sharedStringList.add(new String(ch, start, length)); - } - // lastHandledElementPosition++; - - - } - - }); - inputStream.close(); - } - - private class SheetSource implements Comparable { - - private int id; - - private String sheetName; - - private InputStream inputStream; - - public SheetSource(int id, String sheetName, InputStream inputStream) { - this.id = id; - this.sheetName = sheetName; - this.inputStream = inputStream; - } - - public String getSheetName() { - return sheetName; - } - - public void setSheetName(String sheetName) { - this.sheetName = sheetName; - } - - public InputStream getInputStream() { - return inputStream; - } - - public void setInputStream(InputStream inputStream) { - this.inputStream = inputStream; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public int compareTo(SheetSource o) { - if (o.id == this.id) { - return 0; - } else if (o.id > this.id) { - return -1; - } else { - return 1; - } - } - } - -} diff --git a/src/main/java/com/alibaba/excel/read/event/AnalysisEventListener.java b/src/main/java/com/alibaba/excel/read/event/AnalysisEventListener.java deleted file mode 100644 index 6cbfa64..0000000 --- a/src/main/java/com/alibaba/excel/read/event/AnalysisEventListener.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.alibaba.excel.read.event; - -import com.alibaba.excel.read.context.AnalysisContext; - -/** - * 监听Excel解析每行数据 - * 不能单列,每次使用new一个 - * 不能单列,每次使用new一个 - * 不能单列,每次使用new一个 - * 重要事情说三遍 - * - * @author jipengfei - */ -public abstract class AnalysisEventListener { - - /** - * when read one row trigger invoke function - * - * @param object one row data - * @param context read context - */ - public abstract void invoke(T object, AnalysisContext context); - - /** - * if have something to do after all read - * - * @param context context - */ - public abstract void doAfterAllAnalysed(AnalysisContext context); -} diff --git a/src/main/java/com/alibaba/excel/read/v07/XMLTempFile.java b/src/main/java/com/alibaba/excel/read/v07/XMLTempFile.java deleted file mode 100644 index 2811225..0000000 --- a/src/main/java/com/alibaba/excel/read/v07/XMLTempFile.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.alibaba.excel.read.v07; - -import java.io.File; -import java.security.SecureRandom; - -import com.alibaba.excel.util.EasyExcelTempFile; - -/** - * @author jipengfei - * - */ -public class XMLTempFile { - - private static final String TMP_FILE_NAME = "tmp.xlsx"; - - private static final String XL = "xl"; - - private static final String XML_WORKBOOK = "workbook.xml"; - - private static final String XML_SHARED_STRING = "sharedStrings.xml"; - - private static final String SHEET = "sheet"; - - private static final String WORK_SHEETS = "worksheets"; - - private static final SecureRandom random = new SecureRandom(); - - public static String getTmpFilePath(String path) { - return path + File.separator + TMP_FILE_NAME; - } - - public static String createPath() { - return EasyExcelTempFile.getEasyExcelTmpDir() + File.separator + random.nextLong(); - } - - public static String getWorkBookFilePath(String path) { - return path + File.separator + XL + File.separator + XML_WORKBOOK; - } - - public static String getSharedStringFilePath(String path) { - return path + File.separator + XL + File.separator + XML_SHARED_STRING; - } - - public static String getSheetFilePath(String path, int id) { - return path + File.separator + XL + File.separator + WORK_SHEETS + File.separator + SHEET + id - + ".xml"; - } -} diff --git a/src/main/java/com/alibaba/excel/read/v07/XmlParserFactory.java b/src/main/java/com/alibaba/excel/read/v07/XmlParserFactory.java deleted file mode 100644 index 5b4b113..0000000 --- a/src/main/java/com/alibaba/excel/read/v07/XmlParserFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.alibaba.excel.read.v07; - -import java.io.IOException; -import java.io.InputStream; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.xml.sax.ContentHandler; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; - -/** - * @author jipengfei - * - */ -public class XmlParserFactory { - - /** - * xml解析 - * @param inputStream - * @param contentHandler - * @throws ParserConfigurationException - * @throws SAXException - * @throws IOException - */ - public static void parse(InputStream inputStream, ContentHandler contentHandler) - throws ParserConfigurationException, SAXException, IOException { - InputSource sheetSource = new InputSource(inputStream); - SAXParserFactory saxFactory = SAXParserFactory.newInstance(); - //防止XML实体注注入 - saxFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - saxFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); - saxFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - SAXParser saxParser = saxFactory.newSAXParser(); - XMLReader xmlReader = saxParser.getXMLReader(); - xmlReader.setContentHandler(contentHandler); - xmlReader.parse(sheetSource); - } -} diff --git a/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java b/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java index 623e530..37a8478 100644 --- a/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java +++ b/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java @@ -1,7 +1,6 @@ package com.alibaba.excel.support; /** - * 支持读写的数据格式 * * @author jipengfei */ diff --git a/src/main/java/com/alibaba/excel/util/EasyExcelTempFile.java b/src/main/java/com/alibaba/excel/util/EasyExcelTempFile.java deleted file mode 100644 index 05f9113..0000000 --- a/src/main/java/com/alibaba/excel/util/EasyExcelTempFile.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.alibaba.excel.util; - -import java.io.File; - -/** - * 用于修复POI {@link org.apache.poi.util.DefaultTempFileCreationStrategy}在并发写,创建临时目录抛出异常的BUG。 - * - * @author jipengfei - */ -public class EasyExcelTempFile { - - private static final String JAVA_IO_TMPDIR = "java.io.tmpdir"; - - private static final String POIFILES = "poifiles"; - - private static final String EASY_EXCEL_FILES = "easyexcel"; - - /** - * 在创建ExcelBuilder后尝试创建临时目录,避免poi创建时候报错 - */ - public static void createPOIFilesDirectory() { - - String tmpDir = System.getProperty(JAVA_IO_TMPDIR); - if (tmpDir == null) { - throw new RuntimeException( - "Systems temporary directory not defined - set the -D" + JAVA_IO_TMPDIR + " jvm property!"); - } - File directory = new File(tmpDir, POIFILES); - if (!directory.exists()) { - syncCreatePOIFilesDirectory(directory); - } - - } - - /** - * 获取环境变量的配置 - * @return easyexcel临时目录 - */ - public static String getEasyExcelTmpDir() { - String tmpDir = System.getProperty(JAVA_IO_TMPDIR); - if (tmpDir == null) { - throw new RuntimeException( - "Systems temporary directory not defined - set the -D" + JAVA_IO_TMPDIR + " jvm property!"); - } - File directory = new File(tmpDir, EASY_EXCEL_FILES); - if (!directory.exists()) { - syncCreatePOIFilesDirectory(directory); - } - return tmpDir + File.separator + EASY_EXCEL_FILES; - } - - /** - * 如果directory 不存在则创建 - * - * @param directory - */ - private static synchronized void syncCreatePOIFilesDirectory(File directory) { - if (!directory.exists()) { - directory.mkdirs(); - } - } -} diff --git a/src/main/java/com/alibaba/excel/util/FileUtil.java b/src/main/java/com/alibaba/excel/util/FileUtil.java deleted file mode 100644 index 15408e5..0000000 --- a/src/main/java/com/alibaba/excel/util/FileUtil.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.alibaba.excel.util; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Enumeration; - -import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipFile; -import org.apache.commons.compress.utils.IOUtils; - -/** - * @author jipengfei - */ -public class FileUtil { - - private static final int BUF = 4096; - - public static boolean writeFile(File file, InputStream stream) throws FileNotFoundException { - OutputStream o = null; - try { - makeDirs(file.getAbsolutePath()); - if (!file.exists()) { - file.createNewFile(); - } - - o = new FileOutputStream(file); - byte data[] = new byte[1024]; - int length = -1; - while ((length = stream.read(data)) != -1) { - o.write(data, 0, length); - } - o.flush(); - return true; - } catch (FileNotFoundException e) { - throw new RuntimeException("FileNotFoundException occurred. ", e); - } catch (IOException e) { - throw new RuntimeException("IOException occurred. ", e); - } finally { - try { - o.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - public static boolean makeDirs(String filePath) { - String folderName = getFolderName(filePath); - if (folderName == null || "".equals(folderName)) { - return false; - } - File folder = new File(folderName); - return (folder.exists() && folder.isDirectory()) ? true : folder.mkdirs(); - } - - public static String getFolderName(String filePath) { - - if (filePath == null || "".equals(filePath)) { - return filePath; - } - int filePosi = filePath.lastIndexOf(File.separator); - return (filePosi == -1) ? "" : filePath.substring(0, filePosi); - } - - /** - * 文件解压 - * @param path - * @param file - * @return - * @throws IOException - */ - public static boolean doUnZip(String path, File file) throws IOException { - ZipFile zipFile = new ZipFile(file, "utf-8"); - Enumeration en = zipFile.getEntries(); - ZipArchiveEntry ze; - while (en.hasMoreElements()) { - ze = en.nextElement(); - if(ze.getName().contains("../")){ - //防止目录穿越 - throw new IllegalStateException("unsecurity zipfile!"); - } - File f = new File(path, ze.getName()); - if (ze.isDirectory()) { - f.mkdirs(); - continue; - } else { f.getParentFile().mkdirs(); } - - InputStream is = zipFile.getInputStream(ze); - OutputStream os = new FileOutputStream(f); - IOUtils.copy(is, os, BUF); - is.close(); - os.close(); - } - zipFile.close(); - return true; - } - - public static void deletefile(String delpath) { - File file = new File(delpath); - // 当且仅当此抽象路径名表示的文件存在且 是一个目录时,返回 true - if (!file.isDirectory()) { - file.delete(); - } else if (file.isDirectory()) { - String[] filelist = file.list(); - for (int i = 0; i < filelist.length; i++) { - File delfile = new File(delpath + File.separator + filelist[i]); - if (!delfile.isDirectory()) { - delfile.delete(); - } else if (delfile.isDirectory()) { - deletefile(delpath + File.separator + filelist[i]); - } - } - file.delete(); - } - } - - -} diff --git a/src/main/java/com/alibaba/excel/util/IndexValueConverter.java b/src/main/java/com/alibaba/excel/util/IndexValueConverter.java index ca7e2e2..dc6f13f 100644 --- a/src/main/java/com/alibaba/excel/util/IndexValueConverter.java +++ b/src/main/java/com/alibaba/excel/util/IndexValueConverter.java @@ -1,71 +1,74 @@ -//package com.alibaba.excel.util; -// -//import java.util.ArrayList; -//import java.util.List; -//import java.util.Stack; -// -//import com.alibaba.excel.metadata.IndexValue; -// -///** -// * 去除空Cell -// * @author jipengfei -// */ -//public class IndexValueConverter { -// public static List converter(List i_list) { -// -// List tem = new ArrayList(); -// -// char[] start = {'@'}; -// int j = 0; -// for (; j < i_list.size(); j++) { -// IndexValue currentIndexValue = i_list.get(j); -// char[] currentIndex = currentIndexValue.getV_index().replaceAll("[0-9]", "").toCharArray(); -// if (j > 0) { -// start = i_list.get(j - 1).getV_index().replaceAll("[0-9]", "").toCharArray(); -// } -// int deep = subtraction26(currentIndex, start); -// int k = 0; -// for (; k < deep - 1; k++) { -// tem.add(null); -// } -// tem.add(currentIndexValue.getV_value()); -// } -// return tem; -// } -// -// private static int subtraction26(char[] currentIndex, char[] beforeIndex) { -// int result = 0; -// -// Stack currentStack = new Stack(); -// Stack beforeStack = new Stack(); -// -// for (int i = 0; i < currentIndex.length; i++) { -// currentStack.push(currentIndex[i]); -// } -// for (int i = 0; i < beforeIndex.length; i++) { -// beforeStack.push(beforeIndex[i]); -// } -// int i = 0; -// char beforeChar = '@'; -// while (!currentStack.isEmpty()) { -// char currentChar = currentStack.pop(); -// if (!beforeStack.isEmpty()) { -// beforeChar = beforeStack.pop(); -// } -// int n = currentChar - beforeChar; -// if(n<0){ -// n = n+26; -// if(!currentStack.isEmpty()){ -// char borrow = currentStack.pop(); -// char newBorrow =(char)(borrow -1); -// currentStack.push(newBorrow); -// } -// } -// result += n * Math.pow(26, i); -// i++; -// beforeChar='@'; -// } -// -// return result; -// } -//} +package com.alibaba.excel.util; + +import com.alibaba.excel.metadata.IndexValue; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * 去除空Cell + * @author jipengfei + * @date 2017/04/13 + */ +public class IndexValueConverter { + public static List converter(List i_list) { + + List tem = new ArrayList(); + + char[] start = {'@'}; + int j = 0; + for (; j < i_list.size(); j++) { + IndexValue currentIndexValue = i_list.get(j); + char[] currentIndex = currentIndexValue.getV_index().replaceAll("[0-9]", "").toCharArray(); + if (j > 0) { + start = i_list.get(j - 1).getV_index().replaceAll("[0-9]", "").toCharArray(); + } + int deep = subtraction26(currentIndex, start); + int k = 0; + for (; k < deep - 1; k++) { + tem.add(null); + } + tem.add(currentIndexValue.getV_value()); + } + return tem; + } + + private static int subtraction26(char[] currentIndex, char[] beforeIndex) { + int result = 0; + + Stack currentStack = new Stack(); + Stack berforStack = new Stack(); + + for (int i = 0; i < currentIndex.length; i++) { + currentStack.push(currentIndex[i]); + } + for (int i = 0; i < beforeIndex.length; i++) { + berforStack.push(beforeIndex[i]); + } + int i = 0; + char beforechar = '@'; + while (!currentStack.isEmpty()) { + char currentChar = currentStack.pop(); + if (!berforStack.isEmpty()) { + beforechar = berforStack.pop(); + } + int n = currentChar - beforechar; + if(n<0){ + n = n+26; + if(!currentStack.isEmpty()){ + char borrow = currentStack.pop(); + char newBorrow =(char)(borrow -1); + currentStack.push(newBorrow); + } + } + + + result += n * Math.pow(26, i); + i++; + beforechar='@'; + } + + return result; + } +} diff --git a/src/main/java/com/alibaba/excel/util/POITempFile.java b/src/main/java/com/alibaba/excel/util/POITempFile.java new file mode 100644 index 0000000..c342968 --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/POITempFile.java @@ -0,0 +1,41 @@ +package com.alibaba.excel.util; + +import java.io.File; + +/** + * + * @author jipengfei + * @date 2017/06/22 + */ +public class POITempFile { + + private static final String JAVA_IO_TMPDIR = "java.io.tmpdir"; + + private static final String POIFILES = "poifiles"; + + /** + */ + public static void createPOIFilesDirectory() { + + String tmpDir = System.getProperty(JAVA_IO_TMPDIR); + if (tmpDir == null) { + throw new RuntimeException( + "Systems temporary directory not defined - set the -D" + JAVA_IO_TMPDIR + " jvm property!"); + } + File directory = new File(tmpDir, POIFILES); + if (!directory.exists()) { + syncCreatePOIFilesDirectory(directory); + } + + } + + /** + * + * @param directory + */ + private static synchronized void syncCreatePOIFilesDirectory(File directory) { + if (!directory.exists()) { + directory.mkdirs(); + } + } +} diff --git a/src/main/java/com/alibaba/excel/util/PositionUtils.java b/src/main/java/com/alibaba/excel/util/PositionUtils.java index 37a87dd..f5f084a 100644 --- a/src/main/java/com/alibaba/excel/util/PositionUtils.java +++ b/src/main/java/com/alibaba/excel/util/PositionUtils.java @@ -2,6 +2,7 @@ package com.alibaba.excel.util; /** * @author jipengfei + * @date 2017/08/27 */ public class PositionUtils { diff --git a/src/main/java/com/alibaba/excel/util/TypeUtil.java b/src/main/java/com/alibaba/excel/util/TypeUtil.java index 3ae92f9..dbac004 100644 --- a/src/main/java/com/alibaba/excel/util/TypeUtil.java +++ b/src/main/java/com/alibaba/excel/util/TypeUtil.java @@ -1,5 +1,7 @@ package com.alibaba.excel.util; +import org.apache.poi.hssf.usermodel.HSSFDateUtil; + import java.lang.reflect.Field; import java.math.BigDecimal; import java.text.ParseException; @@ -10,12 +12,9 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.poi.hssf.usermodel.HSSFDateUtil; - /** - * 类型转换工具类 - * * @author jipengfei + * @date 2017/03/15 */ public class TypeUtil { @@ -26,16 +25,35 @@ public class TypeUtil { DATE_FORMAT_LIST.add(new SimpleDateFormat("yyyy-MM-dd 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 (isNotEmpty(value)) { if (String.class.equals(field.getType())) { - return value; + return TypeUtil.formatFloat(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())) { - return Double.parseDouble(value); + 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(); @@ -68,6 +86,27 @@ public class TypeUtil { return null; } + public static Boolean isNum(Field field) { + if (field == null) { + return false; + } + if (Integer.class.equals(field.getType()) || int.class.equals(field.getType())) { + return true; + } + if (Double.class.equals(field.getType()) || double.class.equals(field.getType())) { + return true; + } + + if (Long.class.equals(field.getType()) || long.class.equals(field.getType())) { + return true; + } + + if (BigDecimal.class.equals(field.getType())) { + return true; + } + return false; + } + public static String getDefaultDateString(Date date) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return simpleDateFormat.format(date); @@ -102,7 +141,7 @@ public class TypeUtil { } - private static Boolean isNotEmpty(String value) { + public static Boolean isNotEmpty(String value) { if (value == null) { return false; } @@ -114,7 +153,7 @@ public class TypeUtil { } public static String formatFloat(String value) { - if (value.contains(".")) { + if (null != value && value.contains(".")) { if (isNumeric(value)) { try { BigDecimal decimal = new BigDecimal(value); @@ -127,6 +166,20 @@ public class TypeUtil { return value; } + public static String formatFloat0(String value, int n) { + if (null != value && value.contains(".")) { + if (isNumeric(value)) { + try { + BigDecimal decimal = new BigDecimal(value); + BigDecimal setScale = decimal.setScale(n, BigDecimal.ROUND_HALF_DOWN); + return setScale.toPlainString(); + } catch (Exception e) { + } + } + } + return value; + } + public static final Pattern pattern = Pattern.compile("[\\+\\-]?[\\d]+([\\.][\\d]*)?([Ee][+-]?[\\d]+)?$"); private static boolean isNumeric(String str) { @@ -137,5 +190,13 @@ public class TypeUtil { return true; } + public static String formatDate(Date cellValue, String format) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); + + return simpleDateFormat.format(cellValue); + } + public static void main(String[] args) { + System.out.println(new Date().toString()); + } } diff --git a/src/main/java/com/alibaba/excel/write/ExcelBuilder.java b/src/main/java/com/alibaba/excel/write/ExcelBuilder.java index 4385ea8..75acb58 100644 --- a/src/main/java/com/alibaba/excel/write/ExcelBuilder.java +++ b/src/main/java/com/alibaba/excel/write/ExcelBuilder.java @@ -1,54 +1,31 @@ package com.alibaba.excel.write; -import java.io.OutputStream; -import java.util.List; - import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Table; import com.alibaba.excel.support.ExcelTypeEnum; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; + /** - * Excel构建器 * * @author jipengfei */ public interface ExcelBuilder { - /** - * 初始化Excel构造器 - * - * @param out 文件输出流 - * @param excelType 输出Excel类型,建议使用07版xlsx(性能,内存消耗,cpu使用都远低于03版xls) - * @param needHead 是否需要将表头写入Excel - */ - void init(OutputStream out, ExcelTypeEnum excelType, boolean needHead); - - /** - * 向Excel增加的内容 - * - * @param data 数据格式 - */ - void addContent(List data); - - /** - * 向Excel增加的内容 - * - * @param data 数据格式 - * @param sheetParam 数据写到某个sheet中 - */ + + void init(InputStream templateInputStream, OutputStream out, ExcelTypeEnum excelType, boolean needHead); + + + void addContent(List data, int startRow); + + void addContent(List data, Sheet sheetParam); - /** - * 向Excel增加的内容 - * - * @param data 数据格式 - * @param sheetParam 数据写到某个sheet中 - * @param table 写到某个sheet的某个Table - */ + void addContent(List data, Sheet sheetParam, Table table); - /** - * 关闭资源 - */ + void finish(); } diff --git a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java index 55402ab..998078d 100644 --- a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java +++ b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java @@ -1,64 +1,81 @@ package com.alibaba.excel.write; -import java.io.IOException; -import java.io.OutputStream; -import java.util.List; - -import com.alibaba.excel.write.context.GenerateContext; -import com.alibaba.excel.write.context.GenerateContextImpl; +import com.alibaba.excel.context.GenerateContext; +import com.alibaba.excel.context.GenerateContextImpl; +import com.alibaba.excel.metadata.BaseRowModel; import com.alibaba.excel.metadata.ExcelColumnProperty; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Table; import com.alibaba.excel.support.ExcelTypeEnum; -import com.alibaba.excel.util.EasyExcelTempFile; - -import org.apache.commons.beanutils.BeanUtils; +import com.alibaba.excel.util.POITempFile; +import com.alibaba.excel.util.TypeUtil; +import org.apache.commons.beanutils.BeanUtilsBean; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Date; +import java.util.List; + /** * @author jipengfei + * @date 2017/05/27 */ public class ExcelBuilderImpl implements ExcelBuilder { private GenerateContext context; - public void init(OutputStream out, ExcelTypeEnum excelType, boolean needHead) { - //初始化时候创建临时缓存目录,用于规避POI在并发写bug - EasyExcelTempFile.createPOIFilesDirectory(); + @Override + public void init(InputStream templateInputStream, OutputStream out, ExcelTypeEnum excelType, boolean needHead) { + try { + //初始化时候创建临时缓存目录,用于规避POI在并发写bug + POITempFile.createPOIFilesDirectory(); - context = new GenerateContextImpl(out, excelType, needHead); + context = new GenerateContextImpl(templateInputStream, out, excelType, needHead); + } catch (Exception e) { + throw new RuntimeException(e); + } } - public void addContent(List data) { + @Override + public void addContent(List data, int startRow) { if (data != null && data.size() > 0) { int rowNum = context.getCurrentSheet().getLastRowNum(); if (rowNum == 0) { Row row = context.getCurrentSheet().getRow(0); - if(row ==null) { + if (row == null) { if (context.getExcelHeadProperty() == null || !context.needHead()) { rowNum = -1; } } } + if (rowNum < startRow) { + rowNum = startRow; + } for (int i = 0; i < data.size(); i++) { int n = i + rowNum + 1; + addOneRowOfDataToExcel(data.get(i), n); } } } + @Override public void addContent(List data, Sheet sheetParam) { context.buildCurrentSheet(sheetParam); - addContent(data); + addContent(data, sheetParam.getStartRow()); } + @Override public void addContent(List data, Sheet sheetParam, Table table) { context.buildCurrentSheet(sheetParam); context.buildTable(table); - addContent(data); + addContent(data, sheetParam.getStartRow()); } + @Override public void finish() { try { context.getWorkbook().write(context.getOutputStream()); @@ -67,12 +84,25 @@ public class ExcelBuilderImpl implements ExcelBuilder { } } - private void addOneRowOfDataToExcel(List oneRowData, Row row) { + private void addOneRowOfDataToExcel(List oneRowData, Row row) { if (oneRowData != null && oneRowData.size() > 0) { for (int i = 0; i < oneRowData.size(); i++) { Cell cell = row.createCell(i); cell.setCellStyle(context.getCurrentContentStyle()); - cell.setCellValue(oneRowData.get(i)); + Object cellValue = oneRowData.get(i); + if (cellValue != null) { + if (cellValue instanceof String) { + cell.setCellValue((String)cellValue); + } else if (cellValue instanceof Integer) { + cell.setCellValue(Double.parseDouble(cellValue.toString())); + } else if (cellValue instanceof Double) { + cell.setCellValue((Double)cellValue); + } else if (cellValue instanceof Short) { + cell.setCellValue((Double.parseDouble(cellValue.toString()))); + } + } else { + cell.setCellValue((String)null); + } } } } @@ -81,26 +111,43 @@ public class ExcelBuilderImpl implements ExcelBuilder { int i = 0; for (ExcelColumnProperty excelHeadProperty : context.getExcelHeadProperty().getColumnPropertyList()) { Cell cell = row.createCell(i); - cell.setCellStyle(context.getCurrentContentStyle()); + BaseRowModel baseRowModel = (BaseRowModel)oneRowData; + if (baseRowModel.getStyle(i) != null) { + cell.setCellStyle(baseRowModel.getStyle(i)); + } else { + cell.setCellStyle(context.getCurrentContentStyle()); + } String cellValue = null; try { - cellValue = BeanUtils.getProperty(oneRowData, excelHeadProperty.getField().getName()); + Object value = BeanUtilsBean.getInstance().getPropertyUtils().getNestedProperty(oneRowData, + excelHeadProperty.getField().getName()); + + if (value instanceof Date) { + cellValue = TypeUtil.formatDate((Date)value, excelHeadProperty.getFormat()); + } else { + cellValue = BeanUtilsBean.getInstance().getConvertUtils().convert(value); + } } catch (Exception e) { e.printStackTrace(); } - if (cellValue != null) { - cell.setCellValue(cellValue); + if (TypeUtil.isNotEmpty(cellValue)) { + if (TypeUtil.isNum(excelHeadProperty.getField())) { + cell.setCellValue(Double.parseDouble(cellValue)); + } else { + cell.setCellValue(cellValue); + } } else { cell.setCellValue(""); } i++; } + } private void addOneRowOfDataToExcel(Object oneRowData, int n) { Row row = context.getCurrentSheet().createRow(n); if (oneRowData instanceof List) { - addOneRowOfDataToExcel((List)oneRowData, row); + addOneRowOfDataToExcel((List)oneRowData, row); } else { addOneRowOfDataToExcel(oneRowData, row); } diff --git a/src/test/java/function/listener/ExcelListener.java b/src/test/java/function/listener/ExcelListener.java index 1194597..d89f367 100644 --- a/src/test/java/function/listener/ExcelListener.java +++ b/src/test/java/function/listener/ExcelListener.java @@ -1,18 +1,14 @@ package function.listener; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.ArrayList; -import java.util.List; - import com.alibaba.excel.ExcelWriter; -import com.alibaba.excel.read.context.AnalysisContext; -import com.alibaba.excel.read.event.AnalysisEventListener; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.Sheet; +import java.io.*; +import java.util.ArrayList; +import java.util.List; + /** * Created by jipengfei on 17/3/14. * 解析监听器, diff --git a/src/test/java/function/read/ExelAllDataTypeTest.java b/src/test/java/function/read/ExelAllDataTypeTest.java index e8b925b..a324044 100644 --- a/src/test/java/function/read/ExelAllDataTypeTest.java +++ b/src/test/java/function/read/ExelAllDataTypeTest.java @@ -1,17 +1,16 @@ package function.read; -import java.io.IOException; -import java.io.InputStream; - import com.alibaba.excel.ExcelReader; -import com.alibaba.excel.read.event.AnalysisEventListener; +import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.support.ExcelTypeEnum; - import function.listener.ExcelListener; import junit.framework.TestCase; import org.junit.Test; +import java.io.IOException; +import java.io.InputStream; + /** * Created by jipengfei on 17/3/15. * diff --git a/src/test/java/function/read/NumTest3.java b/src/test/java/function/read/NumTest3.java index 1b96d2a..b1c8fb0 100644 --- a/src/test/java/function/read/NumTest3.java +++ b/src/test/java/function/read/NumTest3.java @@ -1,17 +1,16 @@ package function.read; -import java.io.IOException; -import java.io.InputStream; - import com.alibaba.excel.ExcelReader; -import com.alibaba.excel.read.event.AnalysisEventListener; +import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.support.ExcelTypeEnum; - import function.listener.ExcelListener; import function.model.TestModel3; import org.junit.Test; +import java.io.IOException; +import java.io.InputStream; + /** * Created by jipengfei on 17/3/19. * diff --git a/src/test/java/function/read/ReadSheets.java b/src/test/java/function/read/ReadSheets.java index 61b081b..d5e05b6 100644 --- a/src/test/java/function/read/ReadSheets.java +++ b/src/test/java/function/read/ReadSheets.java @@ -1,19 +1,18 @@ package function.read; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; - import com.alibaba.excel.ExcelReader; import com.alibaba.excel.ExcelWriter; -import com.alibaba.excel.read.event.AnalysisEventListener; +import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.support.ExcelTypeEnum; - import function.listener.ExcelListener; import org.junit.Test; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + /** * Created by jipengfei on 17/3/22. * diff --git a/src/test/java/function/read/XLSX2007FunctionTest.java b/src/test/java/function/read/XLSX2007FunctionTest.java index 0ef5e0a..8cc66d4 100644 --- a/src/test/java/function/read/XLSX2007FunctionTest.java +++ b/src/test/java/function/read/XLSX2007FunctionTest.java @@ -1,18 +1,17 @@ package function.read; -import java.io.IOException; -import java.io.InputStream; - import com.alibaba.excel.ExcelReader; -import com.alibaba.excel.read.event.AnalysisEventListener; +import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.support.ExcelTypeEnum; - import function.listener.ExcelListener; import function.model.OneRowHeadExcelModel; import junit.framework.TestCase; import org.junit.Test; +import java.io.IOException; +import java.io.InputStream; + /** * Created by jipengfei on 17/2/18. */ diff --git a/src/test/java/function/write/ExcelWriteTest1.java b/src/test/java/function/write/ExcelWriteTest1.java index fc2ab92..25618e3 100644 --- a/src/test/java/function/write/ExcelWriteTest1.java +++ b/src/test/java/function/write/ExcelWriteTest1.java @@ -1,19 +1,10 @@ package function.write; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - import com.alibaba.excel.ExcelReader; import com.alibaba.excel.ExcelWriter; -import com.alibaba.excel.read.event.AnalysisEventListener; +import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.support.ExcelTypeEnum; - import function.listener.ExcelListener; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; @@ -21,6 +12,10 @@ import org.apache.poi.xssf.streaming.SXSSFSheet; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.junit.Test; +import java.io.*; +import java.util.ArrayList; +import java.util.List; + /** * @author jipengfei * @date 2017/08/15 diff --git a/src/test/java/javamodel/IdentificationExcel.java b/src/test/java/javamodel/IdentificationExcel.java new file mode 100755 index 0000000..7abfbd7 --- /dev/null +++ b/src/test/java/javamodel/IdentificationExcel.java @@ -0,0 +1,48 @@ +package javamodel; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.metadata.BaseRowModel; + +public class IdentificationExcel extends BaseRowModel{ + @ExcelProperty(index=0) + private String materialnumber; + + @ExcelProperty(index=17) + private String unit; + + @ExcelProperty(index=42) + private String specproc; + + public String getMaterialnumber() { + return materialnumber; + } + + public void setMaterialnumber(String materialnumber) { + this.materialnumber = materialnumber; + } + + public String getUnit() { + return unit; + } + + public void setUnit(String unit) { + this.unit = unit; + } + + public String getSpecproc() { + return specproc; + } + + public void setSpecproc(String specproc) { + this.specproc = specproc; + } + + @Override + public String toString() { + return "IdentificationExcel{" + + "materialnumber='" + materialnumber + '\'' + + ", unit='" + unit + '\'' + + ", specproc='" + specproc + '\'' + + '}'; + } +} diff --git a/src/test/java/read/v03/XLS2003FunctionTest.java b/src/test/java/read/v03/XLS2003FunctionTest.java index 805c8d9..3770375 100644 --- a/src/test/java/read/v03/XLS2003FunctionTest.java +++ b/src/test/java/read/v03/XLS2003FunctionTest.java @@ -1,18 +1,17 @@ package read.v03; -import java.io.IOException; -import java.io.InputStream; - import com.alibaba.excel.ExcelReader; -import com.alibaba.excel.read.event.AnalysisEventListener; +import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.support.ExcelTypeEnum; - import function.listener.ExcelListener; import function.model.LoanInfo; import junit.framework.TestCase; import org.junit.Test; +import java.io.IOException; +import java.io.InputStream; + /** * Created by jipengfei on 17/2/19. */ diff --git a/src/test/java/read/v07/Read2007MeanWhileWrite.java b/src/test/java/read/v07/Read2007MeanWhileWrite.java index 10ecc61..15285b0 100644 --- a/src/test/java/read/v07/Read2007MeanWhileWrite.java +++ b/src/test/java/read/v07/Read2007MeanWhileWrite.java @@ -1,21 +1,20 @@ package read.v07; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; - import com.alibaba.excel.ExcelReader; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.support.ExcelTypeEnum; - import javamodel.ExcelRowJavaModel; import javamodel.ExcelRowJavaModel1; import org.junit.Test; import read.v07.listener.Excel2007NoJavaModelAnalysisListener; import read.v07.listener.Excel2007WithJavaModelAnalysisListener; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + /** * @author jipengfei * @date 2017/08/27 diff --git a/src/test/java/read/v07/Read2007Xlsx.java b/src/test/java/read/v07/Read2007Xlsx.java index fa1958e..672caef 100644 --- a/src/test/java/read/v07/Read2007Xlsx.java +++ b/src/test/java/read/v07/Read2007Xlsx.java @@ -1,21 +1,20 @@ package read.v07; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import com.alibaba.excel.ExcelReader; -import com.alibaba.excel.read.context.AnalysisContext; -import com.alibaba.excel.read.event.AnalysisEventListener; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.support.ExcelTypeEnum; - import javamodel.ExcelRowJavaModel; import javamodel.ExcelRowJavaModel1; +import javamodel.IdentificationExcel; import org.junit.Test; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + /** * @author jipengfei * @date 2017/08/27 @@ -24,7 +23,9 @@ public class Read2007Xlsx { //创建没有自定义模型,没有sheet的解析器,默认解析所有sheet解析结果以List的方式通知监听者 @Test public void noModel() { - InputStream inputStream = getInputStream("1.xlsx"); + InputStream inputStream = getInputStream("需要分批关闭客户名单 2018.8.24.xlsx"); + + final List> ll = new ArrayList>(); try { ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, new AnalysisEventListener>() { @@ -34,6 +35,7 @@ public class Read2007Xlsx { "当前sheet:" + context.getCurrentSheet().getSheetNo() + " 当前行:" + context.getCurrentRowNum() + " data:" + object); + ll.add(object); } @Override @@ -42,6 +44,21 @@ public class Read2007Xlsx { }); reader.read(); + + String aa= ""; + int i= 0; + for (List strings:ll) { + i++; + aa = aa+","+ strings.get(1)+""; + if(i==25000){ + System.out.println(aa); + aa=""; + i=0; + } + + } + System.out.println(aa); + } catch (Exception e) { e.printStackTrace(); @@ -56,12 +73,12 @@ public class Read2007Xlsx { @Test public void withJavaModel() { - InputStream inputStream = getInputStream("2007WithModel.xlsx"); + InputStream inputStream = getInputStream("2-拆分标识数据库.xlsx"); try { ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, - new AnalysisEventListener() { + new AnalysisEventListener() { @Override - public void invoke(ExcelRowJavaModel object, AnalysisContext context) { + public void invoke(IdentificationExcel object, AnalysisContext context) { System.out.println( "当前sheet:" + context.getCurrentSheet().getSheetNo() + " 当前行:" + context.getCurrentRowNum() + " data:" + object); @@ -73,7 +90,7 @@ public class Read2007Xlsx { } }); - reader.read(new Sheet(1, 2, ExcelRowJavaModel.class)); + reader.read(new Sheet(1, 1, IdentificationExcel.class)); } catch (Exception e) { e.printStackTrace(); @@ -375,14 +392,7 @@ public class Read2007Xlsx { } - public static void main(String[] args) { - List mm = new ArrayList(); - mm.add(null); - mm.add(null); - mm.add(null); - mm.add(null); - mm.removeAll(Collections.singleton(null)); - System.out.println(mm); - } + + } diff --git a/src/test/java/read/v07/listener/Excel2007NoJavaModelAnalysisListener.java b/src/test/java/read/v07/listener/Excel2007NoJavaModelAnalysisListener.java index c1334d8..85b6e76 100644 --- a/src/test/java/read/v07/listener/Excel2007NoJavaModelAnalysisListener.java +++ b/src/test/java/read/v07/listener/Excel2007NoJavaModelAnalysisListener.java @@ -1,12 +1,12 @@ package read.v07.listener; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; + import java.util.ArrayList; import java.util.List; -import com.alibaba.excel.ExcelWriter; -import com.alibaba.excel.read.context.AnalysisContext; -import com.alibaba.excel.read.event.AnalysisEventListener; - /** * @author jipengfei * @date 2017/08/27 @@ -27,7 +27,7 @@ public class Excel2007NoJavaModelAnalysisListener extends AnalysisEventListener List> ll = new ArrayList>(); ll.add((List)object); System.out.println(object); - excelWriter.write0(ll,context.getCurrentSheet()); + excelWriter.write0(ll, context.getCurrentSheet()); } public void doAfterAllAnalysed(AnalysisContext context) { diff --git a/src/test/java/read/v07/listener/Excel2007WithJavaModelAnalysisListener.java b/src/test/java/read/v07/listener/Excel2007WithJavaModelAnalysisListener.java index eb4fd52..2248a74 100644 --- a/src/test/java/read/v07/listener/Excel2007WithJavaModelAnalysisListener.java +++ b/src/test/java/read/v07/listener/Excel2007WithJavaModelAnalysisListener.java @@ -1,16 +1,15 @@ package read.v07.listener; -import java.util.ArrayList; -import java.util.List; - import com.alibaba.excel.ExcelWriter; -import com.alibaba.excel.read.context.AnalysisContext; -import com.alibaba.excel.read.event.AnalysisEventListener; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.BaseRowModel; import com.alibaba.excel.metadata.Sheet; - import javamodel.ExcelRowJavaModel; +import java.util.ArrayList; +import java.util.List; + /** * @author jipengfei * @date 2017/08/27 diff --git a/src/test/resources/1.xlsx b/src/test/resources/1.xlsx deleted file mode 100644 index 609646ce1c6b13b371862d95e635069d495e8c91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42803 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