Browse Source

Merge pull request #507 from alibaba/v2.0

V2.0
pull/561/head
Jiaju Zhuang 5 years ago committed by GitHub
parent
commit
cb76ddea61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      .editorconfig
  2. 1
      .mvn/jvm.config
  3. BIN
      .mvn/wrapper/maven-wrapper.jar
  4. 2
      .mvn/wrapper/maven-wrapper.properties
  5. 10
      .travis.yml
  6. 193
      README.md
  7. BIN
      img/WechatIMG8.png
  8. BIN
      img/readme/quickstart/read/demo.png
  9. BIN
      img/readme/quickstart/write/complexHeadWrite.png
  10. BIN
      img/readme/quickstart/write/converterWrite.png
  11. BIN
      img/readme/quickstart/write/customHandlerWrite.png
  12. BIN
      img/readme/quickstart/write/dynamicHeadWrite.png
  13. BIN
      img/readme/quickstart/write/imageWrite.png
  14. BIN
      img/readme/quickstart/write/indexWrite.png
  15. BIN
      img/readme/quickstart/write/longestMatchColumnWidthWrite.png
  16. BIN
      img/readme/quickstart/write/mergeWrite.png
  17. BIN
      img/readme/quickstart/write/repeatedWrite.png
  18. BIN
      img/readme/quickstart/write/simpleWrite.png
  19. BIN
      img/readme/quickstart/write/styleWrite.png
  20. BIN
      img/readme/quickstart/write/tableWrite.png
  21. BIN
      img/readme/quickstart/write/templateWrite.png
  22. BIN
      img/readme/quickstart/write/widthAndHeightWrite.png
  23. BIN
      img/readme/wechat.png
  24. BIN
      img/style/eclipse/step.jpg
  25. BIN
      img/style/idea/step1.png
  26. BIN
      img/style/idea/step2.png
  27. BIN
      img/style/idea/step3.png
  28. 305
      mvnw
  29. 172
      mvnw.cmd
  30. 106
      pom.xml
  31. 1135
      quickstart.md
  32. 8
      src/main/java/com/alibaba/excel/EasyExcel.java
  33. 508
      src/main/java/com/alibaba/excel/EasyExcelFactory.java
  34. 256
      src/main/java/com/alibaba/excel/ExcelReader.java
  35. 297
      src/main/java/com/alibaba/excel/ExcelWriter.java
  36. 87
      src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java
  37. 28
      src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java
  38. 166
      src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
  39. 26
      src/main/java/com/alibaba/excel/analysis/ExcelExecutor.java
  40. 33
      src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java
  41. 61
      src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java
  42. 381
      src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java
  43. 47
      src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java
  44. 76
      src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java
  45. 114
      src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java
  46. 37
      src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java
  47. 38
      src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java
  48. 38
      src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java
  49. 46
      src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java
  50. 39
      src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java
  51. 49
      src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java
  52. 51
      src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java
  53. 37
      src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java
  54. 27
      src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java
  55. 131
      src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java
  56. 31
      src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java
  57. 236
      src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java
  58. 42
      src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java
  59. 182
      src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java
  60. 41
      src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java
  61. 34
      src/main/java/com/alibaba/excel/annotation/ExcelColumnNum.java
  62. 17
      src/main/java/com/alibaba/excel/annotation/ExcelIgnore.java
  63. 53
      src/main/java/com/alibaba/excel/annotation/ExcelProperty.java
  64. 11
      src/main/java/com/alibaba/excel/annotation/FieldType.java
  65. 38
      src/main/java/com/alibaba/excel/annotation/format/DateTimeFormat.java
  66. 39
      src/main/java/com/alibaba/excel/annotation/format/NumberFormat.java
  67. 27
      src/main/java/com/alibaba/excel/annotation/write/style/ColumnWidth.java
  68. 27
      src/main/java/com/alibaba/excel/annotation/write/style/ContentRowHeight.java
  69. 26
      src/main/java/com/alibaba/excel/annotation/write/style/HeadRowHeight.java
  70. 213
      src/main/java/com/alibaba/excel/cache/Ehcache.java
  71. 40
      src/main/java/com/alibaba/excel/cache/MapCache.java
  72. 47
      src/main/java/com/alibaba/excel/cache/ReadCache.java
  73. 12
      src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java
  74. 135
      src/main/java/com/alibaba/excel/context/AnalysisContext.java
  75. 241
      src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java
  76. 308
      src/main/java/com/alibaba/excel/context/WriteContext.java
  77. 398
      src/main/java/com/alibaba/excel/context/WriteContextImpl.java
  78. 36
      src/main/java/com/alibaba/excel/converters/AutoConverter.java
  79. 61
      src/main/java/com/alibaba/excel/converters/Converter.java
  80. 40
      src/main/java/com/alibaba/excel/converters/ConverterKeyBuild.java
  81. 146
      src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java
  82. 46
      src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalBooleanConverter.java
  83. 39
      src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalNumberConverter.java
  84. 41
      src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalStringConverter.java
  85. 38
      src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanBooleanConverter.java
  86. 47
      src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanNumberConverter.java
  87. 38
      src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanStringConverter.java
  88. 41
      src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java
  89. 37
      src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java
  90. 46
      src/main/java/com/alibaba/excel/converters/byteconverter/ByteBooleanConverter.java
  91. 38
      src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java
  92. 41
      src/main/java/com/alibaba/excel/converters/byteconverter/ByteStringConverter.java
  93. 46
      src/main/java/com/alibaba/excel/converters/date/DateNumberConverter.java
  94. 49
      src/main/java/com/alibaba/excel/converters/date/DateStringConverter.java
  95. 46
      src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleBooleanConverter.java
  96. 38
      src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleNumberConverter.java
  97. 40
      src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleStringConverter.java
  98. 41
      src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java
  99. 46
      src/main/java/com/alibaba/excel/converters/floatconverter/FloatBooleanConverter.java
  100. 38
      src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java
  101. Some files were not shown because too many files have changed in this diff Show More

15
.editorconfig

@ -0,0 +1,15 @@
root = true
[*.{groovy, java, kt, xml}]
#缩进风格:空格
indent_style = space
#缩进大小
indent_size = 4
#换行符lf
end_of_line = lf
#字符集utf-8
charset = utf-8
#是否删除行尾的空格
trim_trailing_whitespace = true
#是否在文件的最后插入一个空行
insert_final_newline = true

1
.mvn/jvm.config

@ -0,0 +1 @@
-Xmx1536m

BIN
.mvn/wrapper/maven-wrapper.jar vendored

Binary file not shown.

2
.mvn/wrapper/maven-wrapper.properties vendored

@ -0,0 +1,2 @@
distributionUrl=https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar

10
.travis.yml

@ -0,0 +1,10 @@
language: java
jdk: openjdk8
cache:
directories:
- $HOME/.m2
before_install:
- chmod +x mvnw
install:
- ./mvnw install -Dgpg.skip -B -V -Dmaven.test.skip=true
- ./mvnw javadoc:javadoc

193
README.md

@ -1,150 +1,89 @@
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)
# JAVA解析Excel工具easyexcel # JAVA解析Excel工具easyexcel
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到KB级别,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便 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模式。在上层做了模型转换的封装,让使用者更加简单方便
## 相关文档 ## 相关文档
* [关于软件](/abouteasyexcel.md)
* [快速使用](/quickstart.md) * [快速使用](/quickstart.md)
* [关于软件](/abouteasyexcel.md)
* [常见问题](/problem.md) * [常见问题](/problem.md)
* [更新记事](/update.md) * [更新记事](/update.md)
* [English-README](/easyexcel_en.md) * [English-README](/easyexcel_en.md)
## 二方包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>{latestVersion}</version>
</dependency>
## 最新版本:1.1.2-beta4
## 维护者 ## 维护者
姬朋飞(玉霄) 姬朋飞(玉霄)
## 快速开始 ## 快速开始
### 读Excel ### 读Excel
测试代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/ReadTest.java](/src/test/java/com/alibaba/easyexcel/test/ReadTest.java) DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/demo/read/ReadTest.java](/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java)
读07版小于1000行数据返回List<List<String>> ```java
``` /**
List<Object> data = EasyExcelFactory.read(inputStream, new Sheet(1, 0)); * 最简单的读
``` * <p>1. 创建excel对应的实体对象 参照{@link DemoData}
读07版小于1000行数据返回List<? extend BaseRowModel> * <p>2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
``` * <p>3. 直接读即可
List<Object> data = EasyExcelFactory.read(inputStream, new Sheet(2, 1,JavaModel.class)); */
``` @Test
读07版大于1000行数据返回List<List<String>> public void simpleRead() {
``` String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
ExcelListener excelListener = new ExcelListener(); // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
EasyExcelFactory.readBySax(inputStream, new Sheet(1, 1), excelListener); EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
}
``` ```
读07版大于1000行数据返回List<? extend BaseRowModel>
```
ExcelListener excelListener = new ExcelListener();
EasyExcelFactory.readBySax(inputStream, new Sheet(2, 1,JavaModel.class), excelListener);
```
读03版方法同上
### 写Excel ### 写Excel
测试代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/WriteTest.java](/src/test/java/com/alibaba/easyexcel/test/WriteTest.java) DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java](/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java)
没有模板 ```java
```OutputStream out = new FileOutputStream("/Users/jipengfei/2007.xlsx"); /**
ExcelWriter writer = EasyExcelFactory.getWriter(out); * 最简单的写
* <p>1. 创建excel对应的实体对象 参照{@link com.alibaba.easyexcel.test.demo.write.DemoData}
//写第一个sheet, sheet1 数据全是List<String> 无模型映射关系 * <p>2. 直接写即可
Sheet sheet1 = new Sheet(1, 3); */
sheet1.setSheetName("第一个sheet"); @Test
//设置列宽 设置每列的宽度 public void simpleWrite() {
Map columnWidth = new HashMap(); String fileName = TestFileUtil.getPath() + "write" + System.currentTimeMillis() + ".xlsx";
columnWidth.put(0,10000);columnWidth.put(1,40000);columnWidth.put(2,10000);columnWidth.put(3,10000); // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
sheet1.setColumnWidthMap(columnWidth); // 如果这里想使用03 则 传入excelType参数即可
sheet1.setHead(createTestListStringHead()); EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
//or 设置自适应宽度 }
//sheet1.setAutoWidth(Boolean.TRUE);
writer.write1(createTestListObject(), sheet1);
//写第二个sheet sheet2 模型上打有表头的注解,合并单元格
Sheet sheet2 = new Sheet(2, 3, JavaModel1.class, "第二个sheet", null);
sheet2.setTableStyle(createTableStyle());
writer.write(createTestListJavaMode(), sheet2);
//写第三个sheet包含多个table情况
Sheet sheet3 = new Sheet(3, 0);
sheet3.setSheetName("第三个sheet");
Table table1 = new Table(1);
table1.setHead(createTestListStringHead());
writer.write1(createTestListObject(), sheet3, table1);
//写sheet2 模型上打有表头的注解
Table table2 = new Table(2);
table2.setTableStyle(createTableStyle());
table2.setClazz(JavaModel1.class);
writer.write(createTestListJavaMode(), sheet3, table2);
//关闭资源
writer.finish();
out.close();
```
有模板
```InputStream inputStream = new BufferedInputStream(new FileInputStream("/Users/jipengfei/temp.xlsx"));
OutputStream out = new FileOutputStream("/Users/jipengfei/2007.xlsx");
ExcelWriter writer = EasyExcelFactory.getWriterWithTemp(inputStream,out,ExcelTypeEnum.XLSX,true);
//写第一个sheet, sheet1 数据全是List<String> 无模型映射关系
Sheet sheet1 = new Sheet(1, 3);
sheet1.setSheetName("第一个sheet");
//设置列宽 设置每列的宽度
Map columnWidth = new HashMap();
columnWidth.put(0,10000);columnWidth.put(1,40000);columnWidth.put(2,10000);columnWidth.put(3,10000);
sheet1.setColumnWidthMap(columnWidth);
sheet1.setHead(createTestListStringHead());
//or 设置自适应宽度
//sheet1.setAutoWidth(Boolean.TRUE);
writer.write1(createTestListObject(), sheet1);
//写第二个sheet sheet2 模型上打有表头的注解,合并单元格
Sheet sheet2 = new Sheet(2, 3, JavaModel1.class, "第二个sheet", null);
sheet2.setTableStyle(createTableStyle());
writer.write(createTestListJavaMode(), sheet2);
//写第三个sheet包含多个table情况
Sheet sheet3 = new Sheet(3, 0);
sheet3.setSheetName("第三个sheet");
Table table1 = new Table(1);
table1.setHead(createTestListStringHead());
writer.write1(createTestListObject(), sheet3, table1);
//写sheet2 模型上打有表头的注解
Table table2 = new Table(2);
table2.setTableStyle(createTableStyle());
table2.setClazz(JavaModel1.class);
writer.write(createTestListJavaMode(), sheet3, table2);
//关闭资源
writer.finish();
out.close();
``` ```
### web下载实例写法 ### 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)
public class Down { ```java
@GetMapping("/a.htm") /**
public void cooperation(HttpServletRequest request, HttpServletResponse response) { * 文件下载
ServletOutputStream out = response.getOutputStream(); * <p>1. 创建excel对应的实体对象 参照{@link DownloadData}
response.setContentType("multipart/form-data"); * <p>2. 设置返回的 参数
* <p>3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
*/
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename="+fileName+".xlsx"); response.setHeader("Content-disposition", "attachment;filename=demo.xlsx");
ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX, true); EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
String fileName = new String(("UserInfo " + new SimpleDateFormat("yyyy-MM-dd").format(new Date())) }
.getBytes(), "UTF-8");
Sheet sheet1 = new Sheet(1, 0); /**
sheet1.setSheetName("第一个sheet"); * 文件上传
writer.write0(getListString(), sheet1); * <p>1. 创建excel对应的实体对象 参照{@link UploadData}
writer.finish(); * <p>2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener}
* <p>3. 直接读即可
out.flush(); */
} @PostMapping("upload")
@ResponseBody
public String upload(MultipartFile file) throws IOException {
EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener()).sheet().doRead();
return "success";
} }
}
``` ```
### 联系我们 ### 联系我们
有问题阿里同事可以通过钉钉找到我,阿里外同学可以通过git留言。其他技术非技术相关的也欢迎一起探讨。 有问题阿里同事可以通过钉钉找到我,阿里外同学可以通过git留言。其他技术非技术相关的也欢迎一起探讨。
### 招聘&交流 ### 招聘&交流
阿里巴巴新零售事业部--诚招JAVA资深开发、技术专家。有意向可以微信联系,简历可以发我邮箱jipengfei.jpf@alibaba-inc.com 阿里巴巴新零售事业部--诚招JAVA资深开发、技术专家。有意向可以微信联系,简历可以发我邮箱jipengfei.jpf@alibaba-inc.com
或者加QQ群: 662022184

BIN
img/WechatIMG8.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

BIN
img/readme/quickstart/read/demo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
img/readme/quickstart/write/complexHeadWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
img/readme/quickstart/write/converterWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
img/readme/quickstart/write/customHandlerWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
img/readme/quickstart/write/dynamicHeadWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
img/readme/quickstart/write/imageWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
img/readme/quickstart/write/indexWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
img/readme/quickstart/write/longestMatchColumnWidthWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
img/readme/quickstart/write/mergeWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
img/readme/quickstart/write/repeatedWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
img/readme/quickstart/write/simpleWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
img/readme/quickstart/write/styleWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
img/readme/quickstart/write/tableWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
img/readme/quickstart/write/templateWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
img/readme/quickstart/write/widthAndHeightWrite.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
img/readme/wechat.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
img/style/eclipse/step.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
img/style/idea/step1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
img/style/idea/step2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
img/style/idea/step3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

305
mvnw vendored

@ -0,0 +1,305 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

172
mvnw.cmd vendored

@ -0,0 +1,172 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
echo Found %WRAPPER_JAR%
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar"
)
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
echo Finished downloading %WRAPPER_JAR%
)
@REM End of extension
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%

106
pom.xml

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId> <artifactId>easyexcel</artifactId>
<version>1.1.2-beta5</version> <version>2.0.0-beta1</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>easyexcel</name> <name>easyexcel</name>
@ -26,11 +26,11 @@
</scm> </scm>
<!--<repositories>--> <!--<repositories>-->
<!--<repository>--> <!--<repository>-->
<!--<id>local-file</id>--> <!--<id>local-file</id>-->
<!--<url>file://${basedir}/lib/</url>--> <!--<url>file://${basedir}/lib/</url>-->
<!--<layout>default</layout>--> <!--<layout>default</layout>-->
<!--</repository>--> <!--</repository>-->
<!--</repositories>--> <!--</repositories>-->
<organization> <organization>
@ -59,25 +59,65 @@
<dependency> <dependency>
<groupId>org.apache.poi</groupId> <groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId> <artifactId>poi</artifactId>
<version>3.17</version> <version>4.0.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.poi</groupId> <groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId> <artifactId>poi-ooxml</artifactId>
<version>3.17</version> <version>4.0.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>cglib</groupId> <groupId>cglib</groupId>
<artifactId>cglib</artifactId> <artifactId>cglib</artifactId>
<version>3.1</version> <version>3.1</version>
</dependency> </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.7.1</version>
</dependency>
<!--test-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>1.5.21.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.21.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.12</version> <version>4.12</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<distributionManagement> <distributionManagement>
<snapshotRepository> <snapshotRepository>
@ -92,6 +132,48 @@
<build> <build>
<plugins> <plugins>
<!-- 用pmd校验阿里的p3c规范 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.12.0</version>
<configuration>
<printFailingErrors>true</printFailingErrors>
<verbose>true</verbose>
<rulesets>
<ruleset>rulesets/java/ali-comment.xml</ruleset>
<ruleset>rulesets/java/ali-concurrent.xml</ruleset>
<ruleset>rulesets/java/ali-constant.xml</ruleset>
<ruleset>rulesets/java/ali-exception.xml</ruleset>
<ruleset>rulesets/java/ali-flowcontrol.xml</ruleset>
<ruleset>rulesets/java/ali-naming.xml</ruleset>
<ruleset>rulesets/java/ali-oop.xml</ruleset>
<ruleset>rulesets/java/ali-orm.xml</ruleset>
<ruleset>rulesets/java/ali-other.xml</ruleset>
<ruleset>rulesets/java/ali-set.xml</ruleset>
</rulesets>
<excludes>
<exclude>com/alibaba/excel/event/AnalysisEventListener.java</exclude>
</excludes>
</configuration>
<executions>
<!-- 绑定pmd:check到verify生命周期 -->
<execution>
<id>pmd-check-verify</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.alibaba.p3c</groupId>
<artifactId>p3c-pmd</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
@ -132,7 +214,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version> <version>3.1.0</version>
<executions> <executions>
<execution> <execution>
<id>attach-javadocs</id> <id>attach-javadocs</id>
@ -144,4 +226,4 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

1135
quickstart.md

File diff suppressed because it is too large Load Diff

8
src/main/java/com/alibaba/excel/EasyExcel.java

@ -0,0 +1,8 @@
package com.alibaba.excel;
/**
* This is actually {@link EasyExcelFactory}, and short names look better.
*
* @author jipengfei
*/
public class EasyExcel extends EasyExcelFactory {}

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

@ -1,19 +1,40 @@
package com.alibaba.excel; package com.alibaba.excel;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.event.WriteHandler; import com.alibaba.excel.event.WriteHandler;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import java.io.InputStream; import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import java.io.OutputStream; import com.alibaba.excel.write.builder.ExcelWriterTableBuilder;
import java.util.ArrayList;
import java.util.List;
/** /**
* Reader and writer factory class * Reader and writer factory class
* *
* <h1>Quick start</h1>
* <h2>Read</h2>
* <h3>Sample1</h3>
*
* <h3>Sample2</h3>
*
* <h2>Write</h2>
*
* <h3>Sample1</h3>
*
* <h3>Sample2</h3>
*
*
*
* @author jipengfei * @author jipengfei
*/ */
public class EasyExcelFactory { public class EasyExcelFactory {
@ -21,21 +42,24 @@ public class EasyExcelFactory {
/** /**
* Quickly read small filesno more than 10,000 lines. * Quickly read small filesno more than 10,000 lines.
* *
* @param in the POI filesystem that contains the Workbook stream. * @param in
* @param sheet read sheet. * the POI filesystem that contains the Workbook stream.
* @param sheet
* read sheet.
* @return analysis result. * @return analysis result.
* @deprecated please use 'EasyExcel.read(in).sheet(sheetNo).doReadSync();'
*/ */
@Deprecated
public static List<Object> read(InputStream in, Sheet sheet) { public static List<Object> read(InputStream in, Sheet sheet) {
final List<Object> rows = new ArrayList<Object>(); final List<Object> rows = new ArrayList<Object>();
new ExcelReader(in, null, new AnalysisEventListener() { new ExcelReader(in, null, new AnalysisEventListener<Object>() {
@Override @Override
public void invoke(Object object, AnalysisContext context) { public void invoke(Object object, AnalysisContext context) {
rows.add(object); rows.add(object);
} }
@Override @Override
public void doAfterAllAnalysed(AnalysisContext context) { public void doAfterAllAnalysed(AnalysisContext context) {}
}
}, false).read(sheet); }, false).read(sheet);
return rows; return rows;
} }
@ -43,10 +67,15 @@ public class EasyExcelFactory {
/** /**
* Parsing large file * Parsing large file
* *
* @param in the POI filesystem that contains the Workbook stream. * @param in
* @param sheet read sheet. * the POI filesystem that contains the Workbook stream.
* @param listener Callback method after each row is parsed. * @param sheet
* read sheet.
* @param listener
* Callback method after each row is parsed.
* @deprecated please use 'EasyExcel.read(in,head,listener).sheet(sheetNo).doRead().finish();'
*/ */
@Deprecated
public static void readBySax(InputStream in, Sheet sheet, AnalysisEventListener listener) { public static void readBySax(InputStream in, Sheet sheet, AnalysisEventListener listener) {
new ExcelReader(in, null, listener).read(sheet); new ExcelReader(in, null, listener).read(sheet);
} }
@ -54,10 +83,14 @@ public class EasyExcelFactory {
/** /**
* Get ExcelReader. * Get ExcelReader.
* *
* @param in the POI filesystem that contains the Workbook stream. * @param in
* @param listener Callback method after each row is parsed. * the POI filesystem that contains the Workbook stream.
* @param listener
* Callback method after each row is parsed.
* @return ExcelReader. * @return ExcelReader.
* @deprecated please use {@link EasyExcel#read()} build 'ExcelReader'
*/ */
@Deprecated
public static ExcelReader getReader(InputStream in, AnalysisEventListener listener) { public static ExcelReader getReader(InputStream in, AnalysisEventListener listener) {
return new ExcelReader(in, null, listener); return new ExcelReader(in, null, listener);
} }
@ -65,56 +98,449 @@ public class EasyExcelFactory {
/** /**
* Get ExcelWriter * Get ExcelWriter
* *
* @param outputStream the java OutputStream you wish to write the data to. * @param outputStream
* the java OutputStream you wish to write the value to.
* @return new ExcelWriter. * @return new ExcelWriter.
* @deprecated please use {@link EasyExcel#write()}
*/ */
@Deprecated
public static ExcelWriter getWriter(OutputStream outputStream) { public static ExcelWriter getWriter(OutputStream outputStream) {
return new ExcelWriter(outputStream, ExcelTypeEnum.XLSX, true); return write().file(outputStream).autoCloseStream(Boolean.FALSE).convertAllFiled(Boolean.FALSE).build();
} }
/** /**
* Get ExcelWriter * Get ExcelWriter
* *
* @param outputStream the java OutputStream you wish to write the data to. * @param outputStream
* @param typeEnum 03 or 07 * the java OutputStream you wish to write the value to.
* @param needHead Do you need to write the header to the file? * @param typeEnum
* @return new ExcelWriter * 03 or 07
* @param needHead
* Do you need to write the header to the file?
* @return new ExcelWriter
* @deprecated please use {@link EasyExcel#write()}
*/ */
@Deprecated
public static ExcelWriter getWriter(OutputStream outputStream, ExcelTypeEnum typeEnum, boolean needHead) { public static ExcelWriter getWriter(OutputStream outputStream, ExcelTypeEnum typeEnum, boolean needHead) {
return new ExcelWriter(outputStream, typeEnum, needHead); return write().file(outputStream).excelType(typeEnum).needHead(needHead).autoCloseStream(Boolean.FALSE)
.convertAllFiled(Boolean.FALSE).build();
} }
/** /**
* Get ExcelWriter with a template file * Get ExcelWriter with a template file
* *
* @param temp Append data after a POI file , Can be nullthe template POI filesystem that contains the * @param temp
* Workbook stream) * Append value after a POI file , Can be nullthe template POI filesystem that contains the Workbook
* @param outputStream the java OutputStream you wish to write the data to * stream)
* @param typeEnum 03 or 07 * @param outputStream
* @return new ExcelWriter * the java OutputStream you wish to write the value to
* @param typeEnum
* 03 or 07
* @param needHead
* Whether a write header is required
* @return new ExcelWriter
* @deprecated please use {@link EasyExcel#write()}
*/ */
@Deprecated
public static ExcelWriter getWriterWithTemp(InputStream temp, OutputStream outputStream, ExcelTypeEnum typeEnum, public static ExcelWriter getWriterWithTemp(InputStream temp, OutputStream outputStream, ExcelTypeEnum typeEnum,
boolean needHead) { boolean needHead) {
return new ExcelWriter(temp, outputStream, typeEnum, needHead); return write().withTemplate(temp).file(outputStream).excelType(typeEnum).needHead(needHead)
.autoCloseStream(Boolean.FALSE).convertAllFiled(Boolean.FALSE).build();
} }
/** /**
* Get ExcelWriter with a template file * Get ExcelWriter with a template file
* *
* @param temp Append data after a POI file , Can be nullthe template POI filesystem that contains the * @param temp
* Workbook stream) * Append value after a POI file , Can be nullthe template POI filesystem that contains the Workbook
* @param outputStream the java OutputStream you wish to write the data to * stream)
* @param typeEnum 03 or 07 * @param outputStream
* the java OutputStream you wish to write the value to
* @param typeEnum
* 03 or 07
* @param needHead * @param needHead
* @param handler User-defined callback * Whether a write header is required
* @return new ExcelWriter * @param handler
* User-defined callback
* @return new ExcelWriter
* @deprecated please use {@link EasyExcel#write()}
*/
@Deprecated
public static ExcelWriter getWriterWithTempAndHandler(InputStream temp, OutputStream outputStream,
ExcelTypeEnum typeEnum, boolean needHead, WriteHandler handler) {
return write().withTemplate(temp).file(outputStream).excelType(typeEnum).needHead(needHead)
.registerWriteHandler(handler).autoCloseStream(Boolean.FALSE).convertAllFiled(Boolean.FALSE).build();
}
/**
* Build excel the write
*
* @return
*/
public static ExcelWriterBuilder write() {
return new ExcelWriterBuilder();
}
/**
* Build excel the write
*
* @param file
* File to write
* @return Excel writer builder
*/
public static ExcelWriterBuilder write(File file) {
return write(file, null);
}
/**
* Build excel the write
*
* @param file
* File to write
* @param head
* Annotate the class for configuration information
* @return Excel writer builder
*/
public static ExcelWriterBuilder write(File file, Class head) {
ExcelWriterBuilder excelWriterBuilder = new ExcelWriterBuilder();
excelWriterBuilder.file(file);
if (head != null) {
excelWriterBuilder.head(head);
}
return excelWriterBuilder;
}
/**
* Build excel the write
*
* @param pathName
* File path to write
* @return Excel writer builder
*/
public static ExcelWriterBuilder write(String pathName) {
return write(pathName, null);
}
/**
* Build excel the write
*
* @param pathName
* File path to write
* @param head
* Annotate the class for configuration information
* @return Excel writer builder
*/
public static ExcelWriterBuilder write(String pathName, Class head) {
ExcelWriterBuilder excelWriterBuilder = new ExcelWriterBuilder();
excelWriterBuilder.file(pathName);
if (head != null) {
excelWriterBuilder.head(head);
}
return excelWriterBuilder;
}
/**
* Build excel the write
*
* @param outputStream
* Output stream to write
* @return Excel writer builder
*/
public static ExcelWriterBuilder write(OutputStream outputStream) {
return write(outputStream, null);
}
/**
* Build excel the write
*
* @param outputStream
* Output stream to write
* @param head
* Annotate the class for configuration information.
* @return Excel writer builder
*/
public static ExcelWriterBuilder write(OutputStream outputStream, Class head) {
ExcelWriterBuilder excelWriterBuilder = new ExcelWriterBuilder();
excelWriterBuilder.file(outputStream);
if (head != null) {
excelWriterBuilder.head(head);
}
return excelWriterBuilder;
}
/**
* Build excel the <code>writerSheet</code>
*
* @return Excel sheet writer builder
*/
public static ExcelWriterSheetBuilder writerSheet() {
return writerSheet(null, null);
}
/**
* Build excel the <code>writerSheet</code>
*
* @param sheetNo
* Index of sheet,0 base.
* @return Excel sheet writer builder.
*/
public static ExcelWriterSheetBuilder writerSheet(Integer sheetNo) {
return writerSheet(sheetNo, null);
}
/**
* Build excel the 'writerSheet'
*
* @param sheetName
* The name of sheet.
* @return Excel sheet writer builder.
*/
public static ExcelWriterSheetBuilder writerSheet(String sheetName) {
return writerSheet(null, sheetName);
}
/**
* Build excel the 'writerSheet'
*
* @param sheetNo
* Index of sheet,0 base.
* @param sheetName
* The name of sheet.
* @return Excel sheet writer builder.
*/
public static ExcelWriterSheetBuilder writerSheet(Integer sheetNo, String sheetName) {
ExcelWriterSheetBuilder excelWriterSheetBuilder = new ExcelWriterSheetBuilder();
if (sheetNo != null) {
excelWriterSheetBuilder.sheetNo(sheetNo);
}
if (sheetName != null) {
excelWriterSheetBuilder.sheetName(sheetName);
}
return excelWriterSheetBuilder;
}
/**
* Build excel the <code>writerTable</code>
*
* @return Excel table writer builder.
*/
public static ExcelWriterTableBuilder writerTable() {
return writerTable(null);
}
/**
* Build excel the 'writerTable'
*
* @param tableNo
* Index of table,0 base.
* @return Excel table writer builder.
*/
public static ExcelWriterTableBuilder writerTable(Integer tableNo) {
ExcelWriterTableBuilder excelWriterTableBuilder = new ExcelWriterTableBuilder();
if (tableNo != null) {
excelWriterTableBuilder.tableNo(tableNo);
}
return excelWriterTableBuilder;
}
/**
* Build excel the read
*
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read() {
return new ExcelReaderBuilder();
}
/**
* Build excel the read
*
* @param file
* File to read.
* @return Excel reader builder.
*/ */
public static ExcelWriter getWriterWithTempAndHandler(InputStream temp, public static ExcelReaderBuilder read(File file) {
OutputStream outputStream, return read(file, null, null);
ExcelTypeEnum typeEnum,
boolean needHead,
WriteHandler handler) {
return new ExcelWriter(temp, outputStream, typeEnum, needHead, handler);
} }
/**
* Build excel the read
*
* @param file
* File to read.
* @param readListener
* Read listener.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(File file, ReadListener readListener) {
return read(file, null, readListener);
}
/**
* Build excel the read
*
* @param file
* File to read.
* @param head
* Annotate the class for configuration information.
* @param readListener
* Read listener.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(File file, Class head, ReadListener readListener) {
ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder();
excelReaderBuilder.file(file);
if (head != null) {
excelReaderBuilder.head(head);
}
if (readListener != null) {
excelReaderBuilder.registerReadListener(readListener);
}
return excelReaderBuilder;
}
/**
* Build excel the read
*
* @param pathName
* File path to read.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(String pathName) {
return read(pathName, null, null);
}
/**
* Build excel the read
*
* @param pathName
* File path to read.
* @param readListener
* Read listener.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(String pathName, ReadListener readListener) {
return read(pathName, null, readListener);
}
/**
* Build excel the read
*
* @param pathName
* File path to read.
* @param head
* Annotate the class for configuration information.
* @param readListener
* Read listener.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(String pathName, Class head, ReadListener readListener) {
ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder();
excelReaderBuilder.file(pathName);
if (head != null) {
excelReaderBuilder.head(head);
}
if (readListener != null) {
excelReaderBuilder.registerReadListener(readListener);
}
return excelReaderBuilder;
}
/**
* Build excel the read
*
* @param inputStream
* Input stream to read.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(InputStream inputStream) {
return read(inputStream, null, null);
}
/**
* Build excel the read
*
* @param inputStream
* Input stream to read.
* @param readListener
* Read listener.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(InputStream inputStream, ReadListener readListener) {
return read(inputStream, null, readListener);
}
/**
* Build excel the read
*
* @param inputStream
* Input stream to read.
* @param head
* Annotate the class for configuration information.
* @param readListener
* Read listener.
* @return Excel reader builder.
*/
public static ExcelReaderBuilder read(InputStream inputStream, Class head, ReadListener readListener) {
ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder();
excelReaderBuilder.file(inputStream);
if (head != null) {
excelReaderBuilder.head(head);
}
if (readListener != null) {
excelReaderBuilder.registerReadListener(readListener);
}
return excelReaderBuilder;
}
/**
* Build excel the 'readSheet'
*
* @return Excel sheet reader builder.
*/
public static ExcelReaderSheetBuilder readSheet() {
return readSheet(null, null);
}
/**
* Build excel the 'readSheet'
*
* @param sheetNo
* Index of sheet,0 base.
* @return Excel sheet reader builder.
*/
public static ExcelReaderSheetBuilder readSheet(Integer sheetNo) {
return readSheet(sheetNo, null);
}
/**
* Build excel the 'readSheet'
*
* @param sheetName
* The name of sheet.
* @return Excel sheet reader builder.
*/
public static ExcelReaderSheetBuilder readSheet(String sheetName) {
return readSheet(null, sheetName);
}
/**
* Build excel the 'readSheet'
*
* @param sheetNo
* Index of sheet,0 base.
* @param sheetName
* The name of sheet.
* @return Excel sheet reader builder.
*/
public static ExcelReaderSheetBuilder readSheet(Integer sheetNo, String sheetName) {
ExcelReaderSheetBuilder excelReaderSheetBuilder = new ExcelReaderSheetBuilder();
if (sheetNo != null) {
excelReaderSheetBuilder.sheetNo(sheetNo);
}
if (sheetName != null) {
excelReaderSheetBuilder.sheetName(sheetName);
}
return excelReaderSheetBuilder;
}
} }

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

@ -1,60 +1,84 @@
package com.alibaba.excel; package com.alibaba.excel;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.analysis.ExcelAnalyser; import com.alibaba.excel.analysis.ExcelAnalyser;
import com.alibaba.excel.analysis.ExcelAnalyserImpl; import com.alibaba.excel.analysis.ExcelAnalyserImpl;
import com.alibaba.excel.analysis.ExcelExecutor;
import com.alibaba.excel.cache.MapCache;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.BaseRowModel; import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.parameter.AnalysisParam; import com.alibaba.excel.parameter.AnalysisParam;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.ReadWorkbook;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import java.io.InputStream;
import java.util.List;
/** /**
* Excel readers are all read in event mode. * Excel readers are all read in event mode.
* *
* @author jipengfei * @author jipengfei
*/ */
public class ExcelReader { public class ExcelReader {
private static final Logger LOGGER = LoggerFactory.getLogger(ExcelReader.class);
/** /**
* Analyser * Analyser
*/ */
private ExcelAnalyser analyser ; private ExcelAnalyser excelAnalyser;
private boolean finished = false;
/** /**
* Create new reader * Create new reader
* *
* @param in the POI filesystem that contains the Workbook stream * @param in
* @param excelTypeEnum 03 or 07 * the POI filesystem that contains the Workbook stream
* @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext * @param excelTypeEnum
* @param eventListener Callback method after each row is parsed. * 03 or 07
* @param customContent
* {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext
* @param eventListener
* Callback method after each row is parsed.
* @deprecated please use {@link EasyExcelFactory#read()} build 'ExcelReader'
*/ */
@Deprecated @Deprecated
public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent, public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent,
AnalysisEventListener eventListener) { AnalysisEventListener eventListener) {
this(in, excelTypeEnum, customContent, eventListener, true); this(in, excelTypeEnum, customContent, eventListener, true);
} }
/** /**
* Create new reader * Create new reader
* *
* @param in the POI filesystem that contains the Workbook stream * @param in
* @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext * the POI filesystem that contains the Workbook stream
* @param eventListener Callback method after each row is parsed * @param customContent
* {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext
* @param eventListener
* Callback method after each row is parsed
* @deprecated please use {@link EasyExcelFactory#read()} build 'ExcelReader'
*/ */
public ExcelReader(InputStream in, Object customContent, @Deprecated
AnalysisEventListener eventListener) { public ExcelReader(InputStream in, Object customContent, AnalysisEventListener eventListener) {
this(in, customContent, eventListener, true); this(in, customContent, eventListener, true);
} }
/** /**
* Create new reader * Create new reader
* *
* @param param old param Deprecated * @param param
* @param eventListener Callback method after each row is parsed. * old param Deprecated
* @param eventListener
* Callback method after each row is parsed.
* @deprecated please use {@link EasyExcelFactory#read()} build 'ExcelReader'
*/ */
@Deprecated @Deprecated
public ExcelReader(AnalysisParam param, AnalysisEventListener eventListener) { public ExcelReader(AnalysisParam param, AnalysisEventListener eventListener) {
@ -64,86 +88,210 @@ public class ExcelReader {
/** /**
* Create new reader * Create new reader
* *
* @param in the POI filesystem that contains the Workbook stream * @param in
* @param excelTypeEnum 03 or 07 * @param customContent
* @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext * {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext
* @param eventListener Callback method after each row is parsed. * @param eventListener
* @param trim The content of the form is empty and needs to be empty. The purpose is to be fault-tolerant, * @param trim
* because there are often table contents with spaces that can not be converted into custom * The content of the form is empty and needs to be empty. The purpose is to be fault-tolerant, because
* types. For example: '1234 ' contain a space cannot be converted to int. * there are often table contents with spaces that can not be converted into custom types. For example:
* '1234 ' contain a space cannot be converted to int.
* @deprecated please use {@link EasyExcelFactory#read()} build 'ExcelReader'
*/ */
@Deprecated @Deprecated
public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent, public ExcelReader(InputStream in, Object customContent, AnalysisEventListener eventListener, boolean trim) {
AnalysisEventListener eventListener, boolean trim) { this(in, null, customContent, eventListener, trim);
validateParam(in, eventListener);
analyser = new ExcelAnalyserImpl(in, excelTypeEnum, customContent, eventListener, trim);
} }
/** /**
* Create new reader * Create new reader
* *
* @param in * @param in
* @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext * the POI filesystem that contains the Workbook stream
* @param excelTypeEnum
* 03 or 07
* @param customContent
* {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext
* @param eventListener * @param eventListener
* @param trim The content of the form is empty and needs to be empty. The purpose is to be fault-tolerant, * Callback method after each row is parsed.
* because there are often table contents with spaces that can not be converted into custom * @param trim
* types. For example: '1234 ' contain a space cannot be converted to int. * The content of the form is empty and needs to be empty. The purpose is to be fault-tolerant, because
* there are often table contents with spaces that can not be converted into custom types. For example:
* '1234 ' contain a space cannot be converted to int.
* @deprecated please use {@link EasyExcelFactory#read()} build 'ExcelReader'
*/ */
public ExcelReader(InputStream in, Object customContent, @Deprecated
AnalysisEventListener eventListener, boolean trim) { public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent,
ExcelTypeEnum excelTypeEnum = ExcelTypeEnum.valueOf(in); AnalysisEventListener eventListener, boolean trim) {
validateParam(in, eventListener); ReadWorkbook readWorkbook = new ReadWorkbook();
analyser =new ExcelAnalyserImpl(in, excelTypeEnum, customContent, eventListener, trim); readWorkbook.setInputStream(in);
readWorkbook.setExcelType(excelTypeEnum);
readWorkbook.setCustomObject(customContent);
if (eventListener != null) {
List<ReadListener> customReadListenerList = new ArrayList<ReadListener>();
customReadListenerList.add(eventListener);
readWorkbook.setCustomReadListenerList(customReadListenerList);
}
readWorkbook.setAutoTrim(trim);
readWorkbook.setAutoCloseStream(Boolean.FALSE);
readWorkbook.setMandatoryUseInputStream(Boolean.TRUE);
readWorkbook.setReadCache(new MapCache());
readWorkbook.setConvertAllFiled(Boolean.FALSE);
readWorkbook.setDefaultReturnMap(Boolean.FALSE);
excelAnalyser = new ExcelAnalyserImpl(readWorkbook);
}
public ExcelReader(ReadWorkbook readWorkbook) {
excelAnalyser = new ExcelAnalyserImpl(readWorkbook);
} }
/** /**
* Parse all sheet content by default * Parse all sheet content by default
*/ */
public void read() { public void read() {
analyser.analysis(); ExcelExecutor excelExecutor = excelAnalyser.excelExecutor();
if (excelExecutor.sheetList().isEmpty()) {
LOGGER.warn("Excel doesn't have any sheets.");
return;
}
for (ReadSheet readSheet : excelExecutor.sheetList()) {
read(readSheet);
}
}
/**
* Parse the specified sheetSheetNo start from 1
*
* @param readSheet
* Read sheet
*/
public ExcelReader read(ReadSheet readSheet) {
checkFinished();
excelAnalyser.analysis(readSheet);
return this;
} }
/** /**
* Parse the specified sheetSheetNo start from 1 * Parse the specified sheetSheetNo start from 1
* *
* @param sheet Read sheet * @param sheet
* Read sheet
* @deprecated please us {@link #read(ReadSheet)}
*/ */
@Deprecated
public void read(Sheet sheet) { public void read(Sheet sheet) {
analyser.analysis(sheet); ReadSheet readSheet = null;
if (sheet != null) {
readSheet = new ReadSheet();
readSheet.setSheetNo(sheet.getSheetNo() - 1);
readSheet.setSheetName(sheet.getSheetName());
readSheet.setClazz(sheet.getClazz());
readSheet.setHead(sheet.getHead());
readSheet.setHeadRowNumber(sheet.getHeadLineMun());
}
read(readSheet);
} }
/** /**
* Parse the specified sheet * Parse the specified sheet
* *
* @param sheet Read sheet * @param sheet
* @param clazz object parsed into each row of data * Read sheet
* @param clazz
* object parsed into each row of value
*
* @deprecated Set the class in the sheet before read
*/ */
@Deprecated @Deprecated
public void read(Sheet sheet, Class<? extends BaseRowModel> clazz) { public void read(Sheet sheet, Class clazz) {
sheet.setClazz(clazz); if (sheet != null) {
analyser.analysis(sheet); sheet.setClazz(clazz);
}
read(sheet);
}
/**
* Context for the entire execution process
*
* @return
*/
public AnalysisContext analysisContext() {
checkFinished();
return excelAnalyser.analysisContext();
}
/**
* Current executor
*
* @return
*/
public ExcelExecutor excelExecutor() {
checkFinished();
return excelAnalyser.excelExecutor();
} }
/** /**
* Parse the workBook get all sheets * Parse the workBook get all sheets
* *
* @return workBook all sheets * @return workBook all sheets
*
* @deprecated please use {@link #excelExecutor()}
*/ */
@Deprecated
public List<Sheet> getSheets() { public List<Sheet> getSheets() {
return analyser.getSheets(); List<ReadSheet> sheetList = excelExecutor().sheetList();
List<Sheet> sheets = new ArrayList<Sheet>();
if (sheetList == null || sheetList.isEmpty()) {
return sheets;
}
for (ReadSheet readSheet : sheetList) {
Sheet sheet = new Sheet(readSheet.getSheetNo() + 1);
sheet.setSheetName(readSheet.getSheetName());
sheets.add(sheet);
}
return sheets;
} }
/** /**
* validate param
* *
* @param in * @return
* @param eventListener * @deprecated please use {@link #analysisContext()}
*/
@Deprecated
public AnalysisContext getAnalysisContext() {
return analysisContext();
}
/**
* Complete the entire read file.Release the cache and close stream.
*/
public void finish() {
if (finished) {
return;
}
finished = true;
excelAnalyser.finish();
}
/**
* Prevents calls to {@link #finish} from freeing the cache
*
*/ */
private void validateParam(InputStream in, AnalysisEventListener eventListener) { @Override
if (eventListener == null) { protected void finalize() {
throw new IllegalArgumentException("AnalysisEventListener can not null"); if (finished) {
} else if (in == null) { return;
throw new IllegalArgumentException("InputStream can not null"); }
try {
excelAnalyser.finish();
} catch (Throwable e) {
LOGGER.warn("Destroy object failed", e);
}
}
private void checkFinished() {
if (finished) {
throw new ExcelAnalysisException("Can not use a finished reader.");
} }
} }
} }

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

@ -1,182 +1,292 @@
package com.alibaba.excel; package com.alibaba.excel;
import com.alibaba.excel.event.WriteHandler; import java.io.InputStream;
import com.alibaba.excel.metadata.BaseRowModel; import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table; import com.alibaba.excel.metadata.Table;
import com.alibaba.excel.parameter.GenerateParam; import com.alibaba.excel.parameter.GenerateParam;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.ExcelBuilder; import com.alibaba.excel.write.ExcelBuilder;
import com.alibaba.excel.write.ExcelBuilderImpl; import com.alibaba.excel.write.ExcelBuilderImpl;
import com.alibaba.excel.write.handler.WriteHandler;
import java.io.InputStream; import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy;
import java.io.OutputStream; import com.alibaba.excel.write.metadata.WriteSheet;
import java.util.List; import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.metadata.WriteWorkbook;
/** /**
* Excel Writer This tool is used to write data out to Excel via POI. * Excel Writer This tool is used to write value out to Excel via POI. This object can perform the following two
* This object can perform the following two functions. * functions.
*
* <pre> * <pre>
* 1. Create a new empty Excel workbook, write the data to the stream after the data is filled. * 1. Create a new empty Excel workbook, write the value to the stream after the value is filled.
* 2. Edit existing Excel, write the original Excel file, or write it to other places.} * 2. Edit existing Excel, write the original Excel file, or write it to other places.}
* </pre> * </pre>
*
* @author jipengfei * @author jipengfei
*/ */
public class ExcelWriter { public class ExcelWriter {
private ExcelBuilder excelBuilder; private ExcelBuilder excelBuilder;
/** /**
* Create new writer * Create new writer
* @param outputStream the java OutputStream you wish to write the data to *
* @param typeEnum 03 or 07 * @param writeWorkbook
*/ */
public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum) { public ExcelWriter(WriteWorkbook writeWorkbook) {
this(outputStream, typeEnum, true); excelBuilder = new ExcelBuilderImpl(writeWorkbook);
} }
@Deprecated
private Class<? extends BaseRowModel> objectClass;
/** /**
* @param generateParam * Create new writer
*
* @param outputStream
* the java OutputStream you wish to write the value to
* @param typeEnum
* 03 or 07
* @deprecated please use {@link com.alibaba.excel.write.builder.ExcelWriterBuilder} build ExcelWriter
*/ */
@Deprecated @Deprecated
public ExcelWriter(GenerateParam generateParam) { public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum) {
this(generateParam.getOutputStream(), generateParam.getType(), true); this(outputStream, typeEnum, true);
this.objectClass = generateParam.getClazz();
} }
/** /**
* *
* Create new writer * Create new writer
* @param outputStream the java OutputStream you wish to write the data to *
* @param typeEnum 03 or 07 * @param outputStream
* @param needHead Do you need to write the header to the file? * the java OutputStream you wish to write the value to
* @param typeEnum
* 03 or 07
* @param needHead
* Do you need to write the header to the file?
* @deprecated please use {@link com.alibaba.excel.write.builder.ExcelWriterBuilder} build ExcelWriter
*/ */
@Deprecated
public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum, boolean needHead) { public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum, boolean needHead) {
excelBuilder = new ExcelBuilderImpl(null, outputStream, typeEnum, needHead, null); this(null, outputStream, typeEnum, needHead, null);
} }
/** /**
* Create new writer * Create new writer
* @param templateInputStream Append data after a POI file ,Can be nullthe template POI filesystem that contains the Workbook stream) *
* @param outputStream the java OutputStream you wish to write the data to * @param templateInputStream
* @param typeEnum 03 or 07 * Append value after a POI file ,Can be nullthe template POI filesystem that contains the Workbook
* stream)
* @param outputStream
* the java OutputStream you wish to write the value to
* @param typeEnum
* 03 or 07
* @deprecated please use {@link com.alibaba.excel.write.builder.ExcelWriterBuilder} build ExcelWriter
*/ */
public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum,Boolean needHead) { @Deprecated
excelBuilder = new ExcelBuilderImpl(templateInputStream,outputStream, typeEnum, needHead, null); public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum,
Boolean needHead) {
this(templateInputStream, outputStream, typeEnum, needHead, null);
} }
/**
* Create new writer
*
* @param templateInputStream
* Append value after a POI file ,Can be nullthe template POI filesystem that contains the Workbook
* stream)
* @param outputStream
* the java OutputStream you wish to write the value to
* @param typeEnum
* 03 or 07
* @param writeHandler
* User-defined callback
* @deprecated please use {@link com.alibaba.excel.write.builder.ExcelWriterBuilder} build ExcelWriter
*/
@Deprecated
public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum,
Boolean needHead, WriteHandler writeHandler) {
List<WriteHandler> customWriteHandlerList = new ArrayList<WriteHandler>();
customWriteHandlerList.add(writeHandler);
WriteWorkbook writeWorkbook = new WriteWorkbook();
writeWorkbook.setTemplateInputStream(templateInputStream);
writeWorkbook.setOutputStream(outputStream);
writeWorkbook.setExcelType(typeEnum);
writeWorkbook.setNeedHead(needHead);
writeWorkbook.setCustomWriteHandlerList(customWriteHandlerList);
excelBuilder = new ExcelBuilderImpl(writeWorkbook);
}
/** /**
* Create new writer * @param generateParam
* @param templateInputStream Append data after a POI file ,Can be nullthe template POI filesystem that contains the Workbook stream) * @deprecated please use {@link com.alibaba.excel.write.builder.ExcelWriterBuilder} build ExcelWriter
* @param outputStream the java OutputStream you wish to write the data to
* @param typeEnum 03 or 07
* @param writeHandler User-defined callback
*/ */
public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum, Boolean needHead, @Deprecated
WriteHandler writeHandler) { public ExcelWriter(GenerateParam generateParam) {
excelBuilder = new ExcelBuilderImpl(templateInputStream,outputStream, typeEnum, needHead,writeHandler); this(generateParam.getOutputStream(), generateParam.getType(), true);
} }
/** /**
* Write data to a sheet * Write data to a sheet
* @param data Data to be written *
* @param sheet Write to this sheet * @param data
* Data to be written
* @param writeSheet
* Write to this sheet
* @return this current writer * @return this current writer
*/ */
public ExcelWriter write(List<? extends BaseRowModel> data, Sheet sheet) { public ExcelWriter write(List data, WriteSheet writeSheet) {
excelBuilder.addContent(data, sheet); return write(data, writeSheet, null);
return this;
} }
/**
* Write value to a sheet
*
* @param data
* Data to be written
* @param writeSheet
* Write to this sheet
* @param writeTable
* Write to this table
* @return this
*/
public ExcelWriter write(List data, WriteSheet writeSheet, WriteTable writeTable) {
excelBuilder.addContent(data, writeSheet, writeTable);
return this;
}
/** /**
* Write data to a sheet * Write data to a sheet
* @param data Data to be written *
* @param data
* Data to be written
* @param sheet
* Write to this sheet
* @return this current writer * @return this current writer
* @deprecated please use {@link ExcelWriter#write(List, WriteSheet)}
*/ */
@Deprecated @Deprecated
public ExcelWriter write(List data) { public ExcelWriter write(List data, Sheet sheet) {
if (objectClass != null) { return write(data, sheet, null);
return this.write(data,new Sheet(1,0,objectClass));
}else {
return this.write0(data,new Sheet(1,0,objectClass));
}
} }
/** /**
* Write value to a sheet
* *
* Write data to a sheet * @param data
* @param data Data to be written * Data to be written
* @param sheet Write to this sheet * @param sheet
* Write to this sheet
* @param table
* Write to this table
* @return this * @return this
* @deprecated * @deprecated please use {@link ExcelWriter#write(List, WriteSheet,WriteTable)}
*/ */
public ExcelWriter write1(List<List<Object>> data, Sheet sheet) { @Deprecated
excelBuilder.addContent(data, sheet); public ExcelWriter write(List data, Sheet sheet, Table table) {
return this; WriteSheet writeSheet = null;
if (sheet != null) {
writeSheet = new WriteSheet();
writeSheet.setSheetNo(sheet.getSheetNo() - 1);
writeSheet.setSheetName(sheet.getSheetName());
writeSheet.setClazz(sheet.getClazz());
writeSheet.setHead(sheet.getHead());
writeSheet.setTableStyle(sheet.getTableStyle());
writeSheet.setRelativeHeadRowIndex(sheet.getStartRow());
writeSheet.setColumnWidthMap(sheet.getColumnWidthMap());
}
WriteTable writeTable = null;
if (table != null) {
writeTable = new WriteTable();
writeTable.setTableNo(table.getTableNo());
writeTable.setClazz(table.getClazz());
writeTable.setHead(table.getHead());
writeTable.setTableStyle(table.getTableStyle());
}
return write(data, writeSheet, writeTable);
} }
/** /**
* Write data to a sheet * Write data to a sheet
* @param data Data to be written *
* @param sheet Write to this sheet * @param data
* @return this * Data to be written
* @param sheet
* Write to this sheet
* @return this current writer
* @deprecated please use {@link ExcelWriter#write(List, WriteSheet)}
*/ */
public ExcelWriter write0(List<List<String>> data, Sheet sheet) { @Deprecated
excelBuilder.addContent(data, sheet); public ExcelWriter write0(List data, Sheet sheet) {
return this; return write(data, sheet, null);
} }
/** /**
* Write data to a sheet * Write value to a sheet
* @param data Data to be written *
* @param sheet Write to this sheet * @param data
* @param table Write to this table * Data to be written
* @param sheet
* Write to this sheet
* @param table
* Write to this table
* @return this * @return this
* @deprecated * @deprecated please use {@link ExcelWriter#write(List, WriteSheet,WriteTable)}
*/ */
public ExcelWriter write(List<? extends BaseRowModel> data, Sheet sheet, Table table) { @Deprecated
excelBuilder.addContent(data, sheet, table); public ExcelWriter write0(List data, Sheet sheet, Table table) {
return this; return write(data, sheet, table);
} }
/** /**
* Write data to a sheet * Write data to a sheet
* @param data Data to be written *
* @param sheet Write to this sheet * @param data
* @param table Write to this table * Data to be written
* @return this * @param sheet
* Write to this sheet
* @return this current writer
* @deprecated please use {@link ExcelWriter#write(List, WriteSheet)}
*/ */
public ExcelWriter write0(List<List<String>> data, Sheet sheet, Table table) { @Deprecated
excelBuilder.addContent(data, sheet, table); public ExcelWriter write1(List data, Sheet sheet) {
return this; return write(data, sheet, null);
} }
/** /**
* Merge CellsIndexes are zero-based. * Write value to a sheet
* *
* @param firstRow Index of first row * @param data
* @param lastRow Index of last row (inclusive), must be equal to or larger than {@code firstRow} * Data to be written
* @param firstCol Index of first column * @param sheet
* @param lastCol Index of last column (inclusive), must be equal to or larger than {@code firstCol} * Write to this sheet
* @param table
* Write to this table
* @return this
* @deprecated * @deprecated please use {@link ExcelWriter#write(List, WriteSheet,WriteTable)}
*/ */
public ExcelWriter merge(int firstRow, int lastRow, int firstCol, int lastCol){ @Deprecated
excelBuilder.merge(firstRow,lastRow,firstCol,lastCol); public ExcelWriter write1(List data, Sheet sheet, Table table) {
return this; return write(data, sheet, table);
} }
/** /**
* Write data to a sheet * Merge CellsIndexes are zero-based.
* @param data Data to be written *
* @param sheet Write to this sheet * @param firstRow
* @param table Write to this table * Index of first row
* @return * @param lastRow
* Index of last row (inclusive), must be equal to or larger than {@code firstRow}
* @param firstCol
* Index of first column
* @param lastCol
* Index of last column (inclusive), must be equal to or larger than {@code firstCol}
* @deprecated please use{@link OnceAbsoluteMergeStrategy}
*/ */
public ExcelWriter write1(List<List<Object>> data, Sheet sheet, Table table) { @Deprecated
excelBuilder.addContent(data, sheet, table); public ExcelWriter merge(int firstRow, int lastRow, int firstCol, int lastCol) {
excelBuilder.merge(firstRow, lastRow, firstCol, lastCol);
return this; return this;
} }
@ -186,4 +296,5 @@ public class ExcelWriter {
public void finish() { public void finish() {
excelBuilder.finish(); excelBuilder.finish();
} }
} }

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

@ -1,87 +0,0 @@
package com.alibaba.excel.analysis;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.event.AnalysisEventRegisterCenter;
import com.alibaba.excel.event.OneRowAnalysisFinishEvent;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.util.TypeUtil;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* @author jipengfei
*/
public abstract class BaseSaxAnalyser implements AnalysisEventRegisterCenter, ExcelAnalyser {
protected AnalysisContext analysisContext;
private LinkedHashMap<String, AnalysisEventListener> listeners = new LinkedHashMap<String, AnalysisEventListener>();
/**
* execute method
*/
protected abstract void execute();
@Override
public void appendLister(String name, AnalysisEventListener listener) {
if (!listeners.containsKey(name)) {
listeners.put(name, listener);
}
}
@Override
public void analysis(Sheet sheetParam) {
execute();
}
@Override
public void analysis() {
execute();
}
/**
*/
@Override
public void cleanAllListeners() {
listeners = new LinkedHashMap<String, AnalysisEventListener>();
}
@Override
public void notifyListeners(OneRowAnalysisFinishEvent event) {
analysisContext.setCurrentRowAnalysisResult(event.getData());
/** Parsing header content **/
if (analysisContext.getCurrentRowNum() < analysisContext.getCurrentSheet().getHeadLineMun()) {
if (analysisContext.getCurrentRowNum() <= analysisContext.getCurrentSheet().getHeadLineMun() - 1) {
analysisContext.buildExcelHeadProperty(null,
(List<String>)analysisContext.getCurrentRowAnalysisResult());
}
} else {
List<String> content = converter((List<String>)event.getData());
/** Parsing Analyze the body content **/
analysisContext.setCurrentRowAnalysisResult(content);
if (listeners.size() == 1) {
analysisContext.setCurrentRowAnalysisResult(content);
}
/** notify all event listeners **/
for (Map.Entry<String, AnalysisEventListener> entry : listeners.entrySet()) {
entry.getValue().invoke(analysisContext.getCurrentRowAnalysisResult(), analysisContext);
}
}
}
private List<String> converter(List<String> data) {
List<String> list = new ArrayList<String>();
if (data != null) {
for (String str : data) {
list.add(TypeUtil.formatFloat(str));
}
}
return list;
}
}

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

@ -1,8 +1,7 @@
package com.alibaba.excel.analysis; package com.alibaba.excel.analysis;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.metadata.ReadSheet;
import java.util.List;
/** /**
* Excel file analyser * Excel file analyser
@ -10,24 +9,31 @@ import java.util.List;
* @author jipengfei * @author jipengfei
*/ */
public interface ExcelAnalyser { public interface ExcelAnalyser {
/** /**
* parse one sheet * parse one sheet
* *
* @param sheetParam * @param readSheet
* sheet to read
*/
void analysis(ReadSheet readSheet);
/**
* Complete the entire read file.Release the cache and close stream
*/ */
void analysis(Sheet sheetParam); void finish();
/** /**
* parse all sheets * Acquisition excel executor
*
* @return Excel file Executor
*/ */
void analysis(); ExcelExecutor excelExecutor();
/** /**
* get all sheet of workbook * get the analysis context.
* *
* @return all sheets * @return analysis context
*/ */
List<Sheet> getSheets(); AnalysisContext analysisContext();
} }

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

@ -1,95 +1,145 @@
package com.alibaba.excel.analysis; package com.alibaba.excel.analysis;
import java.io.InputStream;
import org.apache.poi.poifs.crypt.Decryptor;
import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.analysis.v03.XlsSaxAnalyser; import com.alibaba.excel.analysis.v03.XlsSaxAnalyser;
import com.alibaba.excel.analysis.v07.XlsxSaxAnalyser; import com.alibaba.excel.analysis.v07.XlsxSaxAnalyser;
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.context.AnalysisContextImpl; import com.alibaba.excel.context.AnalysisContextImpl;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.modelbuild.ModelBuildEventListener; import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.ReadWorkbook;
import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.FileUtils;
import java.io.InputStream;
import java.util.List;
/** /**
* @author jipengfei * @author jipengfei
*/ */
public class ExcelAnalyserImpl implements ExcelAnalyser { public class ExcelAnalyserImpl implements ExcelAnalyser {
private static final Logger LOGGER = LoggerFactory.getLogger(ExcelAnalyserImpl.class);
private AnalysisContext analysisContext; private AnalysisContext analysisContext;
private BaseSaxAnalyser saxAnalyser; private ExcelExecutor excelExecutor;
public ExcelAnalyserImpl(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom, public ExcelAnalyserImpl(ReadWorkbook readWorkbook) {
AnalysisEventListener eventListener, boolean trim) { try {
analysisContext = new AnalysisContextImpl(inputStream, excelTypeEnum, custom, analysisContext = new AnalysisContextImpl(readWorkbook);
eventListener, trim); choiceExcelExecutor();
} catch (RuntimeException e) {
finish();
throw e;
} catch (Throwable e) {
finish();
throw new ExcelAnalysisException(e);
}
} }
private BaseSaxAnalyser getSaxAnalyser() { private void choiceExcelExecutor() throws Exception {
if (saxAnalyser != null) { ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder();
return this.saxAnalyser; ExcelTypeEnum excelType = readWorkbookHolder.getExcelType();
if (excelType == null) {
excelExecutor = new XlsxSaxAnalyser(analysisContext, null);
return;
} }
try { switch (excelType) {
if (analysisContext.getExcelType() != null) { case XLS:
switch (analysisContext.getExcelType()) { POIFSFileSystem poifsFileSystem = null;
case XLS: if (readWorkbookHolder.getFile() != null) {
this.saxAnalyser = new XlsSaxAnalyser(analysisContext); poifsFileSystem = new POIFSFileSystem(readWorkbookHolder.getFile());
break; } else {
case XLSX: poifsFileSystem = new POIFSFileSystem(readWorkbookHolder.getInputStream());
this.saxAnalyser = new XlsxSaxAnalyser(analysisContext);
break;
} }
} else { // So in encrypted excel, it looks like XLS but it's actually XLSX
try { if (poifsFileSystem.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
this.saxAnalyser = new XlsxSaxAnalyser(analysisContext); InputStream decryptedStream = null;
} catch (Exception e) { try {
if (!analysisContext.getInputStream().markSupported()) { decryptedStream = DocumentFactoryHelper.getDecryptedStream(poifsFileSystem.getRoot(), null);
throw new ExcelAnalysisException( excelExecutor = new XlsxSaxAnalyser(analysisContext, decryptedStream);
"Xls must be available markSupported,you can do like this <code> new " return;
+ "BufferedInputStream(new FileInputStream(\"/xxxx\"))</code> "); } finally {
IOUtils.closeQuietly(decryptedStream);
// as we processed the full stream already, we can close the filesystem here
// otherwise file handles are leaked
poifsFileSystem.close();
} }
this.saxAnalyser = new XlsSaxAnalyser(analysisContext);
} }
} excelExecutor = new XlsSaxAnalyser(analysisContext, poifsFileSystem);
} catch (Exception e) { break;
throw new ExcelAnalysisException("File type error,io must be available markSupported,you can do like " case XLSX:
+ "this <code> new BufferedInputStream(new FileInputStream(\\\"/xxxx\\\"))</code> \"", e); excelExecutor = new XlsxSaxAnalyser(analysisContext, null);
break;
default:
} }
return this.saxAnalyser;
} }
@Override @Override
public void analysis(Sheet sheetParam) { public void analysis(ReadSheet readSheet) {
analysisContext.setCurrentSheet(sheetParam); try {
analysis(); analysisContext.currentSheet(excelExecutor, readSheet);
try {
excelExecutor.execute();
} catch (ExcelAnalysisStopException e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Custom stop!");
}
}
analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext);
} catch (RuntimeException e) {
finish();
throw e;
} catch (Throwable e) {
finish();
throw new ExcelAnalysisException(e);
}
} }
@Override @Override
public void analysis() { public void finish() {
BaseSaxAnalyser saxAnalyser = getSaxAnalyser(); if (analysisContext == null || analysisContext.readWorkbookHolder() == null) {
appendListeners(saxAnalyser); return;
saxAnalyser.execute(); }
analysisContext.getEventListener().doAfterAllAnalysed(analysisContext); ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder();
try {
if (readWorkbookHolder.getReadCache() != null) {
readWorkbookHolder.getReadCache().destroy();
}
} catch (Throwable e) {
throw new ExcelAnalysisException("Can not close IO", e);
}
try {
if (analysisContext.readWorkbookHolder().getAutoCloseStream()
&& readWorkbookHolder.getInputStream() != null) {
readWorkbookHolder.getInputStream().close();
}
} catch (Throwable e) {
throw new ExcelAnalysisException("Can not close IO", e);
}
try {
if (readWorkbookHolder.getTempFile() != null) {
FileUtils.delete(readWorkbookHolder.getTempFile());
}
} catch (Throwable e) {
throw new ExcelAnalysisException("Can not close IO", e);
}
} }
@Override @Override
public List<Sheet> getSheets() { public com.alibaba.excel.analysis.ExcelExecutor excelExecutor() {
BaseSaxAnalyser saxAnalyser = getSaxAnalyser(); return excelExecutor;
saxAnalyser.cleanAllListeners();
return saxAnalyser.getSheets();
} }
private void appendListeners(BaseSaxAnalyser saxAnalyser) { @Override
saxAnalyser.cleanAllListeners(); public AnalysisContext analysisContext() {
if (analysisContext.getCurrentSheet() != null && analysisContext.getCurrentSheet().getClazz() != null) { return analysisContext;
saxAnalyser.appendLister("model_build_listener", new ModelBuildEventListener());
}
if (analysisContext.getEventListener() != null) {
saxAnalyser.appendLister("user_define_listener", analysisContext.getEventListener());
}
} }
} }

26
src/main/java/com/alibaba/excel/analysis/ExcelExecutor.java

@ -0,0 +1,26 @@
package com.alibaba.excel.analysis;
import java.util.List;
import com.alibaba.excel.read.metadata.ReadSheet;
/**
* Excel file Executor
*
* @author Jiaju Zhuang
*/
public interface ExcelExecutor {
/**
* Returns the actual sheet in excel
*
* @return Actual sheet in excel
*/
List<ReadSheet> sheetList();
/**
* Read sheet
*/
void execute();
}

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

@ -0,0 +1,33 @@
package com.alibaba.excel.analysis.v03;
import com.alibaba.excel.metadata.CellData;
/**
*
* @author Dan Zheng
*/
public abstract class AbstractXlsRecordHandler implements XlsRecordHandler {
protected int row = -1;
protected int column = -1;
protected CellData cellData;
@Override
public int getRow() {
return row;
}
@Override
public int getColumn() {
return column;
}
@Override
public CellData getCellData() {
return cellData;
}
@Override
public int compareTo(XlsRecordHandler o) {
return this.getOrder() - o.getOrder();
}
}

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

@ -0,0 +1,61 @@
package com.alibaba.excel.analysis.v03;
import org.apache.poi.hssf.record.Record;
import com.alibaba.excel.metadata.CellData;
/**
* Intercepts handle xls reads.
*
* @author Dan Zheng
*/
public interface XlsRecordHandler extends Comparable<XlsRecordHandler> {
/**
* Which tags are supported
*
* @param record
* Excel analysis record
* @return Which tags are supported
*/
boolean support(Record record);
/**
* Initialize
*/
void init();
/**
* Processing record
*
* @param record
*/
void processRecord(Record record);
/**
* Get row
*
* @return Row index
*/
int getRow();
/**
* Get column
*
* @return Column index
*/
int getColumn();
/**
* Get value
*
* @return Excel internal cell data
*/
CellData getCellData();
/**
* Get order
*
* @return Order
*/
int getOrder();
}

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

@ -1,292 +1,154 @@
package com.alibaba.excel.analysis.v03; package com.alibaba.excel.analysis.v03;
import com.alibaba.excel.analysis.BaseSaxAnalyser; import java.io.IOException;
import com.alibaba.excel.context.AnalysisContext; import java.util.ArrayList;
import com.alibaba.excel.event.OneRowAnalysisFinishEvent; import java.util.Collections;
import com.alibaba.excel.exception.ExcelAnalysisException; import java.util.List;
import com.alibaba.excel.metadata.Sheet; import java.util.Map;
import org.apache.poi.hssf.eventusermodel.*; import java.util.TreeMap;
import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
import org.apache.poi.hssf.eventusermodel.HSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener;
import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import java.io.IOException; import com.alibaba.excel.analysis.ExcelExecutor;
import java.util.ArrayList; import com.alibaba.excel.analysis.v03.handlers.BlankOrErrorRecordHandler;
import java.util.List; import com.alibaba.excel.analysis.v03.handlers.BofRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.FormulaRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.LabelRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.MissingCellDummyRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.NoteRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.NumberRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.RkRecordHandler;
import com.alibaba.excel.analysis.v03.handlers.SstRecordHandler;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.read.listener.event.EachRowAnalysisFinishEvent;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.util.CollectionUtils;
/** /**
* /** * A text extractor for Excel files. * <p> * Returns the textual content of the file, suitable for * indexing by * /** * A text extractor for Excel files. *
* something like Lucene, but not really * intended for display to the user. * </p> * <p> * To turn an excel file into * <p>
* a CSV or similar, then see * the XLS2CSVmra example * </p> * * @see * * Returns the textual content of the file, suitable for * indexing by something like Lucene, but not really *
* <a href="http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java">XLS2CSVmra</a> * intended for display to the user. *
* </p>
* *
* <p>
* * To turn an excel file into a CSV or similar, then see * the XLS2CSVmra example *
* </p>
* * * @see <a href=
* "http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java">XLS2CSVmra</a>
* *
* @author jipengfei * @author jipengfei
*/ */
public class XlsSaxAnalyser extends BaseSaxAnalyser implements HSSFListener { public class XlsSaxAnalyser implements HSSFListener, ExcelExecutor {
private boolean outputFormulaValues = true;
private boolean analyAllSheet = false; private POIFSFileSystem poifsFileSystem;
private int lastRowNumber;
private int lastColumnNumber;
private boolean notAllEmpty = false;
/**
* For parsing Formulas
*/
private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener;
private FormatTrackingHSSFListener formatListener;
private Map<Integer, CellData> records;
private List<ReadSheet> sheets = new ArrayList<ReadSheet>();
private HSSFWorkbook stubWorkbook;
private List<XlsRecordHandler> recordHandlers = new ArrayList<XlsRecordHandler>();
private AnalysisContext analysisContext;
public XlsSaxAnalyser(AnalysisContext context) throws IOException { public XlsSaxAnalyser(AnalysisContext context, POIFSFileSystem poifsFileSystem) throws IOException {
this.analysisContext = context; this.analysisContext = context;
this.records = new ArrayList<String>(); this.records = new TreeMap<Integer, CellData>();
if (analysisContext.getCurrentSheet() == null) { this.poifsFileSystem = poifsFileSystem;
this.analyAllSheet = true;
}
context.setCurrentRowNum(0);
this.fs = new POIFSFileSystem(analysisContext.getInputStream());
} }
@Override @Override
public List<Sheet> getSheets() { public List<ReadSheet> sheetList() {
execute();
return sheets; return sheets;
} }
@Override @Override
public void execute() { public void execute() {
init();
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this); MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
formatListener = new FormatTrackingHSSFListener(listener); formatListener = new FormatTrackingHSSFListener(listener);
workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener);
if (workbookBuildingListener != null && stubWorkbook == null) {
stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();
}
init();
HSSFEventFactory factory = new HSSFEventFactory(); HSSFEventFactory factory = new HSSFEventFactory();
HSSFRequest request = new HSSFRequest(); HSSFRequest request = new HSSFRequest();
if (outputFormulaValues) { if (outputFormulaValues) {
request.addListenerForAllRecords(formatListener); request.addListenerForAllRecords(formatListener);
} else { } else {
workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener);
request.addListenerForAllRecords(workbookBuildingListener); request.addListenerForAllRecords(workbookBuildingListener);
} }
try { try {
factory.processWorkbookEvents(request, fs); factory.processWorkbookEvents(request, poifsFileSystem);
} catch (IOException e) { } catch (IOException e) {
throw new ExcelAnalysisException(e); throw new ExcelAnalysisException(e);
} }
// Sometimes tables lack the end record of the last column
if (!records.isEmpty()) {
endRow();
}
} }
private void init() { private void init() {
lastRowNumber = 0; lastRowNumber = 0;
lastColumnNumber = 0; lastColumnNumber = 0;
nextRow = 0; records = new TreeMap<Integer, CellData>();
sheets = new ArrayList<ReadSheet>();
nextColumn = 0; buildXlsRecordHandlers();
sheetIndex = 0;
records = new ArrayList<String>();
notAllEmpty = false;
orderedBSRs = null;
boundSheetRecords = new ArrayList<BoundSheetRecord>();
sheets = new ArrayList<Sheet>();
if (analysisContext.getCurrentSheet() == null) {
this.analyAllSheet = true;
} else {
this.analyAllSheet = false;
}
} }
private POIFSFileSystem fs; @Override
private int lastRowNumber;
private int lastColumnNumber;
/**
* Should we output the formula, or the value it has?
*/
private boolean outputFormulaValues = true;
/**
* For parsing Formulas
*/
private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener;
private HSSFWorkbook stubWorkbook;
private SSTRecord sstRecord;
private FormatTrackingHSSFListener formatListener;
/**
* So we known which sheet we're on
*/
private int nextRow;
private int nextColumn;
private boolean outputNextStringRecord;
/**
* Main HSSFListener method, processes events, and outputs the CSV as the file is processed.
*/
private int sheetIndex;
private List<String> records;
private boolean notAllEmpty = false;
private BoundSheetRecord[] orderedBSRs;
private List<BoundSheetRecord> boundSheetRecords = new ArrayList<BoundSheetRecord>();
private List<Sheet> sheets = new ArrayList<Sheet>();
public void processRecord(Record record) { public void processRecord(Record record) {
int thisRow = -1; int thisRow = -1;
int thisColumn = -1; int thisColumn = -1;
String thisStr = null; CellData cellData = null;
for (XlsRecordHandler handler : this.recordHandlers) {
switch (record.getSid()) { if (handler.support(record)) {
case BoundSheetRecord.sid: handler.processRecord(record);
boundSheetRecords.add((BoundSheetRecord)record); thisRow = handler.getRow();
break; thisColumn = handler.getColumn();
case BOFRecord.sid: cellData = handler.getCellData();
BOFRecord br = (BOFRecord)record; if (cellData != null) {
if (br.getType() == BOFRecord.TYPE_WORKSHEET) { records.put(thisColumn, cellData);
// Create sub workbook if required
if (workbookBuildingListener != null && stubWorkbook == null) {
stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();
}
if (orderedBSRs == null) {
orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords);
}
sheetIndex++;
Sheet sheet = new Sheet(sheetIndex, 0);
sheet.setSheetName(orderedBSRs[sheetIndex - 1].getSheetname());
sheets.add(sheet);
if (this.analyAllSheet) {
analysisContext.setCurrentSheet(sheet);
}
}
break;
case SSTRecord.sid:
sstRecord = (SSTRecord)record;
break;
case BlankRecord.sid:
BlankRecord brec = (BlankRecord)record;
thisRow = brec.getRow();
thisColumn = brec.getColumn();
thisStr = "";
break;
case BoolErrRecord.sid:
BoolErrRecord berec = (BoolErrRecord)record;
thisRow = berec.getRow();
thisColumn = berec.getColumn();
thisStr = "";
break;
case FormulaRecord.sid:
FormulaRecord frec = (FormulaRecord)record;
thisRow = frec.getRow();
thisColumn = frec.getColumn();
if (outputFormulaValues) {
if (Double.isNaN(frec.getValue())) {
// Formula result is a string
// This is stored in the next record
outputNextStringRecord = true;
nextRow = frec.getRow();
nextColumn = frec.getColumn();
} else {
thisStr = formatListener.formatNumberDateCell(frec);
}
} else {
thisStr = HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression());
}
break;
case StringRecord.sid:
if (outputNextStringRecord) {
// String for formula
StringRecord srec = (StringRecord)record;
thisStr = srec.getString();
thisRow = nextRow;
thisColumn = nextColumn;
outputNextStringRecord = false;
}
break;
case LabelRecord.sid:
LabelRecord lrec = (LabelRecord)record;
thisRow = lrec.getRow();
thisColumn = lrec.getColumn();
thisStr = lrec.getValue();
break;
case LabelSSTRecord.sid:
LabelSSTRecord lsrec = (LabelSSTRecord)record;
thisRow = lsrec.getRow();
thisColumn = lsrec.getColumn();
if (sstRecord == null) {
thisStr = "";
} else {
thisStr = sstRecord.getString(lsrec.getSSTIndex()).toString();
} }
break; break;
case NoteRecord.sid: }
NoteRecord nrec = (NoteRecord)record;
thisRow = nrec.getRow();
thisColumn = nrec.getColumn();
// TODO: Find object to match nrec.getShapeId()
thisStr = "(TODO)";
break;
case NumberRecord.sid:
NumberRecord numrec = (NumberRecord)record;
thisRow = numrec.getRow();
thisColumn = numrec.getColumn();
// Format
thisStr = formatListener.formatNumberDateCell(numrec);
break;
case RKRecord.sid:
RKRecord rkrec = (RKRecord)record;
thisRow = rkrec.getRow();
thisColumn = rkrec.getColumn();
thisStr = "";
break;
default:
break;
}
// Handle new row
if (thisRow != -1 && thisRow != lastRowNumber) {
lastColumnNumber = -1;
}
// Handle missing column
if (record instanceof MissingCellDummyRecord) {
MissingCellDummyRecord mc = (MissingCellDummyRecord)record;
thisRow = mc.getRow();
thisColumn = mc.getColumn();
thisStr = "";
} }
// If we got something to print out, do so // If we got something to print out, do so
if (thisStr != null) { if (cellData != null) {
if (analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()
if (analysisContext.trim()) { && CellDataTypeEnum.STRING == cellData.getType()) {
thisStr = thisStr.trim(); cellData.setStringValue(cellData.getStringValue().trim());
} }
if (!"".equals(thisStr)) { if (CellDataTypeEnum.EMPTY != cellData.getType()) {
notAllEmpty = true; notAllEmpty = true;
} }
// } }
records.add(thisStr);
// Handle new row
if (thisRow != -1 && thisRow != lastRowNumber) {
lastColumnNumber = -1;
} }
// Update column and row count // Update column and row count
@ -297,22 +159,45 @@ public class XlsSaxAnalyser extends BaseSaxAnalyser implements HSSFListener {
lastColumnNumber = thisColumn; lastColumnNumber = thisColumn;
} }
processLastCellOfRow(record);
}
private void processLastCellOfRow(Record record) {
// Handle end of row // Handle end of row
if (record instanceof LastCellOfRowDummyRecord) { if (record instanceof LastCellOfRowDummyRecord) {
thisRow = ((LastCellOfRowDummyRecord)record).getRow(); endRow();
}
}
if (lastColumnNumber == -1) { private void endRow() {
lastColumnNumber = 0; if (lastColumnNumber == -1) {
} lastColumnNumber = 0;
analysisContext.setCurrentRowNum(thisRow); }
Sheet sheet = analysisContext.getCurrentSheet(); if (notAllEmpty) {
analysisContext.readRowHolder(
new ReadRowHolder(lastRowNumber, analysisContext.readSheetHolder().getGlobalConfiguration()));
analysisContext.readSheetHolder().notifyEndOneRow(new EachRowAnalysisFinishEvent(records), analysisContext);
}
records.clear();
lastColumnNumber = -1;
}
if ((sheet == null || sheet.getSheetNo() == sheetIndex) && notAllEmpty) { private void buildXlsRecordHandlers() {
notifyListeners(new OneRowAnalysisFinishEvent(records)); if (CollectionUtils.isEmpty(recordHandlers)) {
} recordHandlers.add(new BlankOrErrorRecordHandler());
records.clear(); recordHandlers.add(new BofRecordHandler(workbookBuildingListener, analysisContext, sheets));
lastColumnNumber = -1; recordHandlers.add(new FormulaRecordHandler(stubWorkbook, formatListener));
notAllEmpty = false; recordHandlers.add(new LabelRecordHandler());
recordHandlers.add(new NoteRecordHandler());
recordHandlers.add(new NumberRecordHandler(formatListener));
recordHandlers.add(new RkRecordHandler());
recordHandlers.add(new SstRecordHandler());
recordHandlers.add(new MissingCellDummyRecordHandler());
Collections.sort(recordHandlers);
}
for (XlsRecordHandler x : recordHandlers) {
x.init();
} }
} }
} }

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

@ -0,0 +1,47 @@
package com.alibaba.excel.analysis.v03.handlers;
import org.apache.poi.hssf.record.BlankRecord;
import org.apache.poi.hssf.record.BoolErrRecord;
import org.apache.poi.hssf.record.Record;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
/**
* Record handler
*
* @author Dan Zheng
*/
public class BlankOrErrorRecordHandler extends AbstractXlsRecordHandler {
@Override
public boolean support(Record record) {
return BlankRecord.sid == record.getSid() || BoolErrRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
if (record.getSid() == BlankRecord.sid) {
BlankRecord br = (BlankRecord)record;
this.row = br.getRow();
this.column = br.getColumn();
this.cellData = new CellData(CellDataTypeEnum.EMPTY);
} else if (record.getSid() == BoolErrRecord.sid) {
BoolErrRecord ber = (BoolErrRecord)record;
this.row = ber.getRow();
this.column = ber.getColumn();
this.cellData = new CellData(ber.getBooleanValue());
}
}
@Override
public void init() {
}
@Override
public int getOrder() {
return 0;
}
}

76
src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java

@ -0,0 +1,76 @@
package com.alibaba.excel.analysis.v03.handlers;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder;
import org.apache.poi.hssf.record.BOFRecord;
import org.apache.poi.hssf.record.BoundSheetRecord;
import org.apache.poi.hssf.record.Record;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.metadata.ReadSheet;
/**
* Record handler
*
* @author Dan Zheng
*/
public class BofRecordHandler extends AbstractXlsRecordHandler {
private List<BoundSheetRecord> boundSheetRecords = new ArrayList<BoundSheetRecord>();
private BoundSheetRecord[] orderedBsrs;
private int sheetIndex;
private List<ReadSheet> sheets;
private AnalysisContext context;
private boolean analyAllSheet;
private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener;
public BofRecordHandler(EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener,
AnalysisContext context, List<ReadSheet> sheets) {
this.context = context;
this.workbookBuildingListener = workbookBuildingListener;
this.sheets = sheets;
}
@Override
public boolean support(Record record) {
return BoundSheetRecord.sid == record.getSid() || BOFRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
if (record.getSid() == BoundSheetRecord.sid) {
boundSheetRecords.add((BoundSheetRecord)record);
} else if (record.getSid() == BOFRecord.sid) {
BOFRecord br = (BOFRecord)record;
if (br.getType() == BOFRecord.TYPE_WORKSHEET) {
if (orderedBsrs == null) {
orderedBsrs = BoundSheetRecord.orderByBofPosition(boundSheetRecords);
}
sheetIndex++;
ReadSheet readSheet = new ReadSheet(sheetIndex, orderedBsrs[sheetIndex - 1].getSheetname());
sheets.add(readSheet);
if (this.analyAllSheet) {
context.currentSheet(null, readSheet);
}
}
}
}
@Override
public void init() {
if (context.readSheetHolder() == null) {
this.analyAllSheet = true;
}
sheetIndex = 0;
orderedBsrs = null;
boundSheetRecords.clear();
sheets.clear();
}
@Override
public int getOrder() {
return 0;
}
}

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

@ -0,0 +1,114 @@
package com.alibaba.excel.analysis.v03.handlers;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
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.hssf.record.StringRecord;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
/**
* Record handler
*
* @author Dan Zheng
*/
public class FormulaRecordHandler extends AbstractXlsRecordHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(FormulaRecordHandler.class);
private static final String ERROR = "#VALUE!";
private int nextRow;
private int nextColumn;
private boolean outputNextStringRecord;
private CellData tempCellData;
private FormatTrackingHSSFListener formatListener;
private HSSFWorkbook stubWorkbook;
public FormulaRecordHandler(HSSFWorkbook stubWorkbook, FormatTrackingHSSFListener formatListener) {
this.stubWorkbook = stubWorkbook;
this.formatListener = formatListener;
}
@Override
public boolean support(Record record) {
return FormulaRecord.sid == record.getSid() || StringRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
if (record.getSid() == FormulaRecord.sid) {
FormulaRecord frec = (FormulaRecord)record;
this.row = frec.getRow();
this.column = frec.getColumn();
CellType cellType = CellType.forInt(frec.getCachedResultType());
String formulaValue = null;
try {
formulaValue = HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression());
} catch (Exception e) {
LOGGER.warn("Get formula value error.{}", e.getMessage());
}
switch (cellType) {
case STRING:
// Formula result is a string
// This is stored in the next record
outputNextStringRecord = true;
nextRow = frec.getRow();
nextColumn = frec.getColumn();
tempCellData = new CellData(CellDataTypeEnum.STRING);
tempCellData.setFormula(Boolean.TRUE);
tempCellData.setFormulaValue(formulaValue);
break;
case NUMERIC:
this.cellData = new CellData(frec.getValue());
this.cellData.setFormula(Boolean.TRUE);
this.cellData.setFormulaValue(formulaValue);
break;
case ERROR:
this.cellData = new CellData(CellDataTypeEnum.ERROR);
this.cellData.setStringValue(ERROR);
this.cellData.setFormula(Boolean.TRUE);
this.cellData.setFormulaValue(formulaValue);
break;
case BOOLEAN:
this.cellData = new CellData(frec.getCachedBooleanValue());
this.cellData.setFormula(Boolean.TRUE);
this.cellData.setFormulaValue(formulaValue);
break;
default:
this.cellData = new CellData(CellDataTypeEnum.EMPTY);
this.cellData.setFormula(Boolean.TRUE);
this.cellData.setFormulaValue(formulaValue);
break;
}
} else if (record.getSid() == StringRecord.sid) {
if (outputNextStringRecord) {
// String for formula
StringRecord srec = (StringRecord)record;
this.cellData = tempCellData;
this.cellData.setStringValue(srec.getString());
this.row = nextRow;
this.column = nextColumn;
outputNextStringRecord = false;
tempCellData = null;
}
}
}
@Override
public void init() {
this.nextRow = 0;
this.nextColumn = 0;
}
@Override
public int getOrder() {
return 0;
}
}

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

@ -0,0 +1,37 @@
package com.alibaba.excel.analysis.v03.handlers;
import org.apache.poi.hssf.record.LabelRecord;
import org.apache.poi.hssf.record.Record;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import com.alibaba.excel.metadata.CellData;
/**
* Record handler
*
* @author Dan Zheng
*/
public class LabelRecordHandler extends AbstractXlsRecordHandler {
@Override
public boolean support(Record record) {
return LabelRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
LabelRecord lrec = (LabelRecord)record;
this.row = lrec.getRow();
this.column = lrec.getColumn();
this.cellData = new CellData(lrec.getValue());
}
@Override
public void init() {
}
@Override
public int getOrder() {
return 0;
}
}

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

@ -0,0 +1,38 @@
package com.alibaba.excel.analysis.v03.handlers;
import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
import org.apache.poi.hssf.record.Record;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
/**
* Record handler
*
* @author Dan Zheng
*/
public class MissingCellDummyRecordHandler extends AbstractXlsRecordHandler {
@Override
public boolean support(Record record) {
return record instanceof MissingCellDummyRecord;
}
@Override
public void init() {
}
@Override
public void processRecord(Record record) {
MissingCellDummyRecord mcdr = (MissingCellDummyRecord)record;
this.row = mcdr.getRow();
this.column = mcdr.getColumn();
this.cellData = new CellData(CellDataTypeEnum.EMPTY);
}
@Override
public int getOrder() {
return 1;
}
}

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

@ -0,0 +1,38 @@
package com.alibaba.excel.analysis.v03.handlers;
import org.apache.poi.hssf.record.NoteRecord;
import org.apache.poi.hssf.record.Record;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
/**
* Record handler
*
* @author Dan Zheng
*/
public class NoteRecordHandler extends AbstractXlsRecordHandler {
@Override
public boolean support(Record record) {
return NoteRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
NoteRecord nrec = (NoteRecord)record;
this.row = nrec.getRow();
this.column = nrec.getColumn();
this.cellData = new CellData(CellDataTypeEnum.EMPTY);
}
@Override
public void init() {
}
@Override
public int getOrder() {
return 0;
}
}

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

@ -0,0 +1,46 @@
package com.alibaba.excel.analysis.v03.handlers;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.Record;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import com.alibaba.excel.metadata.CellData;
/**
* Record handler
*
* @author Dan Zheng
*/
public class NumberRecordHandler extends AbstractXlsRecordHandler {
private FormatTrackingHSSFListener formatListener;
public NumberRecordHandler(FormatTrackingHSSFListener formatListener) {
this.formatListener = formatListener;
}
@Override
public boolean support(Record record) {
return NumberRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
NumberRecord numrec = (NumberRecord)record;
this.row = numrec.getRow();
this.column = numrec.getColumn();
this.cellData = new CellData(numrec.getValue());
this.cellData.setDataFormat(formatListener.getFormatIndex(numrec));
this.cellData.setDataFormatString(formatListener.getFormatString(numrec));
}
@Override
public void init() {
}
@Override
public int getOrder() {
return 0;
}
}

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

@ -0,0 +1,39 @@
package com.alibaba.excel.analysis.v03.handlers;
import org.apache.poi.hssf.record.RKRecord;
import org.apache.poi.hssf.record.Record;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
/**
* Record handler
*
* @author Dan Zheng
*/
public class RkRecordHandler extends AbstractXlsRecordHandler {
@Override
public boolean support(Record record) {
return RKRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
RKRecord rkrec = (RKRecord)record;
this.row = rkrec.getRow();
this.row = rkrec.getColumn();
this.cellData = new CellData(CellDataTypeEnum.EMPTY);
}
@Override
public void init() {
}
@Override
public int getOrder() {
return 0;
}
}

49
src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java

@ -0,0 +1,49 @@
package com.alibaba.excel.analysis.v03.handlers;
import org.apache.poi.hssf.record.LabelSSTRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.SSTRecord;
import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
/**
* Record handler
*
* @author Dan Zheng
*/
public class SstRecordHandler extends AbstractXlsRecordHandler {
private SSTRecord sstRecord;
@Override
public boolean support(Record record) {
return SSTRecord.sid == record.getSid() || LabelSSTRecord.sid == record.getSid();
}
@Override
public void processRecord(Record record) {
if (record.getSid() == SSTRecord.sid) {
sstRecord = (SSTRecord)record;
} else if (record.getSid() == LabelSSTRecord.sid) {
LabelSSTRecord lsrec = (LabelSSTRecord)record;
this.row = lsrec.getRow();
this.column = lsrec.getColumn();
if (sstRecord == null) {
this.cellData = new CellData(CellDataTypeEnum.EMPTY);
} else {
this.cellData = new CellData(sstRecord.getString(lsrec.getSSTIndex()).toString());
}
}
}
@Override
public void init() {
}
@Override
public int getOrder() {
return 0;
}
}

51
src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java

@ -0,0 +1,51 @@
package com.alibaba.excel.analysis.v07;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
import com.alibaba.excel.cache.ReadCache;
/**
* Sax read sharedStringsTable.xml
*
* @author Jiaju Zhuang
*/
public class SharedStringsTableHandler extends DefaultHandler {
private static final String T_TAG = "t";
private static final String SI_TAG = "si";
/**
* The final piece of data
*/
private String currentData;
/**
* Current element data
*/
private String currentElementData;
private ReadCache readCache;
public SharedStringsTableHandler(ReadCache readCache) {
this.readCache = readCache;
}
@Override
public void startElement(String uri, String localName, String name, Attributes attributes) {
if (SI_TAG.equals(name)) {
currentData = "";
}
}
@Override
public void endElement(String uri, String localName, String name) {
if (T_TAG.equals(name)) {
currentData += currentElementData;
} else if (SI_TAG.equals(name)) {
readCache.put(currentData);
}
}
@Override
public void characters(char[] ch, int start, int length) {
currentElementData = new String(ch, start, length);
}
}

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

@ -0,0 +1,37 @@
package com.alibaba.excel.analysis.v07;
import org.xml.sax.Attributes;
/**
* Cell handler
*
* @author Dan Zheng
*/
public interface XlsxCellHandler {
/**
* Which tags are supported
*
* @param name
* Tag name
* @return Support parsing or not
*/
boolean support(String name);
/**
* Start handle
*
* @param name
* Tag name
* @param attributes
* Tag attributes
*/
void startHandle(String name, Attributes attributes);
/**
* End handle
*
* @param name
* Tag name
*/
void endHandle(String name);
}

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

@ -0,0 +1,27 @@
package com.alibaba.excel.analysis.v07;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.xssf.model.StylesTable;
import com.alibaba.excel.analysis.v07.handlers.CountRowCellHandler;
import com.alibaba.excel.analysis.v07.handlers.DefaultCellHandler;
import com.alibaba.excel.analysis.v07.handlers.ProcessResultCellHandler;
import com.alibaba.excel.context.AnalysisContext;
/**
* Build handler
*
* @author Dan Zheng
*/
public class XlsxHandlerFactory {
public static List<XlsxCellHandler> buildCellHandlers(AnalysisContext analysisContext, StylesTable stylesTable) {
List<XlsxCellHandler> result = new ArrayList<XlsxCellHandler>();
result.add(new CountRowCellHandler(analysisContext));
DefaultCellHandler defaultCellHandler = new DefaultCellHandler(analysisContext, stylesTable);
result.add(defaultCellHandler);
result.add(new ProcessResultCellHandler(analysisContext, defaultCellHandler));
return result;
}
}

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

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

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

@ -0,0 +1,31 @@
package com.alibaba.excel.analysis.v07;
import java.util.Map;
import com.alibaba.excel.metadata.CellData;
/**
* Result holder
*
* @author jipengfei
*/
public interface XlsxRowResultHolder {
/**
* Clear Result
*/
void clearResult();
/**
* Append current 'cellValue'
*
* @param currentCellValue
*/
void appendCurrentCellValue(String currentCellValue);
/**
* Get row content
*
* @return
*/
Map<Integer, CellData> getCurRowContent();
}

236
src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java

@ -1,90 +1,169 @@
package com.alibaba.excel.analysis.v07; package com.alibaba.excel.analysis.v07;
import com.alibaba.excel.analysis.BaseSaxAnalyser; import java.io.File;
import com.alibaba.excel.context.AnalysisContext; import java.io.IOException;
import com.alibaba.excel.exception.ExcelAnalysisException; import java.io.InputStream;
import com.alibaba.excel.metadata.Sheet; import java.util.ArrayList;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException; import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.xssf.eventusermodel.XSSFReader; import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable; import org.apache.poi.xssf.model.StylesTable;
import org.apache.xmlbeans.XmlException; import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument; import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.ContentHandler; import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
import org.xml.sax.XMLReader; import org.xml.sax.XMLReader;
import javax.xml.parsers.SAXParser; import com.alibaba.excel.analysis.ExcelExecutor;
import javax.xml.parsers.SAXParserFactory; import com.alibaba.excel.cache.Ehcache;
import java.io.IOException; import com.alibaba.excel.cache.MapCache;
import java.io.InputStream; import com.alibaba.excel.context.AnalysisContext;
import java.util.ArrayList; import com.alibaba.excel.exception.ExcelAnalysisException;
import java.util.List; import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
import com.alibaba.excel.util.FileUtils;
/** /**
* *
* @author jipengfei * @author jipengfei
*/ */
public class XlsxSaxAnalyser extends BaseSaxAnalyser { public class XlsxSaxAnalyser implements ExcelExecutor {
private static final Logger LOGGER = LoggerFactory.getLogger(XlsxSaxAnalyser.class);
/**
* If it's less than 5M, use map cache, or use ehcache.
*/
private static final long USE_MAP_CACHE_SIZE = 5 * 1000 * 1000L;
private AnalysisContext analysisContext;
private List<ReadSheet> sheetList;
private Map<Integer, InputStream> sheetMap;
/**
* Current style information
*/
private StylesTable stylesTable;
public XlsxSaxAnalyser(AnalysisContext analysisContext, InputStream decryptedStream) throws Exception {
this.analysisContext = analysisContext;
// Initialize cache
ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder();
private XSSFReader xssfReader; OPCPackage pkg = readOpcPackage(readWorkbookHolder, decryptedStream);
PackagePart sharedStringsTablePackagePart =
pkg.getPartsByContentType(XSSFRelation.SHARED_STRINGS.getContentType()).get(0);
private SharedStringsTable sharedStringsTable; // Specify default cache
defaultReadCache(readWorkbookHolder, sharedStringsTablePackagePart);
private List<SheetSource> sheetSourceList = new ArrayList<SheetSource>(); // Analysis sharedStringsTable.xml
analysisSharedStringsTable(sharedStringsTablePackagePart.getInputStream(), readWorkbookHolder);
private boolean use1904WindowDate = false; XSSFReader xssfReader = new XSSFReader(pkg);
analysisUse1904WindowDate(xssfReader, readWorkbookHolder);
public XlsxSaxAnalyser(AnalysisContext analysisContext) throws IOException, OpenXML4JException, XmlException { stylesTable = xssfReader.getStylesTable();
this.analysisContext = analysisContext; sheetList = new ArrayList<ReadSheet>();
sheetMap = new HashMap<Integer, InputStream>();
XSSFReader.SheetIterator ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData();
int index = 0;
if (!ite.hasNext()) {
throw new ExcelAnalysisException("Can not find any sheet!");
}
while (ite.hasNext()) {
InputStream inputStream = ite.next();
sheetList.add(new ReadSheet(index, ite.getSheetName()));
sheetMap.put(index, inputStream);
index++;
}
}
analysisContext.setCurrentRowNum(0); private void defaultReadCache(ReadWorkbookHolder readWorkbookHolder, PackagePart sharedStringsTablePackagePart)
this.xssfReader = new XSSFReader(OPCPackage.open(analysisContext.getInputStream())); throws IOException {
this.sharedStringsTable = this.xssfReader.getSharedStringsTable(); if (readWorkbookHolder.getReadCache() != null) {
readWorkbookHolder.getReadCache().init(analysisContext);
return;
}
long size = sharedStringsTablePackagePart.getSize();
if (size < 0) {
size = sharedStringsTablePackagePart.getInputStream().available();
}
if (size < USE_MAP_CACHE_SIZE) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Use map cache.size:{}", size);
}
readWorkbookHolder.setReadCache(new MapCache());
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Use ehcache.size:{}", size);
}
readWorkbookHolder.setReadCache(new Ehcache());
}
readWorkbookHolder.getReadCache().init(analysisContext);
}
private void analysisUse1904WindowDate(XSSFReader xssfReader, ReadWorkbookHolder readWorkbookHolder)
throws Exception {
if (readWorkbookHolder.globalConfiguration().getUse1904windowing() != null) {
return;
}
InputStream workbookXml = xssfReader.getWorkbookData(); InputStream workbookXml = xssfReader.getWorkbookData();
WorkbookDocument ctWorkbook = WorkbookDocument.Factory.parse(workbookXml); WorkbookDocument ctWorkbook = WorkbookDocument.Factory.parse(workbookXml);
CTWorkbook wb = ctWorkbook.getWorkbook(); CTWorkbook wb = ctWorkbook.getWorkbook();
CTWorkbookPr prefix = wb.getWorkbookPr(); CTWorkbookPr prefix = wb.getWorkbookPr();
if (prefix != null) { if (prefix != null && prefix.getDate1904()) {
this.use1904WindowDate = prefix.getDate1904(); readWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.TRUE);
} else {
readWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.FALSE);
} }
this.analysisContext.setUse1904WindowDate(use1904WindowDate); }
private void analysisSharedStringsTable(InputStream sharedStringsTableInputStream,
ReadWorkbookHolder readWorkbookHolder) throws Exception {
ContentHandler handler = new SharedStringsTableHandler(readWorkbookHolder.getReadCache());
parseXmlSource(sharedStringsTableInputStream, handler);
readWorkbookHolder.getReadCache().putFinished();
}
XSSFReader.SheetIterator ite; private OPCPackage readOpcPackage(ReadWorkbookHolder readWorkbookHolder, InputStream decryptedStream)
sheetSourceList = new ArrayList<SheetSource>(); throws Exception {
ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData(); if (decryptedStream == null && readWorkbookHolder.getFile() != null) {
while (ite.hasNext()) { return OPCPackage.open(readWorkbookHolder.getFile());
InputStream inputStream = ite.next();
String sheetName = ite.getSheetName();
SheetSource sheetSource = new SheetSource(sheetName, inputStream);
sheetSourceList.add(sheetSource);
} }
if (readWorkbookHolder.getMandatoryUseInputStream()) {
if (decryptedStream != null) {
return OPCPackage.open(decryptedStream);
} else {
return OPCPackage.open(readWorkbookHolder.getInputStream());
}
}
File readTempFile = FileUtils.createCacheTmpFile();
readWorkbookHolder.setTempFile(readTempFile);
File tempFile = new File(readTempFile.getPath(), UUID.randomUUID().toString() + ".xlsx");
if (decryptedStream != null) {
FileUtils.writeToFile(tempFile, decryptedStream);
} else {
FileUtils.writeToFile(tempFile, readWorkbookHolder.getInputStream());
}
return OPCPackage.open(tempFile);
} }
@Override @Override
protected void execute() { public List<ReadSheet> sheetList() {
Sheet sheetParam = analysisContext.getCurrentSheet(); return sheetList;
if (sheetParam != null && sheetParam.getSheetNo() > 0 && sheetSourceList.size() >= sheetParam.getSheetNo()) {
InputStream sheetInputStream = sheetSourceList.get(sheetParam.getSheetNo() - 1).getInputStream();
parseXmlSource(sheetInputStream);
} else {
int i = 0;
for (SheetSource sheetSource : sheetSourceList) {
i++;
analysisContext.setCurrentSheet(new Sheet(i));
parseXmlSource(sheetSource.getInputStream());
}
}
} }
private void parseXmlSource(InputStream inputStream) { private void parseXmlSource(InputStream inputStream, ContentHandler handler) {
InputSource sheetSource = new InputSource(inputStream); InputSource inputSource = new InputSource(inputStream);
try { try {
SAXParserFactory saxFactory = SAXParserFactory.newInstance(); SAXParserFactory saxFactory = SAXParserFactory.newInstance();
saxFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); saxFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
@ -92,55 +171,28 @@ public class XlsxSaxAnalyser extends BaseSaxAnalyser {
saxFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); saxFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
SAXParser saxParser = saxFactory.newSAXParser(); SAXParser saxParser = saxFactory.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader(); XMLReader xmlReader = saxParser.getXMLReader();
ContentHandler handler = new XlsxRowHandler(this, sharedStringsTable, analysisContext);
xmlReader.setContentHandler(handler); xmlReader.setContentHandler(handler);
xmlReader.parse(sheetSource); xmlReader.parse(inputSource);
inputStream.close(); inputStream.close();
} catch (ExcelAnalysisException e) {
throw e;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace();
throw new ExcelAnalysisException(e); throw new ExcelAnalysisException(e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
throw new ExcelAnalysisException("Can not close 'inputStream'!");
}
}
} }
} }
@Override @Override
public List<Sheet> getSheets() { public void execute() {
List<Sheet> sheets = new ArrayList<Sheet>(); parseXmlSource(sheetMap.get(analysisContext.readSheetHolder().getSheetNo()),
int i = 1; new XlsxRowHandler(analysisContext, stylesTable));
for (SheetSource sheetSource : sheetSourceList) {
Sheet sheet = new Sheet(i, 0);
sheet.setSheetName(sheetSource.getSheetName());
i++;
sheets.add(sheet);
}
return sheets;
} }
class SheetSource {
private String sheetName;
private InputStream inputStream;
public SheetSource(String sheetName, InputStream inputStream) {
this.sheetName = sheetName;
this.inputStream = inputStream;
}
public String getSheetName() {
return sheetName;
}
public void setSheetName(String sheetName) {
this.sheetName = sheetName;
}
public InputStream getInputStream() {
return inputStream;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
}
} }

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

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

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

@ -0,0 +1,182 @@
package com.alibaba.excel.analysis.v07.handlers;
import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_DATA_FORMAT_TAG;
import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_FORMULA_TAG;
import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_INLINE_STRING_VALUE_TAG;
import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_TAG;
import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_VALUE_TAG;
import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_VALUE_TYPE_TAG;
import java.util.Map;
import java.util.TreeMap;
import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.Attributes;
import com.alibaba.excel.analysis.v07.XlsxCellHandler;
import com.alibaba.excel.analysis.v07.XlsxRowResultHolder;
import com.alibaba.excel.constant.ExcelXmlConstants;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.util.BooleanUtils;
import com.alibaba.excel.util.PositionUtils;
import com.alibaba.excel.util.StringUtils;
/**
* Cell Handler
*
* @author jipengfei
*/
public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder {
private final AnalysisContext analysisContext;
private String currentTag;
private String currentCellIndex;
private int curRow;
private int curCol;
private Map<Integer, CellData> curRowContent = new TreeMap<Integer, CellData>();
private CellData currentCellData;
/**
* Current style information
*/
private StylesTable stylesTable;
public DefaultCellHandler(AnalysisContext analysisContext, StylesTable stylesTable) {
this.analysisContext = analysisContext;
this.stylesTable = stylesTable;
}
@Override
public void clearResult() {
curRowContent = new TreeMap<Integer, CellData>();
}
@Override
public boolean support(String name) {
return CELL_VALUE_TAG.equals(name) || CELL_FORMULA_TAG.equals(name) || CELL_INLINE_STRING_VALUE_TAG.equals(name)
|| CELL_TAG.equals(name);
}
@Override
public void startHandle(String name, Attributes attributes) {
currentTag = name;
// start a cell
if (CELL_TAG.equals(name)) {
currentCellIndex = attributes.getValue(ExcelXmlConstants.POSITION);
int nextRow = PositionUtils.getRow(currentCellIndex);
if (nextRow > curRow) {
curRow = nextRow;
}
analysisContext
.readRowHolder(new ReadRowHolder(curRow, analysisContext.readSheetHolder().getGlobalConfiguration()));
curCol = PositionUtils.getCol(currentCellIndex);
// t="s" ,it's means String
// t="str" ,it's means String,but does not need to be read in the 'sharedStrings.xml'
// t="inlineStr" ,it's means String
// t="b" ,it's means Boolean
// t="e" ,it's means Error
// t="n" ,it's means Number
// t is null ,it's means Empty or Number
CellDataTypeEnum type = CellDataTypeEnum.buildFromCellType(attributes.getValue(CELL_VALUE_TYPE_TAG));
currentCellData = new CellData(type);
// Put in data transformation information
String dateFormatIndex = attributes.getValue(CELL_DATA_FORMAT_TAG);
if (dateFormatIndex != null) {
int dateFormatIndexInteger = Integer.parseInt(dateFormatIndex);
XSSFCellStyle xssfCellStyle = stylesTable.getStyleAt(dateFormatIndexInteger);
int dataFormat = xssfCellStyle.getDataFormat();
String dataFormatString = xssfCellStyle.getDataFormatString();
currentCellData.setDataFormat(dataFormat);
if (dataFormatString == null) {
currentCellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat));
} else {
currentCellData.setDataFormatString(dataFormatString);
}
}
}
// cell is formula
if (CELL_FORMULA_TAG.equals(name)) {
currentCellData.setFormula(Boolean.TRUE);
}
}
@Override
public void endHandle(String name) {
if (CELL_VALUE_TAG.equals(name)) {
// Have to go "sharedStrings.xml" and get it
if (currentCellData.getType() == CellDataTypeEnum.STRING) {
String stringValue = analysisContext.readWorkbookHolder().getReadCache()
.get(Integer.valueOf(currentCellData.getStringValue()));
if (stringValue != null && analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()) {
stringValue = stringValue.trim();
}
currentCellData.setStringValue(stringValue);
} else if (currentCellData.getType() == CellDataTypeEnum.DIRECT_STRING) {
currentCellData.setType(CellDataTypeEnum.STRING);
}
curRowContent.put(curCol, currentCellData);
}
// This is a special form of string
if (CELL_INLINE_STRING_VALUE_TAG.equals(name)) {
XSSFRichTextString richTextString = new XSSFRichTextString(currentCellData.getStringValue());
String stringValue = richTextString.toString();
if (stringValue != null && analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()) {
stringValue = stringValue.trim();
}
currentCellData.setStringValue(stringValue);
curRowContent.put(curCol, currentCellData);
}
}
@Override
public void appendCurrentCellValue(String currentCellValue) {
if (StringUtils.isEmpty(currentCellValue)) {
return;
}
if (currentTag == null) {
return;
}
if (CELL_FORMULA_TAG.equals(currentTag)) {
currentCellData.setFormulaValue(currentCellValue);
return;
}
CellDataTypeEnum oldType = currentCellData.getType();
switch (oldType) {
case DIRECT_STRING:
case STRING:
case ERROR:
if (currentCellData.getStringValue() == null) {
currentCellData.setStringValue(currentCellValue);
} else {
currentCellData.setStringValue(currentCellData.getStringValue() + currentCellValue);
}
break;
case BOOLEAN:
if (currentCellData.getBooleanValue() == null) {
currentCellData.setBooleanValue(BooleanUtils.valueOf(currentCellValue));
}
break;
case NUMBER:
case EMPTY:
currentCellData.setType(CellDataTypeEnum.NUMBER);
if (currentCellData.getDoubleValue() == null) {
currentCellData.setDoubleValue(Double.valueOf(currentCellValue));
}
break;
default:
throw new IllegalStateException("Cannot set values now");
}
}
@Override
public Map<Integer, CellData> getCurRowContent() {
return curRowContent;
}
}

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

@ -0,0 +1,41 @@
package com.alibaba.excel.analysis.v07.handlers;
import static com.alibaba.excel.constant.ExcelXmlConstants.ROW_TAG;
import org.xml.sax.Attributes;
import com.alibaba.excel.analysis.v07.XlsxCellHandler;
import com.alibaba.excel.analysis.v07.XlsxRowResultHolder;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.event.EachRowAnalysisFinishEvent;
/**
* Cell Handler
*
* @author jipengfei
*/
public class ProcessResultCellHandler implements XlsxCellHandler {
private AnalysisContext analysisContext;
private XlsxRowResultHolder rowResultHandler;
public ProcessResultCellHandler(AnalysisContext analysisContext, XlsxRowResultHolder rowResultHandler) {
this.analysisContext = analysisContext;
this.rowResultHandler = rowResultHandler;
}
@Override
public boolean support(String name) {
return ROW_TAG.equals(name);
}
@Override
public void startHandle(String name, Attributes attributes) {}
@Override
public void endHandle(String name) {
analysisContext.readSheetHolder()
.notifyEndOneRow(new EachRowAnalysisFinishEvent(rowResultHandler.getCurRowContent()), analysisContext);
rowResultHandler.clearResult();
}
}

34
src/main/java/com/alibaba/excel/annotation/ExcelColumnNum.java

@ -1,34 +0,0 @@
package com.alibaba.excel.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by jipengfei on 17/3/19.
* Field column num at excel head
*
* @author jipengfei
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ExcelColumnNum {
/**
* col num
* @return
*/
int value();
/**
*
* Default @see com.alibaba.excel.util.TypeUtil
* if default is not meet you can set format
*
* @return
*/
String format() default "";
}

17
src/main/java/com/alibaba/excel/annotation/ExcelIgnore.java

@ -0,0 +1,17 @@
package com.alibaba.excel.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Ignore convert excel
*
* @author Jiaju Zhuang
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ExcelIgnore {}

53
src/main/java/com/alibaba/excel/annotation/ExcelProperty.java

@ -6,6 +6,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import com.alibaba.excel.converters.AutoConverter;
import com.alibaba.excel.converters.Converter;
/** /**
* @author jipengfei * @author jipengfei
*/ */
@ -14,23 +17,41 @@ import java.lang.annotation.Target;
@Inherited @Inherited
public @interface ExcelProperty { public @interface ExcelProperty {
/** /**
* @return * The name of the sheet header.
*/ *
String[] value() default {""}; * <p>
* write: It automatically merges when you have more than one head
* <p>
* read: When you have multiple heads, take the first one
*
* @return The name of the sheet header
*/
String[] value() default {""};
/**
* Index of column
*
* Read or write it on the index of column,If it's equal to -1, it's sorted by Java class
*
* @return Index of column
*/
int index() default -1;
/** /**
* @return * Force the current field to use this converter.
*/ *
int index() default 99999; * @return Converter
*/
Class<? extends Converter> converter() default AutoConverter.class;
/** /**
* *
* default @see com.alibaba.excel.util.TypeUtil * default @see com.alibaba.excel.util.TypeUtil if default is not meet you can set format
* if default is not meet you can set format *
* * @return Format string
* @return * @deprecated please use {@link com.alibaba.excel.annotation.format.DateTimeFormat}
*/ */
String format() default ""; @Deprecated
String format() default "";
} }

11
src/main/java/com/alibaba/excel/annotation/FieldType.java

@ -1,11 +0,0 @@
package com.alibaba.excel.annotation;
/**
*
* @author jipengfei
*/
public enum FieldType {
STRING, INT, LONG, DATE, BOOLEAN, DOUBLE,EMPTY;
}

38
src/main/java/com/alibaba/excel/annotation/format/DateTimeFormat.java

@ -0,0 +1,38 @@
package com.alibaba.excel.annotation.format;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Convert date format.
*
* <p>
* write: It can be used on classes {@link java.util.Date}
* <p>
* read: It can be used on classes {@link String}
*
* @author Jiaju Zhuang
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface DateTimeFormat {
/**
*
* Specific format reference {@link java.text.SimpleDateFormat}
*
* @return Format pattern
*/
String value() default "";
/**
* True if date uses 1904 windowing, or false if using 1900 date windowing.
*
* @return True if date uses 1904 windowing, or false if using 1900 date windowing.
*/
boolean use1904windowing() default false;
}

39
src/main/java/com/alibaba/excel/annotation/format/NumberFormat.java

@ -0,0 +1,39 @@
package com.alibaba.excel.annotation.format;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.math.RoundingMode;
/**
* Convert number format.
*
* <p>
* write: It can be used on classes that inherit {@link Number}
* <p>
* read: It can be used on classes {@link String}
*
* @author Jiaju Zhuang
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface NumberFormat {
/**
*
* Specific format reference {@link org.apache.commons.math3.fraction.BigFractionFormat}
*
* @return Format pattern
*/
String value() default "";
/**
* Rounded by default
*
* @return RoundingMode
*/
RoundingMode roundingMode() default RoundingMode.HALF_UP;
}

27
src/main/java/com/alibaba/excel/annotation/write/style/ColumnWidth.java

@ -0,0 +1,27 @@
package com.alibaba.excel.annotation.write.style;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Set the width of the table
*
* @author Jiaju Zhuang
*/
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ColumnWidth {
/**
* Column width
* <p>
* -1 means the default column width is used
*
* @return Column width
*/
int value() default -1;
}

27
src/main/java/com/alibaba/excel/annotation/write/style/ContentRowHeight.java

@ -0,0 +1,27 @@
package com.alibaba.excel.annotation.write.style;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Set the height of each table
*
* @author Jiaju Zhuang
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ContentRowHeight {
/**
* Set the content height
* <p>
* -1 mean the auto set height
*
* @return Content height
*/
short value() default -1;
}

26
src/main/java/com/alibaba/excel/annotation/write/style/HeadRowHeight.java

@ -0,0 +1,26 @@
package com.alibaba.excel.annotation.write.style;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Set the height of each table
*
* @author Jiaju Zhuang
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface HeadRowHeight {
/**
* Set the header height
* <p>
* -1 mean the auto set height
*
* @return Header height
*/
short value() default -1;
}

213
src/main/java/com/alibaba/excel/cache/Ehcache.java vendored

@ -0,0 +1,213 @@
package com.alibaba.excel.cache;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.ehcache.CacheManager;
import org.ehcache.PersistentCacheManager;
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.FileUtils;
import com.alibaba.excel.util.StringUtils;
/**
* Default cache
*
* @author Jiaju Zhuang
*/
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 CHECK_INTERVAL = 500;
private static final int MAX_CACHE_ACTIVATE = 10;
private static final String CACHE = "cache";
private static final String DATA_SEPARATOR = "@";
private static final String KEY_VALUE_SEPARATOR = "!";
private static final String SPECIAL_SEPARATOR = "&";
private static final String ESCAPED_DATA_SEPARATOR = "&d;";
private static final String ESCAPED_KEY_VALUE_SEPARATOR = "&kv;";
private static final String ESCAPED_SPECIAL_SEPARATOR = "&s;";
private static final int DEBUG_WRITE_SIZE = 100 * 10000;
private static final int DEBUG_CACHE_MISS_SIZE = 1000;
/**
* Key index
*/
private int index = 0;
private StringBuilder data = new StringBuilder();
private CacheManager cacheManager;
/**
* Bulk storage data
*/
private org.ehcache.Cache<Integer, String> cache;
/**
* Currently active cache
*/
private Map<Integer, Map<Integer, String>> cacheMap = new HashMap<Integer, Map<Integer, String>>();
/**
* Count how many times get
*/
private int getCount = 0;
/**
* Count active cache
*
*/
private LinkedList<Integer> countList = new LinkedList<Integer>();
/**
* Count the last {@link #CHECK_INTERVAL} used
*/
private Set<Integer> lastCheckIntervalUsedSet = new HashSet<Integer>();
/**
* Count the number of cache misses
*/
private int cacheMiss = 0;
@Override
public void init(AnalysisContext analysisContext) {
File readTempFile = analysisContext.readWorkbookHolder().getTempFile();
if (readTempFile == null) {
readTempFile = FileUtils.createCacheTmpFile();
analysisContext.readWorkbookHolder().setTempFile(readTempFile);
}
File cacheFile = new File(readTempFile.getPath(), UUID.randomUUID().toString());
PersistentCacheManager persistentCacheManager =
CacheManagerBuilder.newCacheManagerBuilder().with(CacheManagerBuilder.persistence(cacheFile))
.withCache(CACHE, CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder().disk(10, MemoryUnit.GB)))
.build(true);
cacheManager = persistentCacheManager;
cache = persistentCacheManager.getCache(CACHE, Integer.class, String.class);
}
@Override
public void put(String value) {
data.append(index).append(KEY_VALUE_SEPARATOR).append(escape(value)).append(DATA_SEPARATOR);
if ((index + 1) % BATCH_COUNT == 0) {
cache.put(index / BATCH_COUNT, data.toString());
data = new StringBuilder();
}
index++;
if (LOGGER.isDebugEnabled()) {
if (index % DEBUG_WRITE_SIZE == 0) {
LOGGER.debug("Already put :{}", index);
}
}
}
private String escape(String str) {
if (StringUtils.isEmpty(str)) {
return str;
}
str = str.replaceAll(SPECIAL_SEPARATOR, ESCAPED_SPECIAL_SEPARATOR);
str = str.replaceAll(DATA_SEPARATOR, ESCAPED_DATA_SEPARATOR);
str = str.replaceAll(KEY_VALUE_SEPARATOR, ESCAPED_KEY_VALUE_SEPARATOR);
return str;
}
private String unescape(String str) {
if (StringUtils.isEmpty(str)) {
return str;
}
str = str.replaceAll(ESCAPED_KEY_VALUE_SEPARATOR, KEY_VALUE_SEPARATOR);
str = str.replaceAll(ESCAPED_DATA_SEPARATOR, DATA_SEPARATOR);
str = str.replaceAll(ESCAPED_SPECIAL_SEPARATOR, SPECIAL_SEPARATOR);
return str;
}
@Override
public String get(Integer key) {
if (key == null || key < 0) {
return null;
}
getCount++;
int route = key / BATCH_COUNT;
if (cacheMap.containsKey(route)) {
lastCheckIntervalUsedSet.add(route);
String value = cacheMap.get(route).get(key);
checkClear();
return value;
}
Map<Integer, String> tempCacheMap = new HashMap<Integer, String>(BATCH_COUNT / 3 * 4 + 1);
String batchData = cache.get(route);
String[] dataStrings = batchData.split(DATA_SEPARATOR);
for (String dataString : dataStrings) {
String[] keyValue = dataString.split(KEY_VALUE_SEPARATOR);
tempCacheMap.put(Integer.valueOf(keyValue[0]), unescape(keyValue[1]));
}
countList.add(route);
cacheMap.put(route, tempCacheMap);
if (LOGGER.isDebugEnabled()) {
if (cacheMiss++ % DEBUG_CACHE_MISS_SIZE == 0) {
LOGGER.debug("Cache misses count:{}", cacheMiss);
}
}
lastCheckIntervalUsedSet.add(route);
String value = tempCacheMap.get(key);
checkClear();
return value;
}
private void checkClear() {
if (countList.size() > MAX_CACHE_ACTIVATE) {
Integer route = countList.getFirst();
countList.removeFirst();
cacheMap.remove(route);
}
if (getCount++ % CHECK_INTERVAL != 0) {
return;
}
Iterator<Map.Entry<Integer, Map<Integer, String>>> iterator = cacheMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Integer, Map<Integer, String>> entry = iterator.next();
if (lastCheckIntervalUsedSet.contains(entry.getKey())) {
continue;
}
// Last 'CHECK_INTERVAL' not use
iterator.remove();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Cache remove because {} times unused.", CHECK_INTERVAL);
}
Iterator<Integer> countIterator = countList.iterator();
while (countIterator.hasNext()) {
Integer route = countIterator.next();
if (route.equals(entry.getKey())) {
countIterator.remove();
break;
}
}
}
lastCheckIntervalUsedSet.clear();
}
@Override
public void putFinished() {
if (StringUtils.isEmpty(data.toString())) {
return;
}
cache.put(index / BATCH_COUNT, data.toString());
}
@Override
public void destroy() {
cacheManager.close();
}
}

40
src/main/java/com/alibaba/excel/cache/MapCache.java vendored

@ -0,0 +1,40 @@
package com.alibaba.excel.cache;
import java.util.HashMap;
import java.util.Map;
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<Integer, String> cache = new HashMap<Integer, String>();
private int index = 0;
@Override
public void init(AnalysisContext analysisContext) {}
@Override
public void put(String value) {
cache.put(index++, value);
}
@Override
public String get(Integer key) {
if (key == null || key < 0) {
return null;
}
return cache.get(key);
}
@Override
public void putFinished() {}
@Override
public void destroy() {}
}

47
src/main/java/com/alibaba/excel/cache/ReadCache.java vendored

@ -0,0 +1,47 @@
package com.alibaba.excel.cache;
import com.alibaba.excel.context.AnalysisContext;
/**
* Read cache
*
* @author Jiaju Zhuang
*/
public interface ReadCache {
/**
* Initialize cache
*
* @param analysisContext
* A context is the main anchorage point of a excel reader.
*/
void init(AnalysisContext analysisContext);
/**
* Automatically generate the key and put it in the cache.Key start from 0
*
* @param value
* Cache value
*/
void put(String value);
/**
* Get value
*
* @param key
* Index
* @return Value
*/
String get(Integer key);
/**
* It's called when all the values are put in
*/
void putFinished();
/**
* Called when the excel read is complete
*/
void destroy();
}

12
src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java

@ -10,8 +10,16 @@ public class ExcelXmlConstants {
public static final String ROW_TAG = "row"; public static final String ROW_TAG = "row";
public static final String CELL_TAG = "c"; public static final String CELL_TAG = "c";
public static final String CELL_VALUE_TYPE_TAG = "t";
/**
* Number formatted label
*/
public static final String CELL_DATA_FORMAT_TAG = "s";
public static final String CELL_FORMULA_TAG = "f";
public static final String CELL_VALUE_TAG = "v"; public static final String CELL_VALUE_TAG = "v";
/**
public static final String CELL_VALUE_TAG_1 = "t"; * When the data is "inlineStr" his tag is "t"
*/
public static final String CELL_INLINE_STRING_VALUE_TAG = "t";
} }

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

@ -1,132 +1,137 @@
package com.alibaba.excel.context; package com.alibaba.excel.context;
import java.io.InputStream;
import com.alibaba.excel.analysis.ExcelExecutor;
import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.ExcelHeadProperty;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.holder.ReadHolder;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.read.metadata.holder.ReadSheetHolder;
import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import java.io.InputStream;
import java.util.List;
/** /**
* *
* A context is the main anchorage point of a excel reader. * A context is the main anchorage point of a excel reader.
*
* @author jipengfei * @author jipengfei
*/ */
public interface AnalysisContext { public interface AnalysisContext {
/** /**
* Custom attribute * Select the current table
*
* @param excelExecutor
* Excel file Executor
* @param readSheet
* sheet to read
*/ */
Object getCustom(); void currentSheet(ExcelExecutor excelExecutor, ReadSheet readSheet);
/** /**
* get current sheet * All information about the workbook you are currently working on
* *
* @return current analysis sheet * @return Current workbook holder
*/ */
Sheet getCurrentSheet(); ReadWorkbookHolder readWorkbookHolder();
/** /**
* set current sheet * All information about the sheet you are currently working on
* @param sheet *
* @return Current sheet holder
*/ */
void setCurrentSheet(Sheet sheet); ReadSheetHolder readSheetHolder();
/** /**
* Set row of currently operated cell
* *
* get excel type * @param readRowHolder
* @return excel type * Current row holder
*/ */
ExcelTypeEnum getExcelType(); void readRowHolder(ReadRowHolder readRowHolder);
/** /**
* get in io * Row of currently operated cell
* @return file io *
* @return Current row holder
*/ */
InputStream getInputStream(); ReadRowHolder readRowHolder();
/** /**
* The current read operation corresponds to the <code>readSheetHolder</code> or <code>readWorkbookHolder</code>
* *
* custom listener * @return Current holder
* @return listener
*/ */
AnalysisEventListener getEventListener(); ReadHolder currentReadHolder();
/** /**
* get current row * Custom attribute
*
* @return * @return
*/ */
Integer getCurrentRowNum(); Object getCustom();
/**
* set current row num
* @param row
*/
void setCurrentRowNum(Integer row);
/** /**
* get total row ,Data may be inaccurate * get current sheet
* @return *
* @return current analysis sheet
* @deprecated please use {@link #readSheetHolder()}
*/ */
@Deprecated @Deprecated
Integer getTotalCount(); Sheet getCurrentSheet();
/** /**
* get total row ,Data may be inaccurate
* *
* @param totalCount * get excel type
*/ *
void setTotalCount(Integer totalCount); * @return excel type
* @deprecated please use {@link #readWorkbookHolder()}
/**
* get excel head
* @return
*/ */
ExcelHeadProperty getExcelHeadProperty(); @Deprecated
ExcelTypeEnum getExcelType();
/** /**
* get in io
* *
* @param clazz * @return file io
* @param headOneRow * @deprecated please use {@link #readWorkbookHolder()}
*/ */
void buildExcelHeadProperty(Class<? extends BaseRowModel> clazz, List<String> headOneRow); @Deprecated
InputStream getInputStream();
/** /**
* get current row
* *
*if need to short match the content
* @return * @return
* @deprecated please use {@link #readRowHolder()}
*/ */
boolean trim(); @Deprecated
Integer getCurrentRowNum();
/** /**
* set current result * get total row ,Data may be inaccurate
* @param result *
* @return
* @deprecated please use {@link #readRowHolder()}
*/ */
void setCurrentRowAnalysisResult(Object result); @Deprecated
Integer getTotalCount();
/** /**
* get current result * get current result
* @return get current result *
* @return get current result
* @deprecated please use {@link #readRowHolder()}
*/ */
@Deprecated
Object getCurrentRowAnalysisResult(); Object getCurrentRowAnalysisResult();
/** /**
* Interrupt execution * Interrupt execution
*
* @deprecated please use {@link AnalysisEventListener#hasNext(AnalysisContext)}
*/ */
@Deprecated
void interrupt(); void interrupt();
/**
* date use1904WindowDate
* @return
*/
boolean use1904WindowDate();
/**
* date use1904WindowDate
* @param use1904WindowDate
*/
void setUse1904WindowDate(boolean use1904WindowDate);
} }

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

@ -1,172 +1,189 @@
package com.alibaba.excel.context; package com.alibaba.excel.context;
import com.alibaba.excel.event.AnalysisEventListener; import java.io.InputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.analysis.ExcelExecutor;
import com.alibaba.excel.analysis.v07.XlsxSaxAnalyser;
import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.ExcelHeadProperty;
import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.ReadWorkbook;
import com.alibaba.excel.read.metadata.holder.ReadHolder;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.read.metadata.holder.ReadSheetHolder;
import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.StringUtils;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/** /**
* *
* @author jipengfei * @author jipengfei
*/ */
public class AnalysisContextImpl implements AnalysisContext { public class AnalysisContextImpl implements AnalysisContext {
private static final Logger LOGGER = LoggerFactory.getLogger(AnalysisContextImpl.class);
private Object custom; /**
* The Workbook currently written
private Sheet currentSheet; */
private ReadWorkbookHolder readWorkbookHolder;
private ExcelTypeEnum excelType; /**
* Current sheet holder
private InputStream inputStream; */
private ReadSheetHolder readSheetHolder;
private AnalysisEventListener eventListener; /**
* Current row holder
private Integer currentRowNum; */
private ReadRowHolder readRowHolder;
private Integer totalCount; /**
* Configuration of currently operated cell
private ExcelHeadProperty excelHeadProperty; */
private ReadHolder currentReadHolder;
private boolean trim;
public AnalysisContextImpl(ReadWorkbook readWorkbook) {
private boolean use1904WindowDate = false; if (readWorkbook == null) {
throw new IllegalArgumentException("Workbook argument cannot be null");
@Override }
public void setUse1904WindowDate(boolean use1904WindowDate) { readWorkbookHolder = new ReadWorkbookHolder(readWorkbook);
this.use1904WindowDate = use1904WindowDate; currentReadHolder = readWorkbookHolder;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Initialization 'AnalysisContextImpl' complete");
}
} }
@Override @Override
public Object getCurrentRowAnalysisResult() { public void currentSheet(ExcelExecutor excelExecutor, ReadSheet readSheet) {
return currentRowAnalysisResult; if (readSheet == null) {
throw new IllegalArgumentException("Sheet argument cannot be null.");
}
readSheetHolder = new ReadSheetHolder(readSheet, readWorkbookHolder);
currentReadHolder = readSheetHolder;
selectSheet(excelExecutor);
if (readWorkbookHolder.getHasReadSheet().contains(readSheetHolder.getSheetNo())) {
throw new ExcelAnalysisException("Cannot read sheet repeatedly.");
}
readWorkbookHolder.getHasReadSheet().add(readSheetHolder.getSheetNo());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Began to read:{}", readSheetHolder);
}
} }
@Override private void selectSheet(ExcelExecutor excelExecutor) {
public void interrupt() { if (excelExecutor instanceof XlsxSaxAnalyser) {
throw new ExcelAnalysisException("interrupt error"); selectSheet07(excelExecutor);
} else {
selectSheet03();
}
} }
@Override private void selectSheet03() {
public boolean use1904WindowDate() { if (readSheetHolder.getSheetNo() != null && readSheetHolder.getSheetNo() >= 0) {
return use1904WindowDate; return;
}
if (!StringUtils.isEmpty(readSheetHolder.getSheetName())) {
LOGGER.warn("Excel 2003 does not support matching sheets by name, defaults to the first one.");
}
readSheetHolder.setSheetNo(0);
}
private void selectSheet07(ExcelExecutor excelExecutor) {
if (readSheetHolder.getSheetNo() != null && readSheetHolder.getSheetNo() >= 0) {
for (ReadSheet readSheetExcel : excelExecutor.sheetList()) {
if (readSheetExcel.getSheetNo().equals(readSheetHolder.getSheetNo())) {
readSheetHolder.setSheetName(readSheetExcel.getSheetName());
return;
}
}
throw new ExcelAnalysisException("Can not find sheet:" + readSheetHolder.getSheetNo());
}
if (!StringUtils.isEmpty(readSheetHolder.getSheetName())) {
for (ReadSheet readSheetExcel : excelExecutor.sheetList()) {
String sheetName = readSheetExcel.getSheetName();
if (sheetName == null) {
continue;
}
if (readSheetHolder.globalConfiguration().getAutoTrim()) {
sheetName = sheetName.trim();
}
if (sheetName.equals(readSheetHolder.getSheetName())) {
readSheetHolder.setSheetNo(readSheetExcel.getSheetNo());
return;
}
}
}
ReadSheet readSheetExcel = excelExecutor.sheetList().get(0);
readSheetHolder.setSheetNo(readSheetExcel.getSheetNo());
readSheetHolder.setSheetName(readSheetExcel.getSheetName());
} }
@Override @Override
public void setCurrentRowAnalysisResult(Object currentRowAnalysisResult) { public ReadWorkbookHolder readWorkbookHolder() {
this.currentRowAnalysisResult = currentRowAnalysisResult; return readWorkbookHolder;
}
private Object currentRowAnalysisResult;
public AnalysisContextImpl(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom,
AnalysisEventListener listener, boolean trim) {
this.custom = custom;
this.eventListener = listener;
this.inputStream = inputStream;
this.excelType = excelTypeEnum;
this.trim = trim;
} }
@Override @Override
public void setCurrentSheet(Sheet currentSheet) { public ReadSheetHolder readSheetHolder() {
cleanCurrentSheet(); return readSheetHolder;
this.currentSheet = currentSheet;
if (currentSheet.getClazz() != null) {
buildExcelHeadProperty(currentSheet.getClazz(), null);
}
} }
private void cleanCurrentSheet() { @Override
this.currentSheet = null; public ReadRowHolder readRowHolder() {
this.excelHeadProperty = null; return readRowHolder;
this.totalCount = 0;
this.currentRowAnalysisResult = null;
this.currentRowNum =0;
} }
@Override @Override
public ExcelTypeEnum getExcelType() { public void readRowHolder(ReadRowHolder readRowHolder) {
return excelType; this.readRowHolder = readRowHolder;
} }
public void setExcelType(ExcelTypeEnum excelType) { @Override
this.excelType = excelType; public ReadHolder currentReadHolder() {
return currentReadHolder;
} }
@Override
public Object getCustom() { public Object getCustom() {
return custom; return readWorkbookHolder.getCustomObject();
}
public void setCustom(Object custom) {
this.custom = custom;
} }
@Override @Override
public Sheet getCurrentSheet() { public Sheet getCurrentSheet() {
return currentSheet; Sheet sheet = new Sheet(readSheetHolder.getSheetNo() + 1);
sheet.setSheetName(readSheetHolder.getSheetName());
sheet.setHead(readSheetHolder.getHead());
sheet.setClazz(readSheetHolder.getClazz());
sheet.setHeadLineMun(readSheetHolder.getHeadRowNumber());
return sheet;
} }
@Override @Override
public InputStream getInputStream() { public ExcelTypeEnum getExcelType() {
return inputStream; return readWorkbookHolder.getExcelType();
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
} }
@Override @Override
public AnalysisEventListener getEventListener() { public InputStream getInputStream() {
return eventListener; return readWorkbookHolder.getInputStream();
}
public void setEventListener(AnalysisEventListener eventListener) {
this.eventListener = eventListener;
} }
@Override @Override
public Integer getCurrentRowNum() { public Integer getCurrentRowNum() {
return this.currentRowNum; return readRowHolder.getRowIndex();
}
@Override
public void setCurrentRowNum(Integer row) {
this.currentRowNum = row;
} }
@Override @Override
public Integer getTotalCount() { public Integer getTotalCount() {
return totalCount; return readSheetHolder.getTotal();
} }
@Override @Override
public void setTotalCount(Integer totalCount) { public Object getCurrentRowAnalysisResult() {
this.totalCount = totalCount; return readRowHolder.getCurrentRowAnalysisResult();
}
@Override
public ExcelHeadProperty getExcelHeadProperty() {
return this.excelHeadProperty;
}
@Override
public void buildExcelHeadProperty(Class<? extends BaseRowModel> clazz, List<String> headOneRow) {
if (this.excelHeadProperty == null && (clazz != null || headOneRow != null)) {
this.excelHeadProperty = new ExcelHeadProperty(clazz, new ArrayList<List<String>>());
}
if (this.excelHeadProperty.getHead() == null && headOneRow != null) {
this.excelHeadProperty.appendOneRow(headOneRow);
}
} }
@Override @Override
public boolean trim() { public void interrupt() {
return this.trim; throw new ExcelAnalysisException("interrupt error");
} }
} }

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

@ -1,293 +1,105 @@
package com.alibaba.excel.context; package com.alibaba.excel.context;
import com.alibaba.excel.event.WriteHandler;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.ExcelHeadProperty;
import com.alibaba.excel.metadata.Table;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.StyleUtil;
import com.alibaba.excel.util.WorkBookUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.alibaba.excel.util.StyleUtil.buildSheetStyle; import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
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;
/** /**
* A context is the main anchorage point of a excel writer. * Write context
* *
* @author jipengfei * @author jipengfei
*/ */
public class WriteContext { public interface WriteContext {
/***
* The sheet currently written
*/
private Sheet currentSheet;
/**
* current param
*/
private com.alibaba.excel.metadata.Sheet currentSheetParam;
/** /**
* The sheet currently written's name * If the current sheet already exists, select it; if not, create it
*
* @param writeSheet Current sheet
*/ */
private String currentSheetName; void currentSheet(WriteSheet writeSheet);
/** /**
* If the current table already exists, select it; if not, create it
* *
* @param writeTable
*/ */
private Table currentTable; void currentTable(WriteTable writeTable);
/** /**
* Excel type * All information about the workbook you are currently working on
*
* @return
*/ */
private ExcelTypeEnum excelType; WriteWorkbookHolder writeWorkbookHolder();
/** /**
* POI Workbook * All information about the sheet you are currently working on
*
* @return
*/ */
private Workbook workbook; WriteSheetHolder writeSheetHolder();
/** /**
* Final output stream * All information about the table you are currently working on
*
* @return
*/ */
private OutputStream outputStream; WriteTableHolder writeTableHolder();
/** /**
* Written form collection * Configuration of currently operated cell. May be 'writeSheetHolder' or 'writeTableHolder' or
* 'writeWorkbookHolder'
*
* @return
*/ */
private Map<Integer, Table> tableMap = new ConcurrentHashMap<Integer, Table>(); WriteHolder currentWriteHolder();
/** /**
* Cell default style * close
*/ */
private CellStyle defaultCellStyle; void finish();
/** /**
* Current table head style * Current sheet
*
* @return
* @deprecated please us e{@link #writeSheetHolder()}
*/ */
private CellStyle currentHeadCellStyle; @Deprecated
Sheet getCurrentSheet();
/** /**
* Current table content style * Need head
*
* @return
* @deprecated please us e{@link #writeSheetHolder()}
*/ */
private CellStyle currentContentCellStyle; @Deprecated
boolean needHead();
/** /**
* the header attribute of excel * Get outputStream
*
* @return
* @deprecated please us e{@link #writeWorkbookHolder()} ()}
*/ */
private ExcelHeadProperty excelHeadProperty; @Deprecated
OutputStream getOutputStream();
private boolean needHead = Boolean.TRUE;
private WriteHandler afterWriteHandler;
public WriteHandler getAfterWriteHandler() {
return afterWriteHandler;
}
public WriteContext(InputStream templateInputStream, OutputStream out, ExcelTypeEnum excelType,
boolean needHead, WriteHandler afterWriteHandler) throws IOException {
this.needHead = needHead;
this.outputStream = out;
this.afterWriteHandler = afterWriteHandler;
this.workbook = WorkBookUtil.createWorkBook(templateInputStream, excelType);
this.defaultCellStyle = StyleUtil.buildDefaultCellStyle(this.workbook);
}
/** /**
* @param sheet * Get workbook
*/
public void currentSheet(com.alibaba.excel.metadata.Sheet sheet) {
if (null == currentSheetParam || currentSheetParam.getSheetNo() != sheet.getSheetNo()) {
cleanCurrentSheet();
currentSheetParam = sheet;
try {
this.currentSheet = workbook.getSheetAt(sheet.getSheetNo() - 1);
} catch (Exception e) {
this.currentSheet = WorkBookUtil.createSheet(workbook, sheet);
if (null != afterWriteHandler) {
this.afterWriteHandler.sheet(sheet.getSheetNo(), currentSheet);
}
}
buildSheetStyle(currentSheet, sheet.getColumnWidthMap());
/** **/
this.initCurrentSheet(sheet);
}
}
private void initCurrentSheet(com.alibaba.excel.metadata.Sheet sheet) {
/** **/
initExcelHeadProperty(sheet.getHead(), sheet.getClazz());
initTableStyle(sheet.getTableStyle());
initTableHead();
}
private void cleanCurrentSheet() {
this.currentSheet = null;
this.currentSheetParam = null;
this.excelHeadProperty = null;
this.currentHeadCellStyle = null;
this.currentContentCellStyle = null;
this.currentTable = null;
}
/**
* init excel header
* *
* @param head * @return
* @param clazz * @deprecated please us e{@link #writeWorkbookHolder()} ()}
*/ */
private void initExcelHeadProperty(List<List<String>> head, Class<? extends BaseRowModel> clazz) { @Deprecated
if (head != null || clazz != null) { this.excelHeadProperty = new ExcelHeadProperty(clazz, head); } Workbook getWorkbook();
}
public void initTableHead() {
if (needHead && null != excelHeadProperty && !CollectionUtils.isEmpty(excelHeadProperty.getHead())) {
int startRow = currentSheet.getLastRowNum();
if (startRow > 0) {
startRow += 4;
} else {
startRow = currentSheetParam.getStartRow();
}
addMergedRegionToCurrentSheet(startRow);
int i = startRow;
for (; i < this.excelHeadProperty.getRowNum() + startRow; i++) {
Row row = WorkBookUtil.createRow(currentSheet, i);
if (null != afterWriteHandler) {
this.afterWriteHandler.row(i, row);
}
addOneRowOfHeadDataToExcel(row, this.excelHeadProperty.getHeadByRowNum(i - startRow));
}
}
}
private void addMergedRegionToCurrentSheet(int startRow) {
for (com.alibaba.excel.metadata.CellRange cellRangeModel : excelHeadProperty.getCellRangeModels()) {
currentSheet.addMergedRegion(new CellRangeAddress(cellRangeModel.getFirstRow() + startRow,
cellRangeModel.getLastRow() + startRow,
cellRangeModel.getFirstCol(), cellRangeModel.getLastCol()));
}
}
private void addOneRowOfHeadDataToExcel(Row row, List<String> headByRowNum) {
if (headByRowNum != null && headByRowNum.size() > 0) {
for (int i = 0; i < headByRowNum.size(); i++) {
Cell cell = WorkBookUtil.createCell(row, i, getCurrentHeadCellStyle(), headByRowNum.get(i));
if (null != afterWriteHandler) {
this.afterWriteHandler.cell(i, cell);
}
}
}
}
private void initTableStyle(com.alibaba.excel.metadata.TableStyle tableStyle) {
if (tableStyle != null) {
this.currentHeadCellStyle = StyleUtil.buildCellStyle(this.workbook, tableStyle.getTableHeadFont(),
tableStyle.getTableHeadBackGroundColor());
this.currentContentCellStyle = StyleUtil.buildCellStyle(this.workbook, tableStyle.getTableContentFont(),
tableStyle.getTableContentBackGroundColor());
}
}
private void cleanCurrentTable() {
this.excelHeadProperty = null;
this.currentHeadCellStyle = null;
this.currentContentCellStyle = null;
this.currentTable = null;
}
public void currentTable(Table table) {
if (null == currentTable || currentTable.getTableNo() != table.getTableNo()) {
cleanCurrentTable();
this.currentTable = table;
this.initExcelHeadProperty(table.getHead(), table.getClazz());
this.initTableStyle(table.getTableStyle());
this.initTableHead();
}
}
public ExcelHeadProperty getExcelHeadProperty() {
return this.excelHeadProperty;
}
public boolean needHead() {
return this.needHead;
}
public Sheet getCurrentSheet() {
return currentSheet;
}
public void setCurrentSheet(Sheet currentSheet) {
this.currentSheet = currentSheet;
}
public String getCurrentSheetName() {
return currentSheetName;
}
public void setCurrentSheetName(String currentSheetName) {
this.currentSheetName = currentSheetName;
}
public ExcelTypeEnum getExcelType() {
return excelType;
}
public void setExcelType(ExcelTypeEnum excelType) {
this.excelType = excelType;
}
public OutputStream getOutputStream() {
return outputStream;
}
public CellStyle getCurrentHeadCellStyle() {
return this.currentHeadCellStyle == null ? defaultCellStyle : this.currentHeadCellStyle;
}
public CellStyle getCurrentContentStyle() {
return this.currentContentCellStyle;
}
public Workbook getWorkbook() {
return workbook;
}
public com.alibaba.excel.metadata.Sheet getCurrentSheetParam() {
return currentSheetParam;
}
public void setCurrentSheetParam(com.alibaba.excel.metadata.Sheet currentSheetParam) {
this.currentSheetParam = currentSheetParam;
}
public Table getCurrentTable() {
return currentTable;
}
public void setCurrentTable(Table currentTable) {
this.currentTable = currentTable;
}
} }

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

@ -0,0 +1,398 @@
package com.alibaba.excel.context;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.excel.exception.ExcelGenerateException;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.util.WorkBookUtil;
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.handler.WriteHandler;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.metadata.WriteWorkbook;
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 com.alibaba.excel.write.property.ExcelWriteHeadProperty;
/**
* A context is the main anchorage point of a excel writer.
*
* @author jipengfei
*/
public class WriteContextImpl implements WriteContext {
private static final Logger LOGGER = LoggerFactory.getLogger(WriteContextImpl.class);
/**
* The Workbook currently written
*/
private WriteWorkbookHolder writeWorkbookHolder;
/**
* Current sheet holder
*/
private WriteSheetHolder writeSheetHolder;
/**
* The table currently written
*/
private WriteTableHolder writeTableHolder;
/**
* Configuration of currently operated cell
*/
private WriteHolder currentWriteHolder;
public WriteContextImpl(WriteWorkbook writeWorkbook) {
if (writeWorkbook == null) {
throw new IllegalArgumentException("Workbook argument cannot be null");
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Begin to Initialization 'WriteContextImpl'");
}
initCurrentWorkbookHolder(writeWorkbook);
beforeWorkbookCreate();
try {
writeWorkbookHolder.setWorkbook(WorkBookUtil.createWorkBook(writeWorkbookHolder));
} catch (Exception e) {
throw new ExcelGenerateException("Create workbook failure", e);
}
afterWorkbookCreate();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Initialization 'WriteContextImpl' complete");
}
}
private void beforeWorkbookCreate() {
List<WriteHandler> handlerList = currentWriteHolder.writeHandlerMap().get(WorkbookWriteHandler.class);
if (handlerList == null || handlerList.isEmpty()) {
return;
}
for (WriteHandler writeHandler : handlerList) {
if (writeHandler instanceof WorkbookWriteHandler) {
((WorkbookWriteHandler)writeHandler).beforeWorkbookCreate();
}
}
}
private void afterWorkbookCreate() {
List<WriteHandler> handlerList = currentWriteHolder.writeHandlerMap().get(WorkbookWriteHandler.class);
if (handlerList == null || handlerList.isEmpty()) {
return;
}
for (WriteHandler writeHandler : handlerList) {
if (writeHandler instanceof WorkbookWriteHandler) {
((WorkbookWriteHandler)writeHandler).afterWorkbookCreate(writeWorkbookHolder);
}
}
}
private void initCurrentWorkbookHolder(WriteWorkbook writeWorkbook) {
writeWorkbookHolder = new WriteWorkbookHolder(writeWorkbook);
currentWriteHolder = writeWorkbookHolder;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("CurrentConfiguration is writeWorkbookHolder");
}
}
/**
* @param writeSheet
*/
@Override
public void currentSheet(WriteSheet writeSheet) {
if (writeSheet == null) {
throw new IllegalArgumentException("Sheet argument cannot be null");
}
if (writeSheet.getSheetNo() == null || writeSheet.getSheetNo() <= 0) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Sheet number is null");
}
writeSheet.setSheetNo(0);
}
if (writeWorkbookHolder.getHasBeenInitializedSheet().containsKey(writeSheet.getSheetNo())) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Sheet:{} is already existed", writeSheet.getSheetNo());
}
writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheet().get(writeSheet.getSheetNo());
writeSheetHolder.setNewInitialization(Boolean.FALSE);
writeTableHolder = null;
currentWriteHolder = writeSheetHolder;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("CurrentConfiguration is writeSheetHolder");
}
return;
}
initCurrentSheetHolder(writeSheet);
beforeSheetCreate();
// Initialization current sheet
initSheet();
afterSheetCreate();
}
private void beforeSheetCreate() {
List<WriteHandler> handlerList = currentWriteHolder.writeHandlerMap().get(SheetWriteHandler.class);
if (handlerList == null || handlerList.isEmpty()) {
return;
}
for (WriteHandler writeHandler : handlerList) {
if (writeHandler instanceof SheetWriteHandler) {
((SheetWriteHandler)writeHandler).beforeSheetCreate(writeWorkbookHolder, writeSheetHolder);
}
}
}
private void afterSheetCreate() {
List<WriteHandler> handlerList = currentWriteHolder.writeHandlerMap().get(SheetWriteHandler.class);
if (handlerList == null || handlerList.isEmpty()) {
return;
}
for (WriteHandler writeHandler : handlerList) {
if (writeHandler instanceof SheetWriteHandler) {
((SheetWriteHandler)writeHandler).afterSheetCreate(writeWorkbookHolder, writeSheetHolder);
}
}
if (null != writeWorkbookHolder.getWriteWorkbook().getWriteHandler()) {
writeWorkbookHolder.getWriteWorkbook().getWriteHandler().sheet(writeSheetHolder.getSheetNo(),
writeSheetHolder.getSheet());
}
}
private void initCurrentSheetHolder(WriteSheet writeSheet) {
writeSheetHolder = new WriteSheetHolder(writeSheet, writeWorkbookHolder);
writeWorkbookHolder.getHasBeenInitializedSheet().put(writeSheet.getSheetNo(), writeSheetHolder);
writeTableHolder = null;
currentWriteHolder = writeSheetHolder;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("CurrentConfiguration is writeSheetHolder");
}
}
private void initSheet() {
Sheet currentSheet;
try {
currentSheet = writeWorkbookHolder.getWorkbook().getSheetAt(writeSheetHolder.getSheetNo());
} catch (Exception e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Can not find sheet:{} ,now create it", writeSheetHolder.getSheetNo());
}
currentSheet = WorkBookUtil.createSheet(writeWorkbookHolder.getWorkbook(), writeSheetHolder.getSheetName());
}
writeSheetHolder.setSheet(currentSheet);
// Initialization head
initHead(writeSheetHolder.excelWriteHeadProperty());
}
public void initHead(ExcelWriteHeadProperty excelWriteHeadProperty) {
if (!currentWriteHolder.needHead() || !currentWriteHolder.excelWriteHeadProperty().hasHead()) {
return;
}
int newRowIndex = writeSheetHolder.getNewRowIndexAndStartDoWrite();
newRowIndex += currentWriteHolder.relativeHeadRowIndex();
// Combined head
addMergedRegionToCurrentSheet(excelWriteHeadProperty, newRowIndex);
for (int relativeRowIndex = 0, i = newRowIndex; i < excelWriteHeadProperty.getHeadRowNumber() + newRowIndex;
i++, relativeRowIndex++) {
beforeRowCreate(newRowIndex, relativeRowIndex);
Row row = WorkBookUtil.createRow(writeSheetHolder.getSheet(), i);
afterRowCreate(row, relativeRowIndex);
addOneRowOfHeadDataToExcel(row, excelWriteHeadProperty.getHeadMap(), relativeRowIndex);
}
}
private void beforeRowCreate(int rowIndex, int relativeRowIndex) {
List<WriteHandler> handlerList = currentWriteHolder.writeHandlerMap().get(RowWriteHandler.class);
if (handlerList == null || handlerList.isEmpty()) {
return;
}
for (WriteHandler writeHandler : handlerList) {
if (writeHandler instanceof RowWriteHandler) {
((RowWriteHandler)writeHandler).beforeRowCreate(writeSheetHolder, writeTableHolder, rowIndex,
relativeRowIndex, true);
}
}
}
private void afterRowCreate(Row row, int relativeRowIndex) {
List<WriteHandler> handlerList = currentWriteHolder.writeHandlerMap().get(RowWriteHandler.class);
if (handlerList == null || handlerList.isEmpty()) {
return;
}
for (WriteHandler writeHandler : handlerList) {
if (writeHandler instanceof RowWriteHandler) {
((RowWriteHandler)writeHandler).afterRowCreate(writeSheetHolder, writeTableHolder, row,
relativeRowIndex, true);
}
}
if (null != writeWorkbookHolder.getWriteWorkbook().getWriteHandler()) {
writeWorkbookHolder.getWriteWorkbook().getWriteHandler().row(row.getRowNum(), row);
}
}
private void addMergedRegionToCurrentSheet(ExcelWriteHeadProperty excelWriteHeadProperty, int rowIndex) {
for (com.alibaba.excel.metadata.CellRange cellRangeModel : excelWriteHeadProperty.headCellRangeList()) {
writeSheetHolder.getSheet().addMergedRegion(new CellRangeAddress(cellRangeModel.getFirstRow() + rowIndex,
cellRangeModel.getLastRow() + rowIndex, cellRangeModel.getFirstCol(), cellRangeModel.getLastCol()));
}
}
private void addOneRowOfHeadDataToExcel(Row row, Map<Integer, Head> headMap, int relativeRowIndex) {
for (Map.Entry<Integer, Head> entry : headMap.entrySet()) {
Head head = entry.getValue();
beforeCellCreate(row, head, relativeRowIndex);
Cell cell = WorkBookUtil.createCell(row, entry.getKey(), head.getHeadNameList().get(relativeRowIndex));
afterCellCreate(head, cell, relativeRowIndex);
}
}
private void beforeCellCreate(Row row, Head head, int relativeRowIndex) {
List<WriteHandler> handlerList = currentWriteHolder.writeHandlerMap().get(CellWriteHandler.class);
if (handlerList == null || handlerList.isEmpty()) {
return;
}
for (WriteHandler writeHandler : handlerList) {
if (writeHandler instanceof CellWriteHandler) {
((CellWriteHandler)writeHandler).beforeCellCreate(writeSheetHolder, writeTableHolder, row, head,
relativeRowIndex, true);
}
}
}
private void afterCellCreate(Head head, Cell cell, int relativeRowIndex) {
List<WriteHandler> handlerList = currentWriteHolder.writeHandlerMap().get(CellWriteHandler.class);
if (handlerList == null || handlerList.isEmpty()) {
return;
}
for (WriteHandler writeHandler : handlerList) {
if (writeHandler instanceof CellWriteHandler) {
((CellWriteHandler)writeHandler).afterCellCreate(writeSheetHolder, writeTableHolder, null, cell, head,
relativeRowIndex, true);
}
}
if (null != writeWorkbookHolder.getWriteWorkbook().getWriteHandler()) {
writeWorkbookHolder.getWriteWorkbook().getWriteHandler().cell(cell.getRowIndex(), cell);
}
}
@Override
public void currentTable(WriteTable writeTable) {
if (writeTable == null) {
return;
}
if (writeTable.getTableNo() == null || writeTable.getTableNo() <= 0) {
writeTable.setTableNo(0);
}
if (writeSheetHolder.getHasBeenInitializedTable().containsKey(writeTable.getTableNo())) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Table:{} is already existed", writeTable.getTableNo());
}
writeTableHolder = writeSheetHolder.getHasBeenInitializedTable().get(writeTable.getTableNo());
writeTableHolder.setNewInitialization(Boolean.FALSE);
currentWriteHolder = writeTableHolder;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("CurrentConfiguration is writeTableHolder");
}
return;
}
initCurrentTableHolder(writeTable);
initHead(writeTableHolder.excelWriteHeadProperty());
}
private void initCurrentTableHolder(WriteTable writeTable) {
writeTableHolder = new WriteTableHolder(writeTable, writeSheetHolder, writeWorkbookHolder);
writeSheetHolder.getHasBeenInitializedTable().put(writeTable.getTableNo(), writeTableHolder);
currentWriteHolder = writeTableHolder;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("CurrentConfiguration is writeTableHolder");
}
}
@Override
public WriteWorkbookHolder writeWorkbookHolder() {
return writeWorkbookHolder;
}
@Override
public WriteSheetHolder writeSheetHolder() {
return writeSheetHolder;
}
@Override
public WriteTableHolder writeTableHolder() {
return writeTableHolder;
}
@Override
public WriteHolder currentWriteHolder() {
return currentWriteHolder;
}
@Override
public void finish() {
if (writeWorkbookHolder == null) {
return;
}
try {
writeWorkbookHolder.getWorkbook().write(writeWorkbookHolder.getOutputStream());
writeWorkbookHolder.getWorkbook().close();
} catch (Throwable e) {
throw new ExcelGenerateException("Can not close IO", e);
}
try {
if (writeWorkbookHolder.getAutoCloseStream() && writeWorkbookHolder.getOutputStream() != null) {
writeWorkbookHolder.getOutputStream().close();
}
} catch (Throwable e) {
throw new ExcelGenerateException("Can not close IO", e);
}
try {
if (writeWorkbookHolder.getAutoCloseStream() && writeWorkbookHolder.getTemplateInputStream() != null) {
writeWorkbookHolder.getTemplateInputStream().close();
}
} catch (Throwable e) {
throw new ExcelGenerateException("Can not close IO", e);
}
try {
if (!writeWorkbookHolder.getAutoCloseStream() && writeWorkbookHolder.getFile() != null
&& writeWorkbookHolder.getOutputStream() != null) {
writeWorkbookHolder.getOutputStream().close();
}
} catch (Throwable e) {
throw new ExcelGenerateException("Can not close IO", e);
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Finished write.");
}
}
@Override
public Sheet getCurrentSheet() {
return writeSheetHolder.getSheet();
}
@Override
public boolean needHead() {
return writeSheetHolder.needHead();
}
@Override
public OutputStream getOutputStream() {
return writeWorkbookHolder.getOutputStream();
}
@Override
public Workbook getWorkbook() {
return writeWorkbookHolder.getWorkbook();
}
}

36
src/main/java/com/alibaba/excel/converters/AutoConverter.java

@ -0,0 +1,36 @@
package com.alibaba.excel.converters;
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;
/**
* An empty converter.It's automatically converted by type.
*
* @author Jiaju Zhuang
*/
public class AutoConverter implements Converter {
@Override
public Class supportJavaTypeKey() {
return null;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return null;
}
@Override
public Object convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return null;
}
@Override
public CellData convertToExcelData(Object value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return null;
}
}

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

@ -0,0 +1,61 @@
package com.alibaba.excel.converters;
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;
/**
* Convert between Java objects and excel objects
*
* @author Dan Zheng
* @param <T>
*/
public interface Converter<T> {
/**
* Back to object types in Java
*
* @return Support for Java class
*/
Class supportJavaTypeKey();
/**
* Back to object enum in excel
*
* @return Support for {@link CellDataTypeEnum}
*/
CellDataTypeEnum supportExcelTypeKey();
/**
* 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.
*/
T convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws Exception;
/**
* 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.
*/
CellData convertToExcelData(T value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration)
throws Exception;
}

40
src/main/java/com/alibaba/excel/converters/ConverterKeyBuild.java

@ -0,0 +1,40 @@
package com.alibaba.excel.converters;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.excel.enums.CellDataTypeEnum;
/**
* Converter unique key.Consider that you can just use class as the key.
*
* @author Jiaju Zhuang
*/
public class ConverterKeyBuild {
private static final Map<String, String> BOXING_MAP = new HashMap<String, String>(16);
static {
BOXING_MAP.put(int.class.getName(), Integer.class.getName());
BOXING_MAP.put(byte.class.getName(), Byte.class.getName());
BOXING_MAP.put(long.class.getName(), Long.class.getName());
BOXING_MAP.put(double.class.getName(), Double.class.getName());
BOXING_MAP.put(float.class.getName(), Float.class.getName());
BOXING_MAP.put(char.class.getName(), Character.class.getName());
BOXING_MAP.put(short.class.getName(), Short.class.getName());
BOXING_MAP.put(boolean.class.getName(), Boolean.class.getName());
}
public static String buildKey(Class clazz) {
String className = clazz.getName();
String boxingClassName = BOXING_MAP.get(clazz.getName());
if (boxingClassName == null) {
return className;
}
return boxingClassName;
}
public static String buildKey(Class clazz, CellDataTypeEnum cellDataTypeEnum) {
return buildKey(clazz) + "-" + cellDataTypeEnum.toString();
}
}

146
src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java

@ -0,0 +1,146 @@
package com.alibaba.excel.converters;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.excel.converters.bigdecimal.BigDecimalBooleanConverter;
import com.alibaba.excel.converters.bigdecimal.BigDecimalNumberConverter;
import com.alibaba.excel.converters.bigdecimal.BigDecimalStringConverter;
import com.alibaba.excel.converters.booleanconverter.BooleanBooleanConverter;
import com.alibaba.excel.converters.booleanconverter.BooleanNumberConverter;
import com.alibaba.excel.converters.booleanconverter.BooleanStringConverter;
import com.alibaba.excel.converters.bytearray.BoxingByteArrayImageConverter;
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.DateNumberConverter;
import com.alibaba.excel.converters.date.DateStringConverter;
import com.alibaba.excel.converters.doubleconverter.DoubleBooleanConverter;
import com.alibaba.excel.converters.doubleconverter.DoubleNumberConverter;
import com.alibaba.excel.converters.doubleconverter.DoubleStringConverter;
import com.alibaba.excel.converters.file.FileImageConverter;
import com.alibaba.excel.converters.floatconverter.FloatBooleanConverter;
import com.alibaba.excel.converters.floatconverter.FloatNumberConverter;
import com.alibaba.excel.converters.floatconverter.FloatStringConverter;
import com.alibaba.excel.converters.inputstream.InputStreamImageConverter;
import com.alibaba.excel.converters.integer.IntegerBooleanConverter;
import com.alibaba.excel.converters.integer.IntegerNumberConverter;
import com.alibaba.excel.converters.integer.IntegerStringConverter;
import com.alibaba.excel.converters.longconverter.LongBooleanConverter;
import com.alibaba.excel.converters.longconverter.LongNumberConverter;
import com.alibaba.excel.converters.longconverter.LongStringConverter;
import com.alibaba.excel.converters.shortconverter.ShortBooleanConverter;
import com.alibaba.excel.converters.shortconverter.ShortNumberConverter;
import com.alibaba.excel.converters.shortconverter.ShortStringConverter;
import com.alibaba.excel.converters.string.StringBooleanConverter;
import com.alibaba.excel.converters.string.StringErrorConverter;
import com.alibaba.excel.converters.string.StringNumberConverter;
import com.alibaba.excel.converters.string.StringStringConverter;
/**
* Load default handler
*
* @author Jiaju Zhuang
*/
public class DefaultConverterLoader {
private static Map<String, Converter> defaultWriteConverter;
private static Map<String, Converter> allConverter;
/**
* Load default write converter
*
* @return
*/
public static Map<String, Converter> loadDefaultWriteConverter() {
if (defaultWriteConverter != null) {
return defaultWriteConverter;
}
defaultWriteConverter = new HashMap<String, Converter>(32);
putWriteConverter(new BigDecimalNumberConverter());
putWriteConverter(new BooleanBooleanConverter());
putWriteConverter(new ByteNumberConverter());
putWriteConverter(new DateStringConverter());
putWriteConverter(new DoubleNumberConverter());
putWriteConverter(new FloatNumberConverter());
putWriteConverter(new IntegerNumberConverter());
putWriteConverter(new LongNumberConverter());
putWriteConverter(new ShortNumberConverter());
putWriteConverter(new StringStringConverter());
putWriteConverter(new FileImageConverter());
putWriteConverter(new InputStreamImageConverter());
putWriteConverter(new ByteArrayImageConverter());
putWriteConverter(new BoxingByteArrayImageConverter());
return defaultWriteConverter;
}
private static void putWriteConverter(Converter converter) {
defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter);
}
/**
* Load default read converter
*
* @return
*/
public static Map<String, Converter> loadDefaultReadConverter() {
return loadAllConverter();
}
/**
* Load all converter
*
* @return
*/
public static Map<String, Converter> loadAllConverter() {
if (allConverter != null) {
return allConverter;
}
allConverter = new HashMap<String, Converter>(64);
putAllConverter(new BigDecimalBooleanConverter());
putAllConverter(new BigDecimalNumberConverter());
putAllConverter(new BigDecimalStringConverter());
putAllConverter(new BooleanBooleanConverter());
putAllConverter(new BooleanNumberConverter());
putAllConverter(new BooleanStringConverter());
putAllConverter(new ByteBooleanConverter());
putAllConverter(new ByteNumberConverter());
putAllConverter(new ByteStringConverter());
putAllConverter(new DateNumberConverter());
putAllConverter(new DateStringConverter());
putAllConverter(new DoubleBooleanConverter());
putAllConverter(new DoubleNumberConverter());
putAllConverter(new DoubleStringConverter());
putAllConverter(new FloatBooleanConverter());
putAllConverter(new FloatNumberConverter());
putAllConverter(new FloatStringConverter());
putAllConverter(new IntegerBooleanConverter());
putAllConverter(new IntegerNumberConverter());
putAllConverter(new IntegerStringConverter());
putAllConverter(new LongBooleanConverter());
putAllConverter(new LongNumberConverter());
putAllConverter(new LongStringConverter());
putAllConverter(new ShortBooleanConverter());
putAllConverter(new ShortNumberConverter());
putAllConverter(new ShortStringConverter());
putAllConverter(new StringBooleanConverter());
putAllConverter(new StringNumberConverter());
putAllConverter(new StringStringConverter());
putAllConverter(new StringErrorConverter());
return allConverter;
}
private static void putAllConverter(Converter converter) {
allConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()),
converter);
}
}

46
src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalBooleanConverter.java

@ -0,0 +1,46 @@
package com.alibaba.excel.converters.bigdecimal;
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;
/**
* BigDecimal and boolean converter
*
* @author Jiaju Zhuang
*/
public class BigDecimalBooleanConverter implements Converter<BigDecimal> {
@Override
public Class supportJavaTypeKey() {
return BigDecimal.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.BOOLEAN;
}
@Override
public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
if (cellData.getBooleanValue()) {
return BigDecimal.ONE;
}
return BigDecimal.ZERO;
}
@Override
public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
if (BigDecimal.ONE.equals(value)) {
return new CellData(Boolean.TRUE);
}
return new CellData(Boolean.FALSE);
}
}

39
src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalNumberConverter.java

@ -0,0 +1,39 @@
package com.alibaba.excel.converters.bigdecimal;
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;
/**
* BigDecimal and number converter
*
* @author Jiaju Zhuang
*/
public class BigDecimalNumberConverter implements Converter<BigDecimal> {
@Override
public Class supportJavaTypeKey() {
return BigDecimal.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.NUMBER;
}
@Override
public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return BigDecimal.valueOf(cellData.getDoubleValue());
}
@Override
public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return new CellData(value.doubleValue());
}
}

41
src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalStringConverter.java

@ -0,0 +1,41 @@
package com.alibaba.excel.converters.bigdecimal;
import java.math.BigDecimal;
import java.text.ParseException;
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;
/**
* BigDecimal and string converter
*
* @author Jiaju Zhuang
*/
public class BigDecimalStringConverter implements Converter<BigDecimal> {
@Override
public Class supportJavaTypeKey() {
return BigDecimal.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
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,
GlobalConfiguration globalConfiguration) {
return NumberUtils.formatToCellData(value, contentProperty);
}
}

38
src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanBooleanConverter.java

@ -0,0 +1,38 @@
package com.alibaba.excel.converters.booleanconverter;
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;
/**
* Boolean and boolean converter
*
* @author Jiaju Zhuang
*/
public class BooleanBooleanConverter implements Converter<Boolean> {
@Override
public Class supportJavaTypeKey() {
return Boolean.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.BOOLEAN;
}
@Override
public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return cellData.getBooleanValue();
}
@Override
public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return new CellData(value);
}
}

47
src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanNumberConverter.java

@ -0,0 +1,47 @@
package com.alibaba.excel.converters.booleanconverter;
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;
/**
* Boolean and number converter
*
* @author Jiaju Zhuang
*/
public class BooleanNumberConverter implements Converter<Boolean> {
private static final Double ONE = 1.0;
private static final Double ZERO = 0.0;
@Override
public Class supportJavaTypeKey() {
return Boolean.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.NUMBER;
}
@Override
public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
if (ONE.equals(cellData.getDoubleValue())) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}
@Override
public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
if (value) {
return new CellData(ONE);
}
return new CellData(ZERO);
}
}

38
src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanStringConverter.java

@ -0,0 +1,38 @@
package com.alibaba.excel.converters.booleanconverter;
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;
/**
* Boolean and string converter
*
* @author Jiaju Zhuang
*/
public class BooleanStringConverter implements Converter<Boolean> {
@Override
public Class supportJavaTypeKey() {
return Boolean.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return Boolean.valueOf(cellData.getStringValue());
}
@Override
public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return new CellData(value.toString());
}
}

41
src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java

@ -0,0 +1,41 @@
package com.alibaba.excel.converters.bytearray;
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;
/**
* Boxing Byte array and image converter
*
* @author Jiaju Zhuang
*/
public class BoxingByteArrayImageConverter implements Converter<Byte[]> {
@Override
public Class supportJavaTypeKey() {
return Byte[].class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.IMAGE;
}
@Override
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,
GlobalConfiguration globalConfiguration) {
byte[] byteValue = new byte[value.length];
for (int i = 0; i < value.length; i++) {
byteValue[i] = value[i];
}
return new CellData(byteValue);
}
}

37
src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java

@ -0,0 +1,37 @@
package com.alibaba.excel.converters.bytearray;
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;
/**
* Byte array and image converter
*
* @author Jiaju Zhuang
*/
public class ByteArrayImageConverter implements Converter<byte[]> {
@Override
public Class supportJavaTypeKey() {
return byte[].class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.IMAGE;
}
@Override
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,
GlobalConfiguration globalConfiguration) {
return new CellData(value);
}
}

46
src/main/java/com/alibaba/excel/converters/byteconverter/ByteBooleanConverter.java

@ -0,0 +1,46 @@
package com.alibaba.excel.converters.byteconverter;
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;
/**
* Byte and boolean converter
*
* @author Jiaju Zhuang
*/
public class ByteBooleanConverter implements Converter<Byte> {
private static final Byte ONE = (byte)1;
private static final Byte ZERO = (byte)0;
@Override
public Class supportJavaTypeKey() {
return Byte.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.BOOLEAN;
}
@Override
public Byte convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
if (cellData.getBooleanValue()) {
return ONE;
}
return ZERO;
}
@Override
public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
if (ONE.equals(value)) {
return new CellData(Boolean.TRUE);
}
return new CellData(Boolean.FALSE);
}
}

38
src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java

@ -0,0 +1,38 @@
package com.alibaba.excel.converters.byteconverter;
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;
/**
* Byte and number converter
*
* @author Jiaju Zhuang
*/
public class ByteNumberConverter implements Converter<Byte> {
@Override
public Class supportJavaTypeKey() {
return Byte.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.NUMBER;
}
@Override
public Byte convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return cellData.getDoubleValue().byteValue();
}
@Override
public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return new CellData(value.doubleValue());
}
}

41
src/main/java/com/alibaba/excel/converters/byteconverter/ByteStringConverter.java

@ -0,0 +1,41 @@
package com.alibaba.excel.converters.byteconverter;
import java.text.ParseException;
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;
/**
* Byte and string converter
*
* @author Jiaju Zhuang
*/
public class ByteStringConverter implements Converter<Byte> {
@Override
public Class supportJavaTypeKey() {
return Byte.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
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,
GlobalConfiguration globalConfiguration) {
return NumberUtils.formatToCellData(value, contentProperty);
}
}

46
src/main/java/com/alibaba/excel/converters/date/DateNumberConverter.java

@ -0,0 +1,46 @@
package com.alibaba.excel.converters.date;
import java.util.Date;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
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;
/**
* Date and number converter
*
* @author Jiaju Zhuang
*/
public class DateNumberConverter implements Converter<Date> {
@Override
public Class supportJavaTypeKey() {
return Date.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.NUMBER;
}
@Override
public Date convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) {
return HSSFDateUtil.getJavaDate(cellData.getDoubleValue(), globalConfiguration.getUse1904windowing(), null);
} else {
return HSSFDateUtil.getJavaDate(cellData.getDoubleValue(),
contentProperty.getDateTimeFormatProperty().getUse1904windowing(), null);
}
}
@Override
public CellData convertToExcelData(Date value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return new CellData((double)(value.getTime()));
}
}

49
src/main/java/com/alibaba/excel/converters/date/DateStringConverter.java

@ -0,0 +1,49 @@
package com.alibaba.excel.converters.date;
import java.text.ParseException;
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.DateUtils;
/**
* Date and string converter
*
* @author Jiaju Zhuang
*/
public class DateStringConverter implements Converter<Date> {
@Override
public Class supportJavaTypeKey() {
return Date.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public Date convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) throws ParseException {
if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) {
return DateUtils.parseDate(cellData.getStringValue(), null);
} else {
return DateUtils.parseDate(cellData.getStringValue(),
contentProperty.getDateTimeFormatProperty().getFormat());
}
}
@Override
public CellData convertToExcelData(Date value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) {
return new CellData(DateUtils.format(value, null));
} else {
return new CellData(DateUtils.format(value, contentProperty.getDateTimeFormatProperty().getFormat()));
}
}
}

46
src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleBooleanConverter.java

@ -0,0 +1,46 @@
package com.alibaba.excel.converters.doubleconverter;
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;
/**
* Double and boolean converter
*
* @author Jiaju Zhuang
*/
public class DoubleBooleanConverter implements Converter<Double> {
private static final Double ONE = 1.0;
private static final Double ZERO = 0.0;
@Override
public Class supportJavaTypeKey() {
return Double.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.BOOLEAN;
}
@Override
public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
if (cellData.getBooleanValue()) {
return ONE;
}
return ZERO;
}
@Override
public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
if (ONE.equals(value)) {
return new CellData(Boolean.TRUE);
}
return new CellData(Boolean.FALSE);
}
}

38
src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleNumberConverter.java

@ -0,0 +1,38 @@
package com.alibaba.excel.converters.doubleconverter;
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;
/**
* Double and number converter
*
* @author Jiaju Zhuang
*/
public class DoubleNumberConverter implements Converter<Double> {
@Override
public Class supportJavaTypeKey() {
return Double.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.NUMBER;
}
@Override
public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return cellData.getDoubleValue();
}
@Override
public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return new CellData(value);
}
}

40
src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleStringConverter.java

@ -0,0 +1,40 @@
package com.alibaba.excel.converters.doubleconverter;
import java.text.ParseException;
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;
/**
* Double and string converter
*
* @author Jiaju Zhuang
*/
public class DoubleStringConverter implements Converter<Double> {
@Override
public Class supportJavaTypeKey() {
return Double.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
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,
GlobalConfiguration globalConfiguration) {
return NumberUtils.formatToCellData(value, contentProperty);
}
}

41
src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java

@ -0,0 +1,41 @@
package com.alibaba.excel.converters.file;
import java.io.File;
import java.io.IOException;
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.FileUtils;
/**
* File and image converter
*
* @author Jiaju Zhuang
*/
public class FileImageConverter implements Converter<File> {
@Override
public Class supportJavaTypeKey() {
return File.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.IMAGE;
}
@Override
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,
GlobalConfiguration globalConfiguration) throws IOException {
return new CellData(FileUtils.readFileToByteArray(value));
}
}

46
src/main/java/com/alibaba/excel/converters/floatconverter/FloatBooleanConverter.java

@ -0,0 +1,46 @@
package com.alibaba.excel.converters.floatconverter;
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;
/**
* Float and boolean converter
*
* @author Jiaju Zhuang
*/
public class FloatBooleanConverter implements Converter<Float> {
private static final Float ONE = (float)1.0;
private static final Float ZERO = (float)0.0;
@Override
public Class supportJavaTypeKey() {
return Float.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.BOOLEAN;
}
@Override
public Float convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
if (cellData.getBooleanValue()) {
return ONE;
}
return ZERO;
}
@Override
public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
if (ONE.equals(value)) {
return new CellData(Boolean.TRUE);
}
return new CellData(Boolean.FALSE);
}
}

38
src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java

@ -0,0 +1,38 @@
package com.alibaba.excel.converters.floatconverter;
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;
/**
* Float and number converter
*
* @author Jiaju Zhuang
*/
public class FloatNumberConverter implements Converter<Float> {
@Override
public Class supportJavaTypeKey() {
return Float.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.NUMBER;
}
@Override
public Float convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return cellData.getDoubleValue().floatValue();
}
@Override
public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return new CellData(value.doubleValue());
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save