diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 0ff24019..4ea8cee6 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -7,6 +7,8 @@ assignees: zhuangjiaju --- +**建议先去看文档** +[快速开始](https://www.yuque.com/easyexcel/doc/easyexcel) 、[常见问题](https://www.yuque.com/easyexcel/faq) **触发场景描述** **触发Bug的代码** diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 06adf1ae..51cea2b3 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,12 +1,14 @@ --- name: question -about: 有使用疑问,请先阅读“快速使用”,上面无法解决再提交问题。处理完请关闭问题。 +about: 有使用疑问,请先阅读“快速开始”,上面无法解决再提交问题。处理完请关闭问题。 title: '' labels: help wanted assignees: '' --- +**建议先去看文档** +[快速开始](https://www.yuque.com/easyexcel/doc/easyexcel) 、[常见问题](https://www.yuque.com/easyexcel/faq) **异常代码** ```java 这里写你的代码 diff --git a/.github/ISSUE_TEMPLATE/suggest.md b/.github/ISSUE_TEMPLATE/suggest.md index cf4948d1..1aeecd86 100644 --- a/.github/ISSUE_TEMPLATE/suggest.md +++ b/.github/ISSUE_TEMPLATE/suggest.md @@ -7,4 +7,6 @@ assignees: '' --- +**建议先去看文档** +[快速开始](https://www.yuque.com/easyexcel/doc/easyexcel) 、[常见问题](https://www.yuque.com/easyexcel/faq) **建议描述** diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..724ecec4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,8 @@ +## 前言 +非常感谢您愿意协助EasyExcel的开发,EasyExcel成长离不开大家的贡献。但是为了合作的更有效率,希望我们在贡献代码的时候能按照如下约定。 +## 提前沟通 +尽量把自己的想法和实现思路提前沟通,可以通过issue,钉钉,QQ都可以,可能很多问题我们内部已经讨论过,由于各种原因后续不会支持,但是您这边又开发好了,这样容易浪费您的时间。 +## 代码规范 +目前代码规范已经集成了自动校验,然后源代码尽量不要有中文注释。在新增功能的时候,尽量注意补充junit。core代表每次travis-ci都会跑的测试案例,然后demo用于对外看到,temp里面随便写。 +## 提交分支 +建议提交到最新的版本号.x上面,比如 3.x之类的版本,为了方便其他同学阅读源代码,所以目前的思路是master和maven center的最新版本代码保持一致,然后您提交过来的代码我们可能会稍微做一些修改。所以提交到开发分支会比较好。fork也可以直接fork该分支。 diff --git a/README.md b/README.md index ecd2000b..9664d654 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,32 @@ -easyexcel +EasyExcel ====================== [![Build Status](https://travis-ci.org/alibaba/easyexcel.svg?branch=master)](https://travis-ci.org/alibaba/easyexcel) [![Maven central](https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel) [![License](http://img.shields.io/:license-apache-brightgreen.svg)](http://www.apache.org/licenses/LICENSE-2.0.html) -[QQ群: 662022184](//shang.qq.com/wpa/qunwpa?idkey=53d9d821b0833e3c14670f007488a61e300f00ff4f1b81fd950590d90dd80f80) -[钉钉群: 21960511](https://qr.dingtalk.com/action/joingroup?code=v1,k1,cchz6k12ci9B08NNqhNRFGXocNVHrZtW0kaOtTKg/Rk=&_dt_no_comment=1&origin=11) -[官方网站: https://alibaba-easyexcel.github.io/](https://alibaba-easyexcel.github.io/) +[QQ1群(已满): 662022184](https://jq.qq.com/?_wv=1027&k=1T21jJxh) +[QQ2群: 1097936804](https://jq.qq.com/?_wv=1027&k=j5zEy6Xl) +[钉钉1群(已满): 21960511](https://qr.dingtalk.com/action/joingroup?code=v1,k1,cchz6k12ci9B08NNqhNRFGXocNVHrZtW0kaOtTKg/Rk=&_dt_no_comment=1&origin=11) +[钉钉2群(已满): 32796397](https://qr.dingtalk.com/action/joingroup?code=v1,k1,jyU9GtEuNU5S0QTyklqYcYJ8qDZtUuTPMM7uPZTS8Hs=&_dt_no_comment=1&origin=11) +[钉钉3群(已满): 33797247](https://qr.dingtalk.com/action/joingroup?code=v1,k1,3UGlEScTGQaHpW2cIRo+gkxJ9EVZ5fz26M6nW3uFP30=&_dt_no_comment=1&origin=11) +[钉钉4群: 33491624](https://qr.dingtalk.com/action/joingroup?code=v1,k1,V14Pb65Too70rQkEaJ9ohb6lZBZbtp6jIL/q9EWh9vA=&_dt_no_comment=1&origin=11) +[官方网站: https://yuque.com/easyexcel](https://www.yuque.com/easyexcel/doc/easyexcel) + +[常见问题](https://www.yuque.com/easyexcel/faq) #### 因为公司不方便用QQ,所以建议加钉钉群 -# JAVA解析Excel工具easyexcel -Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便 +# JAVA解析Excel工具EasyExcel +Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便 ## 64M内存1分钟内读取75M(46W行25列)的Excel -当然还有急速模式能更快,但是内存占用会在100M多一点 +当然还有极速模式能更快,但是内存占用会在100M多一点 ![img](img/readme/large.png) ## 相关文档 -* [快速使用](https://alibaba-easyexcel.github.io/) +* [快速开始](https://www.yuque.com/easyexcel/doc/easyexcel) * [关于软件](/abouteasyexcel.md) * [更新记事](/update.md) -* [贡献代码](https://alibaba-easyexcel.github.io/support/contribute.html) +* [贡献代码](https://www.yuque.com/easyexcel/doc/contribute) ## 维护者 玉霄、庄家钜、怀宇 @@ -63,20 +69,23 @@ DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/ja ### web上传、下载 DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java](/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java) ```java - /** + /** * 文件下载(失败了会返回一个有部分数据的Excel) - *

1. 创建excel对应的实体对象 参照{@link DownloadData} - *

2. 设置返回的 参数 - *

3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大 + *

+ * 1. 创建excel对应的实体对象 参照{@link DownloadData} + *

+ * 2. 设置返回的 参数 + *

+ * 3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大 */ @GetMapping("download") public void download(HttpServletResponse response) throws IOException { // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman - response.setContentType("application/vnd.ms-excel"); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 - String fileName = URLEncoder.encode("测试", "UTF-8"); - response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); + String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data()); } diff --git a/pom.xml b/pom.xml index 51f63232..b5ae5cbf 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.alibaba easyexcel - 2.2.0-beta2 + 3.0.0-beta1 jar easyexcel @@ -16,7 +16,7 @@ UTF-8 - 1.6 + 1.8 true true @@ -60,22 +60,22 @@ org.apache.poi poi - 3.17 + 4.1.2 org.apache.poi poi-ooxml - 3.17 + 4.1.2 org.apache.poi poi-ooxml-schemas - 3.17 + 4.1.2 cglib cglib - 3.1 + 3.3.0 org.slf4j @@ -85,8 +85,15 @@ org.ehcache ehcache - 3.4.0 + 3.8.1 + + org.projectlombok + lombok + 1.18.20 + provided + + ch.qos.logback @@ -97,13 +104,7 @@ com.alibaba fastjson - 1.2.58 - test - - - org.projectlombok - lombok - 1.18.8 + 1.2.71 test @@ -121,7 +122,7 @@ junit junit - 4.12 + 4.13.1 test @@ -162,6 +163,8 @@ com/alibaba/excel/event/AnalysisEventListener.java com/alibaba/excel/metadata/DataFormatter.java com/alibaba/excel/util/DateUtils.java + com/alibaba/excel/metadata/format/DataFormatter.java + com/alibaba/excel/metadata/format/ExcelGeneralNumberFormat.java @@ -185,8 +188,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.6 - 1.6 + 1.8 + 1.8 @@ -230,6 +233,19 @@ + + org.projectlombok + lombok-maven-plugin + 1.18.20.0 + + + generate-sources + + delombok + + + + diff --git a/src/main/java/com/alibaba/excel/ExcelReader.java b/src/main/java/com/alibaba/excel/ExcelReader.java index 07a373b7..7af49eb6 100644 --- a/src/main/java/com/alibaba/excel/ExcelReader.java +++ b/src/main/java/com/alibaba/excel/ExcelReader.java @@ -136,6 +136,8 @@ public class ExcelReader { readWorkbook.setReadCache(new MapCache()); readWorkbook.setConvertAllFiled(Boolean.FALSE); readWorkbook.setDefaultReturnMap(Boolean.FALSE); + // The previous logic was that Article 0 started reading + readWorkbook.setHeadRowNumber(0); excelAnalyser = new ExcelAnalyserImpl(readWorkbook); } @@ -274,7 +276,9 @@ public class ExcelReader { * Complete the entire read file.Release the cache and close stream. */ public void finish() { - excelAnalyser.finish(); + if (excelAnalyser != null) { + excelAnalyser.finish(); + } } /** diff --git a/src/main/java/com/alibaba/excel/ExcelWriter.java b/src/main/java/com/alibaba/excel/ExcelWriter.java index a0b4795b..2f5b61d2 100644 --- a/src/main/java/com/alibaba/excel/ExcelWriter.java +++ b/src/main/java/com/alibaba/excel/ExcelWriter.java @@ -3,6 +3,8 @@ package com.alibaba.excel; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; import org.slf4j.Logger; @@ -142,7 +144,7 @@ public class ExcelWriter { * Write to this sheet * @return this current writer */ - public ExcelWriter write(List data, WriteSheet writeSheet) { + public ExcelWriter write(Collection data, WriteSheet writeSheet) { return write(data, writeSheet, null); } @@ -157,7 +159,7 @@ public class ExcelWriter { * Write to this table * @return this */ - public ExcelWriter write(List data, WriteSheet writeSheet, WriteTable writeTable) { + public ExcelWriter write(Collection data, WriteSheet writeSheet, WriteTable writeTable) { excelBuilder.addContent(data, writeSheet, writeTable); return this; } @@ -194,7 +196,7 @@ public class ExcelWriter { * @param sheet * Write to this sheet * @return this current writer - * @deprecated please use {@link ExcelWriter#write(List, WriteSheet)} + * @deprecated please use {@link ExcelWriter#write(Collection, WriteSheet)} */ @Deprecated public ExcelWriter write(List data, Sheet sheet) { @@ -211,7 +213,7 @@ public class ExcelWriter { * @param table * Write to this table * @return this - * @deprecated * @deprecated please use {@link ExcelWriter#write(List, WriteSheet,WriteTable)} + * @deprecated * @deprecated please use {@link ExcelWriter#write(Collection, WriteSheet,WriteTable)} */ @Deprecated public ExcelWriter write(List data, Sheet sheet, Table table) { @@ -246,7 +248,7 @@ public class ExcelWriter { * @param sheet * Write to this sheet * @return this current writer - * @deprecated please use {@link ExcelWriter#write(List, WriteSheet)} + * @deprecated please use {@link ExcelWriter#write(Collection, WriteSheet)} */ @Deprecated public ExcelWriter write0(List data, Sheet sheet) { @@ -263,7 +265,7 @@ public class ExcelWriter { * @param table * Write to this table * @return this - * @deprecated * @deprecated please use {@link ExcelWriter#write(List, WriteSheet,WriteTable)} + * @deprecated * @deprecated please use {@link ExcelWriter#write(Collection, WriteSheet,WriteTable)} */ @Deprecated public ExcelWriter write0(List data, Sheet sheet, Table table) { @@ -278,7 +280,7 @@ public class ExcelWriter { * @param sheet * Write to this sheet * @return this current writer - * @deprecated please use {@link ExcelWriter#write(List, WriteSheet)} + * @deprecated please use {@link ExcelWriter#write(Collection, WriteSheet)} */ @Deprecated public ExcelWriter write1(List data, Sheet sheet) { @@ -295,7 +297,7 @@ public class ExcelWriter { * @param table * Write to this table * @return this - * @deprecated * @deprecated please use {@link ExcelWriter#write(List, WriteSheet,WriteTable)} + * @deprecated * @deprecated please use {@link ExcelWriter#write(Collection, WriteSheet,WriteTable)} */ @Deprecated public ExcelWriter write1(List data, Sheet sheet, Table table) { @@ -325,7 +327,9 @@ public class ExcelWriter { * Close IO */ public void finish() { - excelBuilder.finish(false); + if (excelBuilder != null) { + excelBuilder.finish(false); + } } /** diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java index 5487ee10..e049dbfc 100644 --- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java @@ -3,6 +3,7 @@ package com.alibaba.excel.analysis; import java.io.InputStream; import java.util.List; +import org.apache.commons.collections4.CollectionUtils; import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey; import org.apache.poi.poifs.crypt.Decryptor; import org.apache.poi.poifs.filesystem.DocumentFactoryHelper; @@ -26,7 +27,6 @@ import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder; import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder; import com.alibaba.excel.support.ExcelTypeEnum; -import com.alibaba.excel.util.CollectionUtils; import com.alibaba.excel.util.DateUtils; import com.alibaba.excel.util.FileUtils; import com.alibaba.excel.util.NumberDataFormatterUtils; diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java index 2b92253e..83f98647 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java @@ -70,12 +70,12 @@ import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder; *

* * To turn an excel file into a CSV or similar, then see * the XLS2CSVmra example * *

- * * * @see XLS2CSVmra + * * * @see XLS2CSVmra * * @author jipengfei */ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { + private static final Logger LOGGER = LoggerFactory.getLogger(XlsSaxAnalyser.class); private static final short DUMMY_RECORD_SID = -1; private XlsReadContext xlsReadContext; @@ -138,11 +138,6 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { } catch (IOException e) { throw new ExcelAnalysisException(e); } - // Sometimes tables lack the end record of the last column - if (!xlsReadContext.xlsReadSheetHolder().getCellMap().isEmpty()) { - // Forge a termination data - processRecord(new LastCellOfRowDummyRecord(xlsReadContext.xlsReadSheetHolder().getRowIndex() + 1, -1)); - } } @Override @@ -151,8 +146,8 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { if (handler == null) { return; } - boolean ignoreRecord = (handler instanceof IgnorableXlsRecordHandler) - && xlsReadContext.xlsReadSheetHolder() != null && xlsReadContext.xlsReadSheetHolder().getIgnoreRecord(); + boolean ignoreRecord = + (handler instanceof IgnorableXlsRecordHandler) && xlsReadContext.xlsReadWorkbookHolder().getIgnoreRecord(); if (ignoreRecord) { // No need to read the current sheet return; diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java index 66e3ab76..3e6713c4 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java @@ -22,10 +22,11 @@ public class BofRecordHandler extends AbstractXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { - BOFRecord br = (BOFRecord)record; + BOFRecord br = (BOFRecord) record; XlsReadWorkbookHolder xlsReadWorkbookHolder = xlsReadContext.xlsReadWorkbookHolder(); if (br.getType() == BOFRecord.TYPE_WORKBOOK) { xlsReadWorkbookHolder.setReadSheetIndex(null); + xlsReadWorkbookHolder.setIgnoreRecord(Boolean.FALSE); return; } if (br.getType() != BOFRecord.TYPE_WORKSHEET) { @@ -38,15 +39,15 @@ public class BofRecordHandler extends AbstractXlsRecordHandler { readSheetIndex = 0; xlsReadWorkbookHolder.setReadSheetIndex(readSheetIndex); } - ReadSheet readSheet = xlsReadWorkbookHolder.getActualSheetDataList().get(readSheetIndex); - assert readSheet != null : "Can't find the sheet."; + ReadSheet actualReadSheet = xlsReadWorkbookHolder.getActualSheetDataList().get(readSheetIndex); + assert actualReadSheet != null : "Can't find the sheet."; // Copy the parameter to the current sheet - readSheet = SheetUtils.match(readSheet, xlsReadContext); + ReadSheet readSheet = SheetUtils.match(actualReadSheet, xlsReadContext); if (readSheet != null) { xlsReadContext.currentSheet(readSheet); - xlsReadContext.xlsReadSheetHolder().setIgnoreRecord(Boolean.FALSE); + xlsReadContext.xlsReadWorkbookHolder().setIgnoreRecord(Boolean.FALSE); } else { - xlsReadContext.xlsReadSheetHolder().setIgnoreRecord(Boolean.TRUE); + xlsReadContext.xlsReadWorkbookHolder().setIgnoreRecord(Boolean.TRUE); } // Go read the next one xlsReadWorkbookHolder.setReadSheetIndex(xlsReadWorkbookHolder.getReadSheetIndex() + 1); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java index 0ca7313e..32b5b882 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java @@ -1,9 +1,16 @@ package com.alibaba.excel.analysis.v03.handlers; +import java.util.LinkedHashMap; + +import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.context.xls.XlsReadContext; +import com.alibaba.excel.enums.RowTypeEnum; +import com.alibaba.excel.metadata.Cell; +import com.alibaba.excel.read.metadata.holder.ReadRowHolder; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; /** * Record handler @@ -14,8 +21,21 @@ public class EofRecordHandler extends AbstractXlsRecordHandler implements Ignora @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { - if (xlsReadContext.readSheetHolder() != null) { - xlsReadContext.analysisEventProcessor().endSheet(xlsReadContext); + if (xlsReadContext.readSheetHolder() == null) { + return; + } + // Sometimes tables lack the end record of the last column + if (!xlsReadContext.xlsReadSheetHolder().getCellMap().isEmpty()) { + XlsReadSheetHolder xlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder(); + // Forge a termination data + xlsReadContext.readRowHolder(new ReadRowHolder(xlsReadContext.xlsReadSheetHolder().getRowIndex() + 1, + xlsReadSheetHolder.getTempRowType(), + xlsReadContext.readSheetHolder().getGlobalConfiguration(), xlsReadSheetHolder.getCellMap())); + xlsReadContext.analysisEventProcessor().endRow(xlsReadContext); + xlsReadSheetHolder.setCellMap(new LinkedHashMap()); + xlsReadSheetHolder.setTempRowType(RowTypeEnum.EMPTY); } + + xlsReadContext.analysisEventProcessor().endSheet(xlsReadContext); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java index 099b3087..5f18b841 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java @@ -3,20 +3,21 @@ package com.alibaba.excel.analysis.v03.handlers; import java.math.BigDecimal; import java.util.Map; -import org.apache.poi.hssf.model.HSSFFormulaParser; -import org.apache.poi.hssf.record.FormulaRecord; -import org.apache.poi.hssf.record.Record; -import org.apache.poi.ss.usermodel.CellType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.constant.BuiltinFormats; import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.enums.RowTypeEnum; import com.alibaba.excel.metadata.Cell; import com.alibaba.excel.metadata.CellData; +import org.apache.poi.hssf.model.HSSFFormulaParser; +import org.apache.poi.hssf.record.FormulaRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.ss.usermodel.CellType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Record handler * @@ -30,7 +31,7 @@ public class FormulaRecordHandler extends AbstractXlsRecordHandler implements Ig public void processRecord(XlsReadContext xlsReadContext, Record record) { FormulaRecord frec = (FormulaRecord)record; Map cellMap = xlsReadContext.xlsReadSheetHolder().getCellMap(); - CellData tempCellData = new CellData(); + CellData tempCellData = new CellData<>(); tempCellData.setRowIndex(frec.getRow()); tempCellData.setColumnIndex((int)frec.getColumn()); CellType cellType = CellType.forInt(frec.getCachedResultType()); @@ -43,6 +44,7 @@ public class FormulaRecordHandler extends AbstractXlsRecordHandler implements Ig } tempCellData.setFormula(Boolean.TRUE); tempCellData.setFormulaValue(formulaValue); + xlsReadContext.xlsReadSheetHolder().setTempRowType(RowTypeEnum.DATA); switch (cellType) { case STRING: // Formula result is a string @@ -55,8 +57,9 @@ public class FormulaRecordHandler extends AbstractXlsRecordHandler implements Ig tempCellData.setNumberValue(BigDecimal.valueOf(frec.getValue())); Integer dataFormat = xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatIndex(frec); - tempCellData.setDataFormat(dataFormat); - tempCellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, + Short dataFormatShort = dataFormat.shortValue(); + tempCellData.setDataFormat(dataFormatShort); + tempCellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormatShort, xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatString(frec), xlsReadContext.readSheetHolder().getGlobalConfiguration().getLocale())); cellMap.put((int)frec.getColumn(), tempCellData); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java index 50608095..f9e27c7a 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java @@ -2,15 +2,15 @@ package com.alibaba.excel.analysis.v03.handlers; import java.math.BigDecimal; -import org.apache.poi.hssf.record.NumberRecord; -import org.apache.poi.hssf.record.Record; - import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.constant.BuiltinFormats; import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.enums.RowTypeEnum; import com.alibaba.excel.metadata.CellData; +import org.apache.poi.hssf.record.NumberRecord; +import org.apache.poi.hssf.record.Record; + /** * Record handler * @@ -21,8 +21,9 @@ public class NumberRecordHandler extends AbstractXlsRecordHandler implements Ign @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { NumberRecord nr = (NumberRecord)record; - CellData cellData = CellData.newInstance(BigDecimal.valueOf(nr.getValue()), nr.getRow(), (int)nr.getColumn()); - Integer dataFormat = xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatIndex(nr); + CellDatacellData = CellData.newInstance(BigDecimal.valueOf(nr.getValue()), nr.getRow(), (int)nr.getColumn()); + short dataFormat = (short)xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatIndex( + nr); cellData.setDataFormat(dataFormat); cellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatString(nr), diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java index 3b95cfdb..2408d219 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java @@ -23,7 +23,7 @@ public class StringRecordHandler extends AbstractXlsRecordHandler implements Ign // String for formula StringRecord srec = (StringRecord)record; XlsReadSheetHolder xlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder(); - CellData tempCellData = xlsReadSheetHolder.getTempCellData(); + CellDatatempCellData = xlsReadSheetHolder.getTempCellData(); if (tempCellData == null) { LOGGER.warn("String type formula but no value found."); return; diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java index a0a9af0e..1b6e6a8b 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java @@ -9,9 +9,26 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; +import com.alibaba.excel.analysis.ExcelReadExecutor; +import com.alibaba.excel.analysis.v07.handlers.sax.SharedStringsTableHandler; +import com.alibaba.excel.analysis.v07.handlers.sax.XlsxRowHandler; +import com.alibaba.excel.cache.ReadCache; +import com.alibaba.excel.context.xlsx.XlsxReadContext; +import com.alibaba.excel.enums.CellExtraTypeEnum; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.metadata.CellExtra; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder; +import com.alibaba.excel.util.FileUtils; +import com.alibaba.excel.util.SheetUtils; +import com.alibaba.excel.util.StringUtils; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackageAccess; import org.apache.poi.openxml4j.opc.PackagePart; @@ -25,26 +42,13 @@ 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.SAXException; import org.xml.sax.XMLReader; -import com.alibaba.excel.analysis.ExcelReadExecutor; -import com.alibaba.excel.analysis.v07.handlers.sax.SharedStringsTableHandler; -import com.alibaba.excel.analysis.v07.handlers.sax.XlsxRowHandler; -import com.alibaba.excel.cache.ReadCache; -import com.alibaba.excel.context.xlsx.XlsxReadContext; -import com.alibaba.excel.enums.CellExtraTypeEnum; -import com.alibaba.excel.exception.ExcelAnalysisException; -import com.alibaba.excel.metadata.CellExtra; -import com.alibaba.excel.read.metadata.ReadSheet; -import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder; -import com.alibaba.excel.util.CollectionUtils; -import com.alibaba.excel.util.FileUtils; -import com.alibaba.excel.util.SheetUtils; -import com.alibaba.excel.util.StringUtils; - /** * @author jipengfei */ +@Slf4j public class XlsxSaxAnalyser implements ExcelReadExecutor { private XlsxReadContext xlsxReadContext; @@ -78,7 +82,9 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { XSSFReader xssfReader = new XSSFReader(pkg); analysisUse1904WindowDate(xssfReader, xlsxReadWorkbookHolder); - xlsxReadWorkbookHolder.setStylesTable(xssfReader.getStylesTable()); + // set style table + setStylesTable(xlsxReadWorkbookHolder, xssfReader); + sheetList = new ArrayList(); sheetMap = new HashMap(); commentsTableMap = new HashMap(); @@ -101,6 +107,17 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { } } + private void setStylesTable(XlsxReadWorkbookHolder xlsxReadWorkbookHolder, XSSFReader xssfReader) { + try { + xlsxReadWorkbookHolder.setStylesTable(xssfReader.getStylesTable()); + } catch (Exception e) { + log.warn( + "Currently excel cannot get style information, but it doesn't affect the data analysis.You can try to" + + " save the file with office again or ignore the current error.", + e); + } + } + private void defaultReadCache(XlsxReadWorkbookHolder xlsxReadWorkbookHolder, PackagePart sharedStringsTablePackagePart) { ReadCache readCache = xlsxReadWorkbookHolder.getReadCacheSelector().readCache(sharedStringsTablePackagePart); @@ -147,9 +164,10 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { xlsxReadWorkbookHolder.setTempFile(readTempFile); File tempFile = new File(readTempFile.getPath(), UUID.randomUUID().toString() + ".xlsx"); if (decryptedStream != null) { - FileUtils.writeToFile(tempFile, decryptedStream); + FileUtils.writeToFile(tempFile, decryptedStream, false); } else { - FileUtils.writeToFile(tempFile, xlsxReadWorkbookHolder.getInputStream()); + FileUtils.writeToFile(tempFile, xlsxReadWorkbookHolder.getInputStream(), + xlsxReadWorkbookHolder.getAutoCloseStream()); } return OPCPackage.open(tempFile, PackageAccess.READ); } @@ -177,9 +195,7 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { xmlReader.setContentHandler(handler); xmlReader.parse(inputSource); inputStream.close(); - } catch (ExcelAnalysisException e) { - throw e; - } catch (Exception e) { + } catch (IOException | ParserConfigurationException | SAXException e) { throw new ExcelAnalysisException(e); } finally { if (inputStream != null) { diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java index 3521e46a..770355b0 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java @@ -7,6 +7,7 @@ import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; import com.alibaba.excel.util.BooleanUtils; +import com.alibaba.excel.util.StringUtils; /** * Cell Value Handler @@ -20,6 +21,7 @@ public abstract class AbstractCellValueTagHandler extends AbstractXlsxTagHandler XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); CellData tempCellData = xlsxReadSheetHolder.getTempCellData(); StringBuilder tempData = xlsxReadSheetHolder.getTempData(); + String tempDataString = tempData.toString(); CellDataTypeEnum oldType = tempCellData.getType(); switch (oldType) { case DIRECT_STRING: @@ -28,10 +30,18 @@ public abstract class AbstractCellValueTagHandler extends AbstractXlsxTagHandler tempCellData.setStringValue(tempData.toString()); break; case BOOLEAN: + if(StringUtils.isEmpty(tempDataString)){ + tempCellData.setType(CellDataTypeEnum.EMPTY); + break; + } tempCellData.setBooleanValue(BooleanUtils.valueOf(tempData.toString())); break; case NUMBER: case EMPTY: + if(StringUtils.isEmpty(tempDataString)){ + tempCellData.setType(CellDataTypeEnum.EMPTY); + break; + } tempCellData.setType(CellDataTypeEnum.NUMBER); tempCellData.setNumberValue(new BigDecimal(tempData.toString())); break; @@ -44,7 +54,7 @@ public abstract class AbstractCellValueTagHandler extends AbstractXlsxTagHandler if (tempCellData.getStringValue() != null && xlsxReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) { - tempCellData.setStringValue(tempCellData.getStringValue()); + tempCellData.setStringValue(tempCellData.getStringValue().trim()); } tempCellData.checkEmpty(); diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellInlineStringValueTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellInlineStringValueTagHandler.java index 277348a7..3058e8e8 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellInlineStringValueTagHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellInlineStringValueTagHandler.java @@ -15,7 +15,7 @@ public class CellInlineStringValueTagHandler extends AbstractCellValueTagHandler @Override protected void setStringValue(XlsxReadContext xlsxReadContext) { // This is a special form of string - CellData tempCellData = xlsxReadContext.xlsxReadSheetHolder().getTempCellData(); + CellData tempCellData = xlsxReadContext.xlsxReadSheetHolder().getTempCellData(); XSSFRichTextString richTextString = new XSSFRichTextString(tempCellData.getStringValue()); tempCellData.setStringValue(richTextString.toString()); } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java index fe5a6421..135153e0 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java @@ -1,8 +1,5 @@ package com.alibaba.excel.analysis.v07.handlers; -import org.apache.poi.xssf.usermodel.XSSFCellStyle; -import org.xml.sax.Attributes; - import com.alibaba.excel.constant.BuiltinFormats; import com.alibaba.excel.constant.ExcelXmlConstants; import com.alibaba.excel.context.xlsx.XlsxReadContext; @@ -12,6 +9,10 @@ import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; import com.alibaba.excel.util.PositionUtils; import com.alibaba.excel.util.StringUtils; +import org.apache.poi.xssf.model.StylesTable; +import org.apache.poi.xssf.usermodel.XSSFCellStyle; +import org.xml.sax.Attributes; + /** * Cell Handler * @@ -46,9 +47,12 @@ public class CellTagHandler extends AbstractXlsxTagHandler { } else { dateFormatIndexInteger = Integer.parseInt(dateFormatIndex); } - XSSFCellStyle xssfCellStyle = - xlsxReadContext.xlsxReadWorkbookHolder().getStylesTable().getStyleAt(dateFormatIndexInteger); - int dataFormat = xssfCellStyle.getDataFormat(); + StylesTable stylesTable = xlsxReadContext.xlsxReadWorkbookHolder().getStylesTable(); + if (stylesTable == null) { + return; + } + XSSFCellStyle xssfCellStyle = stylesTable.getStyleAt(dateFormatIndexInteger); + short dataFormat = xssfCellStyle.getDataFormat(); xlsxReadSheetHolder.getTempCellData().setDataFormat(dataFormat); xlsxReadSheetHolder.getTempCellData().setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, xssfCellStyle.getDataFormatString(), xlsxReadSheetHolder.getGlobalConfiguration().getLocale())); diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellValueTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellValueTagHandler.java index 09c9264e..7e685c97 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellValueTagHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellValueTagHandler.java @@ -3,6 +3,7 @@ package com.alibaba.excel.analysis.v07.handlers; import com.alibaba.excel.context.xlsx.XlsxReadContext; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.util.StringUtils; /** * Cell Value Handler @@ -17,6 +18,10 @@ public class CellValueTagHandler extends AbstractCellValueTagHandler { CellData tempCellData = xlsxReadContext.xlsxReadSheetHolder().getTempCellData(); switch (tempCellData.getType()) { case STRING: + // In some cases, although cell type is a string, it may be an empty tag + if(StringUtils.isEmpty(tempCellData.getStringValue())){ + break; + } String stringValue = xlsxReadContext.readWorkbookHolder().getReadCache() .get(Integer.valueOf(tempCellData.getStringValue())); if (stringValue != null && xlsxReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) { diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java index 61f38733..37965254 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java @@ -2,8 +2,6 @@ package com.alibaba.excel.analysis.v07.handlers; import java.util.LinkedHashMap; -import org.xml.sax.Attributes; - import com.alibaba.excel.constant.ExcelXmlConstants; import com.alibaba.excel.context.xlsx.XlsxReadContext; import com.alibaba.excel.enums.RowTypeEnum; @@ -12,6 +10,9 @@ import com.alibaba.excel.read.metadata.holder.ReadRowHolder; import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; import com.alibaba.excel.util.PositionUtils; +import org.apache.commons.collections4.MapUtils; +import org.xml.sax.Attributes; + /** * Cell Handler * @@ -25,15 +26,13 @@ public class RowTagHandler extends AbstractXlsxTagHandler { int rowIndex = PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R), xlsxReadSheetHolder.getRowIndex()); Integer lastRowIndex = xlsxReadContext.readSheetHolder().getRowIndex(); - if (lastRowIndex != null) { - while (lastRowIndex + 1 < rowIndex) { - xlsxReadContext.readRowHolder(new ReadRowHolder(lastRowIndex + 1, RowTypeEnum.EMPTY, - xlsxReadSheetHolder.getGlobalConfiguration(), new LinkedHashMap())); - xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext); - xlsxReadSheetHolder.setColumnIndex(null); - xlsxReadSheetHolder.setCellMap(new LinkedHashMap()); - lastRowIndex++; - } + while (lastRowIndex + 1 < rowIndex) { + xlsxReadContext.readRowHolder(new ReadRowHolder(lastRowIndex + 1, RowTypeEnum.EMPTY, + xlsxReadSheetHolder.getGlobalConfiguration(), new LinkedHashMap())); + xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext); + xlsxReadSheetHolder.setColumnIndex(null); + xlsxReadSheetHolder.setCellMap(new LinkedHashMap()); + lastRowIndex++; } xlsxReadSheetHolder.setRowIndex(rowIndex); } @@ -41,11 +40,12 @@ public class RowTagHandler extends AbstractXlsxTagHandler { @Override public void endElement(XlsxReadContext xlsxReadContext, String name) { XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); - xlsxReadContext.readRowHolder(new ReadRowHolder(xlsxReadSheetHolder.getRowIndex(), RowTypeEnum.DATA, + RowTypeEnum rowType = MapUtils.isEmpty(xlsxReadSheetHolder.getCellMap()) ? RowTypeEnum.EMPTY : RowTypeEnum.DATA; + xlsxReadContext.readRowHolder(new ReadRowHolder(xlsxReadSheetHolder.getRowIndex(), rowType, xlsxReadSheetHolder.getGlobalConfiguration(), xlsxReadSheetHolder.getCellMap())); xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext); xlsxReadSheetHolder.setColumnIndex(null); - xlsxReadSheetHolder.setCellMap(new LinkedHashMap()); + xlsxReadSheetHolder.setCellMap(new LinkedHashMap<>()); } } diff --git a/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java b/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java index b107d32e..e2b169e3 100644 --- a/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java +++ b/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java @@ -23,7 +23,7 @@ public @interface ExcelProperty { *

* write: It automatically merges when you have more than one head *

- * read: When you have multiple heads, take the first one + * read: When you have multiple heads, take the last one * * @return The name of the sheet header */ @@ -32,12 +32,23 @@ public @interface ExcelProperty { /** * Index of column * - * Read or write it on the index of column,If it's equal to -1, it's sorted by Java class + * Read or write it on the index of column,If it's equal to -1, it's sorted by Java class. + * + * priority: index > order > default sort * * @return Index of column */ int index() default -1; + /** + * Defines the sort order for an column. + * + * priority: index > order > default sort + * + * @return Order of column + */ + int order() default Integer.MAX_VALUE; + /** * Force the current field to use this converter. * diff --git a/src/main/java/com/alibaba/excel/cache/Ehcache.java b/src/main/java/com/alibaba/excel/cache/Ehcache.java index 4e757fcd..a5250900 100644 --- a/src/main/java/com/alibaba/excel/cache/Ehcache.java +++ b/src/main/java/com/alibaba/excel/cache/Ehcache.java @@ -1,50 +1,49 @@ package com.alibaba.excel.cache; import java.io.File; -import java.util.HashMap; +import java.util.ArrayList; import java.util.UUID; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.util.FileUtils; +import com.alibaba.excel.util.ListUtils; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; import org.ehcache.CacheManager; import org.ehcache.config.CacheConfiguration; import org.ehcache.config.builders.CacheConfigurationBuilder; import org.ehcache.config.builders.CacheManagerBuilder; import org.ehcache.config.builders.ResourcePoolsBuilder; import org.ehcache.config.units.MemoryUnit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.util.CollectionUtils; -import com.alibaba.excel.util.FileUtils; /** * Default cache * * @author Jiaju Zhuang */ +@Slf4j public class Ehcache implements ReadCache { - - private static final Logger LOGGER = LoggerFactory.getLogger(Ehcache.class); - private static final int BATCH_COUNT = 1000; - private static final int DEBUG_WRITE_SIZE = 100 * 10000; - private static final int DEBUG_CACHE_MISS_SIZE = 1000; + public static final int BATCH_COUNT = 1000; /** * Key index */ - private int index = 0; - private HashMap dataMap = new HashMap(BATCH_COUNT * 4 / 3 + 1); - private static CacheManager fileCacheManager; - private static CacheConfiguration fileCacheConfiguration; - private static CacheManager activeCacheManager; - private CacheConfiguration activeCacheConfiguration; + private int activeIndex = 0; + public static final int DEBUG_CACHE_MISS_SIZE = 1000; + public static final int DEBUG_WRITE_SIZE = 100 * 10000; + private ArrayList dataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); + private static final CacheManager FILE_CACHE_MANAGER; + private static final CacheConfiguration FILE_CACHE_CONFIGURATION; + private static final CacheManager ACTIVE_CACHE_MANAGER; + private final CacheConfiguration activeCacheConfiguration; /** * Bulk storage data */ - private org.ehcache.Cache fileCache; + private org.ehcache.Cache fileCache; /** * Currently active cache */ - private org.ehcache.Cache activeCache; + private org.ehcache.Cache activeCache; private String cacheAlias; /** * Count the number of cache misses @@ -53,7 +52,7 @@ public class Ehcache implements ReadCache { public Ehcache(int maxCacheActivateSize) { activeCacheConfiguration = CacheConfigurationBuilder - .newCacheConfigurationBuilder(Integer.class, HashMap.class, + .newCacheConfigurationBuilder(Integer.class, ArrayList.class, ResourcePoolsBuilder.newResourcePoolsBuilder().heap(maxCacheActivateSize, MemoryUnit.MB)) .withSizeOfMaxObjectGraph(1000 * 1000L).withSizeOfMaxObjectSize(maxCacheActivateSize, MemoryUnit.MB) .build(); @@ -61,11 +60,11 @@ public class Ehcache implements ReadCache { static { File cacheFile = FileUtils.createCacheTmpFile(); - fileCacheManager = + FILE_CACHE_MANAGER = CacheManagerBuilder.newCacheManagerBuilder().with(CacheManagerBuilder.persistence(cacheFile)).build(true); - activeCacheManager = CacheManagerBuilder.newCacheManagerBuilder().build(true); - fileCacheConfiguration = CacheConfigurationBuilder - .newCacheConfigurationBuilder(Integer.class, HashMap.class, + ACTIVE_CACHE_MANAGER = CacheManagerBuilder.newCacheManagerBuilder().build(true); + FILE_CACHE_CONFIGURATION = CacheConfigurationBuilder + .newCacheConfigurationBuilder(Integer.class, ArrayList.class, ResourcePoolsBuilder.newResourcePoolsBuilder().disk(10, MemoryUnit.GB)) .withSizeOfMaxObjectGraph(1000 * 1000L).withSizeOfMaxObjectSize(10, MemoryUnit.GB).build(); } @@ -73,21 +72,22 @@ public class Ehcache implements ReadCache { @Override public void init(AnalysisContext analysisContext) { cacheAlias = UUID.randomUUID().toString(); - fileCache = fileCacheManager.createCache(cacheAlias, fileCacheConfiguration); - activeCache = activeCacheManager.createCache(cacheAlias, activeCacheConfiguration); + fileCache = FILE_CACHE_MANAGER.createCache(cacheAlias, FILE_CACHE_CONFIGURATION); + activeCache = ACTIVE_CACHE_MANAGER.createCache(cacheAlias, activeCacheConfiguration); } @Override public void put(String value) { - dataMap.put(index, value); - if ((index + 1) % BATCH_COUNT == 0) { - fileCache.put(index / BATCH_COUNT, dataMap); - dataMap = new HashMap(BATCH_COUNT * 4 / 3 + 1); + dataList.add(value); + if (dataList.size() >= BATCH_COUNT) { + fileCache.put(activeIndex, dataList); + activeIndex++; + dataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); } - index++; - if (LOGGER.isDebugEnabled()) { - if (index % DEBUG_WRITE_SIZE == 0) { - LOGGER.debug("Already put :{}", index); + if (log.isDebugEnabled()) { + int alreadyPut = activeIndex * BATCH_COUNT + dataList.size(); + if (alreadyPut % DEBUG_WRITE_SIZE == 0) { + log.debug("Already put :{}", alreadyPut); } } } @@ -98,31 +98,31 @@ public class Ehcache implements ReadCache { return null; } int route = key / BATCH_COUNT; - HashMap dataMap = activeCache.get(route); - if (dataMap == null) { - dataMap = fileCache.get(route); - activeCache.put(route, dataMap); - if (LOGGER.isDebugEnabled()) { + ArrayList dataList = activeCache.get(route); + if (dataList == null) { + dataList = fileCache.get(route); + activeCache.put(route, dataList); + if (log.isDebugEnabled()) { if (cacheMiss++ % DEBUG_CACHE_MISS_SIZE == 0) { - LOGGER.debug("Cache misses count:{}", cacheMiss); + log.debug("Cache misses count:{}", cacheMiss); } } } - return dataMap.get(key); + return dataList.get(key % BATCH_COUNT); } @Override public void putFinished() { - if (CollectionUtils.isEmpty(dataMap)) { + if (CollectionUtils.isEmpty(dataList)) { return; } - fileCache.put(index / BATCH_COUNT, dataMap); + fileCache.put(activeIndex, dataList); } @Override public void destroy() { - fileCacheManager.removeCache(cacheAlias); - activeCacheManager.removeCache(cacheAlias); + FILE_CACHE_MANAGER.removeCache(cacheAlias); + ACTIVE_CACHE_MANAGER.removeCache(cacheAlias); } } diff --git a/src/main/java/com/alibaba/excel/cache/MapCache.java b/src/main/java/com/alibaba/excel/cache/MapCache.java index ae948fbc..f83a1233 100644 --- a/src/main/java/com/alibaba/excel/cache/MapCache.java +++ b/src/main/java/com/alibaba/excel/cache/MapCache.java @@ -1,26 +1,24 @@ package com.alibaba.excel.cache; -import java.util.HashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; import com.alibaba.excel.context.AnalysisContext; /** - * * Putting temporary data directly into a map is a little more efficient but very memory intensive * * @author Jiaju Zhuang */ public class MapCache implements ReadCache { - private Map cache = new HashMap(); - private int index = 0; + private List cache = new ArrayList<>(); @Override public void init(AnalysisContext analysisContext) {} @Override public void put(String value) { - cache.put(index++, value); + cache.add(value); } @Override diff --git a/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java b/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java index 95eb0b8f..b742cb6c 100644 --- a/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java +++ b/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java @@ -17,7 +17,9 @@ import java.util.Locale; **/ public class BuiltinFormats { - private static final String[] BUILTIN_FORMATS_CN = { + public static short GENERAL = 0; + + public static final String[] BUILTIN_FORMATS_CN = { // 0 "General", // 1 @@ -189,7 +191,7 @@ public class BuiltinFormats { // end }; - private static final String[] BUILTIN_FORMATS_US = { + public static final String[] BUILTIN_FORMATS_US = { // 0 "General", // 1 @@ -361,7 +363,7 @@ public class BuiltinFormats { // end }; - public static String getBuiltinFormat(Integer index, String defaultFormat, Locale locale) { + public static String getBuiltinFormat(Short index, String defaultFormat, Locale locale) { String[] builtinFormat = switchBuiltinFormats(locale); if (index == null || index < 0 || index >= builtinFormat.length) { return defaultFormat; diff --git a/src/main/java/com/alibaba/excel/constant/OrderConstant.java b/src/main/java/com/alibaba/excel/constant/OrderConstant.java new file mode 100644 index 00000000..a955025c --- /dev/null +++ b/src/main/java/com/alibaba/excel/constant/OrderConstant.java @@ -0,0 +1,13 @@ +package com.alibaba.excel.constant; + +/** + * Order constant. + * + * @author Jiaju Zhuang + */ +public class OrderConstant { + /** + * Sorting of styles written to cells. + */ + public static final int FILL_DATA_FORMAT = 10000; +} diff --git a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java index 8465cbd2..648a7fe9 100644 --- a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java @@ -6,22 +6,6 @@ import java.io.OutputStream; import java.util.Map; import java.util.UUID; -import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey; -import org.apache.poi.openxml4j.opc.OPCPackage; -import org.apache.poi.openxml4j.opc.PackageAccess; -import org.apache.poi.poifs.crypt.EncryptionInfo; -import org.apache.poi.poifs.crypt.EncryptionMode; -import org.apache.poi.poifs.crypt.Encryptor; -import org.apache.poi.poifs.filesystem.POIFSFileSystem; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.ss.util.CellRangeAddress; -import org.apache.poi.xssf.streaming.SXSSFWorkbook; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.alibaba.excel.enums.WriteTypeEnum; import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.metadata.CellData; @@ -42,6 +26,22 @@ import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; import com.alibaba.excel.write.property.ExcelWriteHeadProperty; +import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey; +import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.openxml4j.opc.PackageAccess; +import org.apache.poi.poifs.crypt.EncryptionInfo; +import org.apache.poi.poifs.crypt.EncryptionMode; +import org.apache.poi.poifs.crypt.Encryptor; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * A context is the main anchorage point of a excel writer. * @@ -50,6 +50,7 @@ import com.alibaba.excel.write.property.ExcelWriteHeadProperty; public class WriteContextImpl implements WriteContext { private static final Logger LOGGER = LoggerFactory.getLogger(WriteContextImpl.class); + private static final String NO_SHEETS="no sheets"; /** * The Workbook currently written @@ -111,15 +112,25 @@ public class WriteContextImpl implements WriteContext { if (selectSheetFromCache(writeSheet)) { return; } + initCurrentSheetHolder(writeSheet); + + // Workbook handler need to supplementary execution + WriteHandlerUtils.beforeWorkbookCreate(this, true); + WriteHandlerUtils.afterWorkbookCreate(this, true); + // Initialization current sheet initSheet(writeType); } private boolean selectSheetFromCache(WriteSheet writeSheet) { writeSheetHolder = null; - if (writeSheet.getSheetNo() != null) { - writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheetIndexMap().get(writeSheet.getSheetNo()); + Integer sheetNo = writeSheet.getSheetNo(); + if (sheetNo == null && StringUtils.isEmpty(writeSheet.getSheetName())) { + sheetNo = 0; + } + if (sheetNo != null) { + writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheetIndexMap().get(sheetNo); } if (writeSheetHolder == null && !StringUtils.isEmpty(writeSheet.getSheetName())) { writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheetNameMap().get(writeSheet.getSheetName()); @@ -153,17 +164,27 @@ public class WriteContextImpl implements WriteContext { Sheet currentSheet; try { if (writeSheetHolder.getSheetNo() != null) { - currentSheet = writeWorkbookHolder.getWorkbook().getSheetAt(writeSheetHolder.getSheetNo()); - writeSheetHolder - .setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheetAt(writeSheetHolder.getSheetNo())); + // When the add default sort order of appearance + if (WriteTypeEnum.ADD.equals(writeType) && writeWorkbookHolder.getTempTemplateInputStream() == null) { + currentSheet = createSheet(); + } else { + currentSheet = writeWorkbookHolder.getWorkbook().getSheetAt(writeSheetHolder.getSheetNo()); + writeSheetHolder + .setCachedSheet( + writeWorkbookHolder.getCachedWorkbook().getSheetAt(writeSheetHolder.getSheetNo())); + } } else { // sheet name must not null currentSheet = writeWorkbookHolder.getWorkbook().getSheet(writeSheetHolder.getSheetName()); writeSheetHolder .setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheet(writeSheetHolder.getSheetName())); } - } catch (Exception e) { - currentSheet = createSheet(); + } catch (IllegalArgumentException e) { + if (e.getMessage() != null && e.getMessage().contains(NO_SHEETS)) { + currentSheet = createSheet(); + } else { + throw e; + } } if (currentSheet == null) { currentSheet = createSheet(); @@ -201,8 +222,8 @@ public class WriteContextImpl implements WriteContext { if (currentWriteHolder.automaticMergeHead()) { addMergedRegionToCurrentSheet(excelWriteHeadProperty, newRowIndex); } - for (int relativeRowIndex = 0, i = newRowIndex; i < excelWriteHeadProperty.getHeadRowNumber() + newRowIndex; - i++, relativeRowIndex++) { + for (int relativeRowIndex = 0, i = newRowIndex; i < excelWriteHeadProperty.getHeadRowNumber() + + newRowIndex; i++, relativeRowIndex++) { WriteHandlerUtils.beforeRowCreate(this, newRowIndex, relativeRowIndex, Boolean.TRUE); Row row = WorkBookUtil.createRow(writeSheetHolder.getSheet(), i); WriteHandlerUtils.afterRowCreate(this, row, relativeRowIndex, Boolean.TRUE); @@ -227,7 +248,7 @@ public class WriteContextImpl implements WriteContext { Cell cell = row.createCell(columnIndex); WriteHandlerUtils.afterCellCreate(this, cell, head, relativeRowIndex, Boolean.TRUE); cell.setCellValue(head.getHeadNameList().get(relativeRowIndex)); - WriteHandlerUtils.afterCellDispose(this, (CellData)null, cell, head, relativeRowIndex, Boolean.TRUE); + WriteHandlerUtils.afterCellDispose(this, (CellData) null, cell, head, relativeRowIndex, Boolean.TRUE); } } @@ -251,7 +272,15 @@ public class WriteContextImpl implements WriteContext { } return; } + initCurrentTableHolder(writeTable); + + // Workbook and sheet handler need to supplementary execution + WriteHandlerUtils.beforeWorkbookCreate(this, true); + WriteHandlerUtils.afterWorkbookCreate(this, true); + WriteHandlerUtils.beforeSheetCreate(this, true); + WriteHandlerUtils.afterSheetCreate(this, true); + initHead(writeTableHolder.excelWriteHeadProperty()); } @@ -322,7 +351,7 @@ public class WriteContextImpl implements WriteContext { try { Workbook workbook = writeWorkbookHolder.getWorkbook(); if (workbook instanceof SXSSFWorkbook) { - ((SXSSFWorkbook)workbook).dispose(); + ((SXSSFWorkbook) workbook).dispose(); } } catch (Throwable t) { throwable = t; diff --git a/src/main/java/com/alibaba/excel/converters/AutoConverter.java b/src/main/java/com/alibaba/excel/converters/AutoConverter.java index 800d2d85..07ad471f 100644 --- a/src/main/java/com/alibaba/excel/converters/AutoConverter.java +++ b/src/main/java/com/alibaba/excel/converters/AutoConverter.java @@ -10,10 +10,10 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; * * @author Jiaju Zhuang */ -public class AutoConverter implements Converter { +public class AutoConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return null; } @@ -23,13 +23,13 @@ public class AutoConverter implements Converter { } @Override - public Object convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Object convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return null; } @Override - public CellData convertToExcelData(Object value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Object value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return null; } diff --git a/src/main/java/com/alibaba/excel/converters/Converter.java b/src/main/java/com/alibaba/excel/converters/Converter.java index 8700d127..3d1a369d 100644 --- a/src/main/java/com/alibaba/excel/converters/Converter.java +++ b/src/main/java/com/alibaba/excel/converters/Converter.java @@ -4,12 +4,16 @@ import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.read.metadata.holder.ReadSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteHolder; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; /** * Convert between Java objects and excel objects * - * @author Dan Zheng * @param + * @author Dan Zheng */ public interface Converter { @@ -18,44 +22,72 @@ public interface Converter { * * @return Support for Java class */ - Class supportJavaTypeKey(); + default Class supportJavaTypeKey() { + throw new UnsupportedOperationException("The current operation is not supported by the current converter."); + } /** * Back to object enum in excel * * @return Support for {@link CellDataTypeEnum} */ - CellDataTypeEnum supportExcelTypeKey(); + default CellDataTypeEnum supportExcelTypeKey() { + throw new UnsupportedOperationException("The current operation is not supported by the current converter."); + } + + /** + * Convert excel objects to Java objects + * + * @param cellData Excel cell data.NotNull. + * @param contentProperty Content property.Nullable. + * @param globalConfiguration Global configuration.NotNull. + * @return Data to put into a Java object + * @throws Exception Exception. + */ + default T convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws Exception { + throw new UnsupportedOperationException("The current operation is not supported by the current converter."); + } /** * Convert excel objects to Java objects * - * @param cellData - * Excel cell data.NotNull. - * @param contentProperty - * Content property.Nullable. - * @param globalConfiguration - * Global configuration.NotNull. + * @param cellData Excel cell data.NotNull. + * @param contentProperty Content property.Nullable. + * @param readSheetHolder .NotNull. * @return Data to put into a Java object - * @throws Exception - * Exception. + * @throws Exception Exception. + */ + default T convertToJavaData(CellData cellData, + ExcelContentProperty contentProperty, ReadSheetHolder readSheetHolder) throws Exception { + return convertToJavaData(cellData, contentProperty, readSheetHolder.globalConfiguration()); + } + + /** + * Convert Java objects to excel objects + * + * @param value Java Data.NotNull. + * @param contentProperty Content property.Nullable. + * @param globalConfiguration Global configuration.NotNull. + * @return Data to put into a Excel + * @throws Exception Exception. */ - T convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, - GlobalConfiguration globalConfiguration) throws Exception; + default CellData convertToExcelData(T value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws Exception { + throw new UnsupportedOperationException("The current operation is not supported by the current converter."); + } /** * Convert Java objects to excel objects * - * @param value - * Java Data.NotNull. - * @param contentProperty - * Content property.Nullable. - * @param globalConfiguration - * Global configuration.NotNull. + * @param value Java Data.NotNull. + * @param contentProperty Content property.Nullable. + * @param currentWriteHolder He would be {@link WriteSheetHolder} or {@link WriteTableHolder}.NotNull. * @return Data to put into a Excel - * @throws Exception - * Exception. + * @throws Exception Exception. */ - CellData convertToExcelData(T value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) - throws Exception; + default CellData convertToExcelData(T value, ExcelContentProperty contentProperty, + WriteHolder currentWriteHolder) throws Exception { + return convertToExcelData(value, contentProperty, currentWriteHolder.globalConfiguration()); + } } diff --git a/src/main/java/com/alibaba/excel/converters/ConverterKeyBuild.java b/src/main/java/com/alibaba/excel/converters/ConverterKeyBuild.java index 0bd54991..a92f3033 100644 --- a/src/main/java/com/alibaba/excel/converters/ConverterKeyBuild.java +++ b/src/main/java/com/alibaba/excel/converters/ConverterKeyBuild.java @@ -1,9 +1,9 @@ package com.alibaba.excel.converters; -import java.util.HashMap; import java.util.Map; import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.util.MapUtils; /** * Converter unique key.Consider that you can just use class as the key. @@ -12,7 +12,7 @@ import com.alibaba.excel.enums.CellDataTypeEnum; */ public class ConverterKeyBuild { - private static final Map BOXING_MAP = new HashMap(16); + private static final Map BOXING_MAP = MapUtils.newHashMap(); static { BOXING_MAP.put(int.class.getName(), Integer.class.getName()); @@ -25,7 +25,7 @@ public class ConverterKeyBuild { BOXING_MAP.put(boolean.class.getName(), Boolean.class.getName()); } - public static String buildKey(Class clazz) { + public static String buildKey(Class clazz) { String className = clazz.getName(); String boxingClassName = BOXING_MAP.get(clazz.getName()); if (boxingClassName == null) { @@ -34,7 +34,11 @@ public class ConverterKeyBuild { return boxingClassName; } - public static String buildKey(Class clazz, CellDataTypeEnum cellDataTypeEnum) { - return buildKey(clazz) + "-" + cellDataTypeEnum.toString(); + public static String buildKey(Class clazz, CellDataTypeEnum cellDataTypeEnum) { + String key = buildKey(clazz); + if (cellDataTypeEnum == null) { + return key; + } + return key + "-" + cellDataTypeEnum.toString(); } } diff --git a/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java b/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java index 01822559..b4cabe0d 100644 --- a/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java +++ b/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java @@ -1,6 +1,5 @@ package com.alibaba.excel.converters; -import java.util.HashMap; import java.util.Map; import com.alibaba.excel.converters.bigdecimal.BigDecimalBooleanConverter; @@ -14,6 +13,7 @@ import com.alibaba.excel.converters.bytearray.ByteArrayImageConverter; import com.alibaba.excel.converters.byteconverter.ByteBooleanConverter; import com.alibaba.excel.converters.byteconverter.ByteNumberConverter; import com.alibaba.excel.converters.byteconverter.ByteStringConverter; +import com.alibaba.excel.converters.date.DateDateConverter; import com.alibaba.excel.converters.date.DateNumberConverter; import com.alibaba.excel.converters.date.DateStringConverter; import com.alibaba.excel.converters.doubleconverter.DoubleBooleanConverter; @@ -38,6 +38,7 @@ import com.alibaba.excel.converters.string.StringErrorConverter; import com.alibaba.excel.converters.string.StringNumberConverter; import com.alibaba.excel.converters.string.StringStringConverter; import com.alibaba.excel.converters.url.UrlImageConverter; +import com.alibaba.excel.util.MapUtils; /** * Load default handler @@ -45,8 +46,8 @@ import com.alibaba.excel.converters.url.UrlImageConverter; * @author Jiaju Zhuang */ public class DefaultConverterLoader { - private static Map defaultWriteConverter; - private static Map allConverter; + private static Map> defaultWriteConverter; + private static Map> allConverter; static { initDefaultWriteConverter(); @@ -54,7 +55,7 @@ public class DefaultConverterLoader { } private static void initAllConverter() { - allConverter = new HashMap(64); + allConverter = MapUtils.newHashMapWithExpectedSize(40); putAllConverter(new BigDecimalBooleanConverter()); putAllConverter(new BigDecimalNumberConverter()); putAllConverter(new BigDecimalStringConverter()); @@ -97,11 +98,11 @@ public class DefaultConverterLoader { } private static void initDefaultWriteConverter() { - defaultWriteConverter = new HashMap(32); + defaultWriteConverter = MapUtils.newHashMapWithExpectedSize(40); putWriteConverter(new BigDecimalNumberConverter()); putWriteConverter(new BooleanBooleanConverter()); putWriteConverter(new ByteNumberConverter()); - putWriteConverter(new DateStringConverter()); + putWriteConverter(new DateDateConverter()); putWriteConverter(new DoubleNumberConverter()); putWriteConverter(new FloatNumberConverter()); putWriteConverter(new IntegerNumberConverter()); @@ -113,6 +114,18 @@ public class DefaultConverterLoader { putWriteConverter(new ByteArrayImageConverter()); putWriteConverter(new BoxingByteArrayImageConverter()); putWriteConverter(new UrlImageConverter()); + + // In some cases, it must be converted to string + putWriteStringConverter(new BigDecimalStringConverter()); + putWriteStringConverter(new BooleanStringConverter()); + putWriteStringConverter(new ByteStringConverter()); + putWriteStringConverter(new DateStringConverter()); + putWriteStringConverter(new DoubleStringConverter()); + putWriteStringConverter(new FloatStringConverter()); + putWriteStringConverter(new IntegerStringConverter()); + putWriteStringConverter(new LongStringConverter()); + putWriteStringConverter(new ShortStringConverter()); + putWriteStringConverter(new StringStringConverter()); } /** @@ -120,20 +133,25 @@ public class DefaultConverterLoader { * * @return */ - public static Map loadDefaultWriteConverter() { + public static Map> loadDefaultWriteConverter() { return defaultWriteConverter; } - private static void putWriteConverter(Converter converter) { + private static void putWriteConverter(Converter converter) { defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter); } + private static void putWriteStringConverter(Converter converter) { + defaultWriteConverter.put( + ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), converter); + } + /** * Load default read converter * * @return */ - public static Map loadDefaultReadConverter() { + public static Map> loadDefaultReadConverter() { return loadAllConverter(); } @@ -142,11 +160,11 @@ public class DefaultConverterLoader { * * @return */ - public static Map loadAllConverter() { + public static Map> loadAllConverter() { return allConverter; } - private static void putAllConverter(Converter converter) { + private static void putAllConverter(Converter converter) { allConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), converter); } diff --git a/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalBooleanConverter.java index 8dcac0c9..f4e9ad6f 100644 --- a/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalBooleanConverter.java +++ b/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalBooleanConverter.java @@ -16,7 +16,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; public class BigDecimalBooleanConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return BigDecimal.class; } @@ -26,7 +26,7 @@ public class BigDecimalBooleanConverter implements Converter { } @Override - public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (cellData.getBooleanValue()) { return BigDecimal.ONE; @@ -35,12 +35,12 @@ public class BigDecimalBooleanConverter implements Converter { } @Override - public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (BigDecimal.ONE.equals(value)) { - return new CellData(Boolean.TRUE); + return new CellData<>(Boolean.TRUE); } - return new CellData(Boolean.FALSE); + return new CellData<>(Boolean.FALSE); } } diff --git a/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalNumberConverter.java b/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalNumberConverter.java index bf9b735f..39061d70 100644 --- a/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalNumberConverter.java @@ -7,6 +7,8 @@ import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.NumberUtils; +import com.alibaba.excel.write.metadata.holder.WriteHolder; /** * BigDecimal and number converter @@ -16,7 +18,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; public class BigDecimalNumberConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return BigDecimal.class; } @@ -26,14 +28,14 @@ public class BigDecimalNumberConverter implements Converter { } @Override - public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return cellData.getNumberValue(); } @Override - public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, - GlobalConfiguration globalConfiguration) { - return new CellData(value); + public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, + WriteHolder currentWriteHolder) { + return NumberUtils.formatToCellData(value, contentProperty, currentWriteHolder); } } diff --git a/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalStringConverter.java b/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalStringConverter.java index 8c5f0f48..356a38c5 100644 --- a/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalStringConverter.java +++ b/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalStringConverter.java @@ -18,7 +18,7 @@ import com.alibaba.excel.util.NumberUtils; public class BigDecimalStringConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return BigDecimal.class; } @@ -28,14 +28,14 @@ public class BigDecimalStringConverter implements Converter { } @Override - public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws ParseException { return NumberUtils.parseBigDecimal(cellData.getStringValue(), contentProperty); } @Override - public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return NumberUtils.formatToCellData(value, contentProperty); + return NumberUtils.formatToCellDataString(value, contentProperty); } } diff --git a/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanBooleanConverter.java index 08b83fe9..56654cd5 100644 --- a/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanBooleanConverter.java +++ b/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanBooleanConverter.java @@ -14,7 +14,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; public class BooleanBooleanConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Boolean.class; } @@ -24,15 +24,15 @@ public class BooleanBooleanConverter implements Converter { } @Override - public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return cellData.getBooleanValue(); } @Override - public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return new CellData(value); + return new CellData<>(value); } } diff --git a/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanNumberConverter.java b/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanNumberConverter.java index a0042eaa..00cd4c2c 100644 --- a/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanNumberConverter.java @@ -15,7 +15,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; */ public class BooleanNumberConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Boolean.class; } @@ -25,7 +25,7 @@ public class BooleanNumberConverter implements Converter { } @Override - public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (BigDecimal.ONE.compareTo(cellData.getNumberValue()) == 0) { return Boolean.TRUE; @@ -34,12 +34,12 @@ public class BooleanNumberConverter implements Converter { } @Override - public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (value) { - return new CellData(BigDecimal.ONE); + return new CellData<>(BigDecimal.ONE); } - return new CellData(BigDecimal.ZERO); + return new CellData<>(BigDecimal.ZERO); } } diff --git a/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanStringConverter.java b/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanStringConverter.java index e86c6ada..9f82f32a 100644 --- a/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanStringConverter.java +++ b/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanStringConverter.java @@ -14,7 +14,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; public class BooleanStringConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Boolean.class; } @@ -24,15 +24,15 @@ public class BooleanStringConverter implements Converter { } @Override - public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return Boolean.valueOf(cellData.getStringValue()); } @Override - public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return new CellData(value.toString()); + return new CellData<>(value.toString()); } } diff --git a/src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java b/src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java index 2840df73..63f387d7 100644 --- a/src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java +++ b/src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java @@ -16,7 +16,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; */ public class BoxingByteArrayImageConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Byte[].class; } @@ -26,13 +26,13 @@ public class BoxingByteArrayImageConverter implements Converter { } @Override - public Byte[] convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Byte[] convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { throw new UnsupportedOperationException("Cannot convert images to byte arrays"); } @Override - public CellData convertToExcelData(Byte[] value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Byte[] value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { byte[] byteValue = new byte[value.length]; for (int i = 0; i < value.length; i++) { diff --git a/src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java b/src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java index b186c374..48b70cbb 100644 --- a/src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java +++ b/src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java @@ -16,7 +16,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; */ public class ByteArrayImageConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return byte[].class; } @@ -26,8 +26,9 @@ public class ByteArrayImageConverter implements Converter { } @Override - public byte[] convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, - GlobalConfiguration globalConfiguration) { + + public byte[] convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { throw new UnsupportedOperationException("Cannot convert images to byte arrays"); } diff --git a/src/main/java/com/alibaba/excel/converters/byteconverter/ByteBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteBooleanConverter.java index 2b621558..afe079cb 100644 --- a/src/main/java/com/alibaba/excel/converters/byteconverter/ByteBooleanConverter.java +++ b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteBooleanConverter.java @@ -16,7 +16,7 @@ public class ByteBooleanConverter implements Converter { private static final Byte ZERO = (byte)0; @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Byte.class; } @@ -26,7 +26,7 @@ public class ByteBooleanConverter implements Converter { } @Override - public Byte convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Byte convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (cellData.getBooleanValue()) { return ONE; @@ -35,12 +35,12 @@ public class ByteBooleanConverter implements Converter { } @Override - public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (ONE.equals(value)) { - return new CellData(Boolean.TRUE); + return new CellData<>(Boolean.TRUE); } - return new CellData(Boolean.FALSE); + return new CellData<>(Boolean.FALSE); } } diff --git a/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java index f1facdfb..891ae714 100644 --- a/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java @@ -7,6 +7,8 @@ import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.NumberUtils; +import com.alibaba.excel.write.metadata.holder.WriteHolder; /** * Byte and number converter @@ -16,7 +18,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; public class ByteNumberConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Byte.class; } @@ -26,15 +28,15 @@ public class ByteNumberConverter implements Converter { } @Override - public Byte convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Byte convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return cellData.getNumberValue().byteValue(); } @Override - public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty, - GlobalConfiguration globalConfiguration) { - return new CellData(new BigDecimal(Byte.toString(value))); + public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty, + WriteHolder currentWriteHolder) { + return NumberUtils.formatToCellData(value, contentProperty, currentWriteHolder); } } diff --git a/src/main/java/com/alibaba/excel/converters/byteconverter/ByteStringConverter.java b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteStringConverter.java index c96114de..041557cf 100644 --- a/src/main/java/com/alibaba/excel/converters/byteconverter/ByteStringConverter.java +++ b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteStringConverter.java @@ -17,7 +17,7 @@ import com.alibaba.excel.util.NumberUtils; public class ByteStringConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Byte.class; } @@ -27,15 +27,15 @@ public class ByteStringConverter implements Converter { } @Override - public Byte convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Byte convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws ParseException { return NumberUtils.parseByte(cellData.getStringValue(), contentProperty); } @Override - public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return NumberUtils.formatToCellData(value, contentProperty); + return NumberUtils.formatToCellDataString(value, contentProperty); } } diff --git a/src/main/java/com/alibaba/excel/converters/date/DateDateConverter.java b/src/main/java/com/alibaba/excel/converters/date/DateDateConverter.java new file mode 100644 index 00000000..73b071af --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/date/DateDateConverter.java @@ -0,0 +1,47 @@ +package com.alibaba.excel.converters.date; + +import java.util.Date; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.WorkBookUtil; +import com.alibaba.excel.write.metadata.holder.WriteHolder; + +/** + * Date and date converter + * + * @author Jiaju Zhuang + */ +public class DateDateConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return Date.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.DATE; + } + + @Override + public Date convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return cellData.getDateValue(); + } + + @Override + public CellData convertToExcelData(Date value, ExcelContentProperty contentProperty, + WriteHolder currentWriteHolder) throws Exception { + CellData cellData = new CellData<>(value); + if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null + || contentProperty.getDateTimeFormatProperty().getFormat() == null) { + return cellData; + } + WorkBookUtil.fillDataFormat(cellData, currentWriteHolder, + contentProperty.getDateTimeFormatProperty().getFormat()); + return cellData; + } +} diff --git a/src/main/java/com/alibaba/excel/converters/date/DateNumberConverter.java b/src/main/java/com/alibaba/excel/converters/date/DateNumberConverter.java index fcc76bb3..6eee4de0 100644 --- a/src/main/java/com/alibaba/excel/converters/date/DateNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/date/DateNumberConverter.java @@ -19,7 +19,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; public class DateNumberConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Date.class; } @@ -29,7 +29,7 @@ public class DateNumberConverter implements Converter { } @Override - public Date convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Date convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { return DateUtil.getJavaDate(cellData.getNumberValue().doubleValue(), @@ -41,13 +41,13 @@ public class DateNumberConverter implements Converter { } @Override - public CellData convertToExcelData(Date value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Date value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { - return new CellData( + return new CellData<>( BigDecimal.valueOf(DateUtil.getExcelDate(value, globalConfiguration.getUse1904windowing()))); } else { - return new CellData(BigDecimal.valueOf( + return new CellData<>(BigDecimal.valueOf( DateUtil.getExcelDate(value, contentProperty.getDateTimeFormatProperty().getUse1904windowing()))); } } diff --git a/src/main/java/com/alibaba/excel/converters/date/DateStringConverter.java b/src/main/java/com/alibaba/excel/converters/date/DateStringConverter.java index ed7eb0a4..687d84d7 100644 --- a/src/main/java/com/alibaba/excel/converters/date/DateStringConverter.java +++ b/src/main/java/com/alibaba/excel/converters/date/DateStringConverter.java @@ -17,7 +17,7 @@ import com.alibaba.excel.util.DateUtils; */ public class DateStringConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Date.class; } @@ -27,7 +27,7 @@ public class DateStringConverter implements Converter { } @Override - public Date convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Date convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws ParseException { if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { return DateUtils.parseDate(cellData.getStringValue(), null); @@ -38,12 +38,12 @@ public class DateStringConverter implements Converter { } @Override - public CellData convertToExcelData(Date value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Date value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { - return new CellData(DateUtils.format(value, null)); + return new CellData<>(DateUtils.format(value, null)); } else { - return new CellData(DateUtils.format(value, contentProperty.getDateTimeFormatProperty().getFormat())); + return new CellData<>(DateUtils.format(value, contentProperty.getDateTimeFormatProperty().getFormat())); } } } diff --git a/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleBooleanConverter.java index cbf0b0b0..6aa509e1 100644 --- a/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleBooleanConverter.java +++ b/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleBooleanConverter.java @@ -16,7 +16,7 @@ public class DoubleBooleanConverter implements Converter { private static final Double ZERO = 0.0; @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Double.class; } @@ -26,7 +26,7 @@ public class DoubleBooleanConverter implements Converter { } @Override - public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (cellData.getBooleanValue()) { return ONE; @@ -35,12 +35,12 @@ public class DoubleBooleanConverter implements Converter { } @Override - public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (ONE.equals(value)) { - return new CellData(Boolean.TRUE); + return new CellData<>(Boolean.TRUE); } - return new CellData(Boolean.FALSE); + return new CellData<>(Boolean.FALSE); } } diff --git a/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleNumberConverter.java b/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleNumberConverter.java index 15fbdae3..c3db3d3b 100644 --- a/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleNumberConverter.java @@ -7,6 +7,8 @@ import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.NumberUtils; +import com.alibaba.excel.write.metadata.holder.WriteHolder; /** * Double and number converter @@ -16,7 +18,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; public class DoubleNumberConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Double.class; } @@ -26,15 +28,14 @@ public class DoubleNumberConverter implements Converter { } @Override - public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return cellData.getNumberValue().doubleValue(); } @Override - public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty, - GlobalConfiguration globalConfiguration) { - return new CellData(BigDecimal.valueOf(value)); + public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty, + WriteHolder currentWriteHolder) { + return NumberUtils.formatToCellData(value, contentProperty, currentWriteHolder); } - } diff --git a/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleStringConverter.java b/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleStringConverter.java index 2572b4ee..351d0b8a 100644 --- a/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleStringConverter.java +++ b/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleStringConverter.java @@ -17,7 +17,7 @@ import com.alibaba.excel.util.NumberUtils; public class DoubleStringConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Double.class; } @@ -27,14 +27,14 @@ public class DoubleStringConverter implements Converter { } @Override - public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws ParseException { return NumberUtils.parseDouble(cellData.getStringValue(), contentProperty); } @Override - public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return NumberUtils.formatToCellData(value, contentProperty); + return NumberUtils.formatToCellDataString(value, contentProperty); } } diff --git a/src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java b/src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java index 2e974378..a94f7c08 100644 --- a/src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java +++ b/src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java @@ -17,7 +17,7 @@ import com.alibaba.excel.util.FileUtils; */ public class FileImageConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return File.class; } @@ -27,13 +27,13 @@ public class FileImageConverter implements Converter { } @Override - public File convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public File convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { throw new UnsupportedOperationException("Cannot convert images to file"); } @Override - public CellData convertToExcelData(File value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(File value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws IOException { ImagePosition imagePosition = contentProperty.getField().getAnnotation(ImagePosition.class); if (imagePosition != null) { diff --git a/src/main/java/com/alibaba/excel/converters/floatconverter/FloatBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatBooleanConverter.java index 8fa2a647..c2f674f2 100644 --- a/src/main/java/com/alibaba/excel/converters/floatconverter/FloatBooleanConverter.java +++ b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatBooleanConverter.java @@ -16,7 +16,7 @@ public class FloatBooleanConverter implements Converter { private static final Float ZERO = (float)0.0; @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Float.class; } @@ -26,7 +26,7 @@ public class FloatBooleanConverter implements Converter { } @Override - public Float convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Float convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (cellData.getBooleanValue()) { return ONE; @@ -35,12 +35,12 @@ public class FloatBooleanConverter implements Converter { } @Override - public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (ONE.equals(value)) { - return new CellData(Boolean.TRUE); + return new CellData<>(Boolean.TRUE); } - return new CellData(Boolean.FALSE); + return new CellData<>(Boolean.FALSE); } } diff --git a/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java index 69cc22e7..1a401dff 100644 --- a/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java @@ -1,12 +1,12 @@ package com.alibaba.excel.converters.floatconverter; -import java.math.BigDecimal; - import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.NumberUtils; +import com.alibaba.excel.write.metadata.holder.WriteHolder; /** * Float and number converter @@ -16,7 +16,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; public class FloatNumberConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Float.class; } @@ -26,15 +26,14 @@ public class FloatNumberConverter implements Converter { } @Override - public Float convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Float convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return cellData.getNumberValue().floatValue(); } @Override - public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty, - GlobalConfiguration globalConfiguration) { - return new CellData(new BigDecimal(Float.toString(value))); + public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty, + WriteHolder currentWriteHolder) { + return NumberUtils.formatToCellData(value, contentProperty, currentWriteHolder); } - } diff --git a/src/main/java/com/alibaba/excel/converters/floatconverter/FloatStringConverter.java b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatStringConverter.java index ee2ef551..29c819b1 100644 --- a/src/main/java/com/alibaba/excel/converters/floatconverter/FloatStringConverter.java +++ b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatStringConverter.java @@ -17,7 +17,7 @@ import com.alibaba.excel.util.NumberUtils; public class FloatStringConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Float.class; } @@ -27,14 +27,14 @@ public class FloatStringConverter implements Converter { } @Override - public Float convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Float convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws ParseException { return NumberUtils.parseFloat(cellData.getStringValue(), contentProperty); } @Override - public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return NumberUtils.formatToCellData(value, contentProperty); + return NumberUtils.formatToCellDataString(value, contentProperty); } } diff --git a/src/main/java/com/alibaba/excel/converters/inputstream/InputStreamImageConverter.java b/src/main/java/com/alibaba/excel/converters/inputstream/InputStreamImageConverter.java index 1e752a54..15043074 100644 --- a/src/main/java/com/alibaba/excel/converters/inputstream/InputStreamImageConverter.java +++ b/src/main/java/com/alibaba/excel/converters/inputstream/InputStreamImageConverter.java @@ -20,7 +20,7 @@ import com.alibaba.excel.util.IoUtils; */ public class InputStreamImageConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return InputStream.class; } @@ -30,13 +30,13 @@ public class InputStreamImageConverter implements Converter { } @Override - public InputStream convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public InputStream convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { throw new UnsupportedOperationException("Cannot convert images to input stream"); } @Override - public CellData convertToExcelData(InputStream value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(InputStream value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws IOException { ImagePosition imagePosition = contentProperty.getField().getAnnotation(ImagePosition.class); if (imagePosition != null) { diff --git a/src/main/java/com/alibaba/excel/converters/integer/IntegerBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/integer/IntegerBooleanConverter.java index 541de08a..37b5d913 100644 --- a/src/main/java/com/alibaba/excel/converters/integer/IntegerBooleanConverter.java +++ b/src/main/java/com/alibaba/excel/converters/integer/IntegerBooleanConverter.java @@ -16,7 +16,7 @@ public class IntegerBooleanConverter implements Converter { private static final Integer ZERO = 0; @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Integer.class; } @@ -26,7 +26,7 @@ public class IntegerBooleanConverter implements Converter { } @Override - public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (cellData.getBooleanValue()) { return ONE; @@ -35,12 +35,12 @@ public class IntegerBooleanConverter implements Converter { } @Override - public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (ONE.equals(value)) { - return new CellData(Boolean.TRUE); + return new CellData<>(Boolean.TRUE); } - return new CellData(Boolean.FALSE); + return new CellData<>(Boolean.FALSE); } } diff --git a/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java b/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java index 117d4c11..95a796b5 100644 --- a/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java @@ -1,12 +1,12 @@ package com.alibaba.excel.converters.integer; -import java.math.BigDecimal; - import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.NumberUtils; +import com.alibaba.excel.write.metadata.holder.WriteHolder; /** * Integer and number converter @@ -16,7 +16,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; public class IntegerNumberConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Integer.class; } @@ -26,15 +26,15 @@ public class IntegerNumberConverter implements Converter { } @Override - public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return cellData.getNumberValue().intValue(); } @Override - public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, - GlobalConfiguration globalConfiguration) { - return new CellData(new BigDecimal(Integer.toString(value))); + public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, + WriteHolder currentWriteHolder) { + return NumberUtils.formatToCellData(value, contentProperty, currentWriteHolder); } } diff --git a/src/main/java/com/alibaba/excel/converters/integer/IntegerStringConverter.java b/src/main/java/com/alibaba/excel/converters/integer/IntegerStringConverter.java index 07bc1b77..e6d91d34 100644 --- a/src/main/java/com/alibaba/excel/converters/integer/IntegerStringConverter.java +++ b/src/main/java/com/alibaba/excel/converters/integer/IntegerStringConverter.java @@ -17,7 +17,7 @@ import com.alibaba.excel.util.NumberUtils; public class IntegerStringConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Integer.class; } @@ -27,14 +27,14 @@ public class IntegerStringConverter implements Converter { } @Override - public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws ParseException { return NumberUtils.parseInteger(cellData.getStringValue(), contentProperty); } @Override - public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return NumberUtils.formatToCellData(value, contentProperty); + return NumberUtils.formatToCellDataString(value, contentProperty); } } diff --git a/src/main/java/com/alibaba/excel/converters/longconverter/LongBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/longconverter/LongBooleanConverter.java index 6ee0217b..298fed5e 100644 --- a/src/main/java/com/alibaba/excel/converters/longconverter/LongBooleanConverter.java +++ b/src/main/java/com/alibaba/excel/converters/longconverter/LongBooleanConverter.java @@ -16,7 +16,7 @@ public class LongBooleanConverter implements Converter { private static final Long ZERO = 0L; @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Long.class; } @@ -26,7 +26,7 @@ public class LongBooleanConverter implements Converter { } @Override - public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (cellData.getBooleanValue()) { return ONE; @@ -35,12 +35,12 @@ public class LongBooleanConverter implements Converter { } @Override - public CellData convertToExcelData(Long value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Long value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (ONE.equals(value)) { - return new CellData(Boolean.TRUE); + return new CellData<>(Boolean.TRUE); } - return new CellData(Boolean.FALSE); + return new CellData<>(Boolean.FALSE); } } diff --git a/src/main/java/com/alibaba/excel/converters/longconverter/LongNumberConverter.java b/src/main/java/com/alibaba/excel/converters/longconverter/LongNumberConverter.java index 8058d624..7e4aa235 100644 --- a/src/main/java/com/alibaba/excel/converters/longconverter/LongNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/longconverter/LongNumberConverter.java @@ -1,12 +1,12 @@ package com.alibaba.excel.converters.longconverter; -import java.math.BigDecimal; - import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.NumberUtils; +import com.alibaba.excel.write.metadata.holder.WriteHolder; /** * Long and number converter @@ -16,7 +16,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; public class LongNumberConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Long.class; } @@ -26,15 +26,15 @@ public class LongNumberConverter implements Converter { } @Override - public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return cellData.getNumberValue().longValue(); } @Override - public CellData convertToExcelData(Long value, ExcelContentProperty contentProperty, - GlobalConfiguration globalConfiguration) { - return new CellData(BigDecimal.valueOf(value)); + public CellData convertToExcelData(Long value, ExcelContentProperty contentProperty, + WriteHolder currentWriteHolder) { + return NumberUtils.formatToCellData(value, contentProperty, currentWriteHolder); } } diff --git a/src/main/java/com/alibaba/excel/converters/longconverter/LongStringConverter.java b/src/main/java/com/alibaba/excel/converters/longconverter/LongStringConverter.java index 06e94f03..873fb113 100644 --- a/src/main/java/com/alibaba/excel/converters/longconverter/LongStringConverter.java +++ b/src/main/java/com/alibaba/excel/converters/longconverter/LongStringConverter.java @@ -17,7 +17,7 @@ import com.alibaba.excel.util.NumberUtils; public class LongStringConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Long.class; } @@ -27,14 +27,14 @@ public class LongStringConverter implements Converter { } @Override - public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws ParseException { return NumberUtils.parseLong(cellData.getStringValue(), contentProperty); } @Override - public CellData convertToExcelData(Long value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Long value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return NumberUtils.formatToCellData(value, contentProperty); + return NumberUtils.formatToCellDataString(value, contentProperty); } } diff --git a/src/main/java/com/alibaba/excel/converters/shortconverter/ShortBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortBooleanConverter.java index 2c0cc61d..eb39b7de 100644 --- a/src/main/java/com/alibaba/excel/converters/shortconverter/ShortBooleanConverter.java +++ b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortBooleanConverter.java @@ -16,7 +16,7 @@ public class ShortBooleanConverter implements Converter { private static final Short ZERO = 0; @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Short.class; } @@ -26,7 +26,7 @@ public class ShortBooleanConverter implements Converter { } @Override - public Short convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Short convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (cellData.getBooleanValue()) { return ONE; @@ -35,12 +35,12 @@ public class ShortBooleanConverter implements Converter { } @Override - public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (ONE.equals(value)) { - return new CellData(Boolean.TRUE); + return new CellData<>(Boolean.TRUE); } - return new CellData(Boolean.FALSE); + return new CellData<>(Boolean.FALSE); } } diff --git a/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java index 357c6aeb..eedfca4f 100644 --- a/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java @@ -7,6 +7,8 @@ import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.NumberUtils; +import com.alibaba.excel.write.metadata.holder.WriteHolder; /** * Short and number converter @@ -16,7 +18,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; public class ShortNumberConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Short.class; } @@ -26,15 +28,14 @@ public class ShortNumberConverter implements Converter { } @Override - public Short convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Short convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return cellData.getNumberValue().shortValue(); } @Override - public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty, - GlobalConfiguration globalConfiguration) { - return new CellData(new BigDecimal(Short.toString(value))); + public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty, + WriteHolder currentWriteHolder) { + return NumberUtils.formatToCellData(value, contentProperty, currentWriteHolder); } - } diff --git a/src/main/java/com/alibaba/excel/converters/shortconverter/ShortStringConverter.java b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortStringConverter.java index a683a038..85c56067 100644 --- a/src/main/java/com/alibaba/excel/converters/shortconverter/ShortStringConverter.java +++ b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortStringConverter.java @@ -17,7 +17,7 @@ import com.alibaba.excel.util.NumberUtils; public class ShortStringConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return Short.class; } @@ -27,14 +27,14 @@ public class ShortStringConverter implements Converter { } @Override - public Short convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public Short convertToJavaData(CellDatacellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws ParseException { return NumberUtils.parseShort(cellData.getStringValue(), contentProperty); } @Override - public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty, + public CellDataconvertToExcelData(Short value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return NumberUtils.formatToCellData(value, contentProperty); + return NumberUtils.formatToCellDataString(value, contentProperty); } } diff --git a/src/main/java/com/alibaba/excel/converters/string/StringBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/string/StringBooleanConverter.java index c405de5e..f2aafb4d 100644 --- a/src/main/java/com/alibaba/excel/converters/string/StringBooleanConverter.java +++ b/src/main/java/com/alibaba/excel/converters/string/StringBooleanConverter.java @@ -14,7 +14,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; public class StringBooleanConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return String.class; } @@ -24,15 +24,15 @@ public class StringBooleanConverter implements Converter { } @Override - public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return cellData.getBooleanValue().toString(); } @Override - public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return new CellData(Boolean.valueOf(value)); + return new CellData<>(Boolean.valueOf(value)); } } diff --git a/src/main/java/com/alibaba/excel/converters/string/StringErrorConverter.java b/src/main/java/com/alibaba/excel/converters/string/StringErrorConverter.java index 66112e1a..f0a71a46 100644 --- a/src/main/java/com/alibaba/excel/converters/string/StringErrorConverter.java +++ b/src/main/java/com/alibaba/excel/converters/string/StringErrorConverter.java @@ -13,7 +13,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; */ public class StringErrorConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return String.class; } @@ -23,15 +23,15 @@ public class StringErrorConverter implements Converter { } @Override - public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return cellData.getStringValue(); } @Override - public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return new CellData(CellDataTypeEnum.ERROR, value); + return new CellData<>(CellDataTypeEnum.ERROR, value); } } diff --git a/src/main/java/com/alibaba/excel/converters/string/StringImageConverter.java b/src/main/java/com/alibaba/excel/converters/string/StringImageConverter.java index c15d9a0e..940d0065 100644 --- a/src/main/java/com/alibaba/excel/converters/string/StringImageConverter.java +++ b/src/main/java/com/alibaba/excel/converters/string/StringImageConverter.java @@ -20,7 +20,7 @@ import com.alibaba.excel.util.IoUtils; */ public class StringImageConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return String.class; } @@ -30,13 +30,13 @@ public class StringImageConverter implements Converter { } @Override - public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { throw new UnsupportedOperationException("Cannot convert images to string"); } @Override - public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws IOException { ImagePosition imagePosition = contentProperty.getField().getAnnotation(ImagePosition.class); if (imagePosition != null) { diff --git a/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java b/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java index b31bc706..e9b6fef6 100644 --- a/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java @@ -22,7 +22,7 @@ import com.alibaba.excel.util.StringUtils; public class StringNumberConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return String.class; } @@ -32,7 +32,7 @@ public class StringNumberConverter implements Converter { } @Override - public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { // If there are "DateTimeFormat", read as date if (contentProperty != null && contentProperty.getDateTimeFormatProperty() != null) { @@ -55,8 +55,8 @@ public class StringNumberConverter implements Converter { } @Override - public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return new CellData(new BigDecimal(value)); + return new CellData<>(new BigDecimal(value)); } } diff --git a/src/main/java/com/alibaba/excel/converters/string/StringStringConverter.java b/src/main/java/com/alibaba/excel/converters/string/StringStringConverter.java index df1b1e14..3b1ce3df 100644 --- a/src/main/java/com/alibaba/excel/converters/string/StringStringConverter.java +++ b/src/main/java/com/alibaba/excel/converters/string/StringStringConverter.java @@ -13,7 +13,7 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; */ public class StringStringConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return String.class; } @@ -23,15 +23,15 @@ public class StringStringConverter implements Converter { } @Override - public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { return cellData.getStringValue(); } @Override - public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return new CellData(value); + return new CellData<>(value); } } diff --git a/src/main/java/com/alibaba/excel/converters/url/UrlImageConverter.java b/src/main/java/com/alibaba/excel/converters/url/UrlImageConverter.java index b622d66d..a9e60df9 100644 --- a/src/main/java/com/alibaba/excel/converters/url/UrlImageConverter.java +++ b/src/main/java/com/alibaba/excel/converters/url/UrlImageConverter.java @@ -19,7 +19,7 @@ import com.alibaba.excel.util.IoUtils; */ public class UrlImageConverter implements Converter { @Override - public Class supportJavaTypeKey() { + public Class supportJavaTypeKey() { return URL.class; } @@ -29,19 +29,19 @@ public class UrlImageConverter implements Converter { } @Override - public URL convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + public URL convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { throw new UnsupportedOperationException("Cannot convert images to url."); } @Override - public CellData convertToExcelData(URL value, ExcelContentProperty contentProperty, + public CellData convertToExcelData(URL value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws IOException { InputStream inputStream = null; try { inputStream = value.openStream(); byte[] bytes = IoUtils.toByteArray(inputStream); - return new CellData(bytes); + return new CellData<>(bytes); } finally { if (inputStream != null) { inputStream.close(); diff --git a/src/main/java/com/alibaba/excel/enums/CellDataTypeEnum.java b/src/main/java/com/alibaba/excel/enums/CellDataTypeEnum.java index 44efc179..6220340a 100644 --- a/src/main/java/com/alibaba/excel/enums/CellDataTypeEnum.java +++ b/src/main/java/com/alibaba/excel/enums/CellDataTypeEnum.java @@ -39,9 +39,15 @@ public enum CellDataTypeEnum { /** * Images are currently supported only when writing */ - IMAGE; + IMAGE, + /** + * date.Support only when writing. + */ + DATE, + ; private static final Map TYPE_ROUTING_MAP = new HashMap(16); + static { TYPE_ROUTING_MAP.put("s", STRING); TYPE_ROUTING_MAP.put("str", DIRECT_STRING); diff --git a/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java b/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java index 4b1b802a..a0cd5078 100644 --- a/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java +++ b/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java @@ -16,7 +16,7 @@ import com.alibaba.excel.util.ConverterUtils; public abstract class AnalysisEventListener implements ReadListener { @Override - public void invokeHead(Map headMap, AnalysisContext context) { + public void invokeHead(Map> headMap, AnalysisContext context) { invokeHeadMap(ConverterUtils.convertToStringMap(headMap, context), context); } diff --git a/src/main/java/com/alibaba/excel/exception/ExcelDataConvertException.java b/src/main/java/com/alibaba/excel/exception/ExcelDataConvertException.java index 5198c20f..7231afd9 100644 --- a/src/main/java/com/alibaba/excel/exception/ExcelDataConvertException.java +++ b/src/main/java/com/alibaba/excel/exception/ExcelDataConvertException.java @@ -4,11 +4,16 @@ import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.write.builder.ExcelWriterBuilder; +import lombok.Getter; +import lombok.Setter; + /** * Data convert exception * * @author Jiaju Zhuang */ +@Getter +@Setter public class ExcelDataConvertException extends RuntimeException { /** * NotNull. @@ -21,7 +26,7 @@ public class ExcelDataConvertException extends RuntimeException { /** * NotNull. */ - private CellData cellData; + private CellData cellData; /** * Nullable.Only when the header is configured and when the class header is used is not null. * @@ -47,35 +52,4 @@ public class ExcelDataConvertException extends RuntimeException { this.excelContentProperty = excelContentProperty; } - public Integer getRowIndex() { - return rowIndex; - } - - public void setRowIndex(Integer rowIndex) { - this.rowIndex = rowIndex; - } - - public Integer getColumnIndex() { - return columnIndex; - } - - public void setColumnIndex(Integer columnIndex) { - this.columnIndex = columnIndex; - } - - public ExcelContentProperty getExcelContentProperty() { - return excelContentProperty; - } - - public void setExcelContentProperty(ExcelContentProperty excelContentProperty) { - this.excelContentProperty = excelContentProperty; - } - - public CellData getCellData() { - return cellData; - } - - public void setCellData(CellData cellData) { - this.cellData = cellData; - } } diff --git a/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java b/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java index 6bfd8252..548503d0 100644 --- a/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java +++ b/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java @@ -34,7 +34,7 @@ public abstract class AbstractHolder implements ConfigurationHolder { *

* Write key: */ - private Map converterMap; + private Map> converterMap; public AbstractHolder(BasicParameter basicParameter, AbstractHolder prentAbstractHolder) { this.newInitialization = Boolean.TRUE; @@ -68,6 +68,7 @@ public abstract class AbstractHolder implements ConfigurationHolder { } else { globalConfiguration.setLocale(basicParameter.getLocale()); } + } public Boolean getNewInitialization() { @@ -102,16 +103,16 @@ public abstract class AbstractHolder implements ConfigurationHolder { this.globalConfiguration = globalConfiguration; } - public Map getConverterMap() { + public Map> getConverterMap() { return converterMap; } - public void setConverterMap(Map converterMap) { + public void setConverterMap(Map> converterMap) { this.converterMap = converterMap; } @Override - public Map converterMap() { + public Map> converterMap() { return getConverterMap(); } diff --git a/src/main/java/com/alibaba/excel/metadata/BasicParameter.java b/src/main/java/com/alibaba/excel/metadata/BasicParameter.java index d00c93a8..5baf5cf5 100644 --- a/src/main/java/com/alibaba/excel/metadata/BasicParameter.java +++ b/src/main/java/com/alibaba/excel/metadata/BasicParameter.java @@ -41,6 +41,13 @@ public class BasicParameter { */ private Locale locale; + /** + * Whether to use scientific Format. + * + * default is false + */ + private Boolean useScientificFormat; + public List> getHead() { return head; } @@ -88,4 +95,12 @@ public class BasicParameter { public void setLocale(Locale locale) { this.locale = locale; } + + public Boolean getUseScientificFormat() { + return useScientificFormat; + } + + public void setUseScientificFormat(Boolean useScientificFormat) { + this.useScientificFormat = useScientificFormat; + } } diff --git a/src/main/java/com/alibaba/excel/metadata/CellData.java b/src/main/java/com/alibaba/excel/metadata/CellData.java index cdce6ad2..5621ed6e 100644 --- a/src/main/java/com/alibaba/excel/metadata/CellData.java +++ b/src/main/java/com/alibaba/excel/metadata/CellData.java @@ -2,10 +2,14 @@ package com.alibaba.excel.metadata; import java.math.BigDecimal; import com.alibaba.excel.annotation.write.style.ImagePosition; +import java.util.Date; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.property.ImagePositionProperty; import com.alibaba.excel.util.StringUtils; +import lombok.Getter; +import lombok.Setter; + /** * Excel internal cell data. * @@ -13,6 +17,8 @@ import com.alibaba.excel.util.StringUtils; * * @author Jiaju Zhuang */ +@Getter +@Setter public class CellData extends AbstractCell { private CellDataTypeEnum type; /** @@ -41,11 +47,15 @@ public class CellData extends AbstractCell { */ private Boolean useImagePositionProperty = false; /** - * The number formatting.Currently only supported when reading + * Support only when writing. + */ + private Date dateValue; + /** + * The number formatting. */ - private Integer dataFormat; + private Short dataFormat; /** - * The string of number formatting.Currently only supported when reading + * The string of number formatting. */ private String dataFormatString; /** @@ -66,6 +76,8 @@ public class CellData extends AbstractCell { this.dataFormat = other.dataFormat; this.dataFormatString = other.dataFormatString; this.data = other.data; + setRowIndex(other.getRowIndex()); + setColumnIndex(other.getColumnIndex()); } public CellData() {} @@ -137,110 +149,23 @@ public class CellData extends AbstractCell { this.formula = Boolean.FALSE; } - public CellData(CellDataTypeEnum type) { - if (type == null) { - throw new IllegalArgumentException("Type can not be null"); + public CellData(Date dateValue) { + if (dateValue == null) { + throw new IllegalArgumentException("DateValue can not be null"); } - this.type = type; + this.type = CellDataTypeEnum.DATE; + this.dateValue = dateValue; this.formula = Boolean.FALSE; } - public CellDataTypeEnum getType() { - return type; - } - public void setType(CellDataTypeEnum type) { + public CellData(CellDataTypeEnum type) { + if (type == null) { + throw new IllegalArgumentException("Type can not be null"); + } this.type = type; } - public BigDecimal getNumberValue() { - return numberValue; - } - - public void setNumberValue(BigDecimal numberValue) { - this.numberValue = numberValue; - } - - public String getStringValue() { - return stringValue; - } - - public void setStringValue(String stringValue) { - this.stringValue = stringValue; - } - - public Boolean getBooleanValue() { - return booleanValue; - } - - public void setBooleanValue(Boolean booleanValue) { - this.booleanValue = booleanValue; - } - - public Boolean getFormula() { - return formula; - } - - public void setFormula(Boolean formula) { - this.formula = formula; - } - - public String getFormulaValue() { - return formulaValue; - } - - public void setFormulaValue(String formulaValue) { - this.formulaValue = formulaValue; - } - - public byte[] getImageValue() { - return imageValue; - } - - public void setImageValue(byte[] imageValue) { - this.imageValue = imageValue; - } - - public ImagePositionProperty getImagePositionProperty() { - return imagePositionProperty; - } - - public void setImagePositionProperty(ImagePositionProperty imagePositionProperty) { - this.imagePositionProperty = imagePositionProperty; - } - - public Boolean getUseImagePositionProperty() { - return useImagePositionProperty; - } - - public void setUseImagePositionProperty(Boolean useImagePositionProperty) { - this.useImagePositionProperty = useImagePositionProperty; - } - - public Integer getDataFormat() { - return dataFormat; - } - - public void setDataFormat(Integer dataFormat) { - this.dataFormat = dataFormat; - } - - public String getDataFormatString() { - return dataFormatString; - } - - public void setDataFormatString(String dataFormatString) { - this.dataFormatString = dataFormatString; - } - - public T getData() { - return data; - } - - public void setData(T data) { - this.data = data; - } - /** * Ensure that the object does not appear null */ @@ -269,37 +194,37 @@ public class CellData extends AbstractCell { } } - public static CellData newEmptyInstance() { + public static CellData newEmptyInstance() { return newEmptyInstance(null, null); } - public static CellData newEmptyInstance(Integer rowIndex, Integer columnIndex) { - CellData cellData = new CellData(CellDataTypeEnum.EMPTY); + public static CellData newEmptyInstance(Integer rowIndex, Integer columnIndex) { + CellData cellData = new CellData<>(CellDataTypeEnum.EMPTY); cellData.setRowIndex(rowIndex); cellData.setColumnIndex(columnIndex); return cellData; } - public static CellData newInstance(Boolean booleanValue) { + public static CellData newInstance(Boolean booleanValue) { return newInstance(booleanValue, null, null); } - public static CellData newInstance(Boolean booleanValue, Integer rowIndex, Integer columnIndex) { - CellData cellData = new CellData(booleanValue); + public static CellData newInstance(Boolean booleanValue, Integer rowIndex, Integer columnIndex) { + CellData cellData = new CellData<>(booleanValue); cellData.setRowIndex(rowIndex); cellData.setColumnIndex(columnIndex); return cellData; } - public static CellData newInstance(String stringValue, Integer rowIndex, Integer columnIndex) { - CellData cellData = new CellData(stringValue); + public static CellData newInstance(String stringValue, Integer rowIndex, Integer columnIndex) { + CellData cellData = new CellData<>(stringValue); cellData.setRowIndex(rowIndex); cellData.setColumnIndex(columnIndex); return cellData; } - public static CellData newInstance(BigDecimal numberValue, Integer rowIndex, Integer columnIndex) { - CellData cellData = new CellData(numberValue); + public static CellData newInstance(BigDecimal numberValue, Integer rowIndex, Integer columnIndex) { + CellData cellData = new CellData<>(numberValue); cellData.setRowIndex(rowIndex); cellData.setColumnIndex(columnIndex); return cellData; @@ -312,14 +237,28 @@ public class CellData extends AbstractCell { } switch (type) { case NUMBER: + if (numberValue == null) { + return StringUtils.EMPTY; + } return numberValue.toString(); case BOOLEAN: + if (booleanValue == null) { + return StringUtils.EMPTY; + } return booleanValue.toString(); case DIRECT_STRING: case STRING: case ERROR: return stringValue; + case DATE: + if (dateValue == null) { + return StringUtils.EMPTY; + } + return dateValue.toString(); case IMAGE: + if (imageValue == null) { + return StringUtils.EMPTY; + } return "image[" + imageValue.length + "]"; default: return StringUtils.EMPTY; diff --git a/src/main/java/com/alibaba/excel/metadata/ConfigurationHolder.java b/src/main/java/com/alibaba/excel/metadata/ConfigurationHolder.java index d84b1d58..ee4d7edf 100644 --- a/src/main/java/com/alibaba/excel/metadata/ConfigurationHolder.java +++ b/src/main/java/com/alibaba/excel/metadata/ConfigurationHolder.java @@ -32,5 +32,5 @@ public interface ConfigurationHolder extends Holder { * * @return Converter */ - Map converterMap(); + Map> converterMap(); } diff --git a/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java b/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java index 12cc8d31..26f3720f 100644 --- a/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java +++ b/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java @@ -25,6 +25,12 @@ public class GlobalConfiguration { * used when formatting dates and numbers. */ private Locale locale; + /** + * Whether to use scientific Format. + * + * default is false + */ + private Boolean useScientificFormat; public Boolean getUse1904windowing() { return use1904windowing; @@ -49,4 +55,12 @@ public class GlobalConfiguration { public void setLocale(Locale locale) { this.locale = locale; } + + public Boolean getUseScientificFormat() { + return useScientificFormat; + } + + public void setUseScientificFormat(Boolean useScientificFormat) { + this.useScientificFormat = useScientificFormat; + } } diff --git a/src/main/java/com/alibaba/excel/metadata/DataFormatter.java b/src/main/java/com/alibaba/excel/metadata/format/DataFormatter.java similarity index 85% rename from src/main/java/com/alibaba/excel/metadata/DataFormatter.java rename to src/main/java/com/alibaba/excel/metadata/format/DataFormatter.java index 7467cd26..e9266c71 100644 --- a/src/main/java/com/alibaba/excel/metadata/DataFormatter.java +++ b/src/main/java/com/alibaba/excel/metadata/format/DataFormatter.java @@ -15,7 +15,7 @@ * can be found in svn at location root/projects/3rd-party/src * ==================================================================== */ -package com.alibaba.excel.metadata; +package com.alibaba.excel.metadata.format; import java.math.BigDecimal; import java.math.RoundingMode; @@ -34,13 +34,15 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.poi.ss.format.CellFormat; +import org.apache.poi.ss.format.CellFormatResult; import org.apache.poi.ss.usermodel.DateUtil; -import org.apache.poi.ss.usermodel.ExcelGeneralNumberFormat; import org.apache.poi.ss.usermodel.ExcelStyleDateFormatter; import org.apache.poi.ss.usermodel.FractionFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.util.DateUtils; /** @@ -138,45 +140,92 @@ public class DataFormatter { * @return */ private Boolean use1904windowing; - /** - * Creates a formatter using the {@link Locale#getDefault() default locale}. + * Whether to use scientific Format. + * + * default is false */ - public DataFormatter() { - this(null, null); - } + private Boolean useScientificFormat; /** * Creates a formatter using the given locale. * */ - public DataFormatter(Locale locale, Boolean use1904windowing) { - this.use1904windowing = use1904windowing != null ? use1904windowing : Boolean.FALSE; - this.locale = locale != null ? locale : Locale.getDefault(); + public DataFormatter(GlobalConfiguration globalConfiguration) { + if (globalConfiguration == null) { + this.use1904windowing = Boolean.FALSE; + this.locale = Locale.getDefault(); + this.useScientificFormat = Boolean.FALSE; + } else { + this.use1904windowing = + globalConfiguration.getUse1904windowing() != null ? globalConfiguration.getUse1904windowing() + : Boolean.FALSE; + this.locale = + globalConfiguration.getLocale() != null ? globalConfiguration.getLocale() : Locale.getDefault(); + this.useScientificFormat = + globalConfiguration.getUseScientificFormat() != null ? globalConfiguration.getUseScientificFormat() + : Boolean.FALSE; + } this.dateSymbols = DateFormatSymbols.getInstance(this.locale); this.decimalSymbols = DecimalFormatSymbols.getInstance(this.locale); } - private Format getFormat(Integer dataFormat, String dataFormatString) { + private Format getFormat(Double data,Short dataFormat, String dataFormatString) { + + // Might be better to separate out the n p and z formats, falling back to p when n and z are not set. + // That however would require other code to be re factored. + // String[] formatBits = formatStrIn.split(";"); + // int i = cellValue > 0.0 ? 0 : cellValue < 0.0 ? 1 : 2; + // String formatStr = (i < formatBits.length) ? formatBits[i] : formatBits[0]; + String formatStr = dataFormatString; + + // Excel supports 2+ part conditional data formats, eg positive/negative/zero, + // or (>1000),(>0),(0),(negative). As Java doesn't handle these kinds + // of different formats for different ranges, just +ve/-ve, we need to + // handle these ourselves in a special way. + // For now, if we detect 2+ parts, we call out to CellFormat to handle it + // TODO Going forward, we should really merge the logic between the two classes + if (formatStr.contains(";") && + (formatStr.indexOf(';') != formatStr.lastIndexOf(';') + || rangeConditionalPattern.matcher(formatStr).matches() + ) ) { + try { + // Ask CellFormat to get a formatter for it + CellFormat cfmt = CellFormat.getInstance(locale, formatStr); + // CellFormat requires callers to identify date vs not, so do so + Object cellValueO = data; + if (DateUtil.isADateFormat(dataFormat, formatStr) && + // don't try to handle Date value 0, let a 3 or 4-part format take care of it + data.doubleValue() != 0.0) { + cellValueO = DateUtil.getJavaDate(data, use1904windowing); + } + // Wrap and return (non-cachable - CellFormat does that) + return new CellFormatResultWrapper( cfmt.apply(cellValueO) ); + } catch (Exception e) { + LOGGER.warn("Formatting failed for format {}, falling back",formatStr, e); + } + } + // See if we already have it cached - Format format = formats.get(dataFormatString); + Format format = formats.get(formatStr); if (format != null) { return format; } + // Is it one of the special built in types, General or @? - if ("General".equalsIgnoreCase(dataFormatString) || "@".equals(dataFormatString)) { + if ("General".equalsIgnoreCase(formatStr) || "@".equals(formatStr)) { format = getDefaultFormat(); - addFormat(dataFormatString, format); + addFormat(formatStr, format); return format; } // Build a formatter, and cache it - format = createFormat(dataFormat, dataFormatString); - addFormat(dataFormatString, format); + format = createFormat(dataFormat, formatStr); + addFormat(formatStr, format); return format; } - private Format createFormat(Integer dataFormat, String dataFormatString) { + private Format createFormat(Short dataFormat, String dataFormatString) { String formatStr = dataFormatString; Format format = checkSpecialConverter(formatStr); @@ -519,7 +568,7 @@ public class DataFormatter { try { return new InternalDecimalFormatWithScale(format, symbols); } catch (IllegalArgumentException iae) { - LOGGER.debug("Formatting failed for format {}, falling back", formatStr, iae); + LOGGER.error("Formatting failed for format {}, falling back", formatStr, iae); // the pattern could not be parsed correctly, // so fall back to the default number format return getDefaultFormat(); @@ -532,7 +581,7 @@ public class DataFormatter { return defaultNumFormat; // otherwise use general format } - defaultNumFormat = new ExcelGeneralNumberFormat(locale); + defaultNumFormat = new ExcelGeneralNumberFormat(locale, useScientificFormat); return defaultNumFormat; } @@ -558,8 +607,8 @@ public class DataFormatter { * @param dataFormatString * @return Formatted value */ - private String getFormattedDateString(Double data, Integer dataFormat, String dataFormatString) { - Format dateFormat = getFormat(dataFormat, dataFormatString); + private String getFormattedDateString(Double data, Short dataFormat, String dataFormatString) { + Format dateFormat = getFormat(data, dataFormat, dataFormatString); if (dateFormat instanceof ExcelStyleDateFormatter) { // Hint about the raw excel value ((ExcelStyleDateFormatter)dateFormat).setDateToBeFormatted(data); @@ -581,8 +630,8 @@ public class DataFormatter { * @param dataFormatString * @return a formatted number string */ - private String getFormattedNumberString(Double data, Integer dataFormat, String dataFormatString) { - Format numberFormat = getFormat(dataFormat, dataFormatString); + private String getFormattedNumberString(Double data, Short dataFormat, String dataFormatString) { + Format numberFormat = getFormat(data, dataFormat, dataFormatString); String formatted = numberFormat.format(data); return formatted.replaceFirst("E(\\d)", "E+$1"); // to match Excel's E-notation } @@ -595,7 +644,7 @@ public class DataFormatter { * @param dataFormatString * @return */ - public String format(Double data, Integer dataFormat, String dataFormatString) { + public String format(Double data, Short dataFormat, String dataFormatString) { if (DateUtils.isADateFormat(dataFormat, dataFormatString)) { return getFormattedDateString(data, dataFormat, dataFormatString); } @@ -783,4 +832,26 @@ public class DataFormatter { } } + /** + * Workaround until we merge {@link org.apache.poi.ss.usermodel.DataFormatter} with {@link CellFormat}. Constant, non-cachable wrapper around a + * {@link CellFormatResult} + */ + private final class CellFormatResultWrapper extends Format { + private final CellFormatResult result; + + private CellFormatResultWrapper(CellFormatResult result) { + this.result = result; + } + + @Override + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + return toAppendTo.append(result.text.trim()); + } + + @Override + public Object parseObject(String source, ParsePosition pos) { + return null; // Not supported + } + } + } diff --git a/src/main/java/com/alibaba/excel/metadata/format/ExcelGeneralNumberFormat.java b/src/main/java/com/alibaba/excel/metadata/format/ExcelGeneralNumberFormat.java new file mode 100644 index 00000000..cdeb5e85 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/format/ExcelGeneralNumberFormat.java @@ -0,0 +1,81 @@ +package com.alibaba.excel.metadata.format; + +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.FieldPosition; +import java.text.Format; +import java.text.ParsePosition; +import java.util.Locale; + +import org.apache.poi.ss.usermodel.DataFormatter; + +/** + * Written with reference to {@link org.apache.poi.ss.usermodel.ExcelGeneralNumberFormat }. + *

+ * Supported Do not use scientific notation. + * + * @author JiaJu Zhuang + **/ +public class ExcelGeneralNumberFormat extends Format { + + private static final long serialVersionUID = 1L; + + private static final MathContext TO_10_SF = new MathContext(10, RoundingMode.HALF_UP); + + private final DecimalFormatSymbols decimalSymbols; + private final DecimalFormat integerFormat; + private final DecimalFormat decimalFormat; + private final DecimalFormat scientificFormat; + + public ExcelGeneralNumberFormat(final Locale locale, final boolean useScientificFormat) { + decimalSymbols = DecimalFormatSymbols.getInstance(locale); + // Supported Do not use scientific notation. + if (useScientificFormat) { + scientificFormat = new DecimalFormat("0.#####E0", decimalSymbols); + } else { + scientificFormat = new DecimalFormat("#", decimalSymbols); + } + org.apache.poi.ss.usermodel.DataFormatter.setExcelStyleRoundingMode(scientificFormat); + integerFormat = new DecimalFormat("#", decimalSymbols); + org.apache.poi.ss.usermodel.DataFormatter.setExcelStyleRoundingMode(integerFormat); + decimalFormat = new DecimalFormat("#.##########", decimalSymbols); + DataFormatter.setExcelStyleRoundingMode(decimalFormat); + } + + @Override + public StringBuffer format(Object number, StringBuffer toAppendTo, FieldPosition pos) { + final double value; + if (number instanceof Number) { + value = ((Number) number).doubleValue(); + if (Double.isInfinite(value) || Double.isNaN(value)) { + return integerFormat.format(number, toAppendTo, pos); + } + } else { + // testBug54786 gets here with a date, so retain previous behaviour + return integerFormat.format(number, toAppendTo, pos); + } + + final double abs = Math.abs(value); + if (abs >= 1E11 || (abs <= 1E-10 && abs > 0)) { + return scientificFormat.format(number, toAppendTo, pos); + } else if (Math.floor(value) == value || abs >= 1E10) { + // integer, or integer portion uses all 11 allowed digits + return integerFormat.format(number, toAppendTo, pos); + } + // Non-integers of non-scientific magnitude are formatted as "up to 11 + // numeric characters, with the decimal point counting as a numeric + // character". We know there is a decimal point, so limit to 10 digits. + // https://support.microsoft.com/en-us/kb/65903 + final double rounded = new BigDecimal(value).round(TO_10_SF).doubleValue(); + return decimalFormat.format(rounded, toAppendTo, pos); + } + + @Override + public Object parseObject(String source, ParsePosition pos) { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java b/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java index e846befc..5915cf06 100644 --- a/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java +++ b/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; +import org.apache.commons.collections4.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -75,7 +76,7 @@ public class ExcelHeadProperty { int headIndex = 0; for (int i = 0; i < head.size(); i++) { if (holder instanceof AbstractWriteHolder) { - if (((AbstractWriteHolder)holder).ignore(null, i)) { + if (((AbstractWriteHolder) holder).ignore(null, i)) { continue; } } @@ -119,116 +120,31 @@ public class ExcelHeadProperty { return; } // Declared fields - List defaultFieldList = new ArrayList(); - Map customFieldMap = new TreeMap(); - ClassUtils.declaredFields(headClazz, defaultFieldList, customFieldMap, ignoreMap, convertAllField); - - List> exportFieldBoolPairsList = new ArrayList>(); - int index = 0; - while (customFieldMap.containsKey(index)) { - Field field = customFieldMap.get(index); - Map.Entry fieldBooleanPair = - new AbstractMap.SimpleEntry(field, Boolean.TRUE); - exportFieldBoolPairsList.add(fieldBooleanPair); - index++; - } - for (Field field : defaultFieldList) { - Map.Entry fieldBoolPair = new AbstractMap.SimpleEntry(field, Boolean.FALSE); - exportFieldBoolPairsList.add(fieldBoolPair); - } - - sortExportColumnFields(holder, exportFieldBoolPairsList); - initColumnProperties(holder, exportFieldBoolPairsList); - - for (Map.Entry entry : customFieldMap.entrySet()) { - initOneColumnProperty(holder, entry.getKey(), entry.getValue(), Boolean.TRUE); - } - headKind = HeadKindEnum.CLASS; - } - - /** - * Give the field and flag pair list and arrange them in the specified order according to the user's settings. The - * field is what the user want to export to excel, the flag indicates whether the order of the field in excel is - * specified. - * - * @param holder - * Write holder which keeps the parameters of a sheet. - * @param exportFieldBoolPairList - * Keep all the fields and the flag(which indicate whether the field order is specified) of the head - * class except the ignored. It will be modified after this function is called. - */ - private void sortExportColumnFields(Holder holder, List> exportFieldBoolPairList) { - if (holder instanceof AbstractWriteHolder) { - Collection includeColumnFieldNames = ((AbstractWriteHolder)holder).getIncludeColumnFieldNames(); - if (includeColumnFieldNames != null) { - Map> exportFieldMap = - new TreeMap>(); - List includeColumnFieldNameList = new ArrayList(includeColumnFieldNames); - for (Map.Entry fieldBoolPair : exportFieldBoolPairList) { - if (includeColumnFieldNameList.contains(fieldBoolPair.getKey().getName())) { - exportFieldMap.put(fieldBoolPair.getKey().getName(), fieldBoolPair); - } - } - exportFieldBoolPairList.clear(); - for (String fieldName : includeColumnFieldNameList) { - exportFieldBoolPairList.add(exportFieldMap.get(fieldName)); - } - return; - } - - Collection includeColumnIndexes = ((AbstractWriteHolder)holder).getIncludeColumnIndexes(); - if (includeColumnIndexes != null) { - List> tempFieldsList = new ArrayList>(); - for (Integer includeColumnIndex : includeColumnIndexes) { - tempFieldsList.add(exportFieldBoolPairList.get(includeColumnIndex)); - } - exportFieldBoolPairList.clear(); - exportFieldBoolPairList.addAll(tempFieldsList); - return; - } - - int index = 0; - for (Map.Entry fieldBoolPair : exportFieldBoolPairList) { - if (((AbstractWriteHolder)holder).ignore(fieldBoolPair.getKey().getName(), index)) { - exportFieldBoolPairList.remove(fieldBoolPair); - } - index++; - } - } - } - - /** - * Initialize column properties. - * - * @param holder - * Write holder which keeps the parameters of a sheet. - * @param exportFieldBoolPairList - * Keep the fields which will be exported to excel and the flag which indicate whether the field order in - * excel is specified. - */ - private void initColumnProperties(Holder holder, List> exportFieldBoolPairList) { - int index = 0; - for (Map.Entry fieldBoolPair : exportFieldBoolPairList) { - initOneColumnProperty(holder, index, fieldBoolPair.getKey(), fieldBoolPair.getValue()); - index++; + Map sortedAllFiledMap = new TreeMap(); + Map indexFiledMap = new TreeMap(); + + boolean needIgnore = (holder instanceof AbstractWriteHolder) && ( + !CollectionUtils.isEmpty(((AbstractWriteHolder) holder).getExcludeColumnFiledNames()) || !CollectionUtils + .isEmpty(((AbstractWriteHolder) holder).getExcludeColumnIndexes()) || !CollectionUtils + .isEmpty(((AbstractWriteHolder) holder).getIncludeColumnFiledNames()) || !CollectionUtils + .isEmpty(((AbstractWriteHolder) holder).getIncludeColumnIndexes())); + ClassUtils.declaredFields(headClazz, sortedAllFiledMap, indexFiledMap, ignoreMap, convertAllFiled, needIgnore, + holder); + + for (Map.Entry entry : sortedAllFiledMap.entrySet()) { + initOneColumnProperty(entry.getKey(), entry.getValue(), indexFiledMap.containsKey(entry.getKey())); } } /** * Initialization column property * - * @param holder * @param index * @param field * @param forceIndex * @return Ignore current field */ - private boolean initOneColumnProperty(Holder holder, int index, Field field, Boolean forceIndex) { - if (holder instanceof AbstractWriteHolder) { - if (((AbstractWriteHolder)holder).ignore(field.getName(), index)) { - return true; - } - } + private void initOneColumnProperty(int index, Field field, Boolean forceIndex) { ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); List tmpHeadList = new ArrayList(); boolean notForceName = excelProperty == null || excelProperty.value().length <= 0 @@ -264,7 +180,6 @@ public class ExcelHeadProperty { headMap.put(index, head); contentPropertyMap.put(index, excelContentProperty); fieldNameContentPropertyMap.put(field.getName(), excelContentProperty); - return false; } public Class getHeadClazz() { diff --git a/src/main/java/com/alibaba/excel/read/builder/AbstractExcelReaderParameterBuilder.java b/src/main/java/com/alibaba/excel/read/builder/AbstractExcelReaderParameterBuilder.java index 4e5e3702..29d676cb 100644 --- a/src/main/java/com/alibaba/excel/read/builder/AbstractExcelReaderParameterBuilder.java +++ b/src/main/java/com/alibaba/excel/read/builder/AbstractExcelReaderParameterBuilder.java @@ -31,6 +31,19 @@ public abstract class AbstractExcelReaderParameterBuilder> { +public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener>> { @Override - public void invokeHead(Map cellDataMap, AnalysisContext context) {} + public void invokeHead(Map> cellDataMap, AnalysisContext context) {} @Override - public void invoke(Map cellDataMap, AnalysisContext context) { - ReadHolder currentReadHolder = context.currentReadHolder(); - if (HeadKindEnum.CLASS.equals(currentReadHolder.excelReadHeadProperty().getHeadKind())) { + public void invoke(Map> cellDataMap, AnalysisContext context) { + ReadSheetHolder readSheetHolder = context.readSheetHolder(); + if (HeadKindEnum.CLASS.equals(readSheetHolder.excelReadHeadProperty().getHeadKind())) { context.readRowHolder() - .setCurrentRowAnalysisResult(buildUserModel(cellDataMap, currentReadHolder, context)); + .setCurrentRowAnalysisResult(buildUserModel(cellDataMap, readSheetHolder, context)); return; } - context.readRowHolder().setCurrentRowAnalysisResult(buildStringList(cellDataMap, currentReadHolder, context)); + context.readRowHolder().setCurrentRowAnalysisResult(buildStringList(cellDataMap, readSheetHolder, context)); } - private Object buildStringList(Map cellDataMap, ReadHolder currentReadHolder, + private Object buildStringList(Map> cellDataMap, ReadSheetHolder readSheetHolder, AnalysisContext context) { int index = 0; if (context.readWorkbookHolder().getDefaultReturnMap()) { Map map = new LinkedHashMap(cellDataMap.size() * 4 / 3 + 1); - for (Map.Entry entry : cellDataMap.entrySet()) { + for (Map.Entry> entry : cellDataMap.entrySet()) { Integer key = entry.getKey(); CellData cellData = entry.getValue(); while (index < key) { @@ -59,10 +60,10 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener continue; } map.put(key, - (String)ConverterUtils.convertToJavaObject(cellData, null, null, currentReadHolder.converterMap(), - currentReadHolder.globalConfiguration(), context.readRowHolder().getRowIndex(), key)); + (String)ConverterUtils.convertToJavaObject(cellData, null, null, readSheetHolder.converterMap(), + readSheetHolder, context.readRowHolder().getRowIndex(), key)); } - int headSize = currentReadHolder.excelReadHeadProperty().getHeadMap().size(); + int headSize = readSheetHolder.excelReadHeadProperty().getHeadMap().size(); while (index < headSize) { map.put(index, null); index++; @@ -70,10 +71,10 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener return map; } else { // Compatible with the old code the old code returns a list - List list = new ArrayList(); - for (Map.Entry entry : cellDataMap.entrySet()) { + List list = new ArrayList<>(); + for (Map.Entry> entry : cellDataMap.entrySet()) { Integer key = entry.getKey(); - CellData cellData = entry.getValue(); + CellData cellData = entry.getValue(); while (index < key) { list.add(null); index++; @@ -84,10 +85,10 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener continue; } list.add( - (String)ConverterUtils.convertToJavaObject(cellData, null, null, currentReadHolder.converterMap(), - currentReadHolder.globalConfiguration(), context.readRowHolder().getRowIndex(), key)); + (String)ConverterUtils.convertToJavaObject(cellData, null, null, readSheetHolder.converterMap(), + readSheetHolder, context.readRowHolder().getRowIndex(), key)); } - int headSize = currentReadHolder.excelReadHeadProperty().getHeadMap().size(); + int headSize = readSheetHolder.excelReadHeadProperty().getHeadMap().size(); while (index < headSize) { list.add(null); index++; @@ -96,15 +97,15 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener } } - private Object buildUserModel(Map cellDataMap, ReadHolder currentReadHolder, + private Object buildUserModel(Map> cellDataMap, ReadSheetHolder readSheetHolder, AnalysisContext context) { - ExcelReadHeadProperty excelReadHeadProperty = currentReadHolder.excelReadHeadProperty(); + ExcelReadHeadProperty excelReadHeadProperty = readSheetHolder.excelReadHeadProperty(); Object resultModel; try { resultModel = excelReadHeadProperty.getHeadClazz().newInstance(); } catch (Exception e) { throw new ExcelDataConvertException(context.readRowHolder().getRowIndex(), 0, - new CellData(CellDataTypeEnum.EMPTY), null, + new CellData<>(CellDataTypeEnum.EMPTY), null, "Can not instance class: " + excelReadHeadProperty.getHeadClazz().getName(), e); } Map headMap = excelReadHeadProperty.getHeadMap(); @@ -115,16 +116,16 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener if (!cellDataMap.containsKey(index)) { continue; } - CellData cellData = cellDataMap.get(index); + CellData cellData = cellDataMap.get(index); if (cellData.getType() == CellDataTypeEnum.EMPTY) { continue; } ExcelContentProperty excelContentProperty = contentPropertyMap.get(index); Object value = ConverterUtils.convertToJavaObject(cellData, excelContentProperty.getField(), - excelContentProperty, currentReadHolder.converterMap(), currentReadHolder.globalConfiguration(), + excelContentProperty, readSheetHolder.converterMap(), readSheetHolder, context.readRowHolder().getRowIndex(), index); if (value != null) { - map.put(excelContentProperty.getField().getName(), value); + map.put(FieldUtils.resolveCglibFieldName(excelContentProperty.getField()), value); } } BeanMap.create(resultModel).putAll(map); diff --git a/src/main/java/com/alibaba/excel/read/listener/ReadListener.java b/src/main/java/com/alibaba/excel/read/listener/ReadListener.java index f1d341f5..b3a2e970 100644 --- a/src/main/java/com/alibaba/excel/read/listener/ReadListener.java +++ b/src/main/java/com/alibaba/excel/read/listener/ReadListener.java @@ -29,7 +29,7 @@ public interface ReadListener extends Listener { * @param headMap * @param context */ - void invokeHead(Map headMap, AnalysisContext context); + void invokeHead(Map> headMap, AnalysisContext context); /** * When analysis one row trigger invoke function. diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java index a0bf7f1e..95bf6f89 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java @@ -1,12 +1,8 @@ package com.alibaba.excel.read.metadata.holder; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.alibaba.excel.converters.Converter; import com.alibaba.excel.converters.ConverterKeyBuild; import com.alibaba.excel.converters.DefaultConverterLoader; @@ -17,6 +13,10 @@ import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.read.metadata.ReadBasicParameter; import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty; +import com.alibaba.excel.util.ListUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Read Holder @@ -24,8 +24,6 @@ import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty; * @author Jiaju Zhuang */ public abstract class AbstractReadHolder extends AbstractHolder implements ReadHolder { - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractReadHolder.class); - /** * Count the number of added heads when read sheet. * @@ -56,6 +54,17 @@ public abstract class AbstractReadHolder extends AbstractHolder implements ReadH getGlobalConfiguration().setUse1904windowing(readBasicParameter.getUse1904windowing()); } + if (readBasicParameter.getUseScientificFormat() == null) { + if (parentAbstractReadHolder == null) { + getGlobalConfiguration().setUseScientificFormat(Boolean.FALSE); + } else { + getGlobalConfiguration() + .setUseScientificFormat(parentAbstractReadHolder.getGlobalConfiguration().getUseScientificFormat()); + } + } else { + getGlobalConfiguration().setUseScientificFormat(readBasicParameter.getUseScientificFormat()); + } + // Initialization property this.excelReadHeadProperty = new ExcelReadHeadProperty(this, getClazz(), getHead(), convertAllFiled); if (readBasicParameter.getHeadRowNumber() == null) { @@ -73,9 +82,9 @@ public abstract class AbstractReadHolder extends AbstractHolder implements ReadH } if (parentAbstractReadHolder == null) { - this.readListenerList = new ArrayList(); + this.readListenerList = ListUtils.newArrayList(); } else { - this.readListenerList = new ArrayList(parentAbstractReadHolder.getReadListenerList()); + this.readListenerList = ListUtils.newArrayList(parentAbstractReadHolder.getReadListenerList()); } if (HolderEnum.WORKBOOK.equals(holderType())) { Boolean useDefaultListener = ((ReadWorkbook)readBasicParameter).getUseDefaultListener(); @@ -91,11 +100,11 @@ public abstract class AbstractReadHolder extends AbstractHolder implements ReadH if (parentAbstractReadHolder == null) { setConverterMap(DefaultConverterLoader.loadDefaultReadConverter()); } else { - setConverterMap(new HashMap(parentAbstractReadHolder.getConverterMap())); + setConverterMap(new HashMap<>(parentAbstractReadHolder.getConverterMap())); } if (readBasicParameter.getCustomConverterList() != null && !readBasicParameter.getCustomConverterList().isEmpty()) { - for (Converter converter : readBasicParameter.getCustomConverterList()) { + for (Converter converter : readBasicParameter.getCustomConverterList()) { getConverterMap().put( ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), converter); diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java index 87185dc2..ddb5ca27 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java @@ -15,6 +15,7 @@ import com.alibaba.excel.read.metadata.ReadSheet; * @author Jiaju Zhuang */ public class ReadSheetHolder extends AbstractReadHolder { + /** * current param */ @@ -50,7 +51,7 @@ public class ReadSheetHolder extends AbstractReadHolder { /** * Current CellData */ - private CellData tempCellData; + private CellData tempCellData; public ReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { super(readSheet, readWorkbookHolder, readWorkbookHolder.getReadWorkbook().getConvertAllFiled()); @@ -59,6 +60,7 @@ public class ReadSheetHolder extends AbstractReadHolder { this.sheetNo = readSheet.getSheetNo(); this.sheetName = readSheet.getSheetName(); this.cellMap = new LinkedHashMap(); + this.rowIndex = -1; } public ReadSheet getReadSheet() { @@ -133,11 +135,11 @@ public class ReadSheetHolder extends AbstractReadHolder { this.rowIndex = rowIndex; } - public CellData getTempCellData() { + public CellData getTempCellData() { return tempCellData; } - public void setTempCellData(CellData tempCellData) { + public void setTempCellData(CellData tempCellData) { this.tempCellData = tempCellData; } diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java index d0171ffc..1d12ab6c 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java @@ -18,10 +18,6 @@ public class XlsReadSheetHolder extends ReadSheetHolder { * Row type.Temporary storage, last set in ReadRowHolder. */ private RowTypeEnum tempRowType; - /** - * Ignore record. - */ - private Boolean ignoreRecord; /** * Temp object index. */ @@ -33,7 +29,6 @@ public class XlsReadSheetHolder extends ReadSheetHolder { public XlsReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { super(readSheet, readWorkbookHolder); - ignoreRecord = Boolean.FALSE; tempRowType = RowTypeEnum.EMPTY; objectCacheMap = new HashMap(16); } @@ -46,13 +41,6 @@ public class XlsReadSheetHolder extends ReadSheetHolder { this.tempRowType = tempRowType; } - public Boolean getIgnoreRecord() { - return ignoreRecord; - } - - public void setIgnoreRecord(Boolean ignoreRecord) { - this.ignoreRecord = ignoreRecord; - } public Integer getTempObjectIndex() { return tempObjectIndex; diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java index 70c1c03a..a8c86a75 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java @@ -42,6 +42,10 @@ public class XlsReadWorkbookHolder extends ReadWorkbookHolder { * Sheet Index */ private Integer readSheetIndex; + /** + * Ignore record. + */ + private Boolean ignoreRecord; public XlsReadWorkbookHolder(ReadWorkbook readWorkbook) { super(readWorkbook); @@ -51,6 +55,7 @@ public class XlsReadWorkbookHolder extends ReadWorkbookHolder { if (getGlobalConfiguration().getUse1904windowing() == null) { getGlobalConfiguration().setUse1904windowing(Boolean.FALSE); } + ignoreRecord = Boolean.FALSE; } public POIFSFileSystem getPoifsFileSystem() { @@ -100,4 +105,12 @@ public class XlsReadWorkbookHolder extends ReadWorkbookHolder { public void setReadSheetIndex(Integer readSheetIndex) { this.readSheetIndex = readSheetIndex; } + + public Boolean getIgnoreRecord() { + return ignoreRecord; + } + + public void setIgnoreRecord(Boolean ignoreRecord) { + this.ignoreRecord = ignoreRecord; + } } diff --git a/src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java b/src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java index ddd19504..f23f58c9 100644 --- a/src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java +++ b/src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java @@ -82,7 +82,7 @@ public class DefaultAnalysisEventProcessor implements AnalysisEventProcessor { private void dealData(AnalysisContext analysisContext) { ReadRowHolder readRowHolder = analysisContext.readRowHolder(); - Map cellDataMap = (Map)readRowHolder.getCellMap(); + Map> cellDataMap = (Map)readRowHolder.getCellMap(); readRowHolder.setCurrentRowAnalysisResult(cellDataMap); int rowIndex = readRowHolder.getRowIndex(); int currentHeadRowNumber = analysisContext.readSheetHolder().getHeadRowNumber(); @@ -111,7 +111,7 @@ public class DefaultAnalysisEventProcessor implements AnalysisEventProcessor { } } - private void buildHead(AnalysisContext analysisContext, Map cellDataMap) { + private void buildHead(AnalysisContext analysisContext, Map> cellDataMap) { if (!HeadKindEnum.CLASS.equals(analysisContext.currentReadHolder().excelReadHeadProperty().getHeadKind())) { return; } diff --git a/src/main/java/com/alibaba/excel/util/BooleanUtils.java b/src/main/java/com/alibaba/excel/util/BooleanUtils.java index 55c48a18..18f6dd39 100644 --- a/src/main/java/com/alibaba/excel/util/BooleanUtils.java +++ b/src/main/java/com/alibaba/excel/util/BooleanUtils.java @@ -25,4 +25,79 @@ public class BooleanUtils { } } + + // boolean Boolean methods + //----------------------------------------------------------------------- + /** + *

Checks if a {@code Boolean} value is {@code true}, + * handling {@code null} by returning {@code false}.

+ * + *
+     *   BooleanUtils.isTrue(Boolean.TRUE)  = true
+     *   BooleanUtils.isTrue(Boolean.FALSE) = false
+     *   BooleanUtils.isTrue(null)          = false
+     * 
+ * + * @param bool the boolean to check, null returns {@code false} + * @return {@code true} only if the input is non-null and true + * @since 2.1 + */ + public static boolean isTrue(final Boolean bool) { + return Boolean.TRUE.equals(bool); + } + + /** + *

Checks if a {@code Boolean} value is not {@code true}, + * handling {@code null} by returning {@code true}.

+ * + *
+     *   BooleanUtils.isNotTrue(Boolean.TRUE)  = false
+     *   BooleanUtils.isNotTrue(Boolean.FALSE) = true
+     *   BooleanUtils.isNotTrue(null)          = true
+     * 
+ * + * @param bool the boolean to check, null returns {@code true} + * @return {@code true} if the input is null or false + * @since 2.3 + */ + public static boolean isNotTrue(final Boolean bool) { + return !isTrue(bool); + } + + /** + *

Checks if a {@code Boolean} value is {@code false}, + * handling {@code null} by returning {@code false}.

+ * + *
+     *   BooleanUtils.isFalse(Boolean.TRUE)  = false
+     *   BooleanUtils.isFalse(Boolean.FALSE) = true
+     *   BooleanUtils.isFalse(null)          = false
+     * 
+ * + * @param bool the boolean to check, null returns {@code false} + * @return {@code true} only if the input is non-null and false + * @since 2.1 + */ + public static boolean isFalse(final Boolean bool) { + return Boolean.FALSE.equals(bool); + } + + /** + *

Checks if a {@code Boolean} value is not {@code false}, + * handling {@code null} by returning {@code true}.

+ * + *
+     *   BooleanUtils.isNotFalse(Boolean.TRUE)  = true
+     *   BooleanUtils.isNotFalse(Boolean.FALSE) = false
+     *   BooleanUtils.isNotFalse(null)          = true
+     * 
+ * + * @param bool the boolean to check, null returns {@code true} + * @return {@code true} if the input is null or true + * @since 2.3 + */ + public static boolean isNotFalse(final Boolean bool) { + return !isFalse(bool); + } + } diff --git a/src/main/java/com/alibaba/excel/util/ClassUtils.java b/src/main/java/com/alibaba/excel/util/ClassUtils.java index 64bc29d7..16643de4 100644 --- a/src/main/java/com/alibaba/excel/util/ClassUtils.java +++ b/src/main/java/com/alibaba/excel/util/ClassUtils.java @@ -6,6 +6,8 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -14,8 +16,12 @@ import java.util.concurrent.ConcurrentHashMap; import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.event.Handler; import com.alibaba.excel.exception.ExcelCommonException; import com.alibaba.excel.metadata.BaseRowModel; +import com.alibaba.excel.metadata.Holder; +import com.alibaba.excel.write.handler.WriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteHolder; /** * Class utils @@ -23,26 +29,54 @@ import com.alibaba.excel.metadata.BaseRowModel; * @author Jiaju Zhuang **/ public class ClassUtils { + private static final Map> FIELD_CACHE = new ConcurrentHashMap>(); - public static void declaredFields(Class clazz, List defaultFieldList, Map customFiledMap, - Map ignoreMap, Boolean convertAllFiled) { + public static void declaredFields(Class clazz, Map sortedAllFiledMap, + Map indexFiledMap, Map ignoreMap, Boolean convertAllFiled, + Boolean needIgnore, Holder holder) { FieldCache fieldCache = getFieldCache(clazz, convertAllFiled); - if (fieldCache != null) { - defaultFieldList.addAll(fieldCache.getDefaultFieldList()); - customFiledMap.putAll(fieldCache.getCustomFiledMap()); + if (fieldCache == null) { + return; + } + if (ignoreMap != null) { ignoreMap.putAll(fieldCache.getIgnoreMap()); } - } + Map tempIndexFildMap = indexFiledMap; + if (tempIndexFildMap == null) { + tempIndexFildMap = new TreeMap(); + } + tempIndexFildMap.putAll(fieldCache.getIndexFiledMap()); - public static void declaredFields(Class clazz, List fieldList, Boolean convertAllFiled) { - FieldCache fieldCache = getFieldCache(clazz, convertAllFiled); - if (fieldCache != null) { - fieldList.addAll(fieldCache.getAllFieldList()); + if (!needIgnore) { + sortedAllFiledMap.putAll(fieldCache.getSortedAllFiledMap()); + return; + } + + int index = 0; + for (Map.Entry entry : fieldCache.getSortedAllFiledMap().entrySet()) { + Field field = entry.getValue(); + if (((WriteHolder) holder).ignore(entry.getValue().getName(), entry.getKey())) { + if (ignoreMap != null) { + ignoreMap.put(field.getName(), field); + } + while (tempIndexFildMap.containsKey(index)) { + tempIndexFildMap.remove(index); + index++; + } + } else { + sortedAllFiledMap.put(index, field); + index++; + } } } + public static void declaredFields(Class clazz, Map sortedAllFiledMap, Boolean convertAllFiled, + Boolean needIgnore, WriteHolder writeHolder) { + declaredFields(clazz, sortedAllFiledMap, null, null, convertAllFiled, needIgnore, writeHolder); + } + private static FieldCache getFieldCache(Class clazz, Boolean convertAllFiled) { if (clazz == null) { return null; @@ -72,79 +106,155 @@ public class ClassUtils { tempClass = tempClass.getSuperclass(); } // Screening of field - List defaultFieldList = new ArrayList(); - Map customFiledMap = new TreeMap(); - List allFieldList = new ArrayList(); + Map> orderFiledMap = new TreeMap>(); + Map indexFiledMap = new TreeMap(); Map ignoreMap = new HashMap(16); ExcelIgnoreUnannotated excelIgnoreUnannotated = - (ExcelIgnoreUnannotated)clazz.getAnnotation(ExcelIgnoreUnannotated.class); + (ExcelIgnoreUnannotated) clazz.getAnnotation(ExcelIgnoreUnannotated.class); for (Field field : tempFieldList) { - ExcelIgnore excelIgnore = field.getAnnotation(ExcelIgnore.class); - if (excelIgnore != null) { - ignoreMap.put(field.getName(), field); - continue; - } - ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); - boolean noExcelProperty = excelProperty == null - && ((convertAllFiled != null && !convertAllFiled) || excelIgnoreUnannotated != null); - if (noExcelProperty) { - ignoreMap.put(field.getName(), field); - continue; - } - boolean isStaticFinalOrTransient = - (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers())) - || Modifier.isTransient(field.getModifiers()); - if (excelProperty == null && isStaticFinalOrTransient) { - ignoreMap.put(field.getName(), field); - continue; - } - if (excelProperty == null || excelProperty.index() < 0) { - defaultFieldList.add(field); - allFieldList.add(field); - continue; + declaredOneField(field, orderFiledMap, indexFiledMap, ignoreMap, excelIgnoreUnannotated, convertAllFiled); + } + FIELD_CACHE.put(clazz, new SoftReference( + new FieldCache(buildSortedAllFiledMap(orderFiledMap, indexFiledMap), indexFiledMap, ignoreMap))); + } + + private static Map buildSortedAllFiledMap(Map> orderFiledMap, + Map indexFiledMap) { + + Map sortedAllFiledMap = new HashMap( + (orderFiledMap.size() + indexFiledMap.size()) * 4 / 3 + 1); + + Map tempIndexFiledMap = new HashMap(indexFiledMap); + int index = 0; + for (List fieldList : orderFiledMap.values()) { + for (Field field : fieldList) { + while (tempIndexFiledMap.containsKey(index)) { + sortedAllFiledMap.put(index, tempIndexFiledMap.get(index)); + tempIndexFiledMap.remove(index); + index++; + } + sortedAllFiledMap.put(index, field); + index++; } - if (customFiledMap.containsKey(excelProperty.index())) { - throw new ExcelCommonException("The index of '" + customFiledMap.get(excelProperty.index()).getName() + } + sortedAllFiledMap.putAll(tempIndexFiledMap); + return sortedAllFiledMap; + } + + private static void declaredOneField(Field field, Map> orderFiledMap, + Map indexFiledMap, Map ignoreMap, ExcelIgnoreUnannotated excelIgnoreUnannotated, + Boolean convertAllFiled) { + ExcelIgnore excelIgnore = field.getAnnotation(ExcelIgnore.class); + if (excelIgnore != null) { + ignoreMap.put(field.getName(), field); + return; + } + ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); + boolean noExcelProperty = excelProperty == null + && ((convertAllFiled != null && !convertAllFiled) || excelIgnoreUnannotated != null); + if (noExcelProperty) { + ignoreMap.put(field.getName(), field); + return; + } + boolean isStaticFinalOrTransient = + (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers())) + || Modifier.isTransient(field.getModifiers()); + if (excelProperty == null && isStaticFinalOrTransient) { + ignoreMap.put(field.getName(), field); + return; + } + if (excelProperty != null && excelProperty.index() >= 0) { + if (indexFiledMap.containsKey(excelProperty.index())) { + throw new ExcelCommonException("The index of '" + indexFiledMap.get(excelProperty.index()).getName() + "' and '" + field.getName() + "' must be inconsistent"); } - customFiledMap.put(excelProperty.index(), field); - allFieldList.add(field); + indexFiledMap.put(excelProperty.index(), field); + return; } - FIELD_CACHE.put(clazz, - new SoftReference(new FieldCache(defaultFieldList, customFiledMap, allFieldList, ignoreMap))); + int order = Integer.MAX_VALUE; + if (excelProperty != null) { + order = excelProperty.order(); + } + List orderFiledList = orderFiledMap.get(order); + if (orderFiledList == null) { + orderFiledList = new ArrayList(); + orderFiledMap.put(order, orderFiledList); + } + orderFiledList.add(field); } private static class FieldCache { - private List defaultFieldList; - private Map customFiledMap; - private List allFieldList; + + private Map sortedAllFiledMap; + private Map indexFiledMap; private Map ignoreMap; - public FieldCache(List defaultFieldList, Map customFiledMap, List allFieldList, + public FieldCache(Map sortedAllFiledMap, Map indexFiledMap, Map ignoreMap) { - this.defaultFieldList = defaultFieldList; - this.customFiledMap = customFiledMap; - this.allFieldList = allFieldList; + this.sortedAllFiledMap = sortedAllFiledMap; + this.indexFiledMap = indexFiledMap; this.ignoreMap = ignoreMap; } - public List getDefaultFieldList() { - return defaultFieldList; + public Map getSortedAllFiledMap() { + return sortedAllFiledMap; } - public Map getCustomFiledMap() { - return customFiledMap; - } - - public List getAllFieldList() { - return allFieldList; + public Map getIndexFiledMap() { + return indexFiledMap; } public Map getIgnoreMap() { return ignoreMap; } + } + + /** + *

Gets a {@code List} of all interfaces implemented by the given + * class and its superclasses.

+ * + *

The order is determined by looking through each interface in turn as + * declared in the source file and following its hierarchy up. Then each + * superclass is considered in the same way. Later duplicates are ignored, + * so the order is maintained.

+ * + * @param cls the class to look up, may be {@code null} + * @return the {@code List} of interfaces in order, + * {@code null} if null input + */ + public static List> getAllInterfaces(final Class cls) { + if (cls == null) { + return null; + } + + final LinkedHashSet> interfacesFound = new LinkedHashSet<>(); + getAllInterfaces(cls, interfacesFound); + + return new ArrayList<>(interfacesFound); + } + + + /** + * Gets the interfaces for the specified class. + * + * @param cls the class to look up, may be {@code null} + * @param interfacesFound the {@code Set} of interfaces for the class + */ + private static void getAllInterfaces(Class cls, final HashSet> interfacesFound) { + while (cls != null) { + final Class[] interfaces = cls.getInterfaces(); + + for (final Class i : interfaces) { + if (interfacesFound.add(i)) { + getAllInterfaces(i, interfacesFound); + } + } + + cls = cls.getSuperclass(); + } } + } diff --git a/src/main/java/com/alibaba/excel/util/CollectionUtils.java b/src/main/java/com/alibaba/excel/util/CollectionUtils.java deleted file mode 100644 index f413be17..00000000 --- a/src/main/java/com/alibaba/excel/util/CollectionUtils.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.alibaba.excel.util; - -import java.util.Collection; -import java.util.Map; - -/** - * Collection utils - * - * @author jipengfei - */ -public class CollectionUtils { - - private CollectionUtils() {} - - public static boolean isEmpty(Collection collection) { - return (collection == null || collection.isEmpty()); - } - - public static boolean isEmpty(Map map) { - return (map == null || map.isEmpty()); - } -} diff --git a/src/main/java/com/alibaba/excel/util/ConverterUtils.java b/src/main/java/com/alibaba/excel/util/ConverterUtils.java index 43b12c53..61f69ac4 100644 --- a/src/main/java/com/alibaba/excel/util/ConverterUtils.java +++ b/src/main/java/com/alibaba/excel/util/ConverterUtils.java @@ -3,7 +3,6 @@ package com.alibaba.excel.util; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.util.HashMap; import java.util.Map; import com.alibaba.excel.context.AnalysisContext; @@ -12,9 +11,9 @@ import com.alibaba.excel.converters.ConverterKeyBuild; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.metadata.CellData; -import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.read.metadata.holder.ReadHolder; +import com.alibaba.excel.read.metadata.holder.ReadSheetHolder; /** * Converting objects @@ -32,13 +31,13 @@ public class ConverterUtils { * @param context * @return */ - public static Map convertToStringMap(Map cellDataMap, AnalysisContext context) { - Map stringMap = new HashMap(cellDataMap.size() * 4 / 3 + 1); - ReadHolder currentReadHolder = context.currentReadHolder(); + public static Map convertToStringMap(Map> cellDataMap, AnalysisContext context) { + Map stringMap = MapUtils.newHashMapWithExpectedSize(cellDataMap.size()); + ReadSheetHolder readSheetHolder = context.readSheetHolder(); int index = 0; - for (Map.Entry entry : cellDataMap.entrySet()) { + for (Map.Entry> entry : cellDataMap.entrySet()) { Integer key = entry.getKey(); - CellData cellData = entry.getValue(); + CellData cellData = entry.getValue(); while (index < key) { stringMap.put(index, null); index++; @@ -48,15 +47,15 @@ public class ConverterUtils { stringMap.put(key, null); continue; } - Converter converter = - currentReadHolder.converterMap().get(ConverterKeyBuild.buildKey(String.class, cellData.getType())); + Converter converter = + readSheetHolder.converterMap().get(ConverterKeyBuild.buildKey(String.class, cellData.getType())); if (converter == null) { throw new ExcelDataConvertException(context.readRowHolder().getRowIndex(), key, cellData, null, "Converter not found, convert " + cellData.getType() + " to String"); } try { stringMap.put(key, - (String)(converter.convertToJavaData(cellData, null, currentReadHolder.globalConfiguration()))); + (String)(converter.convertToJavaData(cellData, null, readSheetHolder))); } catch (Exception e) { throw new ExcelDataConvertException(context.readRowHolder().getRowIndex(), key, cellData, null, "Convert data " + cellData + " to String error ", e); @@ -72,15 +71,15 @@ public class ConverterUtils { * @param field * @param contentProperty * @param converterMap - * @param globalConfiguration + * @param readSheetHolder * @param rowIndex * @param columnIndex * @return */ - public static Object convertToJavaObject(CellData cellData, Field field, ExcelContentProperty contentProperty, - Map converterMap, GlobalConfiguration globalConfiguration, Integer rowIndex, + public static Object convertToJavaObject(CellData cellData, Field field, ExcelContentProperty contentProperty, + Map> converterMap, ReadSheetHolder readSheetHolder, Integer rowIndex, Integer columnIndex) { - Class clazz; + Class clazz; if (field == null) { clazz = String.class; } else { @@ -88,37 +87,37 @@ public class ConverterUtils { } if (clazz == CellData.class) { Type type = field.getGenericType(); - Class classGeneric; + Class classGeneric; if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType)type; - classGeneric = (Class)parameterizedType.getActualTypeArguments()[0]; + classGeneric = (Class)parameterizedType.getActualTypeArguments()[0]; } else { classGeneric = String.class; } - CellData cellDataReturn = new CellData(cellData); + CellData cellDataReturn = new CellData(cellData); cellDataReturn.setData(doConvertToJavaObject(cellData, classGeneric, contentProperty, converterMap, - globalConfiguration, rowIndex, columnIndex)); + readSheetHolder, rowIndex, columnIndex)); return cellDataReturn; } - return doConvertToJavaObject(cellData, clazz, contentProperty, converterMap, globalConfiguration, rowIndex, + return doConvertToJavaObject(cellData, clazz, contentProperty, converterMap, readSheetHolder, rowIndex, columnIndex); } /** - * * @param cellData * @param clazz * @param contentProperty * @param converterMap - * @param globalConfiguration + * @param readSheetHolder * @param rowIndex * @param columnIndex * @return */ - private static Object doConvertToJavaObject(CellData cellData, Class clazz, ExcelContentProperty contentProperty, - Map converterMap, GlobalConfiguration globalConfiguration, Integer rowIndex, + private static Object doConvertToJavaObject(CellData cellData, Class clazz, + ExcelContentProperty contentProperty, + Map> converterMap, ReadSheetHolder readSheetHolder, Integer rowIndex, Integer columnIndex) { - Converter converter = null; + Converter converter = null; if (contentProperty != null) { converter = contentProperty.getConverter(); } @@ -130,7 +129,7 @@ public class ConverterUtils { "Converter not found, convert " + cellData.getType() + " to " + clazz.getName()); } try { - return converter.convertToJavaData(cellData, contentProperty, globalConfiguration); + return converter.convertToJavaData(cellData, contentProperty, readSheetHolder); } catch (Exception e) { throw new ExcelDataConvertException(rowIndex, columnIndex, cellData, contentProperty, "Convert data " + cellData + " to " + clazz + " error ", e); diff --git a/src/main/java/com/alibaba/excel/util/DateUtils.java b/src/main/java/com/alibaba/excel/util/DateUtils.java index 815257b9..bc85adf6 100644 --- a/src/main/java/com/alibaba/excel/util/DateUtils.java +++ b/src/main/java/com/alibaba/excel/util/DateUtils.java @@ -17,16 +17,16 @@ public class DateUtils { /** * Is a cache of dates */ - private static final ThreadLocal> DATE_THREAD_LOCAL = - new ThreadLocal>(); + private static final ThreadLocal> DATE_THREAD_LOCAL = + new ThreadLocal<>(); /** * Is a cache of dates */ private static final ThreadLocal> DATE_FORMAT_THREAD_LOCAL = - new ThreadLocal>(); + new ThreadLocal<>(); /** - * The following patterns are used in {@link #isADateFormat(Integer, String)} + * The following patterns are used in {@link #isADateFormat(Short, String)} */ private static final Pattern date_ptrn1 = Pattern.compile("^\\[\\$\\-.*?\\]"); private static final Pattern date_ptrn2 = Pattern.compile("^\\[[a-zA-Z]+\\]"); @@ -43,11 +43,15 @@ public class DateUtils { public static final String DATE_FORMAT_10 = "yyyy-MM-dd"; public static final String DATE_FORMAT_14 = "yyyyMMddHHmmss"; + public static final String DATE_FORMAT_16 = "yyyy-MM-dd HH:mm"; + public static final String DATE_FORMAT_16_FORWARD_SLASH = "yyyy/MM/dd HH:mm"; public static final String DATE_FORMAT_17 = "yyyyMMdd HH:mm:ss"; public static final String DATE_FORMAT_19 = "yyyy-MM-dd HH:mm:ss"; public static final String DATE_FORMAT_19_FORWARD_SLASH = "yyyy/MM/dd HH:mm:ss"; private static final String MINUS = "-"; + public static String defaultDateFormat = DATE_FORMAT_19; + private DateUtils() {} /** @@ -91,6 +95,12 @@ public class DateUtils { } else { return DATE_FORMAT_19_FORWARD_SLASH; } + case 16: + if (dateString.contains(MINUS)) { + return DATE_FORMAT_16; + } else { + return DATE_FORMAT_16_FORWARD_SLASH; + } case 17: return DATE_FORMAT_17; case 14: @@ -126,7 +136,7 @@ public class DateUtils { return ""; } if (StringUtils.isEmpty(dateFormat)) { - dateFormat = DATE_FORMAT_19; + dateFormat = defaultDateFormat; } return getCacheDateFormat(dateFormat).format(date); } @@ -154,13 +164,13 @@ public class DateUtils { * @param formatString * @return */ - public static boolean isADateFormat(Integer formatIndex, String formatString) { + public static boolean isADateFormat(Short formatIndex, String formatString) { if (formatIndex == null) { return false; } - Map isDateCache = DATE_THREAD_LOCAL.get(); + Map isDateCache = DATE_THREAD_LOCAL.get(); if (isDateCache == null) { - isDateCache = new HashMap(); + isDateCache = MapUtils.newHashMap(); DATE_THREAD_LOCAL.set(isDateCache); } else { Boolean isDateCachedData = isDateCache.get(formatIndex); @@ -180,7 +190,7 @@ public class DateUtils { * @param formatString * @return */ - public static boolean isADateFormatUncached(Integer formatIndex, String formatString) { + public static boolean isADateFormatUncached(Short formatIndex, String formatString) { // First up, is this an internal date format? if (isInternalDateFormat(formatIndex)) { return true; @@ -256,9 +266,9 @@ public class DateUtils { /** * Given a format ID this will check whether the format represents an internal excel date format or not. * - * @see #isADateFormat(Integer, String) + * @see #isADateFormat(Short, String) */ - public static boolean isInternalDateFormat(int format) { + public static boolean isInternalDateFormat(short format) { switch (format) { // Internal Date Formats as described on page 427 in // Microsoft Excel Dev's Kit... diff --git a/src/main/java/com/alibaba/excel/util/FieldUtils.java b/src/main/java/com/alibaba/excel/util/FieldUtils.java new file mode 100644 index 00000000..1e788907 --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/FieldUtils.java @@ -0,0 +1,145 @@ +package com.alibaba.excel.util; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + + +/** + * Field utils + * + * @author Jiaju Zhuang + **/ +public class FieldUtils { + + private static final int START_RESOLVE_FIELD_LENGTH = 2; + + /** + * Parsing the name matching cglib。 + *
    + *
      null -> null
    + *
      string1 -> string1
    + *
      String2 -> string2
    + *
      sTring3 -> STring3
    + *
      STring4 -> STring4
    + *
      STRING5 -> STRING5
    + *
      STRing6 -> STRing6
    + *
+ * + * @param field field + * @return field name. + */ + public static String resolveCglibFieldName(Field field) { + if (field == null) { + return null; + } + String fieldName = field.getName(); + if (StringUtils.isBlank(fieldName) || fieldName.length() < START_RESOLVE_FIELD_LENGTH) { + return fieldName; + } + char firstChar = fieldName.charAt(0); + char secondChar = fieldName.charAt(1); + if (Character.isUpperCase(firstChar) == Character.isUpperCase(secondChar)) { + return fieldName; + } + if (Character.isUpperCase(firstChar)) { + return buildFieldName(Character.toLowerCase(firstChar), fieldName); + } + return buildFieldName(Character.toUpperCase(firstChar), fieldName); + } + + private static String buildFieldName(char firstChar, String fieldName) { + return firstChar + fieldName.substring(1); + } + + + /** + * Gets an accessible {@link Field} by name respecting scope. Superclasses/interfaces will be considered. + * + * @param cls + * the {@link Class} to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @return the Field object + * @throws IllegalArgumentException + * if the class is {@code null}, or the field name is blank or empty + */ + public static Field getField(final Class cls, final String fieldName) { + final Field field = getField(cls, fieldName, false); + MemberUtils.setAccessibleWorkaround(field); + return field; + } + + + + /** + * Gets an accessible {@link Field} by name, breaking scope if requested. Superclasses/interfaces will be + * considered. + * + * @param cls + * the {@link Class} to reflect, must not be {@code null} + * @param fieldName + * the field name to obtain + * @param forceAccess + * whether to break scope restrictions using the + * {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} method. {@code false} will only + * match {@code public} fields. + * @return the Field object + * @throws NullPointerException if the class is {@code null} + * @throws IllegalArgumentException if the field name is blank or empty or is matched at multiple places + * in the inheritance hierarchy + */ + public static Field getField(final Class cls, final String fieldName, final boolean forceAccess) { + Validate.isTrue(cls != null, "The class must not be null"); + Validate.isTrue(StringUtils.isNotBlank(fieldName), "The field name must not be blank/empty"); + // FIXME is this workaround still needed? lang requires Java 6 + // Sun Java 1.3 has a bugged implementation of getField hence we write the + // code ourselves + + // getField() will return the Field object with the declaring class + // set correctly to the class that declares the field. Thus requesting the + // field on a subclass will return the field from the superclass. + // + // priority order for lookup: + // searchclass private/protected/package/public + // superclass protected/package/public + // private/different package blocks access to further superclasses + // implementedinterface public + + // check up the superclass hierarchy + for (Class acls = cls; acls != null; acls = acls.getSuperclass()) { + try { + final Field field = acls.getDeclaredField(fieldName); + // getDeclaredField checks for non-public scopes as well + // and it returns accurate results + if (!Modifier.isPublic(field.getModifiers())) { + if (forceAccess) { + field.setAccessible(true); + } else { + continue; + } + } + return field; + } catch (final NoSuchFieldException ex) { // NOPMD + // ignore + } + } + // check the public interface case. This must be manually searched for + // incase there is a public supersuperclass field hidden by a private/package + // superclass field. + Field match = null; + for (final Class class1 : ClassUtils.getAllInterfaces(cls)) { + try { + final Field test = class1.getField(fieldName); + Validate.isTrue(match == null, "Reference to field %s is ambiguous relative to %s" + + "; a matching field exists on two or more implemented interfaces.", fieldName, cls); + match = test; + } catch (final NoSuchFieldException ex) { // NOPMD + // ignore + } + } + return match; + } + + + +} diff --git a/src/main/java/com/alibaba/excel/util/FileUtils.java b/src/main/java/com/alibaba/excel/util/FileUtils.java index 20b16bc6..bc6b5d8a 100644 --- a/src/main/java/com/alibaba/excel/util/FileUtils.java +++ b/src/main/java/com/alibaba/excel/util/FileUtils.java @@ -9,12 +9,12 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.UUID; -import org.apache.poi.util.DefaultTempFileCreationStrategy; -import org.apache.poi.util.TempFile; - import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelCommonException; +import org.apache.poi.util.DefaultTempFileCreationStrategy; +import org.apache.poi.util.TempFile; + /** * * @author jipengfei @@ -100,10 +100,21 @@ public class FileUtils { /** * Write inputStream to file * - * @param file - * @param inputStream + * @param file file + * @param inputStream inputStream */ public static void writeToFile(File file, InputStream inputStream) { + writeToFile(file, inputStream, true); + } + + /** + * Write inputStream to file + * + * @param file file + * @param inputStream inputStream + * @param closeInputStream closeInputStream + */ + public static void writeToFile(File file, InputStream inputStream, boolean closeInputStream) { OutputStream outputStream = null; try { outputStream = new FileOutputStream(file); @@ -122,7 +133,7 @@ public class FileUtils { throw new ExcelAnalysisException("Can not close 'outputStream'!", e); } } - if (inputStream != null) { + if (inputStream != null && closeInputStream) { try { inputStream.close(); } catch (IOException e) { @@ -132,6 +143,7 @@ public class FileUtils { } } + public static void createPoiFilesDirectory() { File poiFilesPathFile = new File(poiFilesPath); createDirectory(poiFilesPathFile); diff --git a/src/main/java/com/alibaba/excel/util/IntUtils.java b/src/main/java/com/alibaba/excel/util/IntUtils.java new file mode 100644 index 00000000..6d2e244c --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/IntUtils.java @@ -0,0 +1,39 @@ +package com.alibaba.excel.util; + +import java.util.ArrayList; +import java.util.List; + +/** + * Int utils + * + * @author Jiaju Zhuang + **/ +public class IntUtils { + private IntUtils() {} + + + /** + * The largest power of two that can be represented as an {@code int}. + * + * @since 10.0 + */ + public static final int MAX_POWER_OF_TWO = 1 << (Integer.SIZE - 2); + + /** + * Returns the {@code int} nearest in value to {@code value}. + * + * @param value any {@code long} value + * @return the same value cast to {@code int} if it is in the range of the {@code int} type, + * {@link Integer#MAX_VALUE} if it is too large, or {@link Integer#MIN_VALUE} if it is too + * small + */ + public static int saturatedCast(long value) { + if (value > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + if (value < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } + return (int) value; + } +} diff --git a/src/main/java/com/alibaba/excel/util/ListUtils.java b/src/main/java/com/alibaba/excel/util/ListUtils.java new file mode 100644 index 00000000..85d06b4d --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/ListUtils.java @@ -0,0 +1,121 @@ +package com.alibaba.excel.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import lombok.NonNull; +import org.apache.commons.compress.utils.Iterators; + +/** + * List utils + * + * @author Jiaju Zhuang + **/ +public class ListUtils { + private ListUtils() {} + + /** + * Creates a mutable, empty {@code ArrayList} instance (for Java 6 and earlier). + * + *

Note for Java 7 and later: this method is now unnecessary and should be treated as + * deprecated. Instead, use the {@code ArrayList} {@linkplain ArrayList#ArrayList() constructor} + * directly, taking advantage of the new "diamond" syntax. + */ + public static ArrayList newArrayList() { + return new ArrayList<>(); + } + + /** + * Creates a mutable {@code ArrayList} instance containing the given elements; a very thin + * shortcut for creating an empty list and then calling {@link Iterators#addAll}. + * + */ + public static ArrayList newArrayList(Iterator elements) { + ArrayList list = newArrayList(); + Iterators.addAll(list, elements); + return list; + } + + /** + * Creates a mutable {@code ArrayList} instance containing the given elements; + * + * + *

Note for Java 7 and later: if {@code elements} is a {@link Collection}, you don't + * need this method. Use the {@code ArrayList} {@linkplain ArrayList#ArrayList(Collection) + * constructor} directly, taking advantage of the new "diamond" + * syntax. + */ + public static ArrayList newArrayList(Iterable elements) { + checkNotNull(elements); // for GWT + // Let ArrayList's sizing logic work, if possible + return (elements instanceof Collection) + ? new ArrayList<>((Collection)elements) + : newArrayList(elements.iterator()); + } + + /** + * Creates an {@code ArrayList} instance backed by an array with the specified initial size; + * simply delegates to {@link ArrayList#ArrayList(int)}. + * + *

Note for Java 7 and later: this method is now unnecessary and should be treated as + * deprecated. Instead, use {@code new }{@link ArrayList#ArrayList(int) ArrayList}{@code <>(int)} + * directly, taking advantage of the new "diamond" syntax. + * (Unlike here, there is no risk of overload ambiguity, since the {@code ArrayList} constructors + * very wisely did not accept varargs.) + * + * @param initialArraySize the exact size of the initial backing array for the returned array list + * ({@code ArrayList} documentation calls this value the "capacity") + * @return a new, empty {@code ArrayList} which is guaranteed not to resize itself unless its size + * reaches {@code initialArraySize + 1} + * @throws IllegalArgumentException if {@code initialArraySize} is negative + */ + public static ArrayList newArrayListWithCapacity(int initialArraySize) { + checkNonnegative(initialArraySize, "initialArraySize"); + return new ArrayList<>(initialArraySize); + } + + /** + * Creates an {@code ArrayList} instance to hold {@code estimatedSize} elements, plus an + * unspecified amount of padding; you almost certainly mean to call {@link + * #newArrayListWithCapacity} (see that method for further advice on usage). + * + *

Note: This method will soon be deprecated. Even in the rare case that you do want + * some amount of padding, it's best if you choose your desired amount explicitly. + * + * @param estimatedSize an estimate of the eventual {@link List#size()} of the new list + * @return a new, empty {@code ArrayList}, sized appropriately to hold the estimated number of + * elements + * @throws IllegalArgumentException if {@code estimatedSize} is negative + */ + public static ArrayList newArrayListWithExpectedSize(int estimatedSize) { + return new ArrayList<>(computeArrayListCapacity(estimatedSize)); + } + + static int computeArrayListCapacity(int arraySize) { + checkNonnegative(arraySize, "arraySize"); + return IntUtils.saturatedCast(5L + arraySize + (arraySize / 10)); + } + + static int checkNonnegative(int value, String name) { + if (value < 0) { + throw new IllegalArgumentException(name + " cannot be negative but was: " + value); + } + return value; + } + + /** + * Ensures that an object reference passed as a parameter to the calling method is not null. + * + * @param reference an object reference + * @return the non-null reference that was validated + * @throws NullPointerException if {@code reference} is null + */ + public static T checkNotNull(T reference) { + if (reference == null) { + throw new NullPointerException(); + } + return reference; + } +} diff --git a/src/main/java/com/alibaba/excel/util/MapUtils.java b/src/main/java/com/alibaba/excel/util/MapUtils.java new file mode 100644 index 00000000..6af4129e --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/MapUtils.java @@ -0,0 +1,63 @@ +package com.alibaba.excel.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Map utils + * + * @author Jiaju Zhuang + **/ +public class MapUtils { + private MapUtils() {} + /** + * Creates a mutable, empty {@code HashMap} instance. + * + *

Note: if mutability is not required, use {@link ImmutableMap#of()} instead. + * + *

Note: if {@code K} is an {@code enum} type, use {@link #newEnumMap} instead. + * + *

Note for Java 7 and later: this method is now unnecessary and should be treated as + * deprecated. Instead, use the {@code HashMap} constructor directly, taking advantage of the new + * "diamond" syntax. + * + * @return a new, empty {@code HashMap} + */ + public static HashMap newHashMap() { + return new HashMap<>(); + } + + /** + * Creates a {@code HashMap} instance, with a high enough "initial capacity" that it should + * hold {@code expectedSize} elements without growth. This behavior cannot be broadly guaranteed, + * but it is observed to be true for OpenJDK 1.7. It also can't be guaranteed that the method + * isn't inadvertently oversizing the returned map. + * + * @param expectedSize the number of entries you expect to add to the returned map + * @return a new, empty {@code HashMap} with enough capacity to hold {@code expectedSize} entries + * without resizing + * @throws IllegalArgumentException if {@code expectedSize} is negative + */ + public static HashMap newHashMapWithExpectedSize(int expectedSize) { + return new HashMap<>(capacity(expectedSize)); + } + + /** + * Returns a capacity that is sufficient to keep the map from being resized as long as it grows no + * larger than expectedSize and the load factor is ≥ its default (0.75). + */ + static int capacity(int expectedSize) { + if (expectedSize < 3) { + return expectedSize + 1; + } + if (expectedSize < IntUtils.MAX_POWER_OF_TWO) { + // This is the calculation used in JDK8 to resize when a putAll + // happens; it seems to be the most conservative calculation we + // can make. 0.75 is the default load factor. + return (int) ((float) expectedSize / 0.75F + 1.0F); + } + return Integer.MAX_VALUE; + } +} diff --git a/src/main/java/com/alibaba/excel/util/MemberUtils.java b/src/main/java/com/alibaba/excel/util/MemberUtils.java new file mode 100644 index 00000000..6bcfaac6 --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/MemberUtils.java @@ -0,0 +1,54 @@ +package com.alibaba.excel.util; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Member; +import java.lang.reflect.Modifier; + +/** + * Member utils. + * + * @author Jiaju Zhuang + */ +public class MemberUtils { + + private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE; + + + /** + * XXX Default access superclass workaround. + * + * When a {@code public} class has a default access superclass with {@code public} members, + * these members are accessible. Calling them from compiled code works fine. + * Unfortunately, on some JVMs, using reflection to invoke these members + * seems to (wrongly) prevent access even when the modifier is {@code public}. + * Calling {@code setAccessible(true)} solves the problem but will only work from + * sufficiently privileged code. Better workarounds would be gratefully + * accepted. + * @param o the AccessibleObject to set as accessible + * @return a boolean indicating whether the accessibility of the object was set to true. + */ + static boolean setAccessibleWorkaround(final AccessibleObject o) { + if (o == null || o.isAccessible()) { + return false; + } + final Member m = (Member) o; + if (!o.isAccessible() && Modifier.isPublic(m.getModifiers()) && isPackageAccess(m.getDeclaringClass().getModifiers())) { + try { + o.setAccessible(true); + return true; + } catch (final SecurityException e) { // NOPMD + // ignore in favor of subsequent IllegalAccessException + } + } + return false; + } + + /** + * Returns whether a given set of modifiers implies package access. + * @param modifiers to test + * @return {@code true} unless {@code package}/{@code protected}/{@code private} modifier detected + */ + static boolean isPackageAccess(final int modifiers) { + return (modifiers & ACCESS_TEST) == 0; + } +} diff --git a/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java b/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java index 5bceb4a1..de01ad54 100644 --- a/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java +++ b/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java @@ -1,6 +1,6 @@ package com.alibaba.excel.util; -import com.alibaba.excel.metadata.DataFormatter; +import com.alibaba.excel.metadata.format.DataFormatter; import com.alibaba.excel.metadata.GlobalConfiguration; /** @@ -9,6 +9,7 @@ import com.alibaba.excel.metadata.GlobalConfiguration; * @author Jiaju Zhuang **/ public class NumberDataFormatterUtils { + /** * Cache DataFormatter. */ @@ -18,22 +19,16 @@ public class NumberDataFormatterUtils { * Format number data. * * @param data - * @param dataFormat - * Not null. + * @param dataFormat Not null. * @param dataFormatString * @param globalConfiguration * @return */ - public static String format(Double data, Integer dataFormat, String dataFormatString, + public static String format(Double data, Short dataFormat, String dataFormatString, GlobalConfiguration globalConfiguration) { DataFormatter dataFormatter = DATA_FORMATTER_THREAD_LOCAL.get(); if (dataFormatter == null) { - if (globalConfiguration != null) { - dataFormatter = - new DataFormatter(globalConfiguration.getLocale(), globalConfiguration.getUse1904windowing()); - } else { - dataFormatter = new DataFormatter(); - } + dataFormatter = new DataFormatter(globalConfiguration); DATA_FORMATTER_THREAD_LOCAL.set(dataFormatter); } return dataFormatter.format(data, dataFormat, dataFormatString); diff --git a/src/main/java/com/alibaba/excel/util/NumberUtils.java b/src/main/java/com/alibaba/excel/util/NumberUtils.java index e687fbfc..09a15bea 100644 --- a/src/main/java/com/alibaba/excel/util/NumberUtils.java +++ b/src/main/java/com/alibaba/excel/util/NumberUtils.java @@ -7,6 +7,7 @@ import java.text.ParseException; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.write.metadata.holder.WriteHolder; /** * Number utils @@ -46,8 +47,27 @@ public class NumberUtils { * @param contentProperty * @return */ - public static CellData formatToCellData(Number num, ExcelContentProperty contentProperty) { - return new CellData(format(num, contentProperty)); + public static CellData formatToCellDataString(Number num, ExcelContentProperty contentProperty) { + return new CellData<>(format(num, contentProperty)); + } + + /** + * format + * + * @param num + * @param contentProperty + * @param currentWriteHolder + * @return + */ + public static CellData formatToCellData(Number num, ExcelContentProperty contentProperty, + WriteHolder currentWriteHolder) { + CellData cellData = new CellData<>(BigDecimal.valueOf(num.doubleValue())); + if (contentProperty != null && contentProperty.getNumberFormatProperty() != null + && StringUtils.isNotBlank(contentProperty.getNumberFormatProperty().getFormat())) { + WorkBookUtil.fillDataFormat(cellData, currentWriteHolder, + contentProperty.getNumberFormatProperty().getFormat()); + } + return cellData; } /** @@ -167,6 +187,7 @@ public class NumberUtils { RoundingMode roundingMode = contentProperty.getNumberFormatProperty().getRoundingMode(); DecimalFormat decimalFormat = new DecimalFormat(format); decimalFormat.setRoundingMode(roundingMode); + decimalFormat.setParseBigDecimal(true); return decimalFormat.parse(string); } } diff --git a/src/main/java/com/alibaba/excel/util/StringUtils.java b/src/main/java/com/alibaba/excel/util/StringUtils.java index 948ae652..667233dc 100644 --- a/src/main/java/com/alibaba/excel/util/StringUtils.java +++ b/src/main/java/com/alibaba/excel/util/StringUtils.java @@ -6,11 +6,92 @@ package com.alibaba.excel.util; * @author jipengfei */ public class StringUtils { + private StringUtils() {} + + /** + * A String for a space character. + */ + public static final String SPACE = " "; + + /** + * The empty String {@code ""}. + */ public static final String EMPTY = ""; - private StringUtils() {} + /** + *

Checks if a CharSequence is empty ("") or null.

+ * + *
+     * StringUtils.isEmpty(null)      = true
+     * StringUtils.isEmpty("")        = true
+     * StringUtils.isEmpty(" ")       = false
+     * StringUtils.isEmpty("bob")     = false
+     * StringUtils.isEmpty("  bob  ") = false
+     * 
+ * + *

NOTE: This method changed in Lang version 2.0. + * It no longer trims the CharSequence. + * That functionality is available in isBlank().

+ * + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is empty or null + */ + public static boolean isEmpty(final CharSequence cs) { + return cs == null || cs.length() == 0; + } - public static boolean isEmpty(Object str) { - return (str == null || EMPTY.equals(str)); + /** + *

Checks if a CharSequence is empty (""), null or whitespace only.

+ * + *

Whitespace is defined by {@link Character#isWhitespace(char)}.

+ * + *
+     * StringUtils.isBlank(null)      = true
+     * StringUtils.isBlank("")        = true
+     * StringUtils.isBlank(" ")       = true
+     * StringUtils.isBlank("bob")     = false
+     * StringUtils.isBlank("  bob  ") = false
+     * 
+ * + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is null, empty or whitespace only + */ + public static boolean isBlank(final CharSequence cs) { + int strLen; + if (cs == null || (strLen = cs.length()) == 0) { + return true; + } + for (int i = 0; i < strLen; i++) { + if (!Character.isWhitespace(cs.charAt(i))) { + return false; + } + } + return true; } + + + /** + *

Checks if a CharSequence is not empty (""), not null and not whitespace only.

+ * + *

Whitespace is defined by {@link Character#isWhitespace(char)}.

+ * + *
+     * StringUtils.isNotBlank(null)      = false
+     * StringUtils.isNotBlank("")        = false
+     * StringUtils.isNotBlank(" ")       = false
+     * StringUtils.isNotBlank("bob")     = true
+     * StringUtils.isNotBlank("  bob  ") = true
+     * 
+ * + * @param cs the CharSequence to check, may be null + * @return {@code true} if the CharSequence is + * not empty and not null and not whitespace only + * @since 2.0 + * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence) + */ + public static boolean isNotBlank(final CharSequence cs) { + return !isBlank(cs); + } + + } diff --git a/src/main/java/com/alibaba/excel/util/StyleUtil.java b/src/main/java/com/alibaba/excel/util/StyleUtil.java index d0e1bd32..0154f181 100644 --- a/src/main/java/com/alibaba/excel/util/StyleUtil.java +++ b/src/main/java/com/alibaba/excel/util/StyleUtil.java @@ -1,5 +1,8 @@ package com.alibaba.excel.util; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; + import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.FillPatternType; @@ -8,15 +11,17 @@ import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.usermodel.Workbook; - -import com.alibaba.excel.write.metadata.style.WriteCellStyle; -import com.alibaba.excel.write.metadata.style.WriteFont; +import org.apache.poi.xssf.streaming.SXSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFCellStyle; /** * @author jipengfei */ public class StyleUtil { + public static short XSSF_DEFAULT_STYLE = 0; + public static short HSSF_DEFAULT_STYLE = 15; + private StyleUtil() {} /** @@ -183,4 +188,13 @@ public class StyleUtil { } } + public static boolean isDefaultStyle(CellStyle cellStyle) { + if (cellStyle == null) { + return true; + } + if (cellStyle instanceof XSSFCellStyle) { + return cellStyle.getIndex() == XSSF_DEFAULT_STYLE; + } + return cellStyle.getIndex() == HSSF_DEFAULT_STYLE; + } } diff --git a/src/main/java/com/alibaba/excel/util/Validate.java b/src/main/java/com/alibaba/excel/util/Validate.java new file mode 100644 index 00000000..6207bb1a --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/Validate.java @@ -0,0 +1,151 @@ +package com.alibaba.excel.util; + +import java.util.Objects; + +/** + * Validate + * + * @author Jiaju Zhuang + */ +public class Validate { + + private static final String DEFAULT_IS_TRUE_EX_MESSAGE = "The validated expression is false"; + private static final String DEFAULT_IS_NULL_EX_MESSAGE = "The validated object is null"; + + /** + *

Validate that the argument condition is {@code true}; otherwise + * throwing an exception with the specified message. This method is useful when + * validating according to an arbitrary boolean expression, such as validating a + * primitive number or using your own custom validation expression.

+ * + *
Validate.isTrue(i > 0.0, "The value must be greater than zero: %d", i);
+ * + *

For performance reasons, the long value is passed as a separate parameter and + * appended to the exception message only in the case of an error.

+ * + * @param expression the boolean expression to check + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param value the value to append to the message when invalid + * @throws IllegalArgumentException if expression is {@code false} + * @see #isTrue(boolean) + * @see #isTrue(boolean, String, double) + * @see #isTrue(boolean, String, Object...) + */ + public static void isTrue(final boolean expression, final String message, final long value) { + if (!expression) { + throw new IllegalArgumentException(String.format(message, Long.valueOf(value))); + } + } + + /** + *

Validate that the argument condition is {@code true}; otherwise + * throwing an exception with the specified message. This method is useful when + * validating according to an arbitrary boolean expression, such as validating a + * primitive number or using your own custom validation expression.

+ * + *
Validate.isTrue(d > 0.0, "The value must be greater than zero: %s", d);
+ * + *

For performance reasons, the double value is passed as a separate parameter and + * appended to the exception message only in the case of an error.

+ * + * @param expression the boolean expression to check + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param value the value to append to the message when invalid + * @throws IllegalArgumentException if expression is {@code false} + * @see #isTrue(boolean) + * @see #isTrue(boolean, String, long) + * @see #isTrue(boolean, String, Object...) + */ + public static void isTrue(final boolean expression, final String message, final double value) { + if (!expression) { + throw new IllegalArgumentException(String.format(message, Double.valueOf(value))); + } + } + + /** + *

Validate that the argument condition is {@code true}; otherwise + * throwing an exception with the specified message. This method is useful when + * validating according to an arbitrary boolean expression, such as validating a + * primitive number or using your own custom validation expression.

+ * + *
+     * Validate.isTrue(i >= min && i <= max, "The value must be between %d and %d", min, max);
+     * Validate.isTrue(myObject.isOk(), "The object is not okay");
+ * + * @param expression the boolean expression to check + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message, null array not recommended + * @throws IllegalArgumentException if expression is {@code false} + * @see #isTrue(boolean) + * @see #isTrue(boolean, String, long) + * @see #isTrue(boolean, String, double) + */ + public static void isTrue(final boolean expression, final String message, final Object... values) { + if (!expression) { + throw new IllegalArgumentException(String.format(message, values)); + } + } + + /** + *

Validate that the argument condition is {@code true}; otherwise + * throwing an exception. This method is useful when validating according + * to an arbitrary boolean expression, such as validating a + * primitive number or using your own custom validation expression.

+ * + *
+     * Validate.isTrue(i > 0);
+     * Validate.isTrue(myObject.isOk());
+ * + *

The message of the exception is "The validated expression is + * false".

+ * + * @param expression the boolean expression to check + * @throws IllegalArgumentException if expression is {@code false} + * @see #isTrue(boolean, String, long) + * @see #isTrue(boolean, String, double) + * @see #isTrue(boolean, String, Object...) + */ + public static void isTrue(final boolean expression) { + if (!expression) { + throw new IllegalArgumentException(DEFAULT_IS_TRUE_EX_MESSAGE); + } + } + + + /** + *

Validate that the specified argument is not {@code null}; + * otherwise throwing an exception. + * + *

Validate.notNull(myObject, "The object must not be null");
+ * + *

The message of the exception is "The validated object is + * null".

+ * + * @param the object type + * @param object the object to check + * @return the validated object (never {@code null} for method chaining) + * @throws NullPointerException if the object is {@code null} + * @see #notNull(Object, String, Object...) + */ + public static T notNull(final T object) { + return notNull(object, DEFAULT_IS_NULL_EX_MESSAGE); + } + + /** + *

Validate that the specified argument is not {@code null}; + * otherwise throwing an exception with the specified message. + * + *

Validate.notNull(myObject, "The object must not be null");
+ * + * @param the object type + * @param object the object to check + * @param message the {@link String#format(String, Object...)} exception message if invalid, not null + * @param values the optional values for the formatted exception message + * @return the validated object (never {@code null} for method chaining) + * @throws NullPointerException if the object is {@code null} + * @see #notNull(Object) + */ + public static T notNull(final T object, final String message, final Object... values) { + return Objects.requireNonNull(object, () -> String.format(message, values)); + } +} diff --git a/src/main/java/com/alibaba/excel/util/WorkBookUtil.java b/src/main/java/com/alibaba/excel/util/WorkBookUtil.java index 186708c9..0ee92209 100644 --- a/src/main/java/com/alibaba/excel/util/WorkBookUtil.java +++ b/src/main/java/com/alibaba/excel/util/WorkBookUtil.java @@ -2,6 +2,13 @@ package com.alibaba.excel.util; import java.io.IOException; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.support.ExcelTypeEnum; +import com.alibaba.excel.write.metadata.holder.WriteHolder; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; + import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.POIFSFileSystem; @@ -13,16 +20,12 @@ import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; -import com.alibaba.excel.support.ExcelTypeEnum; -import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; - /** - * * @author jipengfei */ public class WorkBookUtil { - private static final int ROW_ACCESS_WINDOW_SIZE = 500; + public static final int ROW_ACCESS_WINDOW_SIZE = 500; private WorkBookUtil() {} @@ -91,4 +94,16 @@ public class WorkBookUtil { cell.setCellValue(cellValue); return cell; } + + public static void fillDataFormat(CellData cellData, WriteHolder currentWriteHolder, String format) { + WriteWorkbookHolder writeWorkbookHolder; + if (currentWriteHolder instanceof WriteSheetHolder) { + writeWorkbookHolder = ((WriteSheetHolder)currentWriteHolder).getParentWriteWorkbookHolder(); + } else { + writeWorkbookHolder = ((WriteTableHolder)currentWriteHolder).getParentWriteSheetHolder() + .getParentWriteWorkbookHolder(); + } + cellData.setDataFormat(writeWorkbookHolder.getDataFormat(format)); + cellData.setDataFormatString(format); + } } diff --git a/src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java b/src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java index 06dcc72b..0bd0a068 100644 --- a/src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java +++ b/src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java @@ -2,9 +2,7 @@ package com.alibaba.excel.util; import java.util.ArrayList; import java.util.List; - -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.Row; +import java.util.Map; import com.alibaba.excel.context.WriteContext; import com.alibaba.excel.metadata.CellData; @@ -15,6 +13,9 @@ import com.alibaba.excel.write.handler.SheetWriteHandler; import com.alibaba.excel.write.handler.WorkbookWriteHandler; import com.alibaba.excel.write.handler.WriteHandler; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; + /** * Write handler utils * @@ -25,8 +26,11 @@ public class WriteHandlerUtils { private WriteHandlerUtils() {} public static void beforeWorkbookCreate(WriteContext writeContext) { - List handlerList = - writeContext.writeWorkbookHolder().writeHandlerMap().get(WorkbookWriteHandler.class); + beforeWorkbookCreate(writeContext, false); + } + + public static void beforeWorkbookCreate(WriteContext writeContext, boolean runOwn) { + List handlerList = getHandlerList(writeContext, WorkbookWriteHandler.class, runOwn); if (handlerList == null || handlerList.isEmpty()) { return; } @@ -38,8 +42,11 @@ public class WriteHandlerUtils { } public static void afterWorkbookCreate(WriteContext writeContext) { - List handlerList = - writeContext.writeWorkbookHolder().writeHandlerMap().get(WorkbookWriteHandler.class); + afterWorkbookCreate(writeContext, false); + } + + public static void afterWorkbookCreate(WriteContext writeContext, boolean runOwn) { + List handlerList = getHandlerList(writeContext, WorkbookWriteHandler.class, runOwn); if (handlerList == null || handlerList.isEmpty()) { return; } @@ -52,7 +59,7 @@ public class WriteHandlerUtils { public static void afterWorkbookDispose(WriteContext writeContext) { List handlerList = - writeContext.writeWorkbookHolder().writeHandlerMap().get(WorkbookWriteHandler.class); + writeContext.currentWriteHolder().writeHandlerMap().get(WorkbookWriteHandler.class); if (handlerList == null || handlerList.isEmpty()) { return; } @@ -64,7 +71,11 @@ public class WriteHandlerUtils { } public static void beforeSheetCreate(WriteContext writeContext) { - List handlerList = writeContext.writeSheetHolder().writeHandlerMap().get(SheetWriteHandler.class); + beforeSheetCreate(writeContext, false); + } + + public static void beforeSheetCreate(WriteContext writeContext, boolean runOwn) { + List handlerList = getHandlerList(writeContext, SheetWriteHandler.class, runOwn); if (handlerList == null || handlerList.isEmpty()) { return; } @@ -77,7 +88,11 @@ public class WriteHandlerUtils { } public static void afterSheetCreate(WriteContext writeContext) { - List handlerList = writeContext.writeSheetHolder().writeHandlerMap().get(SheetWriteHandler.class); + afterSheetCreate(writeContext, false); + } + + public static void afterSheetCreate(WriteContext writeContext, boolean runOwn) { + List handlerList = getHandlerList(writeContext, SheetWriteHandler.class, runOwn); if (handlerList == null || handlerList.isEmpty()) { return; } @@ -140,14 +155,14 @@ public class WriteHandlerUtils { public static void afterCellDispose(WriteContext writeContext, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { - List cellDataList = new ArrayList(); - if (cell != null) { + List> cellDataList = new ArrayList<>(); + if (cellData != null) { cellDataList.add(cellData); } afterCellDispose(writeContext, cellDataList, cell, head, relativeRowIndex, isHead); } - public static void afterCellDispose(WriteContext writeContext, List cellDataList, Cell cell, Head head, + public static void afterCellDispose(WriteContext writeContext, List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { List handlerList = writeContext.currentWriteHolder().writeHandlerMap().get(CellWriteHandler.class); @@ -208,4 +223,15 @@ public class WriteHandlerUtils { writeContext.writeWorkbookHolder().getWriteWorkbook().getWriteHandler().row(row.getRowNum(), row); } } + + private static List getHandlerList(WriteContext writeContext, Class clazz, + boolean runOwn) { + Map, List> writeHandlerMap; + if (runOwn) { + writeHandlerMap = writeContext.currentWriteHolder().ownWriteHandlerMap(); + } else { + writeHandlerMap = writeContext.currentWriteHolder().writeHandlerMap(); + } + return writeHandlerMap.get(clazz); + } } diff --git a/src/main/java/com/alibaba/excel/write/ExcelBuilder.java b/src/main/java/com/alibaba/excel/write/ExcelBuilder.java index d3a50e35..a9f7e601 100644 --- a/src/main/java/com/alibaba/excel/write/ExcelBuilder.java +++ b/src/main/java/com/alibaba/excel/write/ExcelBuilder.java @@ -1,5 +1,6 @@ package com.alibaba.excel.write; +import java.util.Collection; import java.util.List; import com.alibaba.excel.context.WriteContext; @@ -20,10 +21,10 @@ public interface ExcelBuilder { * java basic type or java model extend BaseModel * @param writeSheet * Write the sheet - * @deprecated please use{@link ExcelBuilder#addContent(List, WriteSheet, WriteTable)} + * @deprecated please use{@link ExcelBuilder#addContent(Collection, WriteSheet, WriteTable)} */ @Deprecated - void addContent(List data, WriteSheet writeSheet); + void addContent(Collection data, WriteSheet writeSheet); /** * WorkBook increase value @@ -35,7 +36,7 @@ public interface ExcelBuilder { * @param writeTable * Write the table */ - void addContent(List data, WriteSheet writeSheet, WriteTable writeTable); + void addContent(Collection data, WriteSheet writeSheet, WriteTable writeTable); /** * WorkBook fill value diff --git a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java index 0c7158ed..e172140d 100644 --- a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java +++ b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java @@ -1,13 +1,19 @@ package com.alibaba.excel.write; +import java.lang.reflect.Field; +import java.util.Collection; import java.util.List; +import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.streaming.SXSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFSheet; import com.alibaba.excel.context.WriteContext; import com.alibaba.excel.context.WriteContextImpl; import com.alibaba.excel.enums.WriteTypeEnum; import com.alibaba.excel.exception.ExcelGenerateException; +import com.alibaba.excel.util.FieldUtils; import com.alibaba.excel.util.FileUtils; import com.alibaba.excel.write.executor.ExcelWriteAddExecutor; import com.alibaba.excel.write.executor.ExcelWriteFillExecutor; @@ -43,12 +49,12 @@ public class ExcelBuilderImpl implements ExcelBuilder { } @Override - public void addContent(List data, WriteSheet writeSheet) { + public void addContent(Collection data, WriteSheet writeSheet) { addContent(data, writeSheet, null); } @Override - public void addContent(List data, WriteSheet writeSheet, WriteTable writeTable) { + public void addContent(Collection data, WriteSheet writeSheet, WriteTable writeTable) { try { context.currentSheet(writeSheet, WriteTypeEnum.ADD); context.currentTable(writeTable); diff --git a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java index f79b7710..0ec448e2 100644 --- a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java +++ b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java @@ -1,6 +1,6 @@ package com.alibaba.excel.write.builder; -import java.util.List; +import java.util.Collection; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.exception.ExcelGenerateException; @@ -54,7 +54,7 @@ public class ExcelWriterSheetBuilder extends AbstractExcelWriterParameterBuilder return writeSheet; } - public void doWrite(List data) { + public void doWrite(Collection data) { if (excelWriter == null) { throw new ExcelGenerateException("Must use 'EasyExcelFactory.write().sheet()' to call this method"); } diff --git a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java index 077361ad..b7a90be9 100644 --- a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java +++ b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java @@ -1,6 +1,6 @@ package com.alibaba.excel.write.builder; -import java.util.List; +import java.util.Collection; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.exception.ExcelGenerateException; @@ -47,7 +47,7 @@ public class ExcelWriterTableBuilder extends AbstractExcelWriterParameterBuilder return writeTable; } - public void doWrite(List data) { + public void doWrite(Collection data) { if (excelWriter == null) { throw new ExcelGenerateException("Must use 'EasyExcelFactory.write().sheet().table()' to call this method"); } diff --git a/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java b/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java index eb094d7f..35d95e5a 100644 --- a/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java @@ -1,12 +1,5 @@ package com.alibaba.excel.write.executor; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.ClientAnchor; -import org.apache.poi.ss.usermodel.CreationHelper; -import org.apache.poi.ss.usermodel.Drawing; -import org.apache.poi.ss.usermodel.Sheet; - import com.alibaba.excel.context.WriteContext; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.converters.ConverterKeyBuild; @@ -18,6 +11,13 @@ import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.util.WriteHandlerUtils; import com.alibaba.excel.write.metadata.holder.WriteHolder; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.ClientAnchor; +import org.apache.poi.ss.usermodel.CreationHelper; +import org.apache.poi.ss.usermodel.Drawing; +import org.apache.poi.ss.usermodel.Sheet; + /** * Excel write Executor * @@ -30,15 +30,13 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor { this.writeContext = writeContext; } - protected CellData converterAndSet(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value, + protected CellData converterAndSet(WriteHolder currentWriteHolder, Class clazz, CellDataTypeEnum targetType, + Cell cell, Object value, ExcelContentProperty excelContentProperty, Head head, Integer relativeRowIndex) { - if (value == null) { - return new CellData(CellDataTypeEnum.EMPTY); - } if (value instanceof String && currentWriteHolder.globalConfiguration().getAutoTrim()) { value = ((String)value).trim(); } - CellData cellData = convert(currentWriteHolder, clazz, cell, value, excelContentProperty); + CellData cellData = convert(currentWriteHolder, clazz, targetType, cell, value, excelContentProperty); if (cellData.getFormula() != null && cellData.getFormula()) { cell.setCellFormula(cellData.getFormulaValue()); } @@ -56,6 +54,9 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor { case NUMBER: cell.setCellValue(cellData.getNumberValue().doubleValue()); return cellData; + case DATE: + cell.setCellValue(cellData.getDateValue()); + return cellData; case IMAGE: setImageValue(cellData, cell); return cellData; @@ -64,18 +65,16 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor { default: throw new ExcelDataConvertException(cell.getRow().getRowNum(), cell.getColumnIndex(), cellData, excelContentProperty, "Not supported data:" + value + " return type:" + cell.getCellType() - + "at row:" + cell.getRow().getRowNum()); + + "at row:" + cell.getRow().getRowNum()); } } - protected CellData convert(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value, - ExcelContentProperty excelContentProperty) { - if (value == null) { - return new CellData(CellDataTypeEnum.EMPTY); - } + protected CellData convert(WriteHolder currentWriteHolder, Class clazz, CellDataTypeEnum targetType, + Cell cell, + Object value, ExcelContentProperty excelContentProperty) { // This means that the user has defined the data. if (value instanceof CellData) { - CellData cellDataValue = (CellData)value; + CellData cellDataValue = (CellData)value; if (cellDataValue.getType() != null) { return cellDataValue; } else { @@ -84,8 +83,8 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor { return cellDataValue; } } - CellData cellDataReturn = doConvert(currentWriteHolder, cellDataValue.getData().getClass(), cell, - cellDataValue.getData(), excelContentProperty); + CellData cellDataReturn = doConvert(currentWriteHolder, cellDataValue.getData().getClass(), targetType, + cell, cellDataValue.getData(), excelContentProperty); // The formula information is subject to user input if (cellDataValue.getFormula() != null) { cellDataReturn.setFormula(cellDataValue.getFormula()); @@ -93,41 +92,40 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor { } return cellDataReturn; } - return doConvert(currentWriteHolder, clazz, cell, value, excelContentProperty); + return doConvert(currentWriteHolder, clazz, targetType, cell, value, excelContentProperty); } - private CellData doConvert(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value, - ExcelContentProperty excelContentProperty) { + private CellData doConvert(WriteHolder currentWriteHolder, Class clazz, CellDataTypeEnum targetType, + Cell cell, Object value, ExcelContentProperty excelContentProperty) { Converter converter = null; if (excelContentProperty != null) { converter = excelContentProperty.getConverter(); } if (converter == null) { - converter = currentWriteHolder.converterMap().get(ConverterKeyBuild.buildKey(clazz)); + converter = currentWriteHolder.converterMap().get(ConverterKeyBuild.buildKey(clazz, targetType)); } if (converter == null) { throw new ExcelDataConvertException(cell.getRow().getRowNum(), cell.getColumnIndex(), - new CellData(CellDataTypeEnum.EMPTY), excelContentProperty, + new CellData<>(CellDataTypeEnum.EMPTY), excelContentProperty, "Can not find 'Converter' support class " + clazz.getSimpleName() + "."); } - CellData cellData; + CellData cellData; try { - cellData = - converter.convertToExcelData(value, excelContentProperty, currentWriteHolder.globalConfiguration()); + cellData = converter.convertToExcelData(value, excelContentProperty, currentWriteHolder); } catch (Exception e) { throw new ExcelDataConvertException(cell.getRow().getRowNum(), cell.getColumnIndex(), - new CellData(CellDataTypeEnum.EMPTY), excelContentProperty, + new CellData<>(CellDataTypeEnum.EMPTY), excelContentProperty, "Convert data:" + value + " error,at row:" + cell.getRow().getRowNum(), e); } if (cellData == null || cellData.getType() == null) { throw new ExcelDataConvertException(cell.getRow().getRowNum(), cell.getColumnIndex(), - new CellData(CellDataTypeEnum.EMPTY), excelContentProperty, + new CellData<>(CellDataTypeEnum.EMPTY), excelContentProperty, "Convert data:" + value + " return null,at row:" + cell.getRow().getRowNum()); } return cellData; } - private void setImageValue(CellData cellData, Cell cell) { + private void setImageValue(CellData cellData, Cell cell) { Sheet sheet = cell.getSheet(); int index = sheet.getWorkbook().addPicture(cellData.getImageValue(), HSSFWorkbook.PICTURE_TYPE_PNG); Drawing drawing = sheet.getDrawingPatriarch(); diff --git a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java index d25ee941..4d96e8c4 100644 --- a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java @@ -2,13 +2,11 @@ package com.alibaba.excel.write.executor; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; - -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.Row; +import java.util.TreeMap; import com.alibaba.excel.context.WriteContext; import com.alibaba.excel.enums.HeadKindEnum; @@ -16,13 +14,20 @@ import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.util.ClassUtils; -import com.alibaba.excel.util.CollectionUtils; +import com.alibaba.excel.util.FieldUtils; import com.alibaba.excel.util.WorkBookUtil; import com.alibaba.excel.util.WriteHandlerUtils; +import com.alibaba.excel.write.metadata.CollectionRowData; +import com.alibaba.excel.write.metadata.MapRowData; +import com.alibaba.excel.write.metadata.RowData; import com.alibaba.excel.write.metadata.holder.WriteHolder; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; import net.sf.cglib.beans.BeanMap; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; /** * Add the data into excel @@ -35,42 +40,46 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor { super(writeContext); } - public void add(List data) { + public void add(Collection data) { if (CollectionUtils.isEmpty(data)) { - data = new ArrayList(); + data = new ArrayList<>(); } WriteSheetHolder writeSheetHolder = writeContext.writeSheetHolder(); int newRowIndex = writeSheetHolder.getNewRowIndexAndStartDoWrite(); if (writeSheetHolder.isNew() && !writeSheetHolder.getExcelWriteHeadProperty().hasHead()) { newRowIndex += writeContext.currentWriteHolder().relativeHeadRowIndex(); } - // BeanMap is out of order,so use fieldList - List fieldList = new ArrayList(); - int relativeRowIndex=0; - for(Object oneRowData : data){ - int n = relativeRowIndex + newRowIndex; - addOneRowOfDataToExcel(oneRowData, n, relativeRowIndex, fieldList); + // BeanMap is out of order,so use sortedAllFiledMap + Map sortedAllFiledMap = new TreeMap<>(); + int relativeRowIndex = 0; + for (Object oneRowData : data) { + int lastRowIndex = relativeRowIndex + newRowIndex; + addOneRowOfDataToExcel(oneRowData, lastRowIndex, relativeRowIndex, sortedAllFiledMap); relativeRowIndex++; } } - private void addOneRowOfDataToExcel(Object oneRowData, int n, int relativeRowIndex, List fieldList) { + private void addOneRowOfDataToExcel(Object oneRowData, int n, int relativeRowIndex, + Map sortedAllFiledMap) { if (oneRowData == null) { return; } WriteHandlerUtils.beforeRowCreate(writeContext, n, relativeRowIndex, Boolean.FALSE); Row row = WorkBookUtil.createRow(writeContext.writeSheetHolder().getSheet(), n); WriteHandlerUtils.afterRowCreate(writeContext, row, relativeRowIndex, Boolean.FALSE); - if (oneRowData instanceof List) { - addBasicTypeToExcel((List)oneRowData, row, relativeRowIndex); + + if (oneRowData instanceof Collection) { + addBasicTypeToExcel(new CollectionRowData((Collection)oneRowData), row, relativeRowIndex); + } else if (oneRowData instanceof Map) { + addBasicTypeToExcel(new MapRowData((Map)oneRowData), row, relativeRowIndex); } else { - addJavaObjectToExcel(oneRowData, row, relativeRowIndex, fieldList); + addJavaObjectToExcel(oneRowData, row, relativeRowIndex, sortedAllFiledMap); } WriteHandlerUtils.afterRowDispose(writeContext, row, relativeRowIndex, Boolean.FALSE); } - private void addBasicTypeToExcel(List oneRowData, Row row, int relativeRowIndex) { - if (CollectionUtils.isEmpty(oneRowData)) { + private void addBasicTypeToExcel(RowData oneRowData, Row row, int relativeRowIndex) { + if (oneRowData.isEmpty()) { return; } Map headMap = writeContext.currentWriteHolder().excelWriteHeadProperty().getHeadMap(); @@ -97,21 +106,20 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor { } } - private void doAddBasicTypeToExcel(List oneRowData, Head head, Row row, int relativeRowIndex, int dataIndex, + private void doAddBasicTypeToExcel(RowData oneRowData, Head head, Row row, int relativeRowIndex, + int dataIndex, int cellIndex) { - if (writeContext.currentWriteHolder().ignore(null, cellIndex)) { - return; - } WriteHandlerUtils.beforeCellCreate(writeContext, row, head, cellIndex, relativeRowIndex, Boolean.FALSE); Cell cell = WorkBookUtil.createCell(row, cellIndex); WriteHandlerUtils.afterCellCreate(writeContext, cell, head, relativeRowIndex, Boolean.FALSE); Object value = oneRowData.get(dataIndex); CellData cellData = converterAndSet(writeContext.currentWriteHolder(), value == null ? null : value.getClass(), - cell, value, null, head, relativeRowIndex); + null, cell, value, null, head, relativeRowIndex); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, head, relativeRowIndex, Boolean.FALSE); } - private void addJavaObjectToExcel(Object oneRowData, Row row, int relativeRowIndex, List fieldList) { + private void addJavaObjectToExcel(Object oneRowData, Row row, int relativeRowIndex, + Map sortedAllFiledMap) { WriteHolder currentWriteHolder = writeContext.currentWriteHolder(); BeanMap beanMap = BeanMap.create(oneRowData); Set beanMapHandledSet = new HashSet(); @@ -124,10 +132,7 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor { for (Map.Entry entry : contentPropertyMap.entrySet()) { cellIndex = entry.getKey(); ExcelContentProperty excelContentProperty = entry.getValue(); - String name = excelContentProperty.getField().getName(); - if (writeContext.currentWriteHolder().ignore(name, cellIndex)) { - continue; - } + String name = FieldUtils.resolveCglibFieldName(excelContentProperty.getField()); if (!beanMap.containsKey(name)) { continue; } @@ -136,8 +141,9 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor { Cell cell = WorkBookUtil.createCell(row, cellIndex); WriteHandlerUtils.afterCellCreate(writeContext, cell, head, relativeRowIndex, Boolean.FALSE); Object value = beanMap.get(name); - CellData cellData = converterAndSet(currentWriteHolder, excelContentProperty.getField().getType(), cell, - value, excelContentProperty, head, relativeRowIndex); + CellData cellData = converterAndSet(currentWriteHolder, excelContentProperty.getField().getType(), + null, + cell, value, excelContentProperty, head, relativeRowIndex); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, head, relativeRowIndex, Boolean.FALSE); beanMapHandledSet.add(name); } @@ -146,34 +152,39 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor { if (beanMapHandledSet.size() == beanMap.size()) { return; } - if (cellIndex != 0) { - cellIndex++; - } Map ignoreMap = writeContext.currentWriteHolder().excelWriteHeadProperty().getIgnoreMap(); - initFieldList(oneRowData.getClass(), fieldList); - for (Field field : fieldList) { + initSortedAllFiledMapFieldList(oneRowData.getClass(), sortedAllFiledMap); + for (Map.Entry entry : sortedAllFiledMap.entrySet()) { + cellIndex = entry.getKey(); + Field field = entry.getValue(); String filedName = field.getName(); boolean uselessData = !beanMap.containsKey(filedName) || beanMapHandledSet.contains(filedName) - || ignoreMap.containsKey(filedName) || writeContext.currentWriteHolder().ignore(filedName, cellIndex); + || ignoreMap.containsKey(filedName); if (uselessData) { continue; } Object value = beanMap.get(filedName); WriteHandlerUtils.beforeCellCreate(writeContext, row, null, cellIndex, relativeRowIndex, Boolean.FALSE); - Cell cell = WorkBookUtil.createCell(row, cellIndex++); + Cell cell = WorkBookUtil.createCell(row, cellIndex); WriteHandlerUtils.afterCellCreate(writeContext, cell, null, relativeRowIndex, Boolean.FALSE); - CellData cellData = converterAndSet(currentWriteHolder, value == null ? null : value.getClass(), cell, + CellData cellData = converterAndSet(currentWriteHolder, value == null ? null : value.getClass(), null, cell, value, null, null, relativeRowIndex); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, null, relativeRowIndex, Boolean.FALSE); } } - private void initFieldList(Class clazz, List fieldList) { - if (!fieldList.isEmpty()) { + private void initSortedAllFiledMapFieldList(Class clazz, Map sortedAllFiledMap) { + if (!sortedAllFiledMap.isEmpty()) { return; } - ClassUtils.declaredFields(clazz, fieldList, - writeContext.writeWorkbookHolder().getWriteWorkbook().getConvertAllFiled()); + WriteWorkbookHolder writeWorkbookHolder = writeContext.writeWorkbookHolder(); + boolean needIgnore = + !CollectionUtils.isEmpty(writeWorkbookHolder.getExcludeColumnFiledNames()) || !CollectionUtils + .isEmpty(writeWorkbookHolder.getExcludeColumnIndexes()) || !CollectionUtils + .isEmpty(writeWorkbookHolder.getIncludeColumnFiledNames()) || !CollectionUtils + .isEmpty(writeWorkbookHolder.getIncludeColumnIndexes()); + ClassUtils.declaredFields(clazz, sortedAllFiledMap, + writeWorkbookHolder.getWriteWorkbook().getConvertAllFiled(), needIgnore, writeWorkbookHolder); } } diff --git a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java index 51d7d3a0..9a144534 100644 --- a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java @@ -9,12 +9,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.CellType; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; - import com.alibaba.excel.context.WriteContext; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.enums.WriteDirectionEnum; @@ -22,7 +16,6 @@ import com.alibaba.excel.enums.WriteTemplateAnalysisCellTypeEnum; import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.property.ExcelContentProperty; -import com.alibaba.excel.util.CollectionUtils; import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.util.WriteHandlerUtils; import com.alibaba.excel.write.metadata.fill.AnalysisCell; @@ -31,6 +24,12 @@ import com.alibaba.excel.write.metadata.fill.FillWrapper; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import net.sf.cglib.beans.BeanMap; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; /** * Fill the data into excel @@ -48,28 +47,28 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { /** * Fields to replace in the template */ - private Map> templateAnalysisCache = new HashMap>(8); + private final Map> templateAnalysisCache = new HashMap>(8); /** * Collection fields to replace in the template */ - private Map> templateCollectionAnalysisCache = + private final Map> templateCollectionAnalysisCache = new HashMap>(8); /** * Style cache for collection fields */ - private Map> collectionFieldStyleCache = + private final Map> collectionFieldStyleCache = new HashMap>(8); /** * Row height cache for collection */ - private Map collectionRowHeightCache = new HashMap(8); + private final Map collectionRowHeightCache = new HashMap(8); /** * Last index cache for collection fields */ - private Map> collectionLastIndexCache = + private final Map> collectionLastIndexCache = new HashMap>(8); - private Map relativeRowIndexMap = new HashMap(8); + private final Map relativeRowIndexMap = new HashMap(8); /** * The data prefix that is populated this time */ @@ -156,15 +155,32 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { return; } sheet.shiftRows(maxRowIndex + 1, lastRowIndex, number, true, false); - for (AnalysisCell analysisCell : templateAnalysisCache.get(currentUniqueDataFlag)) { - if (analysisCell.getRowIndex() > maxRowIndex) { - analysisCell.setRowIndex(analysisCell.getRowIndex() + number); + + // The current data is greater than unity rowindex increase + String tablePrefix = tablePrefix(currentUniqueDataFlag); + increaseRowIndex(templateAnalysisCache, number, maxRowIndex, tablePrefix); + increaseRowIndex(templateCollectionAnalysisCache, number, maxRowIndex, tablePrefix); + } + + private void increaseRowIndex(Map> templateAnalysisCache, int number, int maxRowIndex, + String tablePrefix) { + for (Map.Entry> entry : templateAnalysisCache.entrySet()) { + if (!tablePrefix.equals(tablePrefix(entry.getKey()))) { + continue; + } + for (AnalysisCell analysisCell : entry.getValue()) { + if (analysisCell.getRowIndex() > maxRowIndex) { + analysisCell.setRowIndex(analysisCell.getRowIndex() + number); + } } } } private void doFill(List analysisCellList, Object oneRowData, FillConfig fillConfig, Integer relativeRowIndex) { + if (CollectionUtils.isEmpty(analysisCellList)) { + return; + } Map dataMap; if (oneRowData instanceof Map) { dataMap = (Map)oneRowData; @@ -178,31 +194,25 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { Cell cell = getOneCell(analysisCell, fillConfig); if (analysisCell.getOnlyOneVariable()) { String variable = analysisCell.getVariableList().get(0); - if (writeContext.currentWriteHolder().ignore(variable, analysisCell.getColumnIndex())) { - continue; - } if (!dataMap.containsKey(variable)) { continue; } Object value = dataMap.get(variable); - CellData cellData = converterAndSet(writeSheetHolder, value == null ? null : value.getClass(), cell, - value, fieldNameContentPropertyMap.get(variable), null, relativeRowIndex); + CellData cellData = converterAndSet(writeSheetHolder, value == null ? null : value.getClass(), null, + cell, value, fieldNameContentPropertyMap.get(variable), null, relativeRowIndex); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, null, relativeRowIndex, Boolean.FALSE); } else { StringBuilder cellValueBuild = new StringBuilder(); int index = 0; - List cellDataList = new ArrayList(); + List> cellDataList = new ArrayList<>(); for (String variable : analysisCell.getVariableList()) { cellValueBuild.append(analysisCell.getPrepareDataList().get(index++)); - if (writeContext.currentWriteHolder().ignore(variable, analysisCell.getColumnIndex())) { - continue; - } if (!dataMap.containsKey(variable)) { continue; } Object value = dataMap.get(variable); - CellData cellData = convert(writeSheetHolder, value == null ? null : value.getClass(), cell, value, - fieldNameContentPropertyMap.get(variable)); + CellData cellData = convert(writeSheetHolder, value == null ? null : value.getClass(), + CellDataTypeEnum.STRING, cell, value, fieldNameContentPropertyMap.get(variable)); cellDataList.add(cellData); CellDataTypeEnum type = cellData.getType(); if (type != null) { @@ -281,28 +291,9 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { default: throw new ExcelGenerateException("The wrong direction."); } - Row row = sheet.getRow(lastRowIndex); - if (row == null) { - row = cachedSheet.getRow(lastRowIndex); - if (row == null) { - WriteHandlerUtils.beforeRowCreate(writeContext, lastRowIndex, null, Boolean.FALSE); - if (fillConfig.getForceNewRow()) { - row = cachedSheet.createRow(lastRowIndex); - } else { - row = sheet.createRow(lastRowIndex); - } - checkRowHeight(analysisCell, fillConfig, isOriginalCell, row); - WriteHandlerUtils.afterRowCreate(writeContext, row, null, Boolean.FALSE); - } else { - checkRowHeight(analysisCell, fillConfig, isOriginalCell, row); - } - } - Cell cell = row.getCell(lastColumnIndex); - if (cell == null) { - WriteHandlerUtils.beforeCellCreate(writeContext, row, null, lastColumnIndex, null, Boolean.FALSE); - cell = row.createCell(lastColumnIndex); - WriteHandlerUtils.afterCellCreate(writeContext, cell, null, null, Boolean.FALSE); - } + + Row row = createRowIfNecessary(sheet, cachedSheet, lastRowIndex, fillConfig, analysisCell, isOriginalCell); + Cell cell = createCellIfNecessary(row, lastColumnIndex); Map collectionFieldStyleMap = collectionFieldStyleCache.get(currentUniqueDataFlag); if (collectionFieldStyleMap == null) { @@ -320,6 +311,46 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { return cell; } + private Cell createCellIfNecessary(Row row, Integer lastColumnIndex) { + Cell cell = row.getCell(lastColumnIndex); + if (cell != null) { + return cell; + } + WriteHandlerUtils.beforeCellCreate(writeContext, row, null, lastColumnIndex, null, Boolean.FALSE); + cell = row.createCell(lastColumnIndex); + WriteHandlerUtils.afterCellCreate(writeContext, cell, null, null, Boolean.FALSE); + return cell; + } + + private Row createRowIfNecessary(Sheet sheet, Sheet cachedSheet, Integer lastRowIndex, FillConfig fillConfig, + AnalysisCell analysisCell, boolean isOriginalCell) { + Row row = sheet.getRow(lastRowIndex); + if (row != null) { + return row; + } + row = cachedSheet.getRow(lastRowIndex); + if (row == null) { + WriteHandlerUtils.beforeRowCreate(writeContext, lastRowIndex, null, Boolean.FALSE); + if (fillConfig.getForceNewRow()) { + row = cachedSheet.createRow(lastRowIndex); + } else { + // The last row of the middle disk inside empty rows, resulting in cachedSheet can not get inside. + // Will throw Attempting to write a row[" + rownum + "] " + "in the range [0," + this._sh + // .getLastRowNum() + "] that is already written to disk. + try { + row = sheet.createRow(lastRowIndex); + } catch (IllegalArgumentException ignore) { + row = cachedSheet.createRow(lastRowIndex); + } + } + checkRowHeight(analysisCell, fillConfig, isOriginalCell, row); + WriteHandlerUtils.afterRowCreate(writeContext, row, null, Boolean.FALSE); + } else { + checkRowHeight(analysisCell, fillConfig, isOriginalCell, row); + } + return row; + } + private void checkRowHeight(AnalysisCell analysisCell, FillConfig fillConfig, boolean isOriginalCell, Row row) { if (!analysisCell.getFirstRow() || !WriteDirectionEnum.VERTICAL.equals(fillConfig.getDirection())) { return; @@ -515,4 +546,8 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { return prefix + "-" + wrapperName; } + private String tablePrefix(String uniqueDataFlag) { + return uniqueDataFlag.substring(0, uniqueDataFlag.indexOf("-") + 1); + } + } diff --git a/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java index b649af7a..6b663ce9 100644 --- a/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java +++ b/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java @@ -14,7 +14,9 @@ import com.alibaba.excel.write.metadata.holder.WriteTableHolder; * Abstract cell write handler * * @author Jiaju Zhuang + * @deprecated Please use it directly {@link CellWriteHandler} **/ +@Deprecated public abstract class AbstractCellWriteHandler implements CellWriteHandler { @Override @@ -37,7 +39,7 @@ public abstract class AbstractCellWriteHandler implements CellWriteHandler { @Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, - List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { } } diff --git a/src/main/java/com/alibaba/excel/write/handler/AbstractRowWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/AbstractRowWriteHandler.java index d1e8c3a9..286d8757 100644 --- a/src/main/java/com/alibaba/excel/write/handler/AbstractRowWriteHandler.java +++ b/src/main/java/com/alibaba/excel/write/handler/AbstractRowWriteHandler.java @@ -1,15 +1,17 @@ package com.alibaba.excel.write.handler; -import org.apache.poi.ss.usermodel.Row; - import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import org.apache.poi.ss.usermodel.Row; + /** * Abstract row write handler * * @author Jiaju Zhuang + * @deprecated Please use it directly {@link RowWriteHandler} **/ +@Deprecated public abstract class AbstractRowWriteHandler implements RowWriteHandler { @Override public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex, diff --git a/src/main/java/com/alibaba/excel/write/handler/AbstractSheetWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/AbstractSheetWriteHandler.java index 76f4c846..d24f9010 100644 --- a/src/main/java/com/alibaba/excel/write/handler/AbstractSheetWriteHandler.java +++ b/src/main/java/com/alibaba/excel/write/handler/AbstractSheetWriteHandler.java @@ -7,7 +7,9 @@ import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; * Abstract sheet write handler * * @author Jiaju Zhuang + * @deprecated Please use it directly {@link SheetWriteHandler} **/ +@Deprecated public abstract class AbstractSheetWriteHandler implements SheetWriteHandler { @Override public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { diff --git a/src/main/java/com/alibaba/excel/write/handler/AbstractWorkbookWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/AbstractWorkbookWriteHandler.java index baad3920..5bb2fc5f 100644 --- a/src/main/java/com/alibaba/excel/write/handler/AbstractWorkbookWriteHandler.java +++ b/src/main/java/com/alibaba/excel/write/handler/AbstractWorkbookWriteHandler.java @@ -6,7 +6,9 @@ import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; * Abstract workbook write handler * * @author Jiaju Zhuang + * @deprecated Please use it directly {@link WorkbookWriteHandler} **/ +@Deprecated public abstract class AbstractWorkbookWriteHandler implements WorkbookWriteHandler { @Override diff --git a/src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java index 8701d6a0..4c9e39ed 100644 --- a/src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java +++ b/src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java @@ -2,14 +2,14 @@ package com.alibaba.excel.write.handler; import java.util.List; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.Row; - import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; + /** * intercepts handle cell creation * @@ -21,72 +21,54 @@ public interface CellWriteHandler extends WriteHandler { * Called before create the cell * * @param writeSheetHolder - * @param writeTableHolder - * Nullable.It is null without using table writes. + * @param writeTableHolder Nullable.It is null without using table writes. * @param row - * @param head - * Nullable.It is null in the case of fill data and without head. + * @param head Nullable.It is null in the case of fill data and without head. * @param columnIndex - * @param relativeRowIndex - * Nullable.It is null in the case of fill data. - * @param isHead - * It will always be false when fill data. + * @param relativeRowIndex Nullable.It is null in the case of fill data. + * @param isHead It will always be false when fill data. */ - void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, - Integer columnIndex, Integer relativeRowIndex, Boolean isHead); + default void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {} /** * Called after the cell is created * * @param writeSheetHolder - * @param writeTableHolder - * Nullable.It is null without using table writes. + * @param writeTableHolder Nullable.It is null without using table writes. * @param cell - * @param head - * Nullable.It is null in the case of fill data and without head. - * @param relativeRowIndex - * Nullable.It is null in the case of fill data. - * @param isHead - * It will always be false when fill data. + * @param head Nullable.It is null in the case of fill data and without head. + * @param relativeRowIndex Nullable.It is null in the case of fill data. + * @param isHead It will always be false when fill data. */ - void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, - Integer relativeRowIndex, Boolean isHead); + default void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, + Head head, Integer relativeRowIndex, Boolean isHead) {} /** * Called after the cell data is converted * * @param writeSheetHolder - * @param writeTableHolder - * Nullable.It is null without using table writes. + * @param writeTableHolder Nullable.It is null without using table writes. * @param cell - * @param head - * Nullable.It is null in the case of fill data and without head. - * @param cellData - * Nullable.It is null in the case of add header. - * @param relativeRowIndex - * Nullable.It is null in the case of fill data. - * @param isHead - * It will always be false when fill data. + * @param head Nullable.It is null in the case of fill data and without head. + * @param cellData Nullable.It is null in the case of add header. + * @param relativeRowIndex Nullable.It is null in the case of fill data. + * @param isHead It will always be false when fill data. */ - void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, - Cell cell, Head head, Integer relativeRowIndex, Boolean isHead); + default void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {} /** * Called after all operations on the cell have been completed * * @param writeSheetHolder - * @param writeTableHolder - * Nullable.It is null without using table writes. + * @param writeTableHolder Nullable.It is null without using table writes. * @param cell - * @param head - * Nullable.It is null in the case of fill data and without head. - * @param cellDataList - * Nullable.It is null in the case of add header.There may be several when fill the data. - * @param relativeRowIndex - * Nullable.It is null in the case of fill data. - * @param isHead - * It will always be false when fill data. + * @param head Nullable.It is null in the case of fill data and without head. + * @param cellDataList Nullable.It is null in the case of add header.There may be several when fill the data. + * @param relativeRowIndex Nullable.It is null in the case of fill data. + * @param isHead It will always be false when fill data. */ - void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, - List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead); + default void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {} } diff --git a/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java b/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java index dff84d7a..16897076 100644 --- a/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java +++ b/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java @@ -3,12 +3,15 @@ package com.alibaba.excel.write.handler; import java.util.ArrayList; import java.util.List; -import org.apache.poi.ss.usermodel.IndexedColors; - +import com.alibaba.excel.write.handler.impl.DefaultRowWriteHandler; +import com.alibaba.excel.write.handler.impl.DimensionWorkbookWriteHandler; +import com.alibaba.excel.write.handler.impl.FillDataFormatCellWriteHandler; import com.alibaba.excel.write.metadata.style.WriteCellStyle; import com.alibaba.excel.write.metadata.style.WriteFont; import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; +import org.apache.poi.ss.usermodel.IndexedColors; + /** * Load default handler * @@ -16,13 +19,20 @@ import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; */ public class DefaultWriteHandlerLoader { + public static final List DEFAULT_WRITE_HANDLER_LIST = new ArrayList<>(); + + static { + DEFAULT_WRITE_HANDLER_LIST.add(new DimensionWorkbookWriteHandler()); + DEFAULT_WRITE_HANDLER_LIST.add(new DefaultRowWriteHandler()); + } + /** * Load default handler * * @return */ public static List loadDefaultHandler(Boolean useDefaultStyle) { - List handlerList = new ArrayList(); + List handlerList = new ArrayList<>(); if (useDefaultStyle) { WriteCellStyle headWriteCellStyle = new WriteCellStyle(); headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); @@ -31,8 +41,10 @@ public class DefaultWriteHandlerLoader { headWriteFont.setFontHeightInPoints((short)14); headWriteFont.setBold(true); headWriteCellStyle.setWriteFont(headWriteFont); - handlerList.add(new HorizontalCellStyleStrategy(headWriteCellStyle, new ArrayList())); + handlerList.add(new HorizontalCellStyleStrategy(headWriteCellStyle, new ArrayList<>())); } + handlerList.addAll(DEFAULT_WRITE_HANDLER_LIST); + handlerList.add(new FillDataFormatCellWriteHandler()); return handlerList; } diff --git a/src/main/java/com/alibaba/excel/write/handler/RowWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/RowWriteHandler.java index 29ac10b0..e12d98f6 100644 --- a/src/main/java/com/alibaba/excel/write/handler/RowWriteHandler.java +++ b/src/main/java/com/alibaba/excel/write/handler/RowWriteHandler.java @@ -1,10 +1,10 @@ package com.alibaba.excel.write.handler; -import org.apache.poi.ss.usermodel.Row; - import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import org.apache.poi.ss.usermodel.Row; + /** * intercepts handle row creation * @@ -16,44 +16,35 @@ public interface RowWriteHandler extends WriteHandler { * Called before create the row * * @param writeSheetHolder - * @param writeTableHolder - * Nullable.It is null without using table writes. + * @param writeTableHolder Nullable.It is null without using table writes. * @param rowIndex - * @param relativeRowIndex - * Nullable.It is null in the case of fill data. - * @param isHead - * Nullable.It is null in the case of fill data. + * @param relativeRowIndex Nullable.It is null in the case of fill data. + * @param isHead Nullable.It is null in the case of fill data. */ - void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex, - Integer relativeRowIndex, Boolean isHead); + default void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex, + Integer relativeRowIndex, Boolean isHead) {} /** * Called after the row is created * * @param writeSheetHolder - * @param writeTableHolder - * Nullable.It is null without using table writes. + * @param writeTableHolder Nullable.It is null without using table writes. * @param row - * @param relativeRowIndex - * Nullable.It is null in the case of fill data. - * @param isHead - * Nullable.It is null in the case of fill data. + * @param relativeRowIndex Nullable.It is null in the case of fill data. + * @param isHead Nullable.It is null in the case of fill data. */ - void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, - Integer relativeRowIndex, Boolean isHead); + default void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Integer relativeRowIndex, Boolean isHead) {} /** * Called after all operations on the row have been completed.This method is not called when fill the data. * * @param writeSheetHolder - * @param writeTableHolder - * Nullable.It is null without using table writes. + * @param writeTableHolder Nullable.It is null without using table writes. * @param row - * @param relativeRowIndex - * Nullable.It is null in the case of fill data. - * @param isHead - * Nullable.It is null in the case of fill data. + * @param relativeRowIndex Nullable.It is null in the case of fill data. + * @param isHead Nullable.It is null in the case of fill data. */ - void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, - Integer relativeRowIndex, Boolean isHead); + default void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Integer relativeRowIndex, Boolean isHead) {} } diff --git a/src/main/java/com/alibaba/excel/write/handler/SheetWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/SheetWriteHandler.java index b97e1d15..5490fd39 100644 --- a/src/main/java/com/alibaba/excel/write/handler/SheetWriteHandler.java +++ b/src/main/java/com/alibaba/excel/write/handler/SheetWriteHandler.java @@ -16,7 +16,7 @@ public interface SheetWriteHandler extends WriteHandler { * @param writeWorkbookHolder * @param writeSheetHolder */ - void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder); + default void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {} /** * Called after the sheet is created @@ -24,5 +24,5 @@ public interface SheetWriteHandler extends WriteHandler { * @param writeWorkbookHolder * @param writeSheetHolder */ - void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder); + default void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {} } diff --git a/src/main/java/com/alibaba/excel/write/handler/WorkbookWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/WorkbookWriteHandler.java index 8dba9646..c3b758f5 100644 --- a/src/main/java/com/alibaba/excel/write/handler/WorkbookWriteHandler.java +++ b/src/main/java/com/alibaba/excel/write/handler/WorkbookWriteHandler.java @@ -12,19 +12,19 @@ public interface WorkbookWriteHandler extends WriteHandler { /** * Called before create the workbook */ - void beforeWorkbookCreate(); + default void beforeWorkbookCreate() {} /** * Called after the workbook is created * * @param writeWorkbookHolder */ - void afterWorkbookCreate(WriteWorkbookHolder writeWorkbookHolder); + default void afterWorkbookCreate(WriteWorkbookHolder writeWorkbookHolder) {} /** * Called after all operations on the workbook have been completed * * @param writeWorkbookHolder */ - void afterWorkbookDispose(WriteWorkbookHolder writeWorkbookHolder); + default void afterWorkbookDispose(WriteWorkbookHolder writeWorkbookHolder) {} } diff --git a/src/main/java/com/alibaba/excel/write/handler/impl/DefaultRowWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/impl/DefaultRowWriteHandler.java new file mode 100644 index 00000000..36f5ed09 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/handler/impl/DefaultRowWriteHandler.java @@ -0,0 +1,22 @@ +package com.alibaba.excel.write.handler.impl; + +import com.alibaba.excel.write.handler.RowWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; + +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Row; + +/** + * Default row handler. + * + * @author Jiaju Zhuang + */ +@Slf4j +public class DefaultRowWriteHandler implements RowWriteHandler { + @Override + public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Integer relativeRowIndex, Boolean isHead) { + writeSheetHolder.setLastRowIndex(row.getRowNum()); + } +} diff --git a/src/main/java/com/alibaba/excel/write/handler/impl/DimensionWorkbookWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/impl/DimensionWorkbookWriteHandler.java new file mode 100644 index 00000000..6b444a47 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/handler/impl/DimensionWorkbookWriteHandler.java @@ -0,0 +1,81 @@ +package com.alibaba.excel.write.handler.impl; + +import java.lang.reflect.Field; +import java.util.Map; + +import com.alibaba.excel.util.FieldUtils; +import com.alibaba.excel.write.handler.WorkbookWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.MapUtils; +import org.apache.poi.ss.util.CellReference; +import org.apache.poi.xssf.streaming.SXSSFSheet; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet; + +/** + * Handle the problem of unable to write dimension. + * + * https://github.com/alibaba/easyexcel/issues/1282 + * + * @author Jiaju Zhuang + */ +@Slf4j +public class DimensionWorkbookWriteHandler implements WorkbookWriteHandler { + + private static final String XSSF_SHEET_MEMBER_VARIABLE_NAME = "_sh"; + private static final Field XSSF_SHEET_FIELD = FieldUtils.getField(SXSSFSheet.class, XSSF_SHEET_MEMBER_VARIABLE_NAME, + true); + + @Override + public void afterWorkbookDispose(WriteWorkbookHolder writeWorkbookHolder) { + if (writeWorkbookHolder == null || writeWorkbookHolder.getWorkbook() == null) { + return; + } + if (!(writeWorkbookHolder.getWorkbook() instanceof SXSSFWorkbook)) { + return; + } + + Map writeSheetHolderMap = writeWorkbookHolder.getHasBeenInitializedSheetIndexMap(); + if (MapUtils.isEmpty(writeSheetHolderMap)) { + return; + } + for (WriteSheetHolder writeSheetHolder : writeSheetHolderMap.values()) { + if (writeSheetHolder.getSheet() == null || !(writeSheetHolder.getSheet() instanceof SXSSFSheet)) { + continue; + } + SXSSFSheet sxssfSheet = ((SXSSFSheet)writeSheetHolder.getSheet()); + XSSFSheet xssfSheet; + try { + xssfSheet = (XSSFSheet)XSSF_SHEET_FIELD.get(sxssfSheet); + } catch (IllegalAccessException e) { + log.debug("Can not found _sh.", e); + continue; + } + if (xssfSheet == null) { + continue; + } + CTWorksheet ctWorksheet = xssfSheet.getCTWorksheet(); + if (ctWorksheet == null) { + continue; + } + int headSize = 0; + if (MapUtils.isNotEmpty(writeSheetHolder.getExcelWriteHeadProperty().getHeadMap())) { + headSize = writeSheetHolder.getExcelWriteHeadProperty().getHeadMap().size(); + if (headSize > 0) { + headSize--; + } + } + Integer lastRowIndex = writeSheetHolder.getLastRowIndex(); + if (lastRowIndex == null) { + lastRowIndex = 0; + } + + ctWorksheet.getDimension().setRef( + "A1:" + CellReference.convertNumToColString(headSize) + (lastRowIndex + 1)); + } + } +} diff --git a/src/main/java/com/alibaba/excel/write/handler/impl/FillDataFormatCellWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/impl/FillDataFormatCellWriteHandler.java new file mode 100644 index 00000000..a465546b --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/handler/impl/FillDataFormatCellWriteHandler.java @@ -0,0 +1,76 @@ +package com.alibaba.excel.write.handler.impl; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.alibaba.excel.constant.OrderConstant; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.event.Order; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.util.DateUtils; +import com.alibaba.excel.util.StyleUtil; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.DataFormat; +import org.apache.poi.ss.usermodel.Workbook; + +/** + * fill cell style. + * + * @author Jiaju Zhuang + */ +@Slf4j +public class FillDataFormatCellWriteHandler implements CellWriteHandler, Order { + + private final Set cellStyleSet = new HashSet<>(); + + private CellStyle defaultDateCellStyle; + + @Override + public int order() { + return OrderConstant.FILL_DATA_FORMAT; + } + + @Override + public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + if (CollectionUtils.isEmpty(cellDataList) || cellDataList.size() > 1) { + return; + } + CellData cellData = cellDataList.get(0); + CellStyle cellStyle = cell.getCellStyle(); + if (cellStyle == null || StyleUtil.isDefaultStyle(cellStyle)) { + if (cellData.getType() == CellDataTypeEnum.DATE) { + cell.setCellStyle(getDefaultDateCellStyle(writeSheetHolder)); + } + return; + } + if (cellStyleSet.contains(cellStyle)) { + return; + } + if (cellData.getDataFormat() != null && cellData.getDataFormat() >= 0) { + cellStyle.setDataFormat(cellData.getDataFormat()); + } + cellStyleSet.add(cellStyle); + } + + private CellStyle getDefaultDateCellStyle(WriteSheetHolder writeSheetHolder) { + if (defaultDateCellStyle != null) { + return defaultDateCellStyle; + } + Workbook workbook = writeSheetHolder.getParentWriteWorkbookHolder().getWorkbook(); + defaultDateCellStyle = workbook.createCellStyle(); + DataFormat dataFormat = workbook.createDataFormat(); + defaultDateCellStyle.setDataFormat(dataFormat.getFormat(DateUtils.defaultDateFormat)); + return defaultDateCellStyle; + } + +} diff --git a/src/main/java/com/alibaba/excel/write/merge/AbstractMergeStrategy.java b/src/main/java/com/alibaba/excel/write/merge/AbstractMergeStrategy.java new file mode 100644 index 00000000..7b3d4b2b --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/merge/AbstractMergeStrategy.java @@ -0,0 +1,39 @@ +package com.alibaba.excel.write.merge; + +import java.util.List; + +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Sheet; + +/** + * Merge strategy + * + * @author Jiaju Zhuang + */ +public abstract class AbstractMergeStrategy implements CellWriteHandler { + + @Override + public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + if (isHead) { + return; + } + merge(writeSheetHolder.getSheet(), cell, head, relativeRowIndex); + } + + /** + * merge + * + * @param sheet + * @param cell + * @param head + * @param relativeRowIndex + */ + protected abstract void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex); +} diff --git a/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java b/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java index 5796dde5..13ebe3cb 100644 --- a/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java +++ b/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java @@ -5,6 +5,7 @@ import org.apache.poi.ss.util.CellRangeAddress; import com.alibaba.excel.metadata.property.LoopMergeProperty; import com.alibaba.excel.write.handler.AbstractRowWriteHandler; +import com.alibaba.excel.write.handler.RowWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; @@ -13,7 +14,7 @@ import com.alibaba.excel.write.metadata.holder.WriteTableHolder; * * @author Jiaju Zhuang */ -public class LoopMergeStrategy extends AbstractRowWriteHandler { +public class LoopMergeStrategy implements RowWriteHandler { /** * Each row */ diff --git a/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java b/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java index d85781e1..0fe3dd61 100644 --- a/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java +++ b/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java @@ -4,6 +4,7 @@ import org.apache.poi.ss.util.CellRangeAddress; import com.alibaba.excel.metadata.property.OnceAbsoluteMergeProperty; import com.alibaba.excel.write.handler.AbstractSheetWriteHandler; +import com.alibaba.excel.write.handler.SheetWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; @@ -12,7 +13,7 @@ import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; * * @author Jiaju Zhuang */ -public class OnceAbsoluteMergeStrategy extends AbstractSheetWriteHandler { +public class OnceAbsoluteMergeStrategy implements SheetWriteHandler { /** * First row */ diff --git a/src/main/java/com/alibaba/excel/write/metadata/CollectionRowData.java b/src/main/java/com/alibaba/excel/write/metadata/CollectionRowData.java new file mode 100644 index 00000000..bf98f5c5 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/CollectionRowData.java @@ -0,0 +1,32 @@ +package com.alibaba.excel.write.metadata; + +import java.util.Collection; + +/** + * A collection row of data. + * + * @author Jiaju Zhuang + */ +public class CollectionRowData implements RowData { + + private final Object[] array; + + public CollectionRowData(Collection collection) { + this.array = collection.toArray(); + } + + @Override + public Object get(int index) { + return array[index]; + } + + @Override + public int size() { + return array.length; + } + + @Override + public boolean isEmpty() { + return array.length == 0; + } +} diff --git a/src/main/java/com/alibaba/excel/write/metadata/MapRowData.java b/src/main/java/com/alibaba/excel/write/metadata/MapRowData.java new file mode 100644 index 00000000..409fc58d --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/MapRowData.java @@ -0,0 +1,33 @@ +package com.alibaba.excel.write.metadata; + +import java.util.Map; + +/** + * A map row of data. + * + * @author Jiaju Zhuang + */ +public class MapRowData implements RowData { + + private final Map map; + + public MapRowData(Map map) { + this.map = map; + } + + @Override + public Object get(int index) { + return map.get(index); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + +} diff --git a/src/main/java/com/alibaba/excel/write/metadata/RowData.java b/src/main/java/com/alibaba/excel/write/metadata/RowData.java new file mode 100644 index 00000000..937395b9 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/RowData.java @@ -0,0 +1,31 @@ +package com.alibaba.excel.write.metadata; + +/** + * A row of data. + * + * @author Jiaju Zhuang + */ +public interface RowData { + /** + * Returns the value to which the specified key is mapped, + * or {@code null} if this map contains no mapping for the key. + */ + Object get(int index); + + /** + * Returns the number of elements in this collection. If this collection + * contains more than Integer.MAX_VALUE elements, returns + * Integer.MAX_VALUE. + * + * @return the number of elements in this collection + */ + int size(); + + /** + * Returns true if this collection contains no elements. + * + * @return true if this collection contains no elements + */ + boolean isEmpty(); + +} 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 aa7cbc35..e7132481 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 @@ -9,6 +9,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; +import org.apache.commons.collections4.CollectionUtils; import org.apache.poi.ss.usermodel.FillPatternType; import org.apache.poi.ss.usermodel.IndexedColors; @@ -25,7 +26,6 @@ import com.alibaba.excel.metadata.TableStyle; import com.alibaba.excel.metadata.property.LoopMergeProperty; import com.alibaba.excel.metadata.property.OnceAbsoluteMergeProperty; import com.alibaba.excel.metadata.property.RowHeightProperty; -import com.alibaba.excel.util.CollectionUtils; import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.handler.DefaultWriteHandlerLoader; import com.alibaba.excel.write.handler.RowWriteHandler; @@ -64,9 +64,14 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ */ private ExcelWriteHeadProperty excelWriteHeadProperty; /** - * Write handler for workbook + * Write handler */ private Map, List> writeHandlerMap; + /** + * Own write handler.Created in the sheet in the workbook interceptors will not be executed because the workbook to + * create an event long past. So when initializing sheet, supplementary workbook event. + */ + private Map, List> ownWriteHandlerMap; /** * Use the default style.Default is true. */ @@ -106,6 +111,10 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ getGlobalConfiguration().setUse1904windowing(writeBasicParameter.getUse1904windowing()); } + if (writeBasicParameter.getUseScientificFormat() != null) { + throw new UnsupportedOperationException("Currently does not support setting useScientificFormat."); + } + if (writeBasicParameter.getNeedHead() == null) { if (parentAbstractWriteHolder == null) { this.needHead = Boolean.TRUE; @@ -177,27 +186,28 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ List handlerList = new ArrayList(); // Initialization Annotation - initAnnotationConfig(handlerList); + initAnnotationConfig(handlerList, writeBasicParameter); if (writeBasicParameter.getCustomWriteHandlerList() != null && !writeBasicParameter.getCustomWriteHandlerList().isEmpty()) { handlerList.addAll(writeBasicParameter.getCustomWriteHandlerList()); } + this.ownWriteHandlerMap = sortAndClearUpHandler(handlerList); + Map, List> parentWriteHandlerMap = null; if (parentAbstractWriteHolder != null) { parentWriteHandlerMap = parentAbstractWriteHolder.getWriteHandlerMap(); } else { handlerList.addAll(DefaultWriteHandlerLoader.loadDefaultHandler(useDefaultStyle)); } - - this.writeHandlerMap = sortAndClearUpHandler(handlerList, parentWriteHandlerMap); + this.writeHandlerMap = sortAndClearUpAllHandler(handlerList, parentWriteHandlerMap); // Set converterMap if (parentAbstractWriteHolder == null) { setConverterMap(DefaultConverterLoader.loadDefaultWriteConverter()); } else { - setConverterMap(new HashMap(parentAbstractWriteHolder.getConverterMap())); + setConverterMap(new HashMap<>(parentAbstractWriteHolder.getConverterMap())); } if (writeBasicParameter.getCustomConverterList() != null && !writeBasicParameter.getCustomConverterList().isEmpty()) { @@ -215,13 +225,13 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ switch (holderType()) { case SHEET: compatibleOldCodeCreateRowCellStyleStrategy(writeBasicParameter, - ((WriteSheet)writeBasicParameter).getTableStyle()); + ((WriteSheet) writeBasicParameter).getTableStyle()); compatibleOldCodeCreateHeadColumnWidthStyleStrategy(writeBasicParameter, - ((WriteSheet)writeBasicParameter).getColumnWidthMap()); + ((WriteSheet) writeBasicParameter).getColumnWidthMap()); return; case TABLE: compatibleOldCodeCreateRowCellStyleStrategy(writeBasicParameter, - ((WriteTable)writeBasicParameter).getTableStyle()); + ((WriteTable) writeBasicParameter).getTableStyle()); return; default: } @@ -279,10 +289,13 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ }); } - protected void initAnnotationConfig(List handlerList) { + protected void initAnnotationConfig(List handlerList, WriteBasicParameter writeBasicParameter) { if (!HeadKindEnum.CLASS.equals(getExcelWriteHeadProperty().getHeadKind())) { return; } + if (writeBasicParameter.getClazz() == null) { + return; + } Map headMap = getExcelWriteHeadProperty().getHeadMap(); boolean hasColumnWidth = false; boolean hasStyle = false; @@ -308,7 +321,6 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ dealRowHigh(handlerList); dealOnceAbsoluteMerge(handlerList); - } private void dealStyle(List handlerList) { @@ -376,9 +388,9 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ handlerList.add(columnWidthStyleStrategy); } - protected Map, List> sortAndClearUpHandler( - List handlerList, Map, List> parentHandlerMap) { + protected Map, List> sortAndClearUpAllHandler( + List handlerList, Map, List> parentHandlerMap) { // add if (parentHandlerMap != null) { List parentWriteHandler = parentHandlerMap.get(WriteHandler.class); @@ -386,13 +398,17 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ handlerList.addAll(parentWriteHandler); } } + return sortAndClearUpHandler(handlerList); + } + protected Map, List> sortAndClearUpHandler( + List handlerList) { // sort Map> orderExcelWriteHandlerMap = new TreeMap>(); for (WriteHandler handler : handlerList) { int order = Integer.MIN_VALUE; if (handler instanceof Order) { - order = ((Order)handler).order(); + order = ((Order) handler).order(); } if (orderExcelWriteHandlerMap.containsKey(order)) { orderExcelWriteHandlerMap.get(order).add(handler); @@ -408,7 +424,7 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ for (Map.Entry> entry : orderExcelWriteHandlerMap.entrySet()) { for (WriteHandler handler : entry.getValue()) { if (handler instanceof NotRepeatExecutor) { - String uniqueValue = ((NotRepeatExecutor)handler).uniqueValue(); + String uniqueValue = ((NotRepeatExecutor) handler).uniqueValue(); if (alreadyExistedHandlerSet.contains(uniqueValue)) { continue; } @@ -480,6 +496,15 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ this.writeHandlerMap = writeHandlerMap; } + public Map, List> getOwnWriteHandlerMap() { + return ownWriteHandlerMap; + } + + public void setOwnWriteHandlerMap( + Map, List> ownWriteHandlerMap) { + this.ownWriteHandlerMap = ownWriteHandlerMap; + } + public ExcelWriteHeadProperty getExcelWriteHeadProperty() { return excelWriteHeadProperty; } @@ -554,6 +579,11 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ return getWriteHandlerMap(); } + @Override + public Map, List> ownWriteHandlerMap() { + return getOwnWriteHandlerMap(); + } + @Override public boolean needHead() { return getNeedHead(); diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java index 2aa20665..4896b034 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java @@ -28,6 +28,13 @@ public interface WriteHolder extends ConfigurationHolder { */ Map, List> writeHandlerMap(); + /** + * create your own write handler. + * + * @return + */ + Map, List> ownWriteHandlerMap(); + /** * Is to determine if a field needs to be ignored * diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java index 56fc7e4e..afae52b8 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java @@ -3,21 +3,25 @@ package com.alibaba.excel.write.metadata.holder; import java.util.HashMap; import java.util.Map; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.xssf.streaming.SXSSFSheet; -import org.apache.poi.xssf.usermodel.XSSFSheet; - import com.alibaba.excel.enums.HolderEnum; import com.alibaba.excel.enums.WriteLastRowTypeEnum; import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.write.metadata.WriteSheet; +import lombok.Getter; +import lombok.Setter; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.xssf.streaming.SXSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFSheet; + /** * sheet holder * * @author Jiaju Zhuang */ +@Getter +@Setter public class WriteSheetHolder extends AbstractWriteHolder { /** * current param @@ -65,6 +69,11 @@ public class WriteSheetHolder extends AbstractWriteHolder { */ private WriteLastRowTypeEnum writeLastRowTypeEnum; + /** + * last row index + */ + private Integer lastRowIndex; + public WriteSheetHolder(WriteSheet writeSheet, WriteWorkbookHolder writeWorkbookHolder) { super(writeSheet, writeWorkbookHolder, writeWorkbookHolder.getWriteWorkbook().getConvertAllFiled()); this.writeSheet = writeSheet; @@ -75,76 +84,13 @@ public class WriteSheetHolder extends AbstractWriteHolder { } this.sheetName = writeSheet.getSheetName(); this.parentWriteWorkbookHolder = writeWorkbookHolder; - this.hasBeenInitializedTable = new HashMap(); + this.hasBeenInitializedTable = new HashMap<>(); if (writeWorkbookHolder.getTempTemplateInputStream() != null) { writeLastRowTypeEnum = WriteLastRowTypeEnum.TEMPLATE_EMPTY; } else { writeLastRowTypeEnum = WriteLastRowTypeEnum.COMMON_EMPTY; } - } - - public WriteSheet getWriteSheet() { - return writeSheet; - } - - public void setWriteSheet(WriteSheet writeSheet) { - this.writeSheet = writeSheet; - } - - public Sheet getSheet() { - return sheet; - } - - public void setSheet(Sheet sheet) { - this.sheet = sheet; - } - - public Integer getSheetNo() { - return sheetNo; - } - - public Sheet getCachedSheet() { - return cachedSheet; - } - - public void setCachedSheet(Sheet cachedSheet) { - this.cachedSheet = cachedSheet; - } - - public void setSheetNo(Integer sheetNo) { - this.sheetNo = sheetNo; - } - - public String getSheetName() { - return sheetName; - } - - public void setSheetName(String sheetName) { - this.sheetName = sheetName; - } - - public WriteWorkbookHolder getParentWriteWorkbookHolder() { - return parentWriteWorkbookHolder; - } - - public void setParentWriteWorkbookHolder(WriteWorkbookHolder parentWriteWorkbookHolder) { - this.parentWriteWorkbookHolder = parentWriteWorkbookHolder; - } - - public Map getHasBeenInitializedTable() { - return hasBeenInitializedTable; - } - - public void setHasBeenInitializedTable(Map hasBeenInitializedTable) { - this.hasBeenInitializedTable = hasBeenInitializedTable; - } - - public WriteLastRowTypeEnum getWriteLastRowTypeEnum() { - return writeLastRowTypeEnum; - } - - public void setWriteLastRowTypeEnum(WriteLastRowTypeEnum writeLastRowTypeEnum) { - this.writeLastRowTypeEnum = writeLastRowTypeEnum; + lastRowIndex = 0; } /** diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java index be557ebd..19e4622b 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java @@ -10,23 +10,31 @@ import java.io.OutputStream; import java.util.HashMap; import java.util.Map; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.xssf.streaming.SXSSFWorkbook; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; - +import com.alibaba.excel.constant.BuiltinFormats; import com.alibaba.excel.enums.HolderEnum; import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.util.FileUtils; import com.alibaba.excel.util.IoUtils; +import com.alibaba.excel.util.MapUtils; +import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.write.metadata.WriteWorkbook; +import lombok.Getter; +import lombok.Setter; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.DataFormat; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + /** * Workbook holder * * @author Jiaju Zhuang */ +@Getter +@Setter public class WriteWorkbookHolder extends AbstractWriteHolder { /*** * Current poi Workbook.This is only for writing, and there may be no data in version 07 when template data needs to @@ -111,6 +119,10 @@ public class WriteWorkbookHolder extends AbstractWriteHolder { * Excel is also written in the event of an exception being thrown.The default false. */ private Boolean writeExcelOnException; + /** + * Used to cache data Format. + */ + private Map dataFormatCache; public WriteWorkbookHolder(WriteWorkbook writeWorkbook) { super(writeWorkbook, null, writeWorkbook.getConvertAllFiled()); @@ -138,7 +150,7 @@ public class WriteWorkbookHolder extends AbstractWriteHolder { if (writeWorkbook.getExcelType() == null) { boolean isXls = (file != null && file.getName().endsWith(ExcelTypeEnum.XLS.getValue())) || (writeWorkbook.getTemplateFile() != null - && writeWorkbook.getTemplateFile().getName().endsWith(ExcelTypeEnum.XLS.getValue())); + && writeWorkbook.getTemplateFile().getName().endsWith(ExcelTypeEnum.XLS.getValue())); if (isXls) { this.excelType = ExcelTypeEnum.XLS; } else { @@ -165,6 +177,7 @@ public class WriteWorkbookHolder extends AbstractWriteHolder { } else { this.writeExcelOnException = writeWorkbook.getWriteExcelOnException(); } + this.dataFormatCache = MapUtils.newHashMap(); } private void copyTemplate() throws IOException { @@ -186,136 +199,29 @@ public class WriteWorkbookHolder extends AbstractWriteHolder { this.tempTemplateInputStream = new ByteArrayInputStream(templateFileByte); } - public Workbook getWorkbook() { - return workbook; - } - - public void setWorkbook(Workbook workbook) { - this.workbook = workbook; - } - - public Workbook getCachedWorkbook() { - return cachedWorkbook; - } - - public void setCachedWorkbook(Workbook cachedWorkbook) { - this.cachedWorkbook = cachedWorkbook; - } - - public Map getHasBeenInitializedSheetIndexMap() { - return hasBeenInitializedSheetIndexMap; - } - - public void setHasBeenInitializedSheetIndexMap(Map hasBeenInitializedSheetIndexMap) { - this.hasBeenInitializedSheetIndexMap = hasBeenInitializedSheetIndexMap; - } - - public Map getHasBeenInitializedSheetNameMap() { - return hasBeenInitializedSheetNameMap; - } - - public void setHasBeenInitializedSheetNameMap(Map hasBeenInitializedSheetNameMap) { - this.hasBeenInitializedSheetNameMap = hasBeenInitializedSheetNameMap; - } - - public WriteWorkbook getWriteWorkbook() { - return writeWorkbook; - } - - public void setWriteWorkbook(WriteWorkbook writeWorkbook) { - this.writeWorkbook = writeWorkbook; - } - - public File getFile() { - return file; - } - - public void setFile(File file) { - this.file = file; - } - - public OutputStream getOutputStream() { - return outputStream; - } - - public void setOutputStream(OutputStream outputStream) { - this.outputStream = outputStream; - } - - public InputStream getTemplateInputStream() { - return templateInputStream; - } - - public void setTemplateInputStream(InputStream templateInputStream) { - this.templateInputStream = templateInputStream; - } - - public InputStream getTempTemplateInputStream() { - return tempTemplateInputStream; - } - - public void setTempTemplateInputStream(InputStream tempTemplateInputStream) { - this.tempTemplateInputStream = tempTemplateInputStream; - } - - public File getTemplateFile() { - return templateFile; - } - - public void setTemplateFile(File templateFile) { - this.templateFile = templateFile; - } - - public Boolean getAutoCloseStream() { - return autoCloseStream; - } - - public void setAutoCloseStream(Boolean autoCloseStream) { - this.autoCloseStream = autoCloseStream; - } - - public ExcelTypeEnum getExcelType() { - return excelType; - } - - public void setExcelType(ExcelTypeEnum excelType) { - this.excelType = excelType; - } - - public Boolean getMandatoryUseInputStream() { - return mandatoryUseInputStream; - } - - public void setMandatoryUseInputStream(Boolean mandatoryUseInputStream) { - this.mandatoryUseInputStream = mandatoryUseInputStream; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public Boolean getInMemory() { - return inMemory; - } - - public void setInMemory(Boolean inMemory) { - this.inMemory = inMemory; - } - - public Boolean getWriteExcelOnException() { - return writeExcelOnException; - } - - public void setWriteExcelOnException(Boolean writeExcelOnException) { - this.writeExcelOnException = writeExcelOnException; - } - @Override public HolderEnum holderType() { return HolderEnum.WORKBOOK; } + + /** + * Get a data format. + * + * @param format + * @return + */ + public Short getDataFormat(String format) { + if (StringUtils.isEmpty(format)) { + return BuiltinFormats.GENERAL; + } + Short dataFormat = dataFormatCache.get(format); + if (dataFormat != null) { + return dataFormat; + } + DataFormat dataFormatCreate = workbook.createDataFormat(); + dataFormat = dataFormatCreate.getFormat(format); + dataFormatCache.put(format,dataFormat); + return dataFormat; + } + } diff --git a/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java b/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java index 8fe03497..26af5512 100644 --- a/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java +++ b/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java @@ -39,6 +39,7 @@ import com.alibaba.excel.metadata.property.StyleProperty; * @author jipengfei */ public class ExcelWriteHeadProperty extends ExcelHeadProperty { + private RowHeightProperty headRowHeightProperty; private RowHeightProperty contentRowHeightProperty; private OnceAbsoluteMergeProperty onceAbsoluteMergeProperty; @@ -49,21 +50,25 @@ public class ExcelWriteHeadProperty extends ExcelHeadProperty { return; } this.headRowHeightProperty = - RowHeightProperty.build((HeadRowHeight)headClazz.getAnnotation(HeadRowHeight.class)); + RowHeightProperty.build((HeadRowHeight) headClazz.getAnnotation(HeadRowHeight.class)); this.contentRowHeightProperty = - RowHeightProperty.build((ContentRowHeight)headClazz.getAnnotation(ContentRowHeight.class)); + RowHeightProperty.build((ContentRowHeight) headClazz.getAnnotation(ContentRowHeight.class)); this.onceAbsoluteMergeProperty = - OnceAbsoluteMergeProperty.build((OnceAbsoluteMerge)headClazz.getAnnotation(OnceAbsoluteMerge.class)); + OnceAbsoluteMergeProperty.build((OnceAbsoluteMerge) headClazz.getAnnotation(OnceAbsoluteMerge.class)); - ColumnWidth parentColumnWidth = (ColumnWidth)headClazz.getAnnotation(ColumnWidth.class); - HeadStyle parentHeadStyle = (HeadStyle)headClazz.getAnnotation(HeadStyle.class); - HeadFontStyle parentHeadFontStyle = (HeadFontStyle)headClazz.getAnnotation(HeadFontStyle.class); - ContentStyle parentContentStyle = (ContentStyle)headClazz.getAnnotation(ContentStyle.class); - ContentFontStyle parentContentFontStyle = (ContentFontStyle)headClazz.getAnnotation(ContentFontStyle.class); + ColumnWidth parentColumnWidth = (ColumnWidth) headClazz.getAnnotation(ColumnWidth.class); + HeadStyle parentHeadStyle = (HeadStyle) headClazz.getAnnotation(HeadStyle.class); + HeadFontStyle parentHeadFontStyle = (HeadFontStyle) headClazz.getAnnotation(HeadFontStyle.class); + ContentStyle parentContentStyle = (ContentStyle) headClazz.getAnnotation(ContentStyle.class); + ContentFontStyle parentContentFontStyle = (ContentFontStyle) headClazz.getAnnotation(ContentFontStyle.class); for (Map.Entry entry : getContentPropertyMap().entrySet()) { Integer index = entry.getKey(); ExcelContentProperty excelContentPropertyData = entry.getValue(); + if (excelContentPropertyData == null) { + throw new IllegalArgumentException( + "Passing in the class and list the head, the two must be the same size."); + } Field field = excelContentPropertyData.getField(); Head headData = getHeadMap().get(index); ColumnWidth columnWidth = field.getAnnotation(ColumnWidth.class); @@ -97,14 +102,6 @@ public class ExcelWriteHeadProperty extends ExcelHeadProperty { headData.setContentFontProperty(FontProperty.build(contentFontStyle)); headData.setLoopMergeProperty(LoopMergeProperty.build(field.getAnnotation(ContentLoopMerge.class))); - // If have @NumberFormat, 'NumberStringConverter' is specified by default - if (excelContentPropertyData.getConverter() == null) { - NumberFormat numberFormat = field.getAnnotation(NumberFormat.class); - if (numberFormat != null) { - excelContentPropertyData.setConverter(DefaultConverterLoader.loadAllConverter() - .get(ConverterKeyBuild.buildKey(field.getType(), CellDataTypeEnum.STRING))); - } - } } } @@ -176,7 +173,8 @@ public class ExcelWriteHeadProperty extends ExcelHeadProperty { if (j == lastRow && i == lastCol) { continue; } - cellRangeList.add(new CellRange(j, lastRow, i, lastCol)); + cellRangeList + .add(new CellRange(j, lastRow, head.getColumnIndex(), headList.get(lastCol).getColumnIndex())); } } return cellRangeList; diff --git a/src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java index 4790ab11..f131c456 100644 --- a/src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java +++ b/src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java @@ -2,25 +2,25 @@ package com.alibaba.excel.write.style; import java.util.List; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Workbook; - import com.alibaba.excel.event.NotRepeatExecutor; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.write.handler.CellWriteHandler; -import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.handler.WorkbookWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Workbook; + /** * Cell style strategy * * @author Jiaju Zhuang */ -public abstract class AbstractCellStyleStrategy implements CellWriteHandler, SheetWriteHandler, NotRepeatExecutor { +public abstract class AbstractCellStyleStrategy implements CellWriteHandler, WorkbookWriteHandler, NotRepeatExecutor { + boolean hasInitialized = false; @Override @@ -28,44 +28,21 @@ public abstract class AbstractCellStyleStrategy implements CellWriteHandler, She return "CellStyleStrategy"; } - @Override - public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, - Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) { - - } - - @Override - public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, - Head head, Integer relativeRowIndex, Boolean isHead) { - - } - - @Override - public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, - CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { - - } - @Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, - List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { - if (isHead == null || head == null) { + List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + if (isHead == null) { return; } if (isHead) { - setHeadCellStyle(cell, head, relativeRowIndex); + setHeadCellStyle(writeSheetHolder, writeTableHolder, cell, head, relativeRowIndex); } else { - setContentCellStyle(cell, head, relativeRowIndex); + setContentCellStyle(writeSheetHolder, writeTableHolder, cell, head, relativeRowIndex); } } @Override - public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { - - } - - @Override - public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + public void afterWorkbookCreate(WriteWorkbookHolder writeWorkbookHolder) { initCellStyle(writeWorkbookHolder.getWorkbook()); hasInitialized = true; } @@ -80,11 +57,27 @@ public abstract class AbstractCellStyleStrategy implements CellWriteHandler, She /** * Sets the cell style of header * + * @param writeSheetHolder + * @param writeTableHolder * @param cell * @param head * @param relativeRowIndex */ - protected abstract void setHeadCellStyle(Cell cell, Head head, Integer relativeRowIndex); + protected void setHeadCellStyle(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + Cell cell, Head head, Integer relativeRowIndex) { + setHeadCellStyle(cell, head, relativeRowIndex); + } + + /** + * Sets the cell style of header + * + * @param cell + * @param head + * @param relativeRowIndex + */ + protected void setHeadCellStyle(Cell cell, Head head, Integer relativeRowIndex) { + throw new UnsupportedOperationException("Custom styles must override the setHeadCellStyle method."); + } /** * Sets the cell style of content @@ -93,6 +86,20 @@ public abstract class AbstractCellStyleStrategy implements CellWriteHandler, She * @param head * @param relativeRowIndex */ - protected abstract void setContentCellStyle(Cell cell, Head head, Integer relativeRowIndex); + protected void setContentCellStyle(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + Cell cell, Head head, Integer relativeRowIndex) { + setContentCellStyle(cell, head, relativeRowIndex); + } + + /** + * Sets the cell style of content + * + * @param cell + * @param head + * @param relativeRowIndex + */ + protected void setContentCellStyle(Cell cell, Head head, Integer relativeRowIndex) { + throw new UnsupportedOperationException("Custom styles must override the setContentCellStyle method."); + } } diff --git a/src/main/java/com/alibaba/excel/write/style/AbstractVerticalCellStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/AbstractVerticalCellStyleStrategy.java index 09903a00..4ae5ac6a 100644 --- a/src/main/java/com/alibaba/excel/write/style/AbstractVerticalCellStyleStrategy.java +++ b/src/main/java/com/alibaba/excel/write/style/AbstractVerticalCellStyleStrategy.java @@ -1,18 +1,19 @@ package com.alibaba.excel.write.style; -import java.util.HashMap; import java.util.Map; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.Workbook; - import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.util.MapUtils; import com.alibaba.excel.util.StyleUtil; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Workbook; + /** - * * Use the same style for the column * * @author Jiaju Zhuang @@ -20,8 +21,8 @@ import com.alibaba.excel.write.metadata.style.WriteCellStyle; public abstract class AbstractVerticalCellStyleStrategy extends AbstractCellStyleStrategy { private Workbook workbook; - private Map headCellStyleCache = new HashMap(); - private Map contentCellStyleCache = new HashMap(); + private final Map>> headCellStyleCache = MapUtils.newHashMap(); + private final Map>> contentCellStyleCache = MapUtils.newHashMap(); @Override protected void initCellStyle(Workbook workbook) { @@ -29,10 +30,16 @@ public abstract class AbstractVerticalCellStyleStrategy extends AbstractCellStyl } @Override - protected void setHeadCellStyle(Cell cell, Head head, Integer relativeRowIndex) { + protected void setHeadCellStyle(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, + Head head, Integer relativeRowIndex) { + if (head == null) { + return; + } + Map styleMap = getStyleMap(headCellStyleCache, writeSheetHolder, writeTableHolder); + int columnIndex = head.getColumnIndex(); - if (headCellStyleCache.containsKey(columnIndex)) { - CellStyle cellStyle = headCellStyleCache.get(columnIndex); + if (styleMap.containsKey(columnIndex)) { + CellStyle cellStyle = styleMap.get(columnIndex); if (cellStyle != null) { cell.setCellStyle(cellStyle); } @@ -40,39 +47,56 @@ public abstract class AbstractVerticalCellStyleStrategy extends AbstractCellStyl } WriteCellStyle headCellStyle = headCellStyle(head); if (headCellStyle == null) { - headCellStyleCache.put(columnIndex, null); + styleMap.put(columnIndex, StyleUtil.buildHeadCellStyle(workbook, null)); } else { CellStyle cellStyle = StyleUtil.buildHeadCellStyle(workbook, headCellStyle); - headCellStyleCache.put(columnIndex, cellStyle); + styleMap.put(columnIndex, cellStyle); cell.setCellStyle(cellStyle); } } @Override - protected void setContentCellStyle(Cell cell, Head head, Integer relativeRowIndex) { + protected void setContentCellStyle(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, + Head head, Integer relativeRowIndex) { + if (head == null) { + return; + } + Map styleMap = getStyleMap(contentCellStyleCache, writeSheetHolder, writeTableHolder); + int columnIndex = head.getColumnIndex(); - if (contentCellStyleCache.containsKey(columnIndex)) { - CellStyle cellStyle = contentCellStyleCache.get(columnIndex); + if (styleMap.containsKey(columnIndex)) { + CellStyle cellStyle = styleMap.get(columnIndex); if (cellStyle != null) { cell.setCellStyle(cellStyle); } return; } - WriteCellStyle contentCellStyle = contentCellStyle(head); + WriteCellStyle contentCellStyle = contentCellStyle(cell, head, relativeRowIndex); if (contentCellStyle == null) { - contentCellStyleCache.put(columnIndex, null); + styleMap.put(columnIndex, StyleUtil.buildContentCellStyle(workbook, null)); } else { CellStyle cellStyle = StyleUtil.buildContentCellStyle(workbook, contentCellStyle); - contentCellStyleCache.put(columnIndex, cellStyle); + styleMap.put(columnIndex, cellStyle); cell.setCellStyle(cellStyle); } } /** - * Returns the column width corresponding to each column head + * Returns the column width corresponding to each column head. * + * @param cell * @param head - * Nullable + * @param relativeRowIndex + * @return + */ + protected WriteCellStyle contentCellStyle(Cell cell, Head head, Integer relativeRowIndex) { + return contentCellStyle(head); + } + + /** + * Returns the column width corresponding to each column head + * + * @param head Nullable * @return */ protected abstract WriteCellStyle headCellStyle(Head head); @@ -80,10 +104,24 @@ public abstract class AbstractVerticalCellStyleStrategy extends AbstractCellStyl /** * Returns the column width corresponding to each column head * - * @param head - * Nullable + * @param head Nullable * @return */ - protected abstract WriteCellStyle contentCellStyle(Head head); + protected WriteCellStyle contentCellStyle(Head head) { + throw new UnsupportedOperationException( + "One of the two methods 'contentCellStyle(Cell cell, Head head, Integer relativeRowIndex)' and " + + "'contentCellStyle(Head head)' must be implemented."); + } + + private Map getStyleMap(Map>> cellStyleCache, + WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder) { + Map> tableStyleMap = cellStyleCache.computeIfAbsent( + writeSheetHolder.getSheetNo(), key -> MapUtils.newHashMap()); + Integer tableNo = 0; + if (writeTableHolder != null) { + tableNo = writeTableHolder.getTableNo(); + } + return tableStyleMap.computeIfAbsent(tableNo, key -> MapUtils.newHashMap()); + } } diff --git a/src/main/java/com/alibaba/excel/write/style/HorizontalCellStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/HorizontalCellStyleStrategy.java index 295cd556..c8914f55 100644 --- a/src/main/java/com/alibaba/excel/write/style/HorizontalCellStyleStrategy.java +++ b/src/main/java/com/alibaba/excel/write/style/HorizontalCellStyleStrategy.java @@ -1,29 +1,23 @@ package com.alibaba.excel.write.style; -import java.util.ArrayList; import java.util.List; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.Workbook; - import com.alibaba.excel.metadata.Head; -import com.alibaba.excel.util.StyleUtil; +import com.alibaba.excel.util.ListUtils; import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.poi.ss.usermodel.Cell; + /** - * * Use the same style for the row * * @author Jiaju Zhuang */ -public class HorizontalCellStyleStrategy extends AbstractCellStyleStrategy { - - private WriteCellStyle headWriteCellStyle; - private List contentWriteCellStyleList; +public class HorizontalCellStyleStrategy extends AbstractVerticalCellStyleStrategy { - private CellStyle headCellStyle; - private List contentCellStyleList; + private final WriteCellStyle headWriteCellStyle; + private final List contentWriteCellStyleList; public HorizontalCellStyleStrategy(WriteCellStyle headWriteCellStyle, List contentWriteCellStyleList) { @@ -33,37 +27,21 @@ public class HorizontalCellStyleStrategy extends AbstractCellStyleStrategy { public HorizontalCellStyleStrategy(WriteCellStyle headWriteCellStyle, WriteCellStyle contentWriteCellStyle) { this.headWriteCellStyle = headWriteCellStyle; - contentWriteCellStyleList = new ArrayList(); + contentWriteCellStyleList = ListUtils.newArrayList(); contentWriteCellStyleList.add(contentWriteCellStyle); } @Override - protected void initCellStyle(Workbook workbook) { - if (headWriteCellStyle != null) { - headCellStyle = StyleUtil.buildHeadCellStyle(workbook, headWriteCellStyle); - } - if (contentWriteCellStyleList != null && !contentWriteCellStyleList.isEmpty()) { - contentCellStyleList = new ArrayList(); - for (WriteCellStyle writeCellStyle : contentWriteCellStyleList) { - contentCellStyleList.add(StyleUtil.buildContentCellStyle(workbook, writeCellStyle)); - } - } - } - - @Override - protected void setHeadCellStyle(Cell cell, Head head, Integer relativeRowIndex) { - if (headCellStyle == null) { - return; - } - cell.setCellStyle(headCellStyle); + protected WriteCellStyle headCellStyle(Head head) { + return headWriteCellStyle; } @Override - protected void setContentCellStyle(Cell cell, Head head, Integer relativeRowIndex) { - if (contentCellStyleList == null || contentCellStyleList.isEmpty()) { - return; + protected WriteCellStyle contentCellStyle(Cell cell, Head head, Integer relativeRowIndex) { + if (CollectionUtils.isEmpty(contentWriteCellStyleList)) { + return new WriteCellStyle(); } - cell.setCellStyle(contentCellStyleList.get(relativeRowIndex % contentCellStyleList.size())); + return contentWriteCellStyleList.get(relativeRowIndex % contentWriteCellStyleList.size()); } } diff --git a/src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java index 005f624e..277f96b9 100644 --- a/src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java +++ b/src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java @@ -8,6 +8,7 @@ import com.alibaba.excel.event.NotRepeatExecutor; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.write.handler.AbstractCellWriteHandler; +import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; @@ -16,7 +17,7 @@ import com.alibaba.excel.write.metadata.holder.WriteTableHolder; * * @author Jiaju Zhuang */ -public abstract class AbstractColumnWidthStyleStrategy extends AbstractCellWriteHandler implements NotRepeatExecutor { +public abstract class AbstractColumnWidthStyleStrategy implements CellWriteHandler,NotRepeatExecutor { @Override public String uniqueValue() { @@ -25,7 +26,7 @@ public abstract class AbstractColumnWidthStyleStrategy extends AbstractCellWrite @Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, - List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { setColumnWidth(writeSheetHolder, cellDataList, cell, head, relativeRowIndex, isHead); } @@ -39,7 +40,7 @@ public abstract class AbstractColumnWidthStyleStrategy extends AbstractCellWrite * @param relativeRowIndex * @param isHead */ - protected abstract void setColumnWidth(WriteSheetHolder writeSheetHolder, List cellDataList, Cell cell, + protected abstract void setColumnWidth(WriteSheetHolder writeSheetHolder, List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead); } diff --git a/src/main/java/com/alibaba/excel/write/style/column/AbstractHeadColumnWidthStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/column/AbstractHeadColumnWidthStyleStrategy.java index 1a88eff6..d306d2e4 100644 --- a/src/main/java/com/alibaba/excel/write/style/column/AbstractHeadColumnWidthStyleStrategy.java +++ b/src/main/java/com/alibaba/excel/write/style/column/AbstractHeadColumnWidthStyleStrategy.java @@ -16,7 +16,7 @@ import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; public abstract class AbstractHeadColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy { @Override - protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List cellDataList, Cell cell, Head head, + protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { boolean needSetWidth = relativeRowIndex != null && (isHead || relativeRowIndex == 0); if (!needSetWidth) { diff --git a/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java index cc8dcb20..c6cc9df1 100644 --- a/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java +++ b/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java @@ -4,12 +4,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.commons.collections4.CollectionUtils; import org.apache.poi.ss.usermodel.Cell; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; -import com.alibaba.excel.util.CollectionUtils; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; /** @@ -27,7 +27,7 @@ public class LongestMatchColumnWidthStyleStrategy extends AbstractColumnWidthSty private Map> cache = new HashMap>(8); @Override - protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List cellDataList, Cell cell, Head head, + protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList); if (!needSetWidth) { @@ -52,7 +52,7 @@ public class LongestMatchColumnWidthStyleStrategy extends AbstractColumnWidthSty } } - private Integer dataLength(List cellDataList, Cell cell, Boolean isHead) { + private Integer dataLength(List> cellDataList, Cell cell, Boolean isHead) { if (isHead) { return cell.getStringCellValue().getBytes().length; } diff --git a/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationData.java b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationData.java index f1e91197..d1c2a4f7 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationData.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationData.java @@ -9,7 +9,6 @@ import com.alibaba.excel.annotation.format.NumberFormat; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentRowHeight; import com.alibaba.excel.annotation.write.style.HeadRowHeight; -import com.alibaba.excel.converters.doubleconverter.DoubleStringConverter; import lombok.Data; @@ -24,7 +23,7 @@ public class AnnotationData { @ExcelProperty("日期") @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒") private Date date; - @ExcelProperty(value = "数字", converter = DoubleStringConverter.class) + @ExcelProperty(value = "数字") @NumberFormat("#.##%") private Double number; @ExcelIgnore diff --git a/src/test/java/com/alibaba/easyexcel/test/core/celldata/CellDataData.java b/src/test/java/com/alibaba/easyexcel/test/core/celldata/CellDataData.java index a4e624fb..ac928ec1 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/celldata/CellDataData.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/celldata/CellDataData.java @@ -17,5 +17,5 @@ public class CellDataData { private CellData date; private CellData integer1; private Integer integer2; - private CellData formulaValue; + private CellData formulaValue; } diff --git a/src/test/java/com/alibaba/easyexcel/test/core/celldata/CellDataDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/celldata/CellDataDataTest.java index 4615cdbc..ad8cbf13 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/celldata/CellDataDataTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/celldata/CellDataDataTest.java @@ -55,7 +55,7 @@ public class CellDataDataTest { private List data() throws Exception { List list = new ArrayList(); CellDataData cellDataData = new CellDataData(); - cellDataData.setDate(new CellData(DateUtils.parseDate("2020-01-01 01:01:01"))); + cellDataData.setDate(new CellData<>(DateUtils.parseDate("2020-01-01 01:01:01"))); CellData integer1 = new CellData(); integer1.setType(CellDataTypeEnum.NUMBER); integer1.setNumberValue(BigDecimal.valueOf(2L)); diff --git a/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterData.java b/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterData.java index 88469470..fdff30e3 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterData.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterData.java @@ -34,5 +34,5 @@ public class ConverterData { @ExcelProperty("字符串") private String string; @ExcelProperty("自定义") - private CellData cellData; + private CellData cellData; } diff --git a/src/test/java/com/alibaba/easyexcel/test/core/excludeorinclude/ExcludeOrIncludeData.java b/src/test/java/com/alibaba/easyexcel/test/core/excludeorinclude/ExcludeOrIncludeData.java new file mode 100644 index 00000000..7c49b01d --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/excludeorinclude/ExcludeOrIncludeData.java @@ -0,0 +1,20 @@ +package com.alibaba.easyexcel.test.core.excludeorinclude; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class ExcludeOrIncludeData { + @ExcelProperty(order = 1) + private String column1; + @ExcelProperty(order = 2) + private String column2; + @ExcelProperty(order = 3) + private String column3; + @ExcelProperty(order = 4) + private String column4; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/excludeorinclude/ExcludeOrIncludeDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/excludeorinclude/ExcludeOrIncludeDataTest.java new file mode 100644 index 00000000..e6a8fc1c --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/excludeorinclude/ExcludeOrIncludeDataTest.java @@ -0,0 +1,161 @@ +package com.alibaba.easyexcel.test.core.excludeorinclude; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import com.alibaba.easyexcel.test.core.sort.SortData; +import com.alibaba.easyexcel.test.core.sort.SortDataListener; +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; + +/** + * @author Jiaju Zhuang + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class ExcludeOrIncludeDataTest { + + private static File excludeIndex07; + private static File excludeIndex03; + private static File excludeFiledName07; + private static File excludeFiledName03; + private static File includeIndex07; + private static File includeIndex03; + private static File includeFiledName07; + private static File includeFiledName03; + + @BeforeClass + public static void init() { + excludeIndex07 = TestFileUtil.createNewFile("excludeIndex.xlsx"); + excludeIndex03 = TestFileUtil.createNewFile("excludeIndex.xls"); + excludeFiledName07 = TestFileUtil.createNewFile("excludeFiledName.xlsx"); + excludeFiledName03 = TestFileUtil.createNewFile("excludeFiledName.xls"); + includeIndex07 = TestFileUtil.createNewFile("includeIndex.xlsx"); + includeIndex03 = TestFileUtil.createNewFile("includeIndex.xls"); + includeFiledName07 = TestFileUtil.createNewFile("includeFiledName.xlsx"); + includeFiledName03 = TestFileUtil.createNewFile("includeFiledName.xls"); + } + + @Test + public void t01ExcludeIndex07() { + excludeIndex(excludeIndex07); + } + + @Test + public void t02ExcludeIndex07() { + excludeIndex(excludeIndex03); + } + + @Test + public void t03ExcludeFiledName07() { + excludeFiledName(excludeFiledName07); + } + + @Test + public void t04ExcludeFiledName07() { + excludeFiledName(excludeFiledName03); + } + + + @Test + public void t05IncludeIndex07() { + includeIndex(includeIndex07); + } + + @Test + public void t06IncludeIndex07() { + includeIndex(includeIndex03); + } + + @Test + public void t07IncludeFiledName07() { + includeFiledName(includeFiledName07); + } + + @Test + public void t08IncludeFiledName07() { + includeFiledName(includeFiledName03); + } + + + private void excludeIndex(File file) { + Set excludeColumnIndexes = new HashSet(); + excludeColumnIndexes.add(0); + excludeColumnIndexes.add(3); + EasyExcel.write(file, ExcludeOrIncludeData.class).excludeColumnIndexes(excludeColumnIndexes).sheet() + .doWrite(data()); + List> dataMap = EasyExcel.read(file).sheet().doReadSync(); + Assert.assertEquals(1, dataMap.size()); + Map record = dataMap.get(0); + Assert.assertEquals(2, record.size()); + Assert.assertEquals("column2", record.get(0)); + Assert.assertEquals("column3", record.get(1)); + + } + + private void excludeFiledName(File file) { + Set excludeColumnFiledNames = new HashSet(); + excludeColumnFiledNames.add("column1"); + excludeColumnFiledNames.add("column3"); + excludeColumnFiledNames.add("column4"); + EasyExcel.write(file, ExcludeOrIncludeData.class).excludeColumnFiledNames(excludeColumnFiledNames).sheet() + .doWrite(data()); + List> dataMap = EasyExcel.read(file).sheet().doReadSync(); + Assert.assertEquals(1, dataMap.size()); + Map record = dataMap.get(0); + Assert.assertEquals(1, record.size()); + Assert.assertEquals("column2", record.get(0)); + + } + + private void includeIndex(File file) { + Set includeColumnIndexes = new HashSet(); + includeColumnIndexes.add(1); + includeColumnIndexes.add(2); + EasyExcel.write(file, ExcludeOrIncludeData.class).includeColumnIndexes(includeColumnIndexes).sheet() + .doWrite(data()); + List> dataMap = EasyExcel.read(file).sheet().doReadSync(); + Assert.assertEquals(1, dataMap.size()); + Map record = dataMap.get(0); + Assert.assertEquals(2, record.size()); + Assert.assertEquals("column2", record.get(0)); + Assert.assertEquals("column3", record.get(1)); + + } + + private void includeFiledName(File file) { + Set includeColumnFiledNames = new HashSet(); + includeColumnFiledNames.add("column2"); + includeColumnFiledNames.add("column3"); + EasyExcel.write(file, ExcludeOrIncludeData.class).includeColumnFiledNames(includeColumnFiledNames).sheet() + .doWrite(data()); + List> dataMap = EasyExcel.read(file).sheet().doReadSync(); + Assert.assertEquals(1, dataMap.size()); + Map record = dataMap.get(0); + Assert.assertEquals(2, record.size()); + Assert.assertEquals("column2", record.get(0)); + Assert.assertEquals("column3", record.get(1)); + } + + + private List data() { + List list = new ArrayList(); + ExcludeOrIncludeData excludeOrIncludeData = new ExcludeOrIncludeData(); + excludeOrIncludeData.setColumn1("column1"); + excludeOrIncludeData.setColumn2("column2"); + excludeOrIncludeData.setColumn3("column3"); + excludeOrIncludeData.setColumn4("column4"); + list.add(excludeOrIncludeData); + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java index 5c400305..3df12b1c 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java @@ -147,11 +147,11 @@ public class FillDataTest { excelWriter.finish(); List list = EasyExcel.read(file).ignoreEmptyRow(false).sheet().headRowNumber(0).doReadSync(); - Map map0 = (Map)list.get(0); + Map map0 = (Map) list.get(0); Assert.assertEquals("张三", map0.get(21)); - Map map27 = (Map)list.get(27); + Map map27 = (Map) list.get(27); Assert.assertEquals("张三", map27.get(0)); - Map map29 = (Map)list.get(29); + Map map29 = (Map) list.get(29); Assert.assertEquals("张三", map29.get(3)); } @@ -168,7 +168,7 @@ public class FillDataTest { List list = EasyExcel.read(file).sheet().headRowNumber(0).doReadSync(); Assert.assertEquals(list.size(), 5L); - Map map0 = (Map)list.get(0); + Map map0 = (Map) list.get(0); Assert.assertEquals("张三", map0.get(2)); } @@ -185,7 +185,7 @@ public class FillDataTest { excelWriter.finish(); List list = EasyExcel.read(file).sheet().headRowNumber(3).doReadSync(); Assert.assertEquals(list.size(), 21L); - Map map19 = (Map)list.get(19); + Map map19 = (Map) list.get(19); Assert.assertEquals("张三", map19.get(0)); } @@ -203,6 +203,9 @@ public class FillDataTest { list.add(fillData); fillData.setName("张三"); fillData.setNumber(5.2); + if (i == 5) { + fillData.setName(null); + } } return list; } diff --git a/src/test/java/com/alibaba/easyexcel/test/core/handler/WriteHandler.java b/src/test/java/com/alibaba/easyexcel/test/core/handler/WriteHandler.java new file mode 100644 index 00000000..cf9c5d26 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/handler/WriteHandler.java @@ -0,0 +1,280 @@ +package com.alibaba.easyexcel.test.core.handler; + +import java.util.List; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.junit.Assert; + +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.RowWriteHandler; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.handler.WorkbookWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; + +/** + * + * + * @author JiaJu Zhuang + **/ +public class WriteHandler implements WorkbookWriteHandler, SheetWriteHandler, RowWriteHandler, CellWriteHandler { + + private long beforeCellCreate = 0L; + private long afterCellCreate = 0L; + private long afterCellDataConverted = 0L; + private long afterCellDispose = 0L; + private long beforeRowCreate = 0L; + private long afterRowCreate = 0L; + private long afterRowDispose = 0L; + private long beforeSheetCreate = 0L; + private long afterSheetCreate = 0L; + private long beforeWorkbookCreate = 0L; + private long afterWorkbookCreate = 0L; + private long afterWorkbookDispose = 0L; + + + @Override + public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) { + if (isHead) { + Assert.assertEquals(0L, beforeCellCreate); + Assert.assertEquals(0L, afterCellCreate); + Assert.assertEquals(0L, afterCellDataConverted); + Assert.assertEquals(0L, afterCellDispose); + Assert.assertEquals(1L, beforeRowCreate); + Assert.assertEquals(1L, afterRowCreate); + Assert.assertEquals(0L, afterRowDispose); + Assert.assertEquals(1L, beforeSheetCreate); + Assert.assertEquals(1L, afterSheetCreate); + Assert.assertEquals(1L, beforeWorkbookCreate); + Assert.assertEquals(1L, afterWorkbookCreate); + Assert.assertEquals(0L, afterWorkbookDispose); + beforeCellCreate++; + } + + } + + @Override + public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, + Head head, Integer relativeRowIndex, Boolean isHead) { + if (isHead) { + Assert.assertEquals(1L, beforeCellCreate); + Assert.assertEquals(0L, afterCellCreate); + Assert.assertEquals(0L, afterCellDataConverted); + Assert.assertEquals(0L, afterCellDispose); + Assert.assertEquals(1L, beforeRowCreate); + Assert.assertEquals(1L, afterRowCreate); + Assert.assertEquals(0L, afterRowDispose); + Assert.assertEquals(1L, beforeSheetCreate); + Assert.assertEquals(1L, afterSheetCreate); + Assert.assertEquals(1L, beforeWorkbookCreate); + Assert.assertEquals(1L, afterWorkbookCreate); + Assert.assertEquals(0L, afterWorkbookDispose); + afterCellCreate++; + } + } + + @Override + public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + Assert.assertEquals(1L, beforeCellCreate); + Assert.assertEquals(1L, afterCellCreate); + Assert.assertEquals(0L, afterCellDataConverted); + Assert.assertEquals(1, afterCellDispose); + Assert.assertEquals(1L, beforeRowCreate); + Assert.assertEquals(1L, afterRowCreate); + Assert.assertEquals(1L, afterRowDispose); + Assert.assertEquals(1L, beforeSheetCreate); + Assert.assertEquals(1L, afterSheetCreate); + Assert.assertEquals(1L, beforeWorkbookCreate); + Assert.assertEquals(1L, afterWorkbookCreate); + Assert.assertEquals(0L, afterWorkbookDispose); + afterCellDataConverted++; + } + + @Override + public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + if (isHead) { + Assert.assertEquals(1L, beforeCellCreate); + Assert.assertEquals(1L, afterCellCreate); + Assert.assertEquals(0L, afterCellDataConverted); + Assert.assertEquals(0L, afterCellDispose); + Assert.assertEquals(1L, beforeRowCreate); + Assert.assertEquals(1L, afterRowCreate); + Assert.assertEquals(0L, afterRowDispose); + Assert.assertEquals(1L, beforeSheetCreate); + Assert.assertEquals(1L, afterSheetCreate); + Assert.assertEquals(1L, beforeWorkbookCreate); + Assert.assertEquals(1L, afterWorkbookCreate); + Assert.assertEquals(0L, afterWorkbookDispose); + afterCellDispose++; + } + } + + @Override + public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex, + Integer relativeRowIndex, Boolean isHead) { + if (isHead) { + Assert.assertEquals(0L, beforeCellCreate); + Assert.assertEquals(0L, afterCellCreate); + Assert.assertEquals(0L, afterCellDataConverted); + Assert.assertEquals(0L, afterCellDispose); + Assert.assertEquals(0L, beforeRowCreate); + Assert.assertEquals(0L, afterRowCreate); + Assert.assertEquals(0L, afterRowDispose); + Assert.assertEquals(1L, beforeSheetCreate); + Assert.assertEquals(1L, afterSheetCreate); + Assert.assertEquals(1L, beforeWorkbookCreate); + Assert.assertEquals(1L, afterWorkbookCreate); + Assert.assertEquals(0L, afterWorkbookDispose); + beforeRowCreate++; + } + + } + + @Override + public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Integer relativeRowIndex, Boolean isHead) { + if (isHead) { + Assert.assertEquals(0L, beforeCellCreate); + Assert.assertEquals(0L, afterCellCreate); + Assert.assertEquals(0L, afterCellDataConverted); + Assert.assertEquals(0L, afterCellDispose); + Assert.assertEquals(1L, beforeRowCreate); + Assert.assertEquals(0L, afterRowCreate); + Assert.assertEquals(0L, afterRowDispose); + Assert.assertEquals(1L, beforeSheetCreate); + Assert.assertEquals(1L, afterSheetCreate); + Assert.assertEquals(1L, beforeWorkbookCreate); + Assert.assertEquals(1L, afterWorkbookCreate); + Assert.assertEquals(0L, afterWorkbookDispose); + afterRowCreate++; + } + } + + @Override + public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Integer relativeRowIndex, Boolean isHead) { + if (isHead) { + Assert.assertEquals(1L, beforeCellCreate); + Assert.assertEquals(1L, afterCellCreate); + Assert.assertEquals(0L, afterCellDataConverted); + Assert.assertEquals(1L, afterCellDispose); + Assert.assertEquals(1L, beforeRowCreate); + Assert.assertEquals(1L, afterRowCreate); + Assert.assertEquals(0L, afterRowDispose); + Assert.assertEquals(1L, beforeSheetCreate); + Assert.assertEquals(1L, afterSheetCreate); + Assert.assertEquals(1L, beforeWorkbookCreate); + Assert.assertEquals(1L, afterWorkbookCreate); + Assert.assertEquals(0L, afterWorkbookDispose); + afterRowDispose++; + } + } + + @Override + public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + Assert.assertEquals(0L, beforeCellCreate); + Assert.assertEquals(0L, afterCellCreate); + Assert.assertEquals(0L, afterCellDataConverted); + Assert.assertEquals(0L, afterCellDispose); + Assert.assertEquals(0L, beforeRowCreate); + Assert.assertEquals(0L, afterRowCreate); + Assert.assertEquals(0L, afterRowDispose); + Assert.assertEquals(0L, beforeSheetCreate); + Assert.assertEquals(0L, afterSheetCreate); + Assert.assertEquals(1L, beforeWorkbookCreate); + Assert.assertEquals(1L, afterWorkbookCreate); + Assert.assertEquals(0L, afterWorkbookDispose); + beforeSheetCreate++; + } + + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + Assert.assertEquals(0L, beforeCellCreate); + Assert.assertEquals(0L, afterCellCreate); + Assert.assertEquals(0L, afterCellDataConverted); + Assert.assertEquals(0L, afterCellDispose); + Assert.assertEquals(0L, beforeRowCreate); + Assert.assertEquals(0L, afterRowCreate); + Assert.assertEquals(0L, afterRowDispose); + Assert.assertEquals(1L, beforeSheetCreate); + Assert.assertEquals(0L, afterSheetCreate); + Assert.assertEquals(1L, beforeWorkbookCreate); + Assert.assertEquals(1L, afterWorkbookCreate); + Assert.assertEquals(0L, afterWorkbookDispose); + afterSheetCreate++; + } + + @Override + public void beforeWorkbookCreate() { + Assert.assertEquals(0L, beforeCellCreate); + Assert.assertEquals(0L, afterCellCreate); + Assert.assertEquals(0L, afterCellDataConverted); + Assert.assertEquals(0L, afterCellDispose); + Assert.assertEquals(0L, beforeRowCreate); + Assert.assertEquals(0L, afterRowCreate); + Assert.assertEquals(0L, afterRowDispose); + Assert.assertEquals(0L, beforeSheetCreate); + Assert.assertEquals(0L, afterSheetCreate); + Assert.assertEquals(0L, beforeWorkbookCreate); + Assert.assertEquals(0L, afterWorkbookCreate); + Assert.assertEquals(0L, afterWorkbookDispose); + beforeWorkbookCreate++; + } + + @Override + public void afterWorkbookCreate(WriteWorkbookHolder writeWorkbookHolder) { + Assert.assertEquals(0L, beforeCellCreate); + Assert.assertEquals(0L, afterCellCreate); + Assert.assertEquals(0L, afterCellDataConverted); + Assert.assertEquals(0L, afterCellDispose); + Assert.assertEquals(0L, beforeRowCreate); + Assert.assertEquals(0L, afterRowCreate); + Assert.assertEquals(0L, afterRowDispose); + Assert.assertEquals(0L, beforeSheetCreate); + Assert.assertEquals(0L, afterSheetCreate); + Assert.assertEquals(1L, beforeWorkbookCreate); + Assert.assertEquals(0L, afterWorkbookCreate); + Assert.assertEquals(0L, afterWorkbookDispose); + afterWorkbookCreate++; + } + + @Override + public void afterWorkbookDispose(WriteWorkbookHolder writeWorkbookHolder) { + Assert.assertEquals(1L, beforeCellCreate); + Assert.assertEquals(1L, afterCellCreate); + Assert.assertEquals(1L, afterCellDataConverted); + Assert.assertEquals(1L, afterCellDispose); + Assert.assertEquals(1L, beforeRowCreate); + Assert.assertEquals(1L, afterRowCreate); + Assert.assertEquals(1L, afterRowDispose); + Assert.assertEquals(1L, beforeSheetCreate); + Assert.assertEquals(1L, afterSheetCreate); + Assert.assertEquals(1L, beforeWorkbookCreate); + Assert.assertEquals(1L, afterWorkbookCreate); + Assert.assertEquals(0L, afterWorkbookDispose); + afterWorkbookDispose++; + + } + + public void afterAll() { + Assert.assertEquals(1L, beforeCellCreate); + Assert.assertEquals(1L, afterCellCreate); + Assert.assertEquals(1L, afterCellDataConverted); + Assert.assertEquals(1L, afterCellDispose); + Assert.assertEquals(1L, beforeRowCreate); + Assert.assertEquals(1L, afterRowCreate); + Assert.assertEquals(1L, afterRowDispose); + Assert.assertEquals(1L, beforeSheetCreate); + Assert.assertEquals(1L, afterSheetCreate); + Assert.assertEquals(1L, beforeWorkbookCreate); + Assert.assertEquals(1L, afterWorkbookCreate); + Assert.assertEquals(1L, afterWorkbookDispose); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/handler/WriteHandlerData.java b/src/test/java/com/alibaba/easyexcel/test/core/handler/WriteHandlerData.java new file mode 100644 index 00000000..ad2188aa --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/handler/WriteHandlerData.java @@ -0,0 +1,14 @@ +package com.alibaba.easyexcel.test.core.handler; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class WriteHandlerData { + @ExcelProperty("姓名") + private String name; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/handler/WriteHandlerTest.java b/src/test/java/com/alibaba/easyexcel/test/core/handler/WriteHandlerTest.java new file mode 100644 index 00000000..a96d133e --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/handler/WriteHandlerTest.java @@ -0,0 +1,96 @@ +package com.alibaba.easyexcel.test.core.handler; + +import java.io.File; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import com.alibaba.easyexcel.test.core.head.ListHeadDataListener; +import com.alibaba.easyexcel.test.core.simple.SimpleData; +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.util.DateUtils; +import com.alibaba.excel.write.handler.WorkbookWriteHandler; + +/** + * + * @author Jiaju Zhuang + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class WriteHandlerTest { + + private static File file07; + private static File file03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("writeHandler07.xlsx"); + file03 = TestFileUtil.createNewFile("writeHandler03.xls"); + } + + @Test + public void t01WorkbookWrite07() throws Exception { + workbookWrite(file07); + } + + @Test + public void t02WorkbookWrite03() throws Exception { + workbookWrite(file03); + } + + @Test + public void t03SheetWrite07() throws Exception { + sheetWrite(file07); + } + + @Test + public void t04SheetWrite03() throws Exception { + sheetWrite(file03); + } + + @Test + public void t05TableWrite07() throws Exception { + workbookWrite(file07); + tableWrite(file07); + } + + @Test + public void t06TableWrite03() throws Exception { + tableWrite(file03); + } + + + private void workbookWrite(File file) { + WriteHandler writeHandler = new WriteHandler(); + EasyExcel.write(file).head(WriteHandlerData.class).registerWriteHandler(writeHandler).sheet().doWrite(data()); + writeHandler.afterAll(); + } + + private void sheetWrite(File file) { + WriteHandler writeHandler = new WriteHandler(); + EasyExcel.write(file).head(WriteHandlerData.class).sheet().registerWriteHandler(writeHandler).doWrite(data()); + writeHandler.afterAll(); + } + + private void tableWrite(File file) { + WriteHandler writeHandler = new WriteHandler(); + EasyExcel.write(file).head(WriteHandlerData.class).sheet().table(0).registerWriteHandler(writeHandler) + .doWrite(data()); + writeHandler.afterAll(); + } + + private List data() { + List list = new ArrayList(); + for (int i = 0; i < 1; i++) { + WriteHandlerData data = new WriteHandlerData(); + data.setName("姓名" + i); + list.add(data); + } + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/nomodel/NoModelDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/nomodel/NoModelDataTest.java new file mode 100644 index 00000000..1a0cf088 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/nomodel/NoModelDataTest.java @@ -0,0 +1,76 @@ +package com.alibaba.easyexcel.test.core.nomodel; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.util.DateUtils; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * @author Jiaju Zhuang + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class NoModelDataTest { + + private static File file07; + private static File file03; + private static File fileRepeat07; + private static File fileRepeat03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("noModel07.xlsx"); + file03 = TestFileUtil.createNewFile("noModel03.xls"); + fileRepeat07 = TestFileUtil.createNewFile("noModelRepeat07.xlsx"); + fileRepeat03 = TestFileUtil.createNewFile("noModelRepeat03.xls"); + } + + @Test + public void t01ReadAndWrite07() throws Exception { + readAndWrite(file07, fileRepeat07); + } + + @Test + public void t02ReadAndWrite03() throws Exception { + readAndWrite(file03, fileRepeat03); + } + + private void readAndWrite(File file, File fileRepeat) throws Exception { + EasyExcel.write(file).sheet().doWrite(data()); + List> result = EasyExcel.read(file).headRowNumber(0).sheet().doReadSync(); + Assert.assertEquals(10, result.size()); + Map data10 = result.get(9); + Assert.assertEquals("string19", data10.get(0)); + Assert.assertEquals("109", data10.get(1)); + Assert.assertEquals("2020-01-01 01:01:01", data10.get(2)); + + EasyExcel.write(fileRepeat).sheet().doWrite(result); + result = EasyExcel.read(fileRepeat).headRowNumber(0).sheet().doReadSync(); + Assert.assertEquals(10, result.size()); + data10 = result.get(9); + Assert.assertEquals("string19", data10.get(0)); + Assert.assertEquals("109", data10.get(1)); + Assert.assertEquals("2020-01-01 01:01:01", data10.get(2)); + } + + private List> data() throws Exception { + List> list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + List data = new ArrayList<>(); + data.add("string1" + i); + data.add(100 + i); + data.add(DateUtils.parseDate("2020-01-01 01:01:01")); + list.add(data); + } + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/noncamel/UnCamelData.java b/src/test/java/com/alibaba/easyexcel/test/core/noncamel/UnCamelData.java new file mode 100644 index 00000000..dd010fc7 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/noncamel/UnCamelData.java @@ -0,0 +1,16 @@ +package com.alibaba.easyexcel.test.core.noncamel; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class UnCamelData { + private String string1; + private String String2; + private String sTring3; + private String STring4; + private String STRING5; + private String STRing6; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/noncamel/UnCamelDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/noncamel/UnCamelDataListener.java new file mode 100644 index 00000000..2f36d665 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/noncamel/UnCamelDataListener.java @@ -0,0 +1,49 @@ +package com.alibaba.easyexcel.test.core.noncamel; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; + +/** + * @author Jiaju Zhuang + */ +@Slf4j +public class UnCamelDataListener extends AnalysisEventListener { + List list = new ArrayList<>(); + + @Override + public void invokeHeadMap(Map headMap, AnalysisContext context) { + log.debug("Head is:{}", JSON.toJSONString(headMap)); + Assert.assertEquals(headMap.get(0), "string1"); + Assert.assertEquals(headMap.get(1), "String2"); + Assert.assertEquals(headMap.get(2), "sTring3"); + Assert.assertEquals(headMap.get(3), "STring4"); + Assert.assertEquals(headMap.get(4), "STRING5"); + Assert.assertEquals(headMap.get(5), "STRing6"); + } + + @Override + public void invoke(UnCamelData data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 10); + UnCamelData unCamelData = list.get(0); + Assert.assertEquals(unCamelData.getString1(), "string1"); + Assert.assertEquals(unCamelData.getString2(), "string2"); + Assert.assertEquals(unCamelData.getSTring3(), "string3"); + Assert.assertEquals(unCamelData.getSTring4(), "string4"); + Assert.assertEquals(unCamelData.getSTRING5(), "string5"); + Assert.assertEquals(unCamelData.getSTRing6(), "string6"); + log.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/noncamel/UnCamelDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/noncamel/UnCamelDataTest.java new file mode 100644 index 00000000..689c9f8a --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/noncamel/UnCamelDataTest.java @@ -0,0 +1,59 @@ +package com.alibaba.easyexcel.test.core.noncamel; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; + +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * @author Jiaju Zhuang + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class UnCamelDataTest { + + private static File file07; + private static File file03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("unCame07.xlsx"); + file03 = TestFileUtil.createNewFile("unCame03.xls"); + } + + @Test + public void t01ReadAndWrite07() { + readAndWrite(file07); + } + + @Test + public void t02ReadAndWrite03() { + readAndWrite(file03); + } + + private void readAndWrite(File file) { + EasyExcel.write(file, UnCamelData.class).sheet().doWrite(data()); + EasyExcel.read(file, UnCamelData.class, new UnCamelDataListener()).sheet().doRead(); + } + + private List data() { + List list = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + UnCamelData unCamelData = new UnCamelData(); + unCamelData.setString1("string1"); + unCamelData.setString2("string2"); + unCamelData.setSTring3("string3"); + unCamelData.setSTring4("string4"); + unCamelData.setSTRING5("string5"); + unCamelData.setSTRing6("string6"); + list.add(unCamelData); + } + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/skip/SkipData.java b/src/test/java/com/alibaba/easyexcel/test/core/skip/SkipData.java new file mode 100644 index 00000000..1476448b --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/skip/SkipData.java @@ -0,0 +1,15 @@ +package com.alibaba.easyexcel.test.core.skip; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class SkipData { + + @ExcelProperty("姓名") + private String name; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/skip/SkipDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/skip/SkipDataTest.java new file mode 100644 index 00000000..3f62994e --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/skip/SkipDataTest.java @@ -0,0 +1,86 @@ +package com.alibaba.easyexcel.test.core.skip; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import com.alibaba.easyexcel.test.core.simple.SimpleData; +import com.alibaba.easyexcel.test.core.simple.SimpleDataListener; +import com.alibaba.easyexcel.test.core.simple.SimpleDataSheetNameListener; +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.event.SyncReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.write.metadata.WriteSheet; + +/** + * @author Jiaju Zhuang + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class SkipDataTest { + + private static File file07; + private static File file03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("skip.xlsx"); + file03 = TestFileUtil.createNewFile("skip.xls"); + } + + @Test + public void t01ReadAndWrite07() { + readAndWrite(file07); + } + + @Test + public void t02ReadAndWrite03() { + readAndWrite(file03); + } + + private void readAndWrite(File file) { + ExcelWriter excelWriter = EasyExcel.write(file, SimpleData.class).build(); + WriteSheet writeSheet0 = EasyExcel.writerSheet(0, "第一个").build(); + WriteSheet writeSheet1 = EasyExcel.writerSheet(1, "第二个").build(); + WriteSheet writeSheet2 = EasyExcel.writerSheet(2, "第三个").build(); + WriteSheet writeSheet3 = EasyExcel.writerSheet(3, "第四个").build(); + excelWriter.write(data("name1"), writeSheet0); + excelWriter.write(data("name2"), writeSheet1); + excelWriter.write(data("name3"), writeSheet2); + excelWriter.write(data("name4"), writeSheet3); + excelWriter.finish(); + + List list = EasyExcel.read(file, SkipData.class, null).sheet("第二个").doReadSync(); + Assert.assertEquals(1, list.size()); + Assert.assertEquals("name2", list.get(0).getName()); + + SyncReadListener syncReadListener = new SyncReadListener(); + ExcelReader excelReader = EasyExcel.read(file, SkipData.class, null).registerReadListener(syncReadListener) + .build(); + ReadSheet readSheet1 = EasyExcel.readSheet("第二个").build(); + ReadSheet readSheet3 = EasyExcel.readSheet("第四个").build(); + excelReader.read(readSheet1, readSheet3); + List syncList = syncReadListener.getList(); + Assert.assertEquals(2, syncList.size()); + Assert.assertEquals("name2", ((SkipData) syncList.get(0)).getName()); + Assert.assertEquals("name4", ((SkipData) syncList.get(1)).getName()); + excelReader.finish(); + } + + + private List data(String name) { + List list = new ArrayList(); + SkipData data = new SkipData(); + data.setName(name); + list.add(data); + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/sort/SortData.java b/src/test/java/com/alibaba/easyexcel/test/core/sort/SortData.java new file mode 100644 index 00000000..870abe87 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/sort/SortData.java @@ -0,0 +1,22 @@ +package com.alibaba.easyexcel.test.core.sort; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class SortData { + private String column5; + private String column6; + @ExcelProperty(order = 100) + private String column4; + @ExcelProperty(order = 99) + private String column3; + @ExcelProperty(value = "column2", index = 1) + private String column2; + @ExcelProperty(value = "column1", index = 0) + private String column1; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/sort/SortDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/sort/SortDataListener.java new file mode 100644 index 00000000..227bddfd --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/sort/SortDataListener.java @@ -0,0 +1,41 @@ +package com.alibaba.easyexcel.test.core.sort; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.core.simple.SimpleData; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class SortDataListener extends AnalysisEventListener { + + private static final Logger LOGGER = LoggerFactory.getLogger(SortDataListener.class); + List list = new ArrayList(); + + + @Override + public void invoke(SortData data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 1); + SortData sortData = list.get(0); + Assert.assertEquals("column1", sortData.getColumn1()); + Assert.assertEquals("column2", sortData.getColumn2()); + Assert.assertEquals("column3", sortData.getColumn3()); + Assert.assertEquals("column4", sortData.getColumn4()); + Assert.assertEquals("column5", sortData.getColumn5()); + Assert.assertEquals("column6", sortData.getColumn6()); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/sort/SortDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/sort/SortDataTest.java new file mode 100644 index 00000000..698078a1 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/sort/SortDataTest.java @@ -0,0 +1,111 @@ +package com.alibaba.easyexcel.test.core.sort; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; + +/** + * @author Jiaju Zhuang + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class SortDataTest { + + private static File file07; + private static File file03; + private static File sortNoHead07; + private static File sortNoHead03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("sort.xlsx"); + file03 = TestFileUtil.createNewFile("sort.xls"); + sortNoHead07 = TestFileUtil.createNewFile("sortNoHead.xlsx"); + sortNoHead03 = TestFileUtil.createNewFile("sortNoHead.xls"); + } + + @Test + public void t01ReadAndWrite07() { + readAndWrite(file07); + } + + @Test + public void t02ReadAndWrite03() { + readAndWrite(file03); + } + + @Test + public void t03ReadAndWriteNoHead07() { + readAndWriteNoHead(sortNoHead07); + } + + @Test + public void t04ReadAndWriteNoHead03() { + readAndWriteNoHead(sortNoHead03); + } + + + private void readAndWrite(File file) { + EasyExcel.write(file, SortData.class).sheet().doWrite(data()); + List> dataMap = EasyExcel.read(file).sheet().doReadSync(); + Assert.assertEquals(1, dataMap.size()); + Map record = dataMap.get(0); + Assert.assertEquals("column1", record.get(0)); + Assert.assertEquals("column2", record.get(1)); + Assert.assertEquals("column3", record.get(2)); + Assert.assertEquals("column4", record.get(3)); + Assert.assertEquals("column5", record.get(4)); + Assert.assertEquals("column6", record.get(5)); + + EasyExcel.read(file, SortData.class, new SortDataListener()).sheet().doRead(); + } + + private void readAndWriteNoHead(File file) { + EasyExcel.write(file).head(head()).sheet().doWrite(data()); + List> dataMap = EasyExcel.read(file).sheet().doReadSync(); + Assert.assertEquals(1, dataMap.size()); + Map record = dataMap.get(0); + Assert.assertEquals("column1", record.get(0)); + Assert.assertEquals("column2", record.get(1)); + Assert.assertEquals("column3", record.get(2)); + Assert.assertEquals("column4", record.get(3)); + Assert.assertEquals("column5", record.get(4)); + Assert.assertEquals("column6", record.get(5)); + EasyExcel.read(file, SortData.class, new SortDataListener()).sheet().doRead(); + } + + private List> head() { + List> head = new ArrayList>(); + head.add(Collections.singletonList("column1")); + head.add(Collections.singletonList("column2")); + head.add(Collections.singletonList("column3")); + head.add(Collections.singletonList("column4")); + head.add(Collections.singletonList("column5")); + head.add(Collections.singletonList("column6")); + return head; + } + + + private List data() { + List list = new ArrayList(); + SortData sortData = new SortData(); + sortData.setColumn1("column1"); + sortData.setColumn2("column2"); + sortData.setColumn3("column3"); + sortData.setColumn4("column4"); + sortData.setColumn5("column5"); + sortData.setColumn6("column6"); + list.add(sortData); + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java index 7a0e92e5..ffa8280c 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java @@ -2,6 +2,7 @@ package com.alibaba.easyexcel.test.demo.fill; import java.io.File; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -205,7 +206,9 @@ public class FillTest { excelWriter.fill(new FillWrapper("data3", data()), writeSheet); Map map = new HashMap(); - map.put("date", "2019年10月9日13:28:28"); + //map.put("date", "2019年10月9日13:28:28"); + map.put("date", new Date()); + excelWriter.fill(map, writeSheet); // 别忘记关闭流 diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraListener.java index 01adfe72..df2afc36 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraListener.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraListener.java @@ -1,19 +1,18 @@ package com.alibaba.easyexcel.test.demo.read; -import org.junit.Assert; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.CellExtra; import com.alibaba.fastjson.JSON; +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * 读取单元格的批注 * - * @author: kaiux - * @date: 2019-10-23 14:10 + * @author Jiaju Zhuang **/ public class DemoExtraListener extends AnalysisEventListener { private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class); diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java index edcf8a0b..ea011b31 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java @@ -27,6 +27,7 @@ import com.alibaba.fastjson.JSON; */ @Ignore public class ReadTest { + private static final Logger LOGGER = LoggerFactory.getLogger(ReadTest.class); /** @@ -48,11 +49,17 @@ public class ReadTest { // 写法2: fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; - ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build(); - ReadSheet readSheet = EasyExcel.readSheet(0).build(); - excelReader.read(readSheet); - // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的 - excelReader.finish(); + ExcelReader excelReader = null; + try { + excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build(); + ReadSheet readSheet = EasyExcel.readSheet(0).build(); + excelReader.read(readSheet); + } finally { + if (excelReader != null) { + // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的 + excelReader.finish(); + } + } } /** @@ -90,16 +97,23 @@ public class ReadTest { // 读取部分sheet fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; - ExcelReader excelReader = EasyExcel.read(fileName).build(); - // 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener - ReadSheet readSheet1 = - EasyExcel.readSheet(0).head(DemoData.class).registerReadListener(new DemoDataListener()).build(); - ReadSheet readSheet2 = - EasyExcel.readSheet(1).head(DemoData.class).registerReadListener(new DemoDataListener()).build(); - // 这里注意 一定要把sheet1 sheet2 一起传进去,不然有个问题就是03版的excel 会读取多次,浪费性能 - excelReader.read(readSheet1, readSheet2); - // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的 - excelReader.finish(); + ExcelReader excelReader = null; + try { + excelReader = EasyExcel.read(fileName).build(); + + // 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener + ReadSheet readSheet1 = + EasyExcel.readSheet(0).head(DemoData.class).registerReadListener(new DemoDataListener()).build(); + ReadSheet readSheet2 = + EasyExcel.readSheet(1).head(DemoData.class).registerReadListener(new DemoDataListener()).build(); + // 这里注意 一定要把sheet1 sheet2 一起传进去,不然有个问题就是03版的excel 会读取多次,浪费性能 + excelReader.read(readSheet1, readSheet2); + } finally { + if (excelReader != null) { + // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的 + excelReader.finish(); + } + } } /** diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java index b80022d9..0a147564 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java @@ -18,6 +18,7 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.fastjson.JSON; /** @@ -43,11 +44,11 @@ public class WebTest { @GetMapping("download") public void download(HttpServletResponse response) throws IOException { // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman - response.setContentType("application/vnd.ms-excel"); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 - String fileName = URLEncoder.encode("测试", "UTF-8"); - response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); + String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data()); } @@ -60,11 +61,11 @@ public class WebTest { public void downloadFailedUsingJson(HttpServletResponse response) throws IOException { // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman try { - response.setContentType("application/vnd.ms-excel"); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 - String fileName = URLEncoder.encode("测试", "UTF-8"); - response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); + String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); // 这里需要设置不关闭流 EasyExcel.write(response.getOutputStream(), DownloadData.class).autoCloseStream(Boolean.FALSE).sheet("模板") .doWrite(data()); diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/CommentWriteHandler.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/CommentWriteHandler.java new file mode 100644 index 00000000..d6eacb42 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/CommentWriteHandler.java @@ -0,0 +1,38 @@ +package com.alibaba.easyexcel.test.demo.write; + +import org.apache.poi.ss.usermodel.Comment; +import org.apache.poi.ss.usermodel.Drawing; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFRichTextString; + +import com.alibaba.excel.write.handler.AbstractRowWriteHandler; +import com.alibaba.excel.write.handler.RowWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; + +/** + * 自定义拦截器.新增注释,第一行头加批注 + * + * @author Jiaju Zhuang + */ +public class CommentWriteHandler implements RowWriteHandler { + + @Override + public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Integer relativeRowIndex, Boolean isHead) { + if (isHead) { + Sheet sheet = writeSheetHolder.getSheet(); + Drawing drawingPatriarch = sheet.createDrawingPatriarch(); + // 在第一行 第二列创建一个批注 + Comment comment = + drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short)1, 0, (short)2, 1)); + // 输入批注信息 + comment.setString(new XSSFRichTextString("创建批注!")); + // 将批注添加到单元格对象中 + sheet.getRow(0).getCell(1).setCellComment(comment); + } + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java index b1bcb7dc..b4ade88f 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java @@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.write.handler.AbstractCellWriteHandler; +import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; @@ -20,13 +21,13 @@ import com.alibaba.excel.write.metadata.holder.WriteTableHolder; * * @author Jiaju Zhuang */ -public class CustomCellWriteHandler extends AbstractCellWriteHandler { +public class CustomCellWriteHandler implements CellWriteHandler { private static final Logger LOGGER = LoggerFactory.getLogger(CustomCellWriteHandler.class); @Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, - List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { // 这里可以对cell进行任何操作 LOGGER.info("第{}行,第{}列写入完成。", cell.getRowIndex(), cell.getColumnIndex()); if (isHead && cell.getColumnIndex() == 0) { diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java index 49621979..80cd631f 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java @@ -40,6 +40,7 @@ import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy */ @Ignore public class WriteTest { + /** * 最简单的写 *

@@ -58,11 +59,17 @@ public class WriteTest { // 写法2 fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx"; // 这里 需要指定写用哪个class去写 - ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); - WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); - excelWriter.write(data(), writeSheet); - /// 千万别忘记finish 会帮忙关闭流 - excelWriter.finish(); + ExcelWriter excelWriter = null; + try { + excelWriter = EasyExcel.write(fileName, DemoData.class).build(); + WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); + excelWriter.write(data(), writeSheet); + } finally { + // 千万别忘记finish 会帮忙关闭流 + if (excelWriter != null) { + excelWriter.finish(); + } + } } /** @@ -141,48 +148,64 @@ public class WriteTest { public void repeatedWrite() { // 方法1 如果写到同一个sheet String fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx"; - // 这里 需要指定写用哪个class去写 - ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); - // 这里注意 如果同一个sheet只要创建一次 - WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); - // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来 - for (int i = 0; i < 5; i++) { - // 分页去数据库查询数据 这里可以去数据库查询每一页的数据 - List data = data(); - excelWriter.write(data, writeSheet); + ExcelWriter excelWriter = null; + try { + // 这里 需要指定写用哪个class去写 + excelWriter = EasyExcel.write(fileName, DemoData.class).build(); + // 这里注意 如果同一个sheet只要创建一次 + WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); + // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来 + for (int i = 0; i < 5; i++) { + // 分页去数据库查询数据 这里可以去数据库查询每一页的数据 + List data = data(); + excelWriter.write(data, writeSheet); + } + } finally { + // 千万别忘记finish 会帮忙关闭流 + if (excelWriter != null) { + excelWriter.finish(); + } } - /// 千万别忘记finish 会帮忙关闭流 - excelWriter.finish(); // 方法2 如果写到不同的sheet 同一个对象 fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx"; - // 这里 指定文件 - excelWriter = EasyExcel.write(fileName, DemoData.class).build(); - // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面 - for (int i = 0; i < 5; i++) { - // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样 - writeSheet = EasyExcel.writerSheet(i, "模板" + i).build(); - // 分页去数据库查询数据 这里可以去数据库查询每一页的数据 - List data = data(); - excelWriter.write(data, writeSheet); + try { + // 这里 指定文件 + excelWriter = EasyExcel.write(fileName, DemoData.class).build(); + // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面 + for (int i = 0; i < 5; i++) { + // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样 + WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).build(); + // 分页去数据库查询数据 这里可以去数据库查询每一页的数据 + List data = data(); + excelWriter.write(data, writeSheet); + } + } finally { + // 千万别忘记finish 会帮忙关闭流 + if (excelWriter != null) { + excelWriter.finish(); + } } - /// 千万别忘记finish 会帮忙关闭流 - excelWriter.finish(); // 方法3 如果写到不同的sheet 不同的对象 fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx"; - // 这里 指定文件 - excelWriter = EasyExcel.write(fileName).build(); - // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面 - for (int i = 0; i < 5; i++) { - // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样。这里注意DemoData.class 可以每次都变,我这里为了方便 所以用的同一个class 实际上可以一直变 - writeSheet = EasyExcel.writerSheet(i, "模板" + i).head(DemoData.class).build(); - // 分页去数据库查询数据 这里可以去数据库查询每一页的数据 - List data = data(); - excelWriter.write(data, writeSheet); + try { + // 这里 指定文件 + excelWriter = EasyExcel.write(fileName).build(); + // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面 + for (int i = 0; i < 5; i++) { + // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样。这里注意DemoData.class 可以每次都变,我这里为了方便 所以用的同一个class 实际上可以一直变 + WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).head(DemoData.class).build(); + // 分页去数据库查询数据 这里可以去数据库查询每一页的数据 + List data = data(); + excelWriter.write(data, writeSheet); + } + } finally { + // 千万别忘记finish 会帮忙关闭流 + if (excelWriter != null) { + excelWriter.finish(); + } } - /// 千万别忘记finish 会帮忙关闭流 - excelWriter.finish(); } /** @@ -335,7 +358,7 @@ public class WriteTest { // 背景设置为红色 headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex()); WriteFont headWriteFont = new WriteFont(); - headWriteFont.setFontHeightInPoints((short)20); + headWriteFont.setFontHeightInPoints((short) 20); headWriteCellStyle.setWriteFont(headWriteFont); // 内容的策略 WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); @@ -345,7 +368,7 @@ public class WriteTest { contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex()); WriteFont contentWriteFont = new WriteFont(); // 字体大小 - contentWriteFont.setFontHeightInPoints((short)20); + contentWriteFont.setFontHeightInPoints((short) 20); contentWriteCellStyle.setWriteFont(contentWriteFont); // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现 HorizontalCellStyleStrategy horizontalCellStyleStrategy = @@ -395,18 +418,24 @@ public class WriteTest { String fileName = TestFileUtil.getPath() + "tableWrite" + System.currentTimeMillis() + ".xlsx"; // 这里直接写多个table的案例了,如果只有一个 也可以直一行代码搞定,参照其他案例 // 这里 需要指定写用哪个class去写 - ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); - // 把sheet设置为不需要头 不然会输出sheet的头 这样看起来第一个table 就有2个头了 - WriteSheet writeSheet = EasyExcel.writerSheet("模板").needHead(Boolean.FALSE).build(); - // 这里必须指定需要头,table 会继承sheet的配置,sheet配置了不需要,table 默认也是不需要 - WriteTable writeTable0 = EasyExcel.writerTable(0).needHead(Boolean.TRUE).build(); - WriteTable writeTable1 = EasyExcel.writerTable(1).needHead(Boolean.TRUE).build(); - // 第一次写入会创建头 - excelWriter.write(data(), writeSheet, writeTable0); - // 第二次写如也会创建头,然后在第一次的后面写入数据 - excelWriter.write(data(), writeSheet, writeTable1); - /// 千万别忘记finish 会帮忙关闭流 - excelWriter.finish(); + ExcelWriter excelWriter = null; + try { + excelWriter = EasyExcel.write(fileName, DemoData.class).build(); + // 把sheet设置为不需要头 不然会输出sheet的头 这样看起来第一个table 就有2个头了 + WriteSheet writeSheet = EasyExcel.writerSheet("模板").needHead(Boolean.FALSE).build(); + // 这里必须指定需要头,table 会继承sheet的配置,sheet配置了不需要,table 默认也是不需要 + WriteTable writeTable0 = EasyExcel.writerTable(0).needHead(Boolean.TRUE).build(); + WriteTable writeTable1 = EasyExcel.writerTable(1).needHead(Boolean.TRUE).build(); + // 第一次写入会创建头 + excelWriter.write(data(), writeSheet, writeTable0); + // 第二次写如也会创建头,然后在第一次的后面写入数据 + excelWriter.write(data(), writeSheet, writeTable1); + } finally { + // 千万别忘记finish 会帮忙关闭流 + if (excelWriter != null) { + excelWriter.finish(); + } + } } /** @@ -432,8 +461,7 @@ public class WriteTest { /** * 自动列宽(不太精确) *

- * 这个目前不是很好用,比如有数字就会导致换行。而且长度也不是刚好和实际长度一致。 所以需要精确到刚好列宽的慎用。 当然也可以自己参照 - * {@link LongestMatchColumnWidthStyleStrategy}重新实现. + * 这个目前不是很好用,比如有数字就会导致换行。而且长度也不是刚好和实际长度一致。 所以需要精确到刚好列宽的慎用。 当然也可以自己参照 {@link LongestMatchColumnWidthStyleStrategy}重新实现. *

* poi 自带{@link SXSSFSheet#autoSizeColumn(int)} 对中文支持也不太好。目前没找到很好的算法。 有的话可以推荐下。 * @@ -472,6 +500,24 @@ public class WriteTest { .registerWriteHandler(new CustomCellWriteHandler()).sheet("模板").doWrite(data()); } + /** + * 插入批注 + *

+ * 1. 创建excel对应的实体对象 参照{@link DemoData} + *

+ * 2. 注册拦截器 {@link CommentWriteHandler} + *

+ * 2. 直接写即可 + */ + @Test + public void commentWrite() { + String fileName = TestFileUtil.getPath() + "commentWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 这里要注意inMemory 要设置为true,才能支持批注。目前没有好的办法解决 不在内存处理批注。这个需要自己选择。 + EasyExcel.write(fileName, DemoData.class).inMemory(Boolean.TRUE).registerWriteHandler(new CommentWriteHandler()) + .sheet("模板").doWrite(data()); + } + /** * 可变标题处理(包括标题国际化等) *

diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/CamlData.java b/src/test/java/com/alibaba/easyexcel/test/temp/CamlData.java new file mode 100644 index 00000000..9c3f39e4 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/CamlData.java @@ -0,0 +1,18 @@ +package com.alibaba.easyexcel.test.temp; + +import lombok.Data; + +/** + * TODO + * + * @author 是仪 + */ +@Data +public class CamlData { + private String string1; + private String String2; + private String sTring3; + private String STring4; + private String STRING5; + private String STRing6; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/FillTempTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/FillTempTest.java index 0ed625da..7917e063 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/FillTempTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/FillTempTest.java @@ -13,6 +13,7 @@ import com.alibaba.easyexcel.test.temp.fill.FillData2; import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy; import com.alibaba.excel.write.metadata.WriteSheet; /** @@ -33,16 +34,21 @@ public class FillTempTest { public void complexFill() { // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替 // {} 代表普通变量 {.} 代表是list的变量 - String templateFileName = "D:\\test\\simple.xlsx"; + OnceAbsoluteMergeStrategy onceAbsoluteMergeStrategy = new OnceAbsoluteMergeStrategy(2, 2, 0, 1); String fileName = TestFileUtil.getPath() + "complexFill" + System.currentTimeMillis() + ".xlsx"; - ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build(); - WriteSheet writeSheet = EasyExcel.writerSheet().build(); - excelWriter.fill(teamp(), writeSheet); + ExcelWriter excelWriter = EasyExcel.write(fileName).registerWriteHandler(onceAbsoluteMergeStrategy).withTemplate(TestFileUtil.readUserHomeFile("test/simple.xlsx")).build(); + WriteSheet writeSheet0 = EasyExcel.writerSheet(0).build(); + WriteSheet writeSheet1 = EasyExcel.writerSheet(1).build(); + + excelWriter.fill(teamp(), writeSheet0); + excelWriter.fill(teamp(), writeSheet1); + Map map = new HashMap(); map.put("date", "2019年10月9日13:28:28"); map.put("total", 1000); - excelWriter.fill(map, writeSheet); + excelWriter.fill(map, writeSheet0); + excelWriter.finish(); } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java b/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java index 6c9bd8d4..e8545670 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java @@ -28,19 +28,30 @@ import com.alibaba.fastjson.JSON; **/ @Ignore public class Lock2Test { + private static final Logger LOGGER = LoggerFactory.getLogger(Lock2Test.class); @Test public void test() throws Exception { - File file = new File("D:\\test\\headt1.xlsx"); +// File file = TestFileUtil.readUserHomeFile("test/test6.xls"); + File file = new File("/Users/zhuangjiaju/Downloads/1.xlsx"); - List list = EasyExcel.read(file).sheet().headRowNumber(0).doReadSync(); + List list = EasyExcel.read(file).sheet(0).headRowNumber(0).doReadSync(); LOGGER.info("数据:{}", list.size()); for (Object data : list) { LOGGER.info("返回数据:{}", JSON.toJSONString(data)); } } + @Test + public void test33() throws Exception { + File file = TestFileUtil.readUserHomeFile("test/test6.xlsx"); + + EasyExcel.read(file, LockData.class, new LockDataListener()).sheet(0).headRowNumber(0) + .doRead(); + + } + @Test public void write() throws Exception { String fileName = TestFileUtil.getPath() + "styleWrite" + System.currentTimeMillis() + ".xlsx"; @@ -49,7 +60,7 @@ public class Lock2Test { // 背景设置为红色 headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex()); WriteFont headWriteFont = new WriteFont(); - headWriteFont.setFontHeightInPoints((short)20); + headWriteFont.setFontHeightInPoints((short) 20); headWriteCellStyle.setWriteFont(headWriteFont); // 内容的策略 WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); @@ -59,7 +70,7 @@ public class Lock2Test { contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex()); WriteFont contentWriteFont = new WriteFont(); // 字体大小 - contentWriteFont.setFontHeightInPoints((short)20); + contentWriteFont.setFontHeightInPoints((short) 20); contentWriteCellStyle.setWriteFont(contentWriteFont); // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现 HorizontalCellStyleStrategy horizontalCellStyleStrategy = diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/LockData.java b/src/test/java/com/alibaba/easyexcel/test/temp/LockData.java index 2e1ed7b0..14fa65e3 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/LockData.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/LockData.java @@ -1,5 +1,7 @@ package com.alibaba.easyexcel.test.temp; +import com.alibaba.excel.annotation.format.NumberFormat; + import lombok.Data; /** @@ -9,7 +11,8 @@ import lombok.Data; **/ @Data public class LockData { - private String string0; + @NumberFormat("#.##%") + private Double string0; private String string1; private String string2; private String string3; diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/LockDataListener.java b/src/test/java/com/alibaba/easyexcel/test/temp/LockDataListener.java index d5891115..64cce8db 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/LockDataListener.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/LockDataListener.java @@ -18,16 +18,16 @@ import com.alibaba.fastjson.JSON; * * @author Jiaju Zhuang */ -public class LockDataListener extends AnalysisEventListener> { +public class LockDataListener extends AnalysisEventListener { private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class); /** * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 */ private static final int BATCH_COUNT = 5; - List> list = new ArrayList>(); + List list = new ArrayList(); @Override - public void invoke(Map data, AnalysisContext context) { + public void invoke(LockData data, AnalysisContext context) { LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); list.add(data); if (list.size() >= BATCH_COUNT) { diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/LockTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/LockTest.java index 27f820bc..ad09717f 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/LockTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/LockTest.java @@ -26,11 +26,7 @@ public class LockTest { public void test() throws Exception { List list = - EasyExcel.read(new FileInputStream("D:\\test\\testbug嘉惠.xlsx")).sheet().headRowNumber(0).doReadSync(); - for (Object data : list) { - LOGGER.info("返回数据:{}", JSON.toJSONString(data)); - } - list = EasyExcel.read(new File("D:\\test\\t222.xlsx")).sheet().headRowNumber(0).doReadSync(); + EasyExcel.read(new FileInputStream("/Users/zhuangjiaju/Downloads/点位配置表 (1).xlsx")).doReadAllSync(); for (Object data : list) { LOGGER.info("返回数据:{}", JSON.toJSONString(data)); } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/WriteLargeTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/WriteLargeTest.java new file mode 100644 index 00000000..23f623b6 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/WriteLargeTest.java @@ -0,0 +1,97 @@ +package com.alibaba.easyexcel.test.temp; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.easyexcel.test.core.large.LargeData; +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; + +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 临时测试 + * + * @author Jiaju Zhuang + **/ +@Ignore +public class WriteLargeTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(WriteLargeTest.class); + private int i = 0; + + @Test + public void test() throws Exception { + // 方法2 如果写到不同的sheet 同一个对象 + String fileName = TestFileUtil.getPath() + "large" + System.currentTimeMillis() + ".xlsx"; + // 头的策略 + WriteCellStyle headWriteCellStyle = new WriteCellStyle(); + // 背景设置为红色 + headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex()); + WriteFont headWriteFont = new WriteFont(); + headWriteFont.setFontHeightInPoints((short)20); + headWriteCellStyle.setWriteFont(headWriteFont); + // 内容的策略 + WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); + // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定 + contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); + // 背景绿色 + contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex()); + WriteFont contentWriteFont = new WriteFont(); + // 字体大小 + contentWriteFont.setFontHeightInPoints((short)20); + contentWriteCellStyle.setWriteFont(contentWriteFont); + // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现 + HorizontalCellStyleStrategy horizontalCellStyleStrategy = + new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle); + + ExcelWriter excelWriter = EasyExcel.write(fileName, LargeData.class).registerWriteHandler( + horizontalCellStyleStrategy).build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + for (int j = 0; j < 100; j++) { + excelWriter.write(data(), writeSheet); + LOGGER.info("{} fill success.", j); + } + excelWriter.finish(); + + } + + @Test + public void test2() throws Exception { + // 方法2 如果写到不同的sheet 同一个对象 + String fileName = TestFileUtil.getPath() + "large" + System.currentTimeMillis() + ".xlsx"; + + ExcelWriter excelWriter = EasyExcel.write(fileName, LargeData.class).build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + for (int j = 0; j < 100; j++) { + excelWriter.write(data(), writeSheet); + LOGGER.info("{} fill success.", j); + } + excelWriter.finish(); + + } + + private List> data() { + List> list = new ArrayList<>(); + + for (int j = 0; j < 10000; j++) { + List oneRow = new ArrayList<>(); + for (int i = 0; i < 150; i++) { + oneRow.add("这是测试字段" + i); + } + list.add(oneRow); + } + + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/WriteV33Test.java b/src/test/java/com/alibaba/easyexcel/test/temp/WriteV33Test.java new file mode 100644 index 00000000..f8db7f9c --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/WriteV33Test.java @@ -0,0 +1,67 @@ +package com.alibaba.easyexcel.test.temp; + +import java.io.File; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.poi.hssf.util.CellReference; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.demo.write.DemoData; +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; +import com.alibaba.fastjson.JSON; + +/** + * 临时测试 + * + * @author Jiaju Zhuang + **/ +@Ignore +public class WriteV33Test { + + private static final Logger LOGGER = LoggerFactory.getLogger(WriteV33Test.class); + + @Test + public void test() throws Exception { + // 方法2 如果写到不同的sheet 同一个对象 + String fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx"; + OnceAbsoluteMergeStrategy onceAbsoluteMergeStrategy = new OnceAbsoluteMergeStrategy(2, 2, 0, 1); + + // 这里 指定文件 + ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).registerWriteHandler(onceAbsoluteMergeStrategy).build(); + WriteSheet writeSheet1 = EasyExcel.writerSheet(1, "模板1").build(); + WriteSheet writeSheet2 = EasyExcel.writerSheet(2, "模板2").build(); + WriteSheet writeSheet3 = EasyExcel.writerSheet(3, "模板3").build(); + excelWriter.write(data(2), writeSheet2); + excelWriter.write(data(3), writeSheet3); + excelWriter.write(data(1), writeSheet1); + excelWriter.write(data(3), writeSheet3); + excelWriter.write(data(1), writeSheet1); + /// 千万别忘记finish 会帮忙关闭流 + excelWriter.finish(); + } + + private List data(int no) { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + DemoData data = new DemoData(); + data.setString("字符串" + no + "---" + i); + list.add(data); + } + return list; + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/WriteV34Test.java b/src/test/java/com/alibaba/easyexcel/test/temp/WriteV34Test.java new file mode 100644 index 00000000..cf815292 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/WriteV34Test.java @@ -0,0 +1,91 @@ +package com.alibaba.easyexcel.test.temp; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.demo.write.DemoData; +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; + +/** + * 临时测试 + * + * @author Jiaju Zhuang + **/ +@Ignore +public class WriteV34Test { + + private static final Logger LOGGER = LoggerFactory.getLogger(WriteV34Test.class); + + @Test + public void test() throws Exception { + String fileName = TestFileUtil.getPath() + "handlerStyleWrite" + System.currentTimeMillis() + ".xlsx"; + // 头的策略 + WriteCellStyle headWriteCellStyle = new WriteCellStyle(); + // 背景设置为红色 + headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex()); + WriteFont headWriteFont = new WriteFont(); + headWriteFont.setFontHeightInPoints((short)20); + headWriteCellStyle.setWriteFont(headWriteFont); + // 内容的策略 + WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); + // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定 + contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); + // 背景绿色 + contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex()); + WriteFont contentWriteFont = new WriteFont(); + // 字体大小 + contentWriteFont.setFontHeightInPoints((short)20); + contentWriteCellStyle.setWriteFont(contentWriteFont); + // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现 + HorizontalCellStyleStrategy horizontalCellStyleStrategy = + new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle); + + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName,DemoData.class).head(head()).registerWriteHandler(horizontalCellStyleStrategy).sheet("模板") + .doWrite(data(1)); + } + + + private List> head() { + List> list = new ArrayList>(); + List head0 = new ArrayList(); + head0.add("字符串" + System.currentTimeMillis()); + head0.add("再找找"); + List head1 = new ArrayList(); + head1.add("数字" + System.currentTimeMillis()); + List head2 = new ArrayList(); + head2.add("日期" + System.currentTimeMillis()); + List head3 = new ArrayList(); + head3.add("日期" + System.currentTimeMillis()); + list.add(head0); + list.add(head1); + list.add(head2); list.add(head3); + + + return list; + } + + private List data(int no) { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + DemoData data = new DemoData(); + data.setString("字符串" + no + "---" + i); + list.add(data); + } + return list; + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/Xls03Test.java b/src/test/java/com/alibaba/easyexcel/test/temp/Xls03Test.java index c4331b1e..e5d7dfc3 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/Xls03Test.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/Xls03Test.java @@ -2,14 +2,15 @@ package com.alibaba.easyexcel.test.temp; import java.util.List; +import com.alibaba.excel.EasyExcel; +import com.alibaba.fastjson.JSON; + +import net.sf.cglib.core.DebuggingClassWriter; import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import com.alibaba.excel.EasyExcel; -import com.alibaba.excel.EasyExcel; -import com.alibaba.fastjson.JSON; +import org.springframework.cglib.beans.BeanMap; /** * 临时测试 @@ -27,4 +28,24 @@ public class Xls03Test { LOGGER.info("返回数据:{}", JSON.toJSONString(data)); } } + + @Test + public void test2() { + System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); + System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, + "/Users/zhuangjiaju/IdeaProjects/easyexcel/target"); + + CamlData camlData = new CamlData(); + //camlData.setTest("test2"); + //camlData.setAEst("test3"); + //camlData.setTEST("test4"); + + BeanMap beanMap = BeanMap.create(camlData); + + LOGGER.info("test:{}", beanMap.get("test")); + LOGGER.info("test:{}", beanMap.get("Test")); + LOGGER.info("test:{}", beanMap.get("TEst")); + LOGGER.info("test:{}", beanMap.get("TEST")); + + } } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java index e165d987..53902240 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java @@ -44,7 +44,7 @@ public class DataFormatTest { EasyExcel.read(file, DataFormatData.class, null).sheet().headRowNumber(0).doReadSync(); LOGGER.info("数据:{}", list.size()); for (DataFormatData data : list) { - Integer dataFormat = data.getDate().getDataFormat(); + Short dataFormat = data.getDate().getDataFormat(); String dataFormatString = data.getDate().getDataFormatString(); @@ -67,7 +67,7 @@ public class DataFormatTest { EasyExcel.read(file, DataFormatData.class, null).sheet().headRowNumber(0).doReadSync(); LOGGER.info("数据:{}", list.size()); for (DataFormatData data : list) { - Integer dataFormat = data.getDate().getDataFormat(); + Short dataFormat = data.getDate().getDataFormat(); String dataFormatString = data.getDate().getDataFormatString(); diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/large/NoModelLargeDataListener.java b/src/test/java/com/alibaba/easyexcel/test/temp/large/NoModelLargeDataListener.java new file mode 100644 index 00000000..715dc4f4 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/large/NoModelLargeDataListener.java @@ -0,0 +1,36 @@ +package com.alibaba.easyexcel.test.temp.large; + +import java.util.Map; + +import org.apache.poi.ss.formula.functions.Index; +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 NoModelLargeDataListener extends AnalysisEventListener> { + + private static final Logger LOGGER = LoggerFactory.getLogger(NoModelLargeDataListener.class); + private int count = 0; + + @Override + public void invoke(Map data, AnalysisContext context) { + if (count == 0) { + LOGGER.info("First row:{}", JSON.toJSONString(data)); + } + count++; + if (count % 100000 == 0) { + LOGGER.info("Already read:{}", count); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + LOGGER.info("Large row count:{}", count); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/large/TempLargeDataTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/large/TempLargeDataTest.java index 6d142333..7f4a6717 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/large/TempLargeDataTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/large/TempLargeDataTest.java @@ -1,21 +1,25 @@ package com.alibaba.easyexcel.test.temp.large; +import java.io.File; import java.io.FileInputStream; +import java.lang.reflect.Field; +import com.alibaba.easyexcel.test.core.large.LargeDataTest; +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; + +import org.apache.poi.openxml4j.util.ZipSecureFile; import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.alibaba.easyexcel.test.core.large.LargeDataTest; -import com.alibaba.excel.EasyExcel; - /** - * * @author Jiaju Zhuang */ @Ignore public class TempLargeDataTest { + private static final Logger LOGGER = LoggerFactory.getLogger(LargeDataTest.class); @Test @@ -25,4 +29,27 @@ public class TempLargeDataTest { .headRowNumber(2).sheet().doRead(); LOGGER.info("Large data total time spent:{}", System.currentTimeMillis() - start); } + + @Test + public void noModelRead() throws Exception { + ZipSecureFile.setMaxEntrySize(Long.MAX_VALUE); + long start = System.currentTimeMillis(); + EasyExcel.read(TestFileUtil.readUserHomeFile("test/ld.xlsx"), new NoModelLargeDataListener()) + .sheet().doRead(); + LOGGER.info("Large data total time spent:{}", System.currentTimeMillis() - start); + } + + @Test + public void noModelRead2() throws Exception { + Field field = ZipSecureFile.class.getDeclaredField("MAX_ENTRY_SIZE"); + field.setAccessible(true); + field.set(null, Long.MAX_VALUE); + + long start = System.currentTimeMillis(); + EasyExcel.read( + new File("/Users/zhuangjiaju/IdeaProjects/easyexcel/target/test-classes/large1617887262709.xlsx"), + new NoModelLargeDataListener()) + .sheet().doRead(); + LOGGER.info("Large data total time spent:{}", System.currentTimeMillis() - start); + } } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/poi/TestCell.java b/src/test/java/com/alibaba/easyexcel/test/temp/poi/TestCell.java index 3c4e0ab6..bb12c220 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/poi/TestCell.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/poi/TestCell.java @@ -13,6 +13,6 @@ import lombok.Data; **/ @Data public class TestCell { - private CellData c1; + private CellData c1; private CellData> c2; } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/read/HeadListener.java b/src/test/java/com/alibaba/easyexcel/test/temp/read/HeadListener.java new file mode 100644 index 00000000..31875fe2 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/read/HeadListener.java @@ -0,0 +1,42 @@ +package com.alibaba.easyexcel.test.temp.read; + +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * 模板的读取类 + * + * @author Jiaju Zhuang + */ +public class HeadListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(HeadListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static final int BATCH_COUNT = 5; + + @Override + public void invokeHeadMap(Map headMap, AnalysisContext context) { + LOGGER.info("HEAD:{}", JSON.toJSONString(headMap)); + LOGGER.info("total:{}", context.readSheetHolder().getTotal()); + + } + + @Override + public void invoke(HeadReadData data, AnalysisContext context) { + LOGGER.info("index:{}", context.readRowHolder().getRowIndex()); + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + LOGGER.info("所有数据解析完成!"); + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadData.java b/src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadData.java index 538e2663..62d5e317 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadData.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadData.java @@ -11,10 +11,9 @@ import lombok.experimental.Accessors; * @author Jiaju Zhuang **/ @Data -@Accessors(chain = true) public class HeadReadData { - @ExcelProperty("头1") + @ExcelProperty({"主标题","数据1"}) private String h1; - @ExcelProperty({"头", "头2"}) + @ExcelProperty({"主标题", "数据2"}) private String h2; } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadTest.java index b046d143..40aa4b8f 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/read/HeadReadTest.java @@ -1,14 +1,18 @@ package com.alibaba.easyexcel.test.temp.read; import java.io.File; +import java.io.FileInputStream; import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; import com.alibaba.excel.cache.Ehcache; +import com.alibaba.excel.support.ExcelTypeEnum; /** * 临时测试 @@ -18,11 +22,18 @@ import com.alibaba.excel.cache.Ehcache; @Ignore public class HeadReadTest { private static final Logger LOGGER = LoggerFactory.getLogger(HeadReadTest.class); + @Test + public void testread() throws Exception { + FileInputStream fileInputStream = new FileInputStream("D://test/t1.xlsx"); + + ExcelReader excelReader = new ExcelReader(fileInputStream, ExcelTypeEnum.XLSX, null, new TestListener()); + excelReader.read(); + } @Test public void test() throws Exception { - File file = new File("D:\\test\\headt1.xls"); - EasyExcel.read(file, HeadReadData.class, new HDListener()).sheet(0).doRead(); + File file = TestFileUtil.readUserHomeFile("test/t2.xlsx"); + EasyExcel.read(file, HeadReadData.class, new HeadListener()).ignoreEmptyRow(false).sheet(0).doRead(); } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/read/TestListener.java b/src/test/java/com/alibaba/easyexcel/test/temp/read/TestListener.java new file mode 100644 index 00000000..fb80a9a4 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/read/TestListener.java @@ -0,0 +1,27 @@ +package com.alibaba.easyexcel.test.temp.read; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +import lombok.extern.slf4j.Slf4j; + +/** + * TODO + * + * @author JiaJu Zhuang + * @date 2020/4/9 16:33 + **/ +@Slf4j +public class TestListener extends AnalysisEventListener { + + @Override + public void invoke(Object o, AnalysisContext analysisContext) { + log.info("解析一条:{}", JSON.toJSONString(o)); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/DemoData1.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/DemoData1.java new file mode 100644 index 00000000..40b454ec --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/DemoData1.java @@ -0,0 +1,27 @@ +package com.alibaba.easyexcel.test.temp.simple; + +import java.util.Date; + +import org.apache.poi.ss.usermodel.FillPatternType; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.HeadStyle; + +import lombok.Data; + +@Data +public class DemoData1 { + @ExcelProperty("字符串标题") + @HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 42) + private String string; + @ExcelProperty("日期标题") + private Date date; + @ExcelProperty("数字标题") + private Double doubleData; + /** + * 忽略这个字段 + */ + @ExcelIgnore + private String ignore; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/DemoData2.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/DemoData2.java new file mode 100644 index 00000000..a57af8f7 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/DemoData2.java @@ -0,0 +1,27 @@ +package com.alibaba.easyexcel.test.temp.simple; + +import java.util.Date; + +import org.apache.poi.ss.usermodel.FillPatternType; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.HeadStyle; + +import lombok.Data; + +@Data +public class DemoData2 { + @ExcelProperty("字符串标题") + @HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 42) + private String string; + @ExcelProperty("日期标题") + private Date date; + @ExcelProperty("数字标题") + private Double doubleData; + /** + * 忽略这个字段 + */ + @ExcelIgnore + private String ignore; +} 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 61571812..98e77527 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 @@ -5,18 +5,21 @@ import java.util.Date; import java.util.List; import java.util.Map; -import org.junit.Ignore; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.alibaba.easyexcel.test.core.large.LargeData; import com.alibaba.easyexcel.test.demo.write.DemoData; import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.WriteTable; import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; import net.sf.cglib.beans.BeanMap; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * 测试poi @@ -24,6 +27,7 @@ import net.sf.cglib.beans.BeanMap; * @author Jiaju Zhuang **/ @Ignore +@Slf4j public class Wirte { private static final Logger LOGGER = LoggerFactory.getLogger(Wirte.class); @@ -40,6 +44,7 @@ public class Wirte { @Test public void simpleWrite() { + log.info("t5"); // 写法1 String fileName = TestFileUtil.getPath() + "t22" + System.currentTimeMillis() + ".xlsx"; // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 @@ -53,7 +58,18 @@ public class Wirte { String fileName = TestFileUtil.getPath() + "t22" + System.currentTimeMillis() + ".xlsx"; // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 // 如果这里想使用03 则 传入excelType参数即可 - EasyExcel.write(fileName, WriteData.class).sheet("模板").doWrite(data1()); + EasyExcel.write(fileName, WriteData.class).sheet("模板").registerWriteHandler(new WriteHandler()).doWrite( + data1()); + } + + @Test + public void simpleWrite3() { + // 写法1 + String fileName = TestFileUtil.getPath() + "t33" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 如果这里想使用03 则 传入excelType参数即可 + EasyExcel.write(fileName).head(head()).inMemory(true).sheet("模板").registerWriteHandler(new WriteCellHandler()).doWrite( + data1()); } @Test @@ -75,6 +91,23 @@ public class Wirte { } + @Test + public void tableWrite() { + String fileName = TestFileUtil.getPath() + "tableWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里直接写多个table的案例了,如果只有一个 也可以直一行代码搞定,参照其他案例 + // 这里 需要指定写用哪个class去写 + ExcelWriter excelWriter = EasyExcel.write(fileName).build(); + // 把sheet设置为不需要头 不然会输出sheet的头 这样看起来第一个table 就有2个头了 + WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); + // 这里必须指定需要头,table 会继承sheet的配置,sheet配置了不需要,table 默认也是不需要 + WriteTable writeTable0 = EasyExcel.writerTable(0).head(DemoData1.class).build(); + // 第一次写入会创建头 + excelWriter.write(data(), writeSheet, writeTable0); + // 第二次写如也会创建头,然后在第一次的后面写入数据 + /// 千万别忘记finish 会帮忙关闭流 + excelWriter.finish(); + } + private List> head() { List> list = new ArrayList>(); List head0 = new ArrayList(); @@ -105,7 +138,8 @@ public class Wirte { List list = new ArrayList(); for (int i = 0; i < 10; i++) { WriteData data = new WriteData(); - data.setF(300.35f); + data.setDd(new Date()); + data.setF1(33f); list.add(data); } return list; diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteCellHandler.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteCellHandler.java new file mode 100644 index 00000000..375cf636 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteCellHandler.java @@ -0,0 +1,40 @@ +package com.alibaba.easyexcel.test.temp.simple; + +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.AbstractCellWriteHandler; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; + +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.CreationHelper; +import org.apache.poi.ss.usermodel.DataFormat; +import org.apache.poi.ss.usermodel.IndexedColors; + +/** + * @author Jiaju Zhuang + */ +@Slf4j +public class WriteCellHandler implements CellWriteHandler { + + @Override + public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + CellData cellData, Cell cell, Head head, Integer integer, Boolean isHead) { + + if (!isHead) { + CreationHelper createHelper = writeSheetHolder.getSheet().getWorkbook().getCreationHelper(); + CellStyle cellStyle = writeSheetHolder.getSheet().getWorkbook().createCellStyle(); + if (cellStyle != null) { + DataFormat dataFormat = createHelper.createDataFormat(); + cellStyle.setWrapText(true); + cellStyle.setFillBackgroundColor(IndexedColors.RED.getIndex()); + cellStyle.setBottomBorderColor(IndexedColors.RED.getIndex()); + cellStyle.setDataFormat(dataFormat.getFormat("yyyy-MM-dd")); + cell.setCellStyle(cellStyle); + } + } + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteData.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteData.java index b8ff14d6..27967b9f 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteData.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteData.java @@ -1,5 +1,9 @@ package com.alibaba.easyexcel.test.temp.simple; +import java.util.Date; + +import com.alibaba.excel.annotation.write.style.ContentStyle; + import lombok.Data; /** @@ -9,5 +13,8 @@ import lombok.Data; **/ @Data public class WriteData { - private float f; +// @ContentStyle(locked = true) + private Date dd; +// @ContentStyle(locked = false) + private float f1; } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteHandler.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteHandler.java new file mode 100644 index 00000000..a82543eb --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteHandler.java @@ -0,0 +1,22 @@ +package com.alibaba.easyexcel.test.temp.simple; + +import com.alibaba.excel.write.handler.AbstractSheetWriteHandler; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; + +import lombok.extern.slf4j.Slf4j; + +/** + * @author Jiaju Zhuang + */ +@Slf4j +public class WriteHandler implements SheetWriteHandler { + + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, + WriteSheetHolder writeSheetHolder) { + log.info("锁住"); + writeSheetHolder.getSheet().protectSheet("edit"); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/util/TestFileUtil.java b/src/test/java/com/alibaba/easyexcel/test/util/TestFileUtil.java index 2031e70a..d4665b44 100644 --- a/src/test/java/com/alibaba/easyexcel/test/util/TestFileUtil.java +++ b/src/test/java/com/alibaba/easyexcel/test/util/TestFileUtil.java @@ -5,6 +5,7 @@ import java.io.InputStream; public class TestFileUtil { + public static InputStream getResourcesFileInputStream(String fileName) { return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); } @@ -29,4 +30,7 @@ public class TestFileUtil { return new File(getPath() + pathName); } + public static File readUserHomeFile(String pathName) { + return new File(System.getProperty("user.home") + File.separator + pathName); + } } diff --git a/update.md b/update.md index 43dd5607..09ca62ac 100644 --- a/update.md +++ b/update.md @@ -1,6 +1,67 @@ -# 2.2.0-beta1 +# 3.0.0-beta1 +* 升级jdk8 不再支持jdk6 jdk7 +* 升级poi 到 4.1.2 +* 升级cglib 到 3.3.0 +* 升级ehcache 到 3.8.1 +* 支持非驼峰的字段读写 +* 修复`CellData`可能不返回行列号 [Issue #1832](https://github.com/alibaba/easyexcel/issues/1832) +* 优化读取性能 +* 修复部分情况下不抛出异常 +* 07版在导出的时候会导出 行数 [Issue #1282](https://github.com/alibaba/easyexcel/issues/1282) +* 修复没有样式的情况下空指针异常 [Issue #1738](https://github.com/alibaba/easyexcel/issues/1738) +* 修改异常抛出逻辑 [Issue #1618](https://github.com/alibaba/easyexcel/issues/1618) +* 兼容一些非官方excel的情况 [Issue #1527](https://github.com/alibaba/easyexcel/issues/1527) +* 修改读的关闭流无效 [Issue #1840](https://github.com/alibaba/easyexcel/issues/1840) +* 写入支持Collection [Issue #1834](https://github.com/alibaba/easyexcel/issues/1834) + + +# 2.2.8 +* 兼容07在特殊的excel的情况下,读取数据异常 + +# 2.2.7 +* 修改07在特殊情况下用`String`接收数字会丢小数位的bug + +# 2.2.6 +* 修改跳着读取03版本空指针bug + +# 2.2.5 +* `ExcelProperty`新增`order` 用于排序 +* 修复导出指定`index`会导致空行的bug + +# 2.2.4 +* 撤销删除`AbstractMergeStrategy` +* 修改默认用String读取数字不使用科学计数法 通过`useScientificFormat`修改 +* 修复07版仅有样式的空行 默认不忽略的bug +* 写入`sheet`不设置`index`和`name`默认不为0的问题 +* 修复多个`sheet`不按照顺序写入 会乱序的bug [Issue #1332](https://github.com/alibaba/easyexcel/issues/1332) +* 修改head是List时,内容单元格的样式不生效 [Issue #1339](https://github.com/alibaba/easyexcel/issues/1339) +* 修复xls仅公式行 不读取的bug [Issue #1324](https://github.com/alibaba/easyexcel/issues/1324) +* 修复xls直接读取第2页 `NPE` 的bug [Issue #1280](https://github.com/alibaba/easyexcel/issues/1280) +* 修复填充的时候,最后一行中间有空行会创建失败的bug +* 修复`includeColumnIndexes`不包含第列 会无法导出数据的bug [Issue #1346](https://github.com/alibaba/easyexcel/issues/1346) +* 修复`@NumberFormat`注解转换double时可能会丢失精度 [Issue #1306](https://github.com/alibaba/easyexcel/issues/1306) + +# 2.2.3 +* 修改填充数据空数据的bug [Issue #1274](https://github.com/alibaba/easyexcel/issues/1274) +* 回退自定义转换器入参为空 + +# 2.2.2 +* 修改`sheet`事件未调用的bug +* 修复复杂表头不是`index=0`开始 合并异常的bug [Issue #1322](https://github.com/alibaba/easyexcel/issues/1322) + +# 2.2.1 +* 发布正式版 +* 修复第一行为空不会调用`invokeHeadMap`的bug [Issue #993](https://github.com/alibaba/easyexcel/issues/993) +* 当类的属性没有按照ExcelProperty的属性index顺序排序的时候,写数据出现错乱 [Issue #1046](https://github.com/alibaba/easyexcel/issues/1046) +* 新增支持自定义转换器 入参可以为空 实现`NullableObjectConverter` 即可 [Issue #1084](https://github.com/alibaba/easyexcel/issues/1084) +* 修复xls丢失结束标记的情况下 会漏读最后一行 +* 修复填充的时候 多次`forceNewRow` 空指针的bug [Issue #1201](https://github.com/alibaba/easyexcel/issues/1201) +* 修复`table`、`sheet`中创建的拦截器不执行`workbook`事件的bug [Issue #1202](https://github.com/alibaba/easyexcel/issues/1202) + +# 2.2.0-beta2 * 修复最长匹配策略不同表格会有影响的bug [Issue #1010](https://github.com/alibaba/easyexcel/issues/1010) * `LinkedList`写入的性能问题 #1121 +* 修复在某些情况下可能出现不必要的`warn`日志 # 2.2.0-beta1 * 重写主流程,代码更加优雅 @@ -19,6 +80,9 @@ * 修复读取转换器的并发问题 * 填充支持多个List对象 +# 2.1.7 +* 修复使用1+版本的写法,第1条开始读修改为第0条开始读 + # 2.1.6 * 修复写入只有`sheetName`会抛异常