From 6890da107e425050e20c01a4b5daed9c7d9f5f58 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Mon, 9 Sep 2019 20:26:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=A9=BA=E8=A1=8C=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=E7=A9=BA=E6=8C=87=E9=92=88=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/API.md | 60 +++++++++++++++++++ pom.xml | 2 +- quickstart.md | 9 +-- .../v07/handlers/DefaultCellHandler.java | 8 --- .../handlers/ProcessResultCellHandler.java | 8 ++- .../excel/annotation/format/NumberFormat.java | 2 +- .../listener/ModelBuildEventListener.java | 3 - .../read/metadata/holder/ReadRowHolder.java | 8 +-- .../alibaba/excel/write/ExcelBuilderImpl.java | 38 ++++++------ .../metadata/holder/AbstractWriteHolder.java | 5 +- .../test/temp/simple/HgListener.java | 35 +++++++++++ .../easyexcel/test/temp/simple/HgTest.java | 8 ++- .../easyexcel/test/temp/simple/Wirte.java | 34 +++++++---- update.md | 4 ++ 14 files changed, 168 insertions(+), 56 deletions(-) create mode 100644 docs/API.md create mode 100644 src/test/java/com/alibaba/easyexcel/test/temp/simple/HgListener.java diff --git a/docs/API.md b/docs/API.md new file mode 100644 index 0000000..032331a --- /dev/null +++ b/docs/API.md @@ -0,0 +1,60 @@ +# 详细参数介绍 +## 关于常见类解析 +* EasyExcel 入口类,用于构建开始各种操作 +* ExcelReaderBuilder ExcelWriterBuilder 构建出一个 ReadWorkbook WriteWorkbook,可以理解成一个excel对象,一个excel只要构建一个 +* ExcelReaderSheetBuilder ExcelWriterSheetBuilder 构建出一个 ReadSheet WriteSheet对象,可以理解成excel里面的一页,每一页都要构建一个 +* ReadListener 在每一行读取完毕后都会调用ReadListener来处理数据 +* WriteHandler 在每一个操作包括创建单元格、创建表格等都会调用WriteHandler来处理数据 +* 所有配置都是继承的,Workbook的配置会被Sheet继承,所以在用EasyExcel设置参数的时候,在EasyExcel...sheet()方法之前作用域是整个sheet,之后针对单个sheet +## 读 +### 注解 +* `ExcelProperty` 指定当前字段对应excel中的那一列。可以根据名字或者Index去匹配。当然也可以不写,默认第一个字段就是index=0,以此类推。千万注意,要么全部不写,要么全部用index,要么全部用名字去匹配。千万别三个混着用,除非你非常了解源代码中三个混着用怎么去排序的。 +* `ExcelIgnore` 默认所有字段都会和excel去匹配,加了这个注解会忽略该字段 +* `DateTimeFormat` 日期转换,用`String`去接收excel日期格式的数据会调用这个注解。里面的`value`参照`java.text.SimpleDateFormat` +* `NumberFormat` 数字转换,用`String`去接收excel数字格式的数据会调用这个注解。里面的`value`参照`java.text.DecimalFormat` +### 参数 +#### 通用参数 +`ReadWorkbook`,`ReadSheet` 都会有的参数,如果为空,默认使用上级。 +* `converter` 转换器,默认加载了很多转换器。也可以自定义。 +* `readListener` 监听器,在读取数据的过程中会不断的调用监听器。 +* `headRowNumber` 需要读的表格有几行头数据。默认有一行头,也就是认为第二行开始起为数据。 +* `head` 与`clazz`二选一。读取文件头对应的列表,会根据列表匹配数据,建议使用class。 +* `clazz` 与`head`二选一。读取文件的头对应的class,也可以使用注解。如果两个都不指定,则会读取全部数据。 +* `autoTrim` 字符串、表头等数据自动trim +#### ReadWorkbook(理解成excel对象)参数 +* `excelType` 当前excel的类型 默认会自动判断 +* `inputStream` 与`file`二选一。读取文件的流,如果接收到的是流就只用,不用流建议使用`file`参数。因为使用了`inputStream` easyexcel会帮忙创建临时文件,最终还是`file` +* `file` 与`inputStream`二选一。读取文件的文件。 +* `autoCloseStream` 自动关闭流。 +* `readCache` 默认小于5M用 内存,超过5M会使用 `EhCache`,这里不建议使用这个参数。 +#### ReadSheet(就是excel的一个Sheet)参数 +* `sheetNo` 需要读取Sheet的编码,建议使用这个来指定读取哪个Sheet +* `sheetName` 根据名字去匹配Sheet,excel 2003不支持根据名字去匹配 +## 写 +### 注解 +* `ExcelProperty` index 指定写到第几列,默认根据成员变量排序。`value`指定写入的名称,默认成员变量的名字,多个`value`可以参照快速开始中的复杂头 +* `ExcelIgnore` 默认所有字段都会写入excel,这个注解会忽略这个字段 +* `DateTimeFormat` 日期转换,将`Date`写到excel会调用这个注解。里面的`value`参照`java.text.SimpleDateFormat` +* `NumberFormat` 数字转换,用`Number`写excel会调用这个注解。里面的`value`参照`java.text.DecimalFormat` +### 参数 +#### 通用参数 +`WriteWorkbook`,`WriteSheet` ,`WriteTable`都会有的参数,如果为空,默认使用上级。 +* `converter` 转换器,默认加载了很多转换器。也可以自定义。 +* `writeHandler` 写的处理器。可以实现`WorkbookWriteHandler`,`SheetWriteHandler`,`RowWriteHandler`,`CellWriteHandler`,在写入excel的不同阶段会调用 +* `relativeHeadRowIndex` 距离多少行后开始。也就是开头空几行 +* `needHead` 是否导出头 +* `head` 与`clazz`二选一。写入文件的头列表,建议使用class。 +* `clazz` 与`head`二选一。写入文件的头对应的class,也可以使用注解。 +* `autoTrim` 字符串、表头等数据自动trim +#### WriteWorkbook(理解成excel对象)参数 +* `excelType` 当前excel的类型 默认`xlsx` +* `outputStream` 与`file`二选一。写入文件的流 +* `file` 与`outputStream`二选一。写入的文件 +* `templateInputStream` 模板的文件流 +* `templateFile` 模板文件 +* `autoCloseStream` 自动关闭流。 +#### WriteSheet(就是excel的一个Sheet)参数 +* `sheetNo` 需要写入的编码。默认0 +* `sheetName` 需要些的Sheet名称,默认同`sheetNo` +#### WriteTable(就把excel的一个Sheet,一块区域看一个table)参数 +* `tableNo` 需要写入的编码。默认0 \ No newline at end of file diff --git a/pom.xml b/pom.xml index cd5f0fe..0a62923 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.alibaba easyexcel - 2.0.0-beta5 + 2.0.0-beta6 jar easyexcel diff --git a/quickstart.md b/quickstart.md index 3e5dd00..27267d8 100644 --- a/quickstart.md +++ b/quickstart.md @@ -7,13 +7,8 @@ * 单个文件的并发写入、读取 * 读取图片 * 宏 -#### 关于常见类解析 -* EasyExcel 入口类,用于构建开始各种操作 -* ExcelReaderBuilder ExcelWriterBuilder 构建出一个 ReadWorkbook WriteWorkbook,可以理解成一个excel对象,一个excel只要构建一个 -* ExcelReaderSheetBuilder ExcelWriterSheetBuilder 构建出一个 ReadSheet WriteSheet对象,可以理解成excel里面的一页,每一页都要构建一个 -* ReadListener 在每一行读取完毕后都会调用ReadListener来处理数据 -* WriteHandler 在每一个操作包括创建单元格、创建表格等都会调用WriteHandler来处理数据 -* 所有配置都是继承的,Workbook的配置会被Sheet继承,所以在用EasyExcel设置参数的时候,在EasyExcel...sheet()方法之前作用域是整个sheet,之后针对单个sheet +#### 详细参数介绍 +有些参数不知道怎么用,或者有些功能不知道用什么参数,参照:[详细参数介绍](/docs/API.md) #### 开源项目不容易,如果觉得本项目对您的工作还是有帮助的话,请在右上角帮忙点个★Star。 ### 读 DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/demo/read/ReadTest.java](/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java) diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java index 92b1909..37d12ad 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java @@ -22,7 +22,6 @@ import com.alibaba.excel.constant.ExcelXmlConstants; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; -import com.alibaba.excel.read.metadata.holder.ReadRowHolder; import com.alibaba.excel.util.BooleanUtils; import com.alibaba.excel.util.PositionUtils; import com.alibaba.excel.util.StringUtils; @@ -36,7 +35,6 @@ public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder private final AnalysisContext analysisContext; private String currentTag; private String currentCellIndex; - private int curRow; private int curCol; private Map curRowContent = new TreeMap(); private CellData currentCellData; @@ -67,12 +65,6 @@ public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder // start a cell if (CELL_TAG.equals(name)) { currentCellIndex = attributes.getValue(ExcelXmlConstants.POSITION); - int nextRow = PositionUtils.getRow(currentCellIndex); - if (nextRow > curRow) { - curRow = nextRow; - } - analysisContext - .readRowHolder(new ReadRowHolder(curRow, analysisContext.readSheetHolder().getGlobalConfiguration())); curCol = PositionUtils.getCol(currentCellIndex); // t="s" ,it's means String diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java index 193cb78..419d43e 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java @@ -6,8 +6,10 @@ import org.xml.sax.Attributes; import com.alibaba.excel.analysis.v07.XlsxCellHandler; import com.alibaba.excel.analysis.v07.XlsxRowResultHolder; +import com.alibaba.excel.constant.ExcelXmlConstants; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.read.listener.event.EachRowAnalysisFinishEvent; +import com.alibaba.excel.read.metadata.holder.ReadRowHolder; /** * Cell Handler @@ -29,7 +31,11 @@ public class ProcessResultCellHandler implements XlsxCellHandler { } @Override - public void startHandle(String name, Attributes attributes) {} + public void startHandle(String name, Attributes attributes) { + analysisContext + .readRowHolder(new ReadRowHolder(Integer.valueOf(attributes.getValue(ExcelXmlConstants.POSITION)), + analysisContext.readSheetHolder().getGlobalConfiguration())); + } @Override public void endHandle(String name) { diff --git a/src/main/java/com/alibaba/excel/annotation/format/NumberFormat.java b/src/main/java/com/alibaba/excel/annotation/format/NumberFormat.java index 8951681..a58ef4f 100644 --- a/src/main/java/com/alibaba/excel/annotation/format/NumberFormat.java +++ b/src/main/java/com/alibaba/excel/annotation/format/NumberFormat.java @@ -24,7 +24,7 @@ public @interface NumberFormat { /** * - * Specific format reference {@link org.apache.commons.math3.fraction.BigFractionFormat} + * Specific format reference {@link java.text.DecimalFormat} * * @return Format pattern */ diff --git a/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java b/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java index 522369e..7896334 100644 --- a/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java +++ b/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java @@ -6,14 +6,11 @@ import java.util.List; import java.util.Map; import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.converters.Converter; -import com.alibaba.excel.converters.ConverterKeyBuild; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.enums.HeadKindEnum; import com.alibaba.excel.event.AbstractIgnoreExceptionReadListener; import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.metadata.CellData; -import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.read.metadata.holder.ReadHolder; diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java index c135c12..9916015 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java @@ -13,7 +13,7 @@ public class ReadRowHolder implements Holder { /** * Returns row index of a row in the sheet that contains this cell.Start form 0. */ - private int rowIndex; + private Integer rowIndex; /** * The result of the previous listener @@ -24,7 +24,7 @@ public class ReadRowHolder implements Holder { */ private GlobalConfiguration globalConfiguration; - public ReadRowHolder(int rowIndex, GlobalConfiguration globalConfiguration) { + public ReadRowHolder(Integer rowIndex, GlobalConfiguration globalConfiguration) { this.rowIndex = rowIndex; this.globalConfiguration = globalConfiguration; } @@ -45,11 +45,11 @@ public class ReadRowHolder implements Holder { this.currentRowAnalysisResult = currentRowAnalysisResult; } - public int getRowIndex() { + public Integer getRowIndex() { return rowIndex; } - public void setRowIndex(int rowIndex) { + public void setRowIndex(Integer rowIndex) { this.rowIndex = rowIndex; } diff --git a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java index c03c843..3c25726 100644 --- a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java +++ b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java @@ -21,6 +21,7 @@ import com.alibaba.excel.context.WriteContext; import com.alibaba.excel.context.WriteContextImpl; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.converters.ConverterKeyBuild; +import com.alibaba.excel.enums.HeadKindEnum; import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.metadata.BaseRowModel; @@ -194,25 +195,28 @@ public class ExcelBuilderImpl implements ExcelBuilder { WriteHolder currentWriteHolder = context.currentWriteHolder(); BeanMap beanMap = BeanMap.create(oneRowData); Set beanMapHandledSet = new HashSet(); - Map headMap = context.currentWriteHolder().excelWriteHeadProperty().getHeadMap(); - Map contentPropertyMap = - context.currentWriteHolder().excelWriteHeadProperty().getContentPropertyMap(); int cellIndex = 0; - for (Map.Entry entry : contentPropertyMap.entrySet()) { - cellIndex = entry.getKey(); - ExcelContentProperty excelContentProperty = entry.getValue(); - String name = excelContentProperty.getField().getName(); - if (!beanMap.containsKey(name)) { - continue; + // If it's a class it needs to be cast by type + if (HeadKindEnum.CLASS.equals(context.currentWriteHolder().excelWriteHeadProperty().getHeadKind())) { + Map headMap = context.currentWriteHolder().excelWriteHeadProperty().getHeadMap(); + Map contentPropertyMap = + context.currentWriteHolder().excelWriteHeadProperty().getContentPropertyMap(); + for (Map.Entry entry : contentPropertyMap.entrySet()) { + cellIndex = entry.getKey(); + ExcelContentProperty excelContentProperty = entry.getValue(); + String name = excelContentProperty.getField().getName(); + if (!beanMap.containsKey(name)) { + continue; + } + Head head = headMap.get(cellIndex); + beforeCellCreate(row, head, relativeRowIndex); + Cell cell = WorkBookUtil.createCell(row, cellIndex); + Object value = beanMap.get(name); + CellData cellData = converterAndSet(currentWriteHolder, excelContentProperty.getField().getType(), cell, + value, excelContentProperty); + afterCellCreate(head, cellData, cell, relativeRowIndex); + beanMapHandledSet.add(name); } - Head head = headMap.get(cellIndex); - beforeCellCreate(row, head, relativeRowIndex); - Cell cell = WorkBookUtil.createCell(row, cellIndex); - Object value = beanMap.get(name); - CellData cellData = converterAndSet(currentWriteHolder, excelContentProperty.getField().getType(), cell, - value, excelContentProperty); - afterCellCreate(head, cellData, cell, relativeRowIndex); - beanMapHandledSet.add(name); } // Finish if (beanMapHandledSet.size() == beanMap.size()) { diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java index c210f28..6592009 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java @@ -214,7 +214,6 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ return; } Map headMap = getExcelWriteHeadProperty().getHeadMap(); - Map contentPropertyMap = getExcelWriteHeadProperty().getContentPropertyMap(); boolean hasColumnWidth = false; for (Map.Entry entry : headMap.entrySet()) { @@ -227,10 +226,10 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ if (hasColumnWidth) { dealColumnWidth(handlerList); } - dealRowHigh(handlerList, contentPropertyMap); + dealRowHigh(handlerList); } - private void dealRowHigh(List handlerList, Map contentPropertyMap) { + private void dealRowHigh(List handlerList) { RowHeightProperty headRowHeightProperty = getExcelWriteHeadProperty().getHeadRowHeightProperty(); RowHeightProperty contentRowHeightProperty = getExcelWriteHeadProperty().getContentRowHeightProperty(); if (headRowHeightProperty == null && contentRowHeightProperty == null) { diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/HgListener.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/HgListener.java new file mode 100644 index 0000000..b8250ea --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/HgListener.java @@ -0,0 +1,35 @@ +package com.alibaba.easyexcel.test.temp.simple; + +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * 模板的读取类 + * + * @author Jiaju Zhuang + */ +public class HgListener extends AnalysisEventListener> { + private static final Logger LOGGER = LoggerFactory.getLogger(HgListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static final int BATCH_COUNT = 5; + + @Override + public void invoke(Map data, AnalysisContext context) { + LOGGER.info("index:{}", context.readRowHolder().getRowIndex()); + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + LOGGER.info("所有数据解析完成!"); + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/HgTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/HgTest.java index b588a11..4ece35e 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/simple/HgTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/HgTest.java @@ -24,10 +24,16 @@ public class HgTest { @Test public void hh() throws IOException { List list = - EasyExcel.read(new FileInputStream("D:\\test\\20190906192340.xlsx")).headRowNumber(0).sheet().doReadSync(); + EasyExcel.read(new FileInputStream("D:\\test\\商户不匹配工单信息收集表格.xlsx")).headRowNumber(0).sheet().doReadSync(); for (Object data : list) { LOGGER.info("返回数据:{}", JSON.toJSONString(data)); } } + @Test + public void hh2() throws IOException { + EasyExcel.read(new FileInputStream("D:\\test\\商户不匹配工单信息收集表格.xlsx")) + .registerReadListener(new HgListener()).headRowNumber(0).sheet().doRead(); + } + } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java index 62b64b5..d5a39d6 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java @@ -30,22 +30,36 @@ public class Wirte { @Test public void simpleWrite() { // 写法1 - String fileName = TestFileUtil.getPath() + "ttttttttt11" + System.currentTimeMillis() + ".xlsx"; + String fileName = TestFileUtil.getPath() + "t22" + System.currentTimeMillis() + ".xlsx"; // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 // 如果这里想使用03 则 传入excelType参数即可 - EasyExcel.write(fileName).sheet("模板").doWrite(data()); + EasyExcel.write(fileName).sheet("模板").head(head()).doWrite(data()); } - private List> data() { - List> list = new ArrayList>(); - for (int i = 0; i < 10; i++) { - List list1 = new ArrayList(); + private List> head() { + List> list = new ArrayList>(); + List head0 = new ArrayList(); + head0.add("字符串" + System.currentTimeMillis()); + List head1 = new ArrayList(); + head1.add("数字" + System.currentTimeMillis()); + List head2 = new ArrayList(); + head2.add("日期" + System.currentTimeMillis()); + list.add(head0); + list.add(head1); + list.add(head2); + return list; + } - list1.add("字符串" + i); - list1.add(new Date()); - list1.add(0.56); - list.add(list1); + private List data() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + DemoData data = new DemoData(); + data.setString("字符串" + i); + data.setDate(new Date()); + data.setDoubleData(0.56); + list.add(data); } return list; } + } diff --git a/update.md b/update.md index 6450894..60dd1ed 100644 --- a/update.md +++ b/update.md @@ -1,3 +1,7 @@ +# 2.0.0-beta6 +* 修复空行读取空指针异常 +* 修复写入指定头为List>,但是数据用List导致的空指针 + # 2.0.0-beta5 * 修复在读取值的时候读取了额外值导致数据转换异常