diff --git a/README.md b/README.md new file mode 100644 index 00000000..f0e592a1 --- /dev/null +++ b/README.md @@ -0,0 +1,89 @@ +# 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模式。在上层做了模型转换的封装,让使用者更加简单方便 + +# 相关文档 + +* [关于软件](/abouteasyexcel.md) +* [快速使用](/quickstart.md) +* [常见问题](/problem.md) +* [更新记事](/update.md) +* [English-README](/easyexcel_en.md) + +# 二方包 + +``` + + com.alibaba.shared + easyexcel + {latestVersion} + +``` + +# 最新版本 +## VERSION : 1.2.16 + +# 维护者 +姬朋飞(玉霄) + +# 快速开始 + +## 读Excel + +``` +public void noModelMultipleSheet() { + InputStream inputStream = getInputStream("2007NoModelMultipleSheet.xlsx"); + try { + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, + new AnalysisEventListener>() { + @Override + public void invoke(List object, AnalysisContext context) { + System.out.println( + "当前sheet:" + context.getCurrentSheet().getSheetNo() + " 当前行:" + context.getCurrentRowNum() + + " data:" + object); + } + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + + } + }); + + reader.read(); + } catch (Exception e) { + e.printStackTrace(); + + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +``` +## 写Excel + +``` +@Test +public void test1() throws FileNotFoundException { + OutputStream out = new FileOutputStream("/Users/jipengfei/78.xlsx"); + try { + ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX); + //写第一个sheet, sheet1 数据全是List 无模型映射关系 + Sheet sheet1 = new Sheet(1, 0,ExcelPropertyIndexModel.class); + writer.write(getData(), sheet1); + writer.finish(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +``` +# 联系我们 + +有问题阿里同事可以通过钉钉找到我,阿里外同学可以通过git留言。其他技术非技术相关的也欢迎一起探讨。 \ No newline at end of file diff --git a/abouteasyexcel.md b/abouteasyexcel.md new file mode 100644 index 00000000..8c06a2a9 --- /dev/null +++ b/abouteasyexcel.md @@ -0,0 +1,53 @@ +# easyexcel要去解决的问题 + +## Excel读写时候内存溢出 + +虽然POI是目前使用最多的用来做excel解析的框架,但这个框架并不那么完美。大部分使用POI都是使用他的userModel模式。userModel的好处是上手容易使用简单,随便拷贝个代码跑一下,剩下就是写业务转换了,虽然转换也要写上百行代码,相对比较好理解。然而userModel模式最大的问题是在于非常大的内存消耗,一个几兆的文件解析要用掉上百兆的内存。现在很多应用采用这种模式,之所以还正常在跑一定是并发不大,并发上来后一定会OOM或者频繁的full gc。 + +## 其他开源框架使用复杂 + +对POI有过深入了解的估计才知道原来POI还有SAX模式。但SAX模式相对比较复杂,excel有03和07两种版本,两个版本数据存储方式截然不同,sax解析方式也各不一样。想要了解清楚这两种解析方式,才去写代码测试,估计两天时间是需要的。再加上即使解析完,要转换到自己业务模型还要很多繁琐的代码。总体下来感觉至少需要三天,由于代码复杂,后续维护成本巨大。 + +## 其他开源框架存在一些BUG修复不及时 + +由于我们的系统大多数都是大并发的情况下运行的,在大并发情况下,我们会发现poi存在一些bug,如果让POI团队修复估计遥遥无期了。所以我们在easyexcel对这些bug做了规避。 +如下一段报错就是在大并发情况下poi抛的一个异常。 +``` +Caused by: java.io.IOException: Could not create temporary directory '/home/admin/dio2o/.default/temp/poifiles' + at org.apache.poi.util.DefaultTempFileCreationStrategy.createTempDirectory(DefaultTempFileCreationStrategy.java:93) ~[poi-3.15.jar:3.15] + at org.apache.poi.util.DefaultTempFileCreationStrategy.createPOIFilesDirectory(DefaultTempFileCreationStrategy.java:82) ~[poi-3.15.jar:3.15] +``` +报错地方poi源码如下 +``` + private void createTempDirectory(File directory) throws IOException { + if (!(directory.exists() || directory.mkdirs()) || !directory.isDirectory()) { + throw new IOException("Could not create temporary directory '" + directory + "'"); + } + } +``` +仔细看代码容易明白如果在并发情况下,如果2个线程同时判断directory.exists()都 为false,但执行directory.mkdirs()如果一些线程优先执行完,另外一个线程就会返回false。最终 throw new IOException("Could not create temporary directory '" + directory + "'")。针对这个问题easyexcel在写文件时候首先创建了该临时目录,避免poi在并发创建时候引起不该有的报错。 + +## Excel格式分析格式分析 + +- xls是Microsoft Excel2007前excel的文件存储格式,实现原理是基于微软的ole db是微软com组件的一种实现,本质上也是一个微型数据库,由于微软的东西很多不开源,另外也已经被淘汰,了解它的细节意义不大,底层的编程都是基于微软的com组件去开发的。 +- xlsx是Microsoft Excel2007后excel的文件存储格式,实现是基于openXml和zip技术。这种存储简单,安全传输方便,同时处理数据也变的简单。 +- csv 我们可以理解为纯文本文件,可以被excel打开。他的格式非常简单,解析起来和解析文本文件一样。 + +## 核心原理 + +写有大量数据的xlsx文件时,POI为我们提供了SXSSFWorkBook类来处理,这个类的处理机制是当内存中的数据条数达到一个极限数量的时候就flush这部分数据,再依次处理余下的数据,这个在大多数场景能够满足需求。 +读有大量数据的文件时,使用WorkBook处理就不行了,因为POI对文件是先将文件中的cell读入内存,生成一个树的结构(针对Excel中的每个sheet,使用TreeMap存储sheet中的行)。如果数据量比较大,则同样会产生java.lang.OutOfMemoryError: Java heap space错误。POI官方推荐使用“XSSF and SAX(event API)”方式来解决。 +分析清楚POI后要解决OOM有3个关键。 + +### 1、文件解压文件读取通过文件形式 + +![屏幕快照 2018-01-22 上午8.52.08.png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/e3a3500014c95f7118d8c200a51acab4.png) + +### 2、避免将全部全部数据一次加载到内存 + +采用sax模式一行一行解析,并将一行的解析结果以观察者的模式通知处理。 +![基础模板1 (2).png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/82bb195ac62532963b2364d2e4da23e5.png) + +### 3、抛弃不重要的数据 + +Excel解析时候会包含样式,字体,宽度等数据,但这些数据是我们不关系的,如果将这部分数据抛弃可以大大降低内存使用。Excel中数据如下Style占了相当大的空间。 \ No newline at end of file diff --git a/easyexcel_en.md b/easyexcel_en.md new file mode 100644 index 00000000..56a6051c --- /dev/null +++ b/easyexcel_en.md @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..31ab488d --- /dev/null +++ b/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + com.alibaba + a2m.china + 3 + + com.alibaba + easyexcel + 1.0.0-release + + + + org.apache.poi + poi + 3.15 + + + org.apache.poi + poi-ooxml + 3.15 + + + commons-beanutils + commons-beanutils + 1.9.2 + + + junit + junit + 4.12 + test + + + org.apache.commons + commons-compress + 1.14 + + + \ No newline at end of file diff --git a/problem.md b/problem.md new file mode 100644 index 00000000..2d9c70cd --- /dev/null +++ b/problem.md @@ -0,0 +1,116 @@ +# 常见问题汇总 + +## 1、系统环境变量缺失或JDK版本不支持 + +``` +java.lang.NullPointerException + at sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1264) + at sun.awt.FontConfiguration.readFontConfigFile(FontConfiguration.java:219) + at sun.awt.FontConfiguration.init(FontConfiguration.java:107) + at sun.awt.X11FontManager.createFontConfiguration(X11FontManager.java:774) + at sun.font.SunFontManager$2.run(SunFontManager.java:431) + at java.security.AccessController.doPrivileged(Native Method) + at sun.font.SunFontManager.(SunFontManager.java:376) + at sun.awt.FcFontManager.(FcFontManager.java:35) + at sun.awt.X11FontManager.(X11FontManager.java:57) + at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) + at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) + at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) + at java.lang.reflect.Constructor.newInstance(Constructor.java:423) + at java.lang.Class.newInstance(Class.java:442) + at sun.font.FontManagerFactory$1.run(FontManagerFactory.java:83) + at java.security.AccessController.doPrivileged(Native Method) + at sun.font.FontManagerFactory.getInstance(FontManagerFactory.java:74) + at java.awt.Font.getFont2D(Font.java:495) + at java.awt.Font.canDisplayUpTo(Font.java:2080) + at java.awt.font.TextLayout.singleFont(TextLayout.java:470) + at java.awt.font.TextLayout.(TextLayout.java:531) + at org.apache.poi.ss.util.SheetUtil.getDefaultCharWidth(SheetUtil.java:275) + at org.apache.poi.xssf.streaming.AutoSizeColumnTracker.(AutoSizeColumnTracker.java:117) + at org.apache.poi.xssf.streaming.SXSSFSheet.(SXSSFSheet.java:79) + at org.apache.poi.xssf.streaming.SXSSFWorkbook.createAndRegisterSXSSFSheet(SXSSFWorkbook.java:656) + at org.apache.poi.xssf.streaming.SXSSFWorkbook.createSheet(SXSSFWorkbook.java:677) + at org.apache.poi.xssf.streaming.SXSSFWorkbook.createSheet(SXSSFWorkbook.java:83) + at com.alibaba.excel.context.GenerateContextImpl.buildCurrentSheet(GenerateContextImpl.java:93) + at com.alibaba.excel.write.ExcelBuilderImpl.addContent(ExcelBuilderImpl.java:53) + at com.alibaba.excel.ExcelWriter.write(ExcelWriter.java:44) +``` + +### 解决方法 + +该异常由于自己的环境变量缺少swing需要的字体配置,检查自己应用是否有配置-Djava.awt.headless=true,如果没有请加上该系统参数,可以解决问题。如果仍旧不行,在dockerfile中增加字体安装命令: +![粘贴图片.png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/a857edfbc8199db7bb35b9e99f1f57d5.png) +参考: +https://lark.alipay.com/aone355606/gfqllg/ulptif +https://stackoverflow.com/questions/30626136/cannot-load-font-in-jre-8 http://www.jianshu.com/p/c05b5fc71bd0 +## 2、xls格式错用xlsx方式解析 + +``` +org.apache.poi.openxml4j.exceptions.OLE2NotOfficeXmlFileException: The supplied data appears to be in the OLE2 Format. You are calling the part of POI that deals with OOXML (Office Open XML) Documents. You need to call a different part of POI to process this data (eg HSSF instead of XSSF) + at org.apache.poi.openxml4j.opc.internal.ZipHelper.verifyZipHeader(ZipHelper.java:172) + at org.apache.poi.openxml4j.opc.internal.ZipHelper.openZipStream(ZipHelper.java:229) + at org.apache.poi.openxml4j.opc.ZipPackage.(ZipPackage.java:97) + at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:342) + at com.alibaba.excel.analysis.v07.XlsxSaxAnalyser.(XlsxSaxAnalyser.java:46) + at com.alibaba.excel.analysis.ExcelAnalyserImpl.getSaxAnalyser(ExcelAnalyserImpl.java:30) + at com.alibaba.excel.analysis.ExcelAnalyserImpl.analysis(ExcelAnalyserImpl.java:51) + at com.alibaba.excel.ExcelReader.read(ExcelReader.java:55) + at read.v07.Read2007Xlsx.noModel(Read2007Xlsx.java:42) + at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.lang.reflect.Method.invoke(Method.java:498) + at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) + at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) + at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) + at mockit.integration.junit4.internal.BlockJUnit4ClassRunnerDecorator.executeTest(BlockJUnit4ClassRunnerDecorator.java:126) + at mockit.integration.junit4.internal.BlockJUnit4ClassRunnerDecorator.invokeExplosively(BlockJUnit4ClassRunnerDecorator.java:104) + at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java) + at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) + at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) + at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) + at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) + at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) + at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) + at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) + at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) + at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) + at org.junit.runners.ParentRunner.run(ParentRunner.java:363) + at org.junit.runner.JUnitCore.run(JUnitCore.java:137) + at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) + at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51) + at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) + at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.lang.reflect.Method.invoke(Method.java:498) + at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) +``` + +### 解决方法 + +该异常时由于03版的xls,文件用07版的方式做解析的报错,请检查excelType是否设置错误。或者是不是手动去修改了excel文件名后缀的xls为xlsx。 + +## 3、xlsx错用xls解析 + +``` +org.apache.poi.poifs.filesystem.OfficeXmlFileException: The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF) + at org.apache.poi.poifs.storage.HeaderBlock.(HeaderBlock.java:152) + at org.apache.poi.poifs.storage.HeaderBlock.(HeaderBlock.java:140) + at org.apache.poi.poifs.filesystem.NPOIFSFileSystem.(NPOIFSFileSystem.java:302) + at org.apache.poi.poifs.filesystem.POIFSFileSystem.(POIFSFileSystem.java:87) + at com.alibaba.excel.analysis.v03.XlsSaxAnalyser.(XlsSaxAnalyser.java:55) + at com.alibaba.excel.analysis.ExcelAnalyserImpl.getSaxAnalyser(ExcelAnalyserImpl.java:27) + at com.alibaba.excel.analysis.ExcelAnalyserImpl.analysis(ExcelAnalyserImpl.java:51) + at com.alibaba.excel.ExcelReader.read(ExcelReader.java:55) + at read.v03.XLS2003FunctionTest.testExcel2003NoModel(XLS2003FunctionTest.java:31) + at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.lang.reflect.Method.invoke(Method.java:498) + at mockit.integration.junit3.internal.JUnitTestCaseDecorator.runTest(JUnitTestCaseDecorator.java:142) + at mockit.integration.junit3.internal.JUnitTestCaseDecorator.originalRunBare(JUnitTestCaseDecorator.java:102) + at mockit.integration.junit3.internal.JUnitTestCaseDecorator.runBare(JUnitTestCaseDecorator.java:87) +``` +原理和原因大致同上 \ No newline at end of file diff --git a/quickstart.md b/quickstart.md new file mode 100644 index 00000000..eb745a28 --- /dev/null +++ b/quickstart.md @@ -0,0 +1,368 @@ +# easyexcel核心功能 + +## *读任意大小的03、07版Excel不会OO]
+## *读Excel自动通过注解,把结果映射为java模型
+## *读Excel支持多sheet
+## *读Excel时候是否对Excel内容做trim()增加容错
+## *写小量数据的03版Excel(不要超过2000行)
+## *写任意大07版Excel不会OOM
+## *写Excel通过注解将表头自动写入Excel
+## *写Excel可以自定义Excel样式 如:字体,加粗,表头颜色,数据内容颜色
+## *写Excel到多个不同sheet
+## *写Excel时一个sheet可以写多个Table
+## *写Excel时候自定义是否需要写表头
+ +## 二方包依赖 + +使用前最好咨询下最新版,或者到mvn仓库搜索先easyexcel的最新版 + +``` + + com.alibaba.shared + easyexcel + 1.2.16 + +``` +## 读Excel + +使用easyexcel解析03、07版本的Excel只是ExcelTypeEnum不同,其他使用完全相同,使用者无需知道底层解析的差异。 + +### 无java模型直接把excel解析的每行结果以List<String>返回 在ExcelListener获取解析结果 + +读excel代码示例如下: +``` + @Test + public void testExcel2003NoModel() { + InputStream inputStream = getInputStream("loan1.xls"); + try { + // 解析每行结果在listener中处理 + ExcelListener listener = new ExcelListener(); + + ExcelReader excelReader = new ExcelReader(inputStream, ExcelTypeEnum.XLS, null, listener); + excelReader.read(); + } catch (Exception e) { + + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +``` +ExcelListener示例代码如下: +``` + /* 解析监听器, + * 每解析一行会回调invoke()方法。 + * 整个excel解析结束会执行doAfterAllAnalysed()方法 + * + * 下面只是我写的一个样例而已,可以根据自己的逻辑修改该类。 + * @author jipengfei + * @date 2017/03/14 + */ +public class ExcelListener extends AnalysisEventListener { + + //自定义用于暂时存储data。 + //可以通过实例获取该值 + private List datas = new ArrayList(); + public void invoke(Object object, AnalysisContext context) { + System.out.println("当前行:"+context.getCurrentRowNum()); + System.out.println(object); + datas.add(object);//数据存储到list,供批量处理,或后续自己业务逻辑处理。 + doSomething(object);//根据自己业务做处理 + } + private void doSomething(Object object) { + //1、入库调用接口 + } + public void doAfterAllAnalysed(AnalysisContext context) { + // datas.clear();//解析结束销毁不用的资源 + } + public List getDatas() { + return datas; + } + public void setDatas(List datas) { + this.datas = datas; + } +} +``` +### 有java模型映射 +java模型写法如下: +``` +public class LoanInfo extends BaseRowModel { + @ExcelProperty(index = 0) + private String bankLoanId; + + @ExcelProperty(index = 1) + private Long customerId; + + @ExcelProperty(index = 2,format = "yyyy/MM/dd") + private Date loanDate; + + @ExcelProperty(index = 3) + private BigDecimal quota; + + @ExcelProperty(index = 4) + private String bankInterestRate; + + @ExcelProperty(index = 5) + private Integer loanTerm; + + @ExcelProperty(index = 6,format = "yyyy/MM/dd") + private Date loanEndDate; + + @ExcelProperty(index = 7) + private BigDecimal interestPerMonth; + + @ExcelProperty(value = {"一级表头","二级表头"}) + private BigDecimal sax; +} +``` +@ExcelProperty(index = 3)数字代表该字段与excel对应列号做映射,也可以采用 @ExcelProperty(value = {"一级表头","二级表头"})用于解决不确切知道excel第几列和该字段映射,位置不固定,但表头的内容知道的情况。 +``` + @Test + public void testExcel2003WithReflectModel() { + InputStream inputStream = getInputStream("loan1.xls"); + try { + // 解析每行结果在listener中处理 + AnalysisEventListener listener = new ExcelListener(); + + ExcelReader excelReader = new ExcelReader(inputStream, ExcelTypeEnum.XLS, null, listener); + + excelReader.read(new Sheet(1, 2, LoanInfo.class)); + } catch (Exception e) { + + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } +``` +带模型解析与不带模型解析主要在构造new Sheet(1, 2, LoanInfo.class)时候包含class。Class需要继承BaseRowModel暂时BaseRowModel没有任何内容,后面升级可能会增加一些默认的数据。 + +## 写Excel + +### 每行数据是List<String>无表头 + +``` + OutputStream out = new FileOutputStream("/Users/jipengfei/77.xlsx"); + try { + ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX,false); + //写第一个sheet, sheet1 数据全是List 无模型映射关系 + Sheet sheet1 = new Sheet(1, 0); + sheet1.setSheetName("第一个sheet"); + writer.write(getListString(), sheet1); + writer.finish(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } +``` + +### 每行数据是一个java模型有表头----表头层级为一 + +生成Excel格式如下图 +![屏幕快照 2017-06-02 上午9.49.39.png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/dfcb44d05380e2e26bce93f850d9fc99.png) + +模型写法如下: +``` +public class ExcelPropertyIndexModel extends BaseRowModel { + + @ExcelProperty(value = "姓名" ,index = 0) + private String name; + + @ExcelProperty(value = "年龄",index = 1) + private String age; + + @ExcelProperty(value = "邮箱",index = 2) + private String email; + + @ExcelProperty(value = "地址",index = 3) + private String address; + + @ExcelProperty(value = "性别",index = 4) + private String sax; + + @ExcelProperty(value = "高度",index = 5) + private String heigh; + + @ExcelProperty(value = "备注",index = 6) + private String last; +} +``` + @ExcelProperty(value = "姓名",index = 0) value是表头数据,默认会写在excel的表头位置,index代表第几列。 +``` + @Test + public void test1() throws FileNotFoundException { + OutputStream out = new FileOutputStream("/Users/jipengfei/78.xlsx"); + try { + ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX); + //写第一个sheet, sheet1 数据全是List 无模型映射关系 + Sheet sheet1 = new Sheet(1, 0,ExcelPropertyIndexModel.class); + writer.write(getData(), sheet1); + writer.finish(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +``` + +### 每行数据是一个java模型有表头----表头层级为多层级 + +生成Excel格式如下图: +![屏幕快照 2017-06-02 上午9.53.07.png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/0cdb1673665e7940cd670871afb4b3d7.png) +java模型写法如下: +``` +public class MultiLineHeadExcelModel extends BaseRowModel { + + @ExcelProperty(value = {"表头1","表头1","表头31"},index = 0) + private String p1; + + @ExcelProperty(value = {"表头1","表头1","表头32"},index = 1) + private String p2; + + @ExcelProperty(value = {"表头3","表头3","表头3"},index = 2) + private int p3; + + @ExcelProperty(value = {"表头4","表头4","表头4"},index = 3) + private long p4; + + @ExcelProperty(value = {"表头5","表头51","表头52"},index = 4) + private String p5; + + @ExcelProperty(value = {"表头6","表头61","表头611"},index = 5) + private String p6; + + @ExcelProperty(value = {"表头6","表头61","表头612"},index = 6) + private String p7; + + @ExcelProperty(value = {"表头6","表头62","表头621"},index = 7) + private String p8; + + @ExcelProperty(value = {"表头6","表头62","表头622"},index = 8) + private String p9; +} +``` +写Excel写法同上,只需将ExcelPropertyIndexModel.class改为MultiLineHeadExcelModel.class + + +### 一个Excel多个sheet写法 + +``` + @Test + public void test1() throws FileNotFoundException { + + OutputStream out = new FileOutputStream("/Users/jipengfei/77.xlsx"); + try { + ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX,false); + //写第一个sheet, sheet1 数据全是List 无模型映射关系 + Sheet sheet1 = new Sheet(1, 0); + sheet1.setSheetName("第一个sheet"); + writer.write(getListString(), sheet1); + + //写第二个sheet sheet2 模型上打有表头的注解,合并单元格 + Sheet sheet2 = new Sheet(2, 3, MultiLineHeadExcelModel.class, "第二个sheet", null); + sheet2.setTableStyle(getTableStyle1()); + writer.write(getModeldatas(), sheet2); + + //写sheet3 模型上没有注解,表头数据动态传入 + List> head = new ArrayList>(); + List headCoulumn1 = new ArrayList(); + List headCoulumn2 = new ArrayList(); + List headCoulumn3 = new ArrayList(); + headCoulumn1.add("第一列"); + headCoulumn2.add("第二列"); + headCoulumn3.add("第三列"); + head.add(headCoulumn1); + head.add(headCoulumn2); + head.add(headCoulumn3); + Sheet sheet3 = new Sheet(3, 1, NoAnnModel.class, "第三个sheet", head); + writer.write(getNoAnnModels(), sheet3); + writer.finish(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +``` + +### 一个sheet中有多个表格 + +``` +@Test + public void test2() throws FileNotFoundException { + OutputStream out = new FileOutputStream("/Users/jipengfei/77.xlsx"); + try { + ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX,false); + + //写sheet1 数据全是List 无模型映射关系 + Sheet sheet1 = new Sheet(1, 0); + sheet1.setSheetName("第一个sheet"); + Table table1 = new Table(1); + writer.write(getListString(), sheet1, table1); + writer.write(getListString(), sheet1, table1); + + //写sheet2 模型上打有表头的注解 + Table table2 = new Table(2); + table2.setTableStyle(getTableStyle1()); + table2.setClazz(MultiLineHeadExcelModel.class); + writer.write(getModeldatas(), sheet1, table2); + + //写sheet3 模型上没有注解,表头数据动态传入,此情况下模型field顺序与excel现实顺序一致 + List> head = new ArrayList>(); + List headCoulumn1 = new ArrayList(); + List headCoulumn2 = new ArrayList(); + List headCoulumn3 = new ArrayList(); + headCoulumn1.add("第一列"); + headCoulumn2.add("第二列"); + headCoulumn3.add("第三列"); + head.add(headCoulumn1); + head.add(headCoulumn2); + head.add(headCoulumn3); + Table table3 = new Table(3); + table3.setHead(head); + table3.setClazz(NoAnnModel.class); + table3.setTableStyle(getTableStyle2()); + writer.write(getNoAnnModels(), sheet1, table3); + writer.write(getNoAnnModels(), sheet1, table3); + + writer.finish(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +``` +## 测试数据分析 + +![POI usermodel PK easyexcel(Excel 2003).png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/02c4bfbbab99a649788523d04f84a42f.png) +![POI usermodel PK easyexcel(Excel 2007).png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/f6a8a19ec959f0eb564e652de523fc9e.png) +![POI usermodel PK easyexcel(Excel 2003) (1).png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/26888f7ea1cb8dc56db494926544edf7.png) +![POI usermodel PK easyexcel(Excel 2007) (1).png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/4de1ac95bdfaa4b1870b224af4f4cb75.png) +从上面的性能测试可以看出easyexcel在解析耗时上比poiuserModel模式弱了一些。主要原因是我内部采用了反射做模型字段映射,中间我也加了cache,但感觉这点差距可以接受的。但在内存消耗上差别就比较明显了,easyexcel在后面文件再增大,内存消耗几乎不会增加了。但poi userModel就不一样了,简直就要爆掉了。想想一个excel解析200M,同时有20个人再用估计一台机器就挂了。 + diff --git a/src/main/java/com/alibaba/excel/ExcelReader.java b/src/main/java/com/alibaba/excel/ExcelReader.java new file mode 100644 index 00000000..ee36f476 --- /dev/null +++ b/src/main/java/com/alibaba/excel/ExcelReader.java @@ -0,0 +1,99 @@ +package com.alibaba.excel; + +import java.io.InputStream; +import java.util.List; + +import com.alibaba.excel.analysis.ExcelAnalyser; +import com.alibaba.excel.analysis.ExcelAnalyserImpl; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +/** + * Excel解析,thread unsafe + * + * @author jipengfei + */ +public class ExcelReader { + + /** + * 解析器 + */ + private ExcelAnalyser analyser = new ExcelAnalyserImpl(); + + /** + * @param in 文件输入流 + * @param excelTypeEnum excel类型03、07 + * @param customContent 自定义模型可以在{@link AnalysisEventListener#invoke(Object, AnalysisContext) + * }AnalysisContext中获取用于监听者回调使用 + * @param eventListener 用户监听 + */ + public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent, + AnalysisEventListener eventListener) { + this(in, excelTypeEnum, customContent, eventListener, true); + } + + /** + * @param in 文件输入流 + * @param excelTypeEnum excel类型03、07 + * @param customContent 自定义模型可以在{@link AnalysisEventListener#invoke(Object, AnalysisContext) + * }AnalysisContext中获取用于监听者回调使用 + * @param eventListener 用户监听 + * @param trim 是否对解析的String做trim()默认true,用于防止 excel中空格引起的装换报错。 + */ + public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent, + AnalysisEventListener eventListener, boolean trim) { + validateParam(in, excelTypeEnum, eventListener); + analyser.init(in, excelTypeEnum, customContent, eventListener, trim); + } + + /** + * 读一个sheet,且没有模型映射 + */ + public void read() { + analyser.analysis(); + } + + /** + * 读指定个sheet,没有模型映射 + * + * @param sheet 需要解析的sheet + */ + public void read(Sheet sheet) { + analyser.analysis(sheet); + } + + /** + * 读取excel中包含哪些sheet + * + * @return + */ + public List getSheets() { + return analyser.getSheets(); + } + + /** + * 关闭流,删除临时目录文件 + */ + public void finish(){ + analyser.stop(); + } + + /** + * 校验入参 + * + * @param in + * @param excelTypeEnum + * @param eventListener + */ + private void validateParam(InputStream in, ExcelTypeEnum excelTypeEnum, AnalysisEventListener eventListener) { + if (eventListener == null) { + throw new IllegalArgumentException("AnalysisEventListener can not null"); + } else if (in == null) { + throw new IllegalArgumentException("InputStream can not null"); + } else if (excelTypeEnum == null) { + throw new IllegalArgumentException("excelTypeEnum can not null"); + } + } +} diff --git a/src/main/java/com/alibaba/excel/ExcelWriter.java b/src/main/java/com/alibaba/excel/ExcelWriter.java new file mode 100644 index 00000000..f15157b5 --- /dev/null +++ b/src/main/java/com/alibaba/excel/ExcelWriter.java @@ -0,0 +1,96 @@ +package com.alibaba.excel; + +import java.io.OutputStream; +import java.util.List; + +import com.alibaba.excel.metadata.BaseRowModel; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.metadata.Table; +import com.alibaba.excel.support.ExcelTypeEnum; +import com.alibaba.excel.write.ExcelBuilder; +import com.alibaba.excel.write.ExcelBuilderImpl; + +/** + * 生成excel,thread unsafe + * + * @author jipengfei + */ +public class ExcelWriter { + + private ExcelBuilder excelBuilder; + + /** + * 生成小Excel低于2000行 + * + * @param outputStream 文件输出流 + * @param typeEnum 输出文件类型03或07,强烈建议使用07版(可以输出超大excel而不内存溢出) + */ + public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum) { + this(outputStream, typeEnum, true); + } + + /** + * 生成小Excel低于2000行 + * + * @param outputStream 文件输出流 + * @param typeEnum 输出文件类型03或07,强烈建议使用07版(可以输出超大excel而不内存溢出) + */ + public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum, boolean needHead) { + excelBuilder = new ExcelBuilderImpl(); + excelBuilder.init(outputStream, typeEnum, needHead); + } + + /** + * 生成多sheet,每个sheet一张表 + * + * @param data 一行数据是一个BaseRowModel子类的模型 + * @param sheet data写入某个sheet + * @return this(当前引用) + */ + public ExcelWriter write(List data, Sheet sheet) { + excelBuilder.addContent(data, sheet); + return this; + } + + /** + * 生成多sheet,每个sheet一张表 + * + * @param data List代表一行数据 + * @param sheet data写入某个sheet + * @return this(当前引用) + */ + public ExcelWriter write0(List> data, Sheet sheet) { + excelBuilder.addContent(data, sheet); + return this; + } + + /** + * 可生成多sheet,每个sheet多张表 + * + * @param data type is 一个java模型一行数据 + * @param sheet data写入某个sheet + * @param table data写入某个table + * @return this(当前引用) + */ + public ExcelWriter write(List data, Sheet sheet, Table table) { + excelBuilder.addContent(data, sheet, table); + return this; + } + + /** + * 可生成多sheet,每个sheet多张表 + * + * @param data List 代表一行数据 + * @param sheet data写入某个sheet + * @param table data写入某个table + * @return this(当前引用) + */ + public ExcelWriter write0(List> data, Sheet sheet, Table table) { + excelBuilder.addContent(data, sheet, table); + return this; + } + + public void finish() { + excelBuilder.finish(); + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java new file mode 100644 index 00000000..c8b09d2b --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java @@ -0,0 +1,72 @@ +package com.alibaba.excel.analysis; + +import java.io.InputStream; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.event.AnalysisEventRegisterCenter; +import com.alibaba.excel.event.OneRowAnalysisFinishEvent; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +/** + * 抽象sax模式 excel 解析类 + * + * @author jipengfei + */ +public abstract class BaseSaxAnalyser implements AnalysisEventRegisterCenter, ExcelAnalyser { + + protected AnalysisContext analysisContext; + + private LinkedHashMap listeners = new LinkedHashMap(); + + /** + * 开始执行解析 + */ + protected abstract void execute(); + + public void init(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom, + AnalysisEventListener eventListener, boolean trim) { + } + + public void appendLister(String name, AnalysisEventListener listener) { + if (!listeners.containsKey(name)) { + listeners.put(name, listener); + } + } + + public void analysis(Sheet sheetParam) { + execute(); + } + + public void analysis() { + execute(); + } + + /** + * 清空所有监听者 + */ + public void cleanAllListeners() { + listeners = new LinkedHashMap(); + } + + public void notifyListeners(OneRowAnalysisFinishEvent event) { + analysisContext.setCurrentRowAnalysisResult(event.getData()); + + //表头数据 + if (analysisContext.getCurrentRowNum() < analysisContext.getCurrentSheet().getHeadLineMun()) { + if (analysisContext.getCurrentRowNum() <= analysisContext.getCurrentSheet().getHeadLineMun() - 1) { + analysisContext.buildExcelHeadProperty(null, + (List)analysisContext.getCurrentRowAnalysisResult()); + } + } else { + analysisContext.setCurrentRowAnalysisResult(event.getData()); + for (Map.Entry entry : listeners.entrySet()) { + entry.getValue().invoke(analysisContext.getCurrentRowAnalysisResult(), analysisContext); + } + } + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java new file mode 100644 index 00000000..3957998f --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java @@ -0,0 +1,54 @@ +package com.alibaba.excel.analysis; + +import java.io.InputStream; +import java.util.List; + +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +/** + * Excel解析器 + * + * @author jipengfei + */ +public interface ExcelAnalyser { + + /** + * Excel解析初始化 + * + * @param inputStream 解析为文件流 + * @param excelTypeEnum 解析文件类型 + * @param custom 用户自定义参数用户回调时候可以获取到 + * @param eventListener 解析器需要的监听器 + * @param trim + */ + void init(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom, AnalysisEventListener eventListener, + boolean trim); + + /** + * 解析指定sheet,{@link AnalysisEventListener}监听中使用 + * + * @param sheetParam + */ + void analysis(Sheet sheetParam); + + + /** + * + * 默认解析第一个sheet,解析结果以List 的格式在 {@link AnalysisEventListener}监听中使用 + */ + void analysis(); + + /** + * 返回excel中包含哪些sheet + * + * @return + */ + List getSheets(); + + /** + * 关闭流 + */ + void stop(); +} diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java new file mode 100644 index 00000000..6c43678d --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java @@ -0,0 +1,79 @@ +package com.alibaba.excel.analysis; + +import java.io.InputStream; +import java.util.List; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.context.AnalysisContextImpl; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.modelbuild.ModelBuildEventListener; +import com.alibaba.excel.support.ExcelTypeEnum; + +/** + * @author jipengfei + */ +public class ExcelAnalyserImpl implements ExcelAnalyser { + + private AnalysisContext analysisContext; + + private BaseSaxAnalyser saxAnalyser; + + private BaseSaxAnalyser getSaxAnalyser() { + if (saxAnalyser == null) { + if (ExcelTypeEnum.XLS.equals(analysisContext.getExcelType())) { + this.saxAnalyser = new SaxAnalyserV03(analysisContext); + } else { + try { + this.saxAnalyser = new SaxAnalyserV07(analysisContext); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + return this.saxAnalyser; + } + + public void init(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom, + AnalysisEventListener eventListener, boolean trim) { + analysisContext = new AnalysisContextImpl(inputStream, excelTypeEnum, custom, + eventListener, trim); + } + + public void analysis(Sheet sheetParam) { + analysisContext.setCurrentSheet(sheetParam); + analysis(); + } + + public void analysis() { + BaseSaxAnalyser saxAnalyser = getSaxAnalyser(); + appendListeners(saxAnalyser); + saxAnalyser.execute(); + + analysisContext.getEventListener().doAfterAllAnalysed(analysisContext); + } + + public List getSheets() { + BaseSaxAnalyser saxAnalyser = getSaxAnalyser(); + saxAnalyser.cleanAllListeners(); + return saxAnalyser.getSheets(); + } + + public void stop() { + saxAnalyser.stop(); + } + + private void appendListeners(BaseSaxAnalyser saxAnalyser) { + if (analysisContext.getCurrentSheet() != null && analysisContext.getCurrentSheet().getClazz() != null) { + saxAnalyser.appendLister("model_build_listener", new ModelBuildEventListener()); + } + if (analysisContext.getEventListener() != null) { + saxAnalyser.appendLister("user_define_listener", analysisContext.getEventListener()); + } + } + + protected void finalize() throws Throwable { + stop(); + } + +} diff --git a/src/main/java/com/alibaba/excel/analysis/SaxAnalyserV03.java b/src/main/java/com/alibaba/excel/analysis/SaxAnalyserV03.java new file mode 100644 index 00000000..a4336aa7 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/SaxAnalyserV03.java @@ -0,0 +1,368 @@ +package com.alibaba.excel.analysis; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.analysis.BaseSaxAnalyser; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.OneRowAnalysisFinishEvent; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.metadata.Sheet; + +import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder; +import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; +import org.apache.poi.hssf.eventusermodel.HSSFEventFactory; +import org.apache.poi.hssf.eventusermodel.HSSFListener; +import org.apache.poi.hssf.eventusermodel.HSSFRequest; +import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener; +import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; +import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; +import org.apache.poi.hssf.model.HSSFFormulaParser; +import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.BlankRecord; +import org.apache.poi.hssf.record.BoolErrRecord; +import org.apache.poi.hssf.record.BoundSheetRecord; +import org.apache.poi.hssf.record.FormulaRecord; +import org.apache.poi.hssf.record.LabelRecord; +import org.apache.poi.hssf.record.LabelSSTRecord; +import org.apache.poi.hssf.record.NoteRecord; +import org.apache.poi.hssf.record.NumberRecord; +import org.apache.poi.hssf.record.RKRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.SSTRecord; +import org.apache.poi.hssf.record.StringRecord; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; + +/** + * 2003版Excel解析器 + * + * @author jipengfei + */ +public class SaxAnalyserV03 extends BaseSaxAnalyser implements HSSFListener { + + private boolean analyAllSheet = false; + + public SaxAnalyserV03(AnalysisContext context) { + this.analysisContext = context; + this.records = new ArrayList(); + if (analysisContext.getCurrentSheet() == null) { + this.analyAllSheet = true; + } + context.setCurrentRowNum(0); + try { + this.fs = new POIFSFileSystem(analysisContext.getInputStream()); + } catch (IOException e) { + throw new ExcelAnalysisException(e); + } + } + + public List getSheets() { + execute(); + return sheets; + } + + public void stop() { + + } + + @Override + public void execute() { + init(); + MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this); + formatListener = new FormatTrackingHSSFListener(listener); + + HSSFEventFactory factory = new HSSFEventFactory(); + HSSFRequest request = new HSSFRequest(); + + if (outputFormulaValues) { + request.addListenerForAllRecords(formatListener); + } else { + workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener); + request.addListenerForAllRecords(workbookBuildingListener); + } + + try { + factory.processWorkbookEvents(request, fs); + } catch (IOException e) { + throw new ExcelAnalysisException(e); + } + } + + private void init() { + lastRowNumber = 0; + lastColumnNumber = 0; + nextRow = 0; + + nextColumn = 0; + + sheetIndex = 0; + + records = new ArrayList(); + + notAllEmpty = false; + + orderedBSRs = null; + + boundSheetRecords = new ArrayList(); + + sheets = new ArrayList(); + if (analysisContext.getCurrentSheet() == null) { + this.analyAllSheet = true; + } else { + this.analyAllSheet = false; + } + } + + private POIFSFileSystem fs; + + private int lastRowNumber; + private int lastColumnNumber; + + /** + * Should we output the formula, or the value it has? + */ + private boolean outputFormulaValues = true; + + /** + * For parsing Formulas + */ + private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener; + private HSSFWorkbook stubWorkbook; + + // Records we pick up as we process + private SSTRecord sstRecord; + private FormatTrackingHSSFListener formatListener; + + /** + * So we known which sheet we're on + */ + // private BoundSheetRecord[] orderedBSRs; + + // @SuppressWarnings("rawtypes") + // private ArrayList boundSheetRecords = new ArrayList(); + + // For handling formulas with string results + private int nextRow; + private int nextColumn; + private boolean outputNextStringRecord; + + /** + * Main HSSFListener method, processes events, and outputs the CSV as the + * file is processed. + */ + + private int sheetIndex; + + private List records; + + private boolean notAllEmpty = false; + + private BoundSheetRecord[] orderedBSRs; + + private List boundSheetRecords = new ArrayList(); + + private List sheets = new ArrayList(); + + public void processRecord(Record record) { + int thisRow = -1; + int thisColumn = -1; + String thisStr = null; + + switch (record.getSid()) { + case BoundSheetRecord.sid: + boundSheetRecords.add((BoundSheetRecord)record); + break; + case BOFRecord.sid: + BOFRecord br = (BOFRecord)record; + if (br.getType() == BOFRecord.TYPE_WORKSHEET) { + // Create sub workbook if required + if (workbookBuildingListener != null && stubWorkbook == null) { + stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook(); + } + + if (orderedBSRs == null) { + orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords); + } + sheetIndex++; + + Sheet sheet = new Sheet(sheetIndex, 0); + sheet.setSheetName(orderedBSRs[sheetIndex - 1].getSheetname()); + sheets.add(sheet); + if (this.analyAllSheet) { + analysisContext.setCurrentSheet(sheet); + } + } + break; + + case SSTRecord.sid: + sstRecord = (SSTRecord)record; + break; + + case BlankRecord.sid: + BlankRecord brec = (BlankRecord)record; + + thisRow = brec.getRow(); + thisColumn = brec.getColumn(); + thisStr = ""; + break; + case BoolErrRecord.sid: + BoolErrRecord berec = (BoolErrRecord)record; + + thisRow = berec.getRow(); + thisColumn = berec.getColumn(); + thisStr = ""; + break; + + case FormulaRecord.sid: + FormulaRecord frec = (FormulaRecord)record; + + thisRow = frec.getRow(); + thisColumn = frec.getColumn(); + + if (outputFormulaValues) { + if (Double.isNaN(frec.getValue())) { + // Formula result is a string + // This is stored in the next record + outputNextStringRecord = true; + nextRow = frec.getRow(); + nextColumn = frec.getColumn(); + } else { + thisStr = formatListener.formatNumberDateCell(frec); + } + } else { + thisStr = HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()); + } + break; + case StringRecord.sid: + if (outputNextStringRecord) { + // String for formula + StringRecord srec = (StringRecord)record; + thisStr = srec.getString(); + thisRow = nextRow; + thisColumn = nextColumn; + outputNextStringRecord = false; + } + break; + + case LabelRecord.sid: + LabelRecord lrec = (LabelRecord)record; + + thisRow = lrec.getRow(); + thisColumn = lrec.getColumn(); + thisStr = lrec.getValue(); + break; + case LabelSSTRecord.sid: + LabelSSTRecord lsrec = (LabelSSTRecord)record; + + thisRow = lsrec.getRow(); + thisColumn = lsrec.getColumn(); + if (sstRecord == null) { + thisStr = ""; + } else { + thisStr = sstRecord.getString(lsrec.getSSTIndex()).toString(); + } + break; + case NoteRecord.sid: + NoteRecord nrec = (NoteRecord)record; + + thisRow = nrec.getRow(); + thisColumn = nrec.getColumn(); + // TODO: Find object to match nrec.getShapeId() + thisStr = "(TODO)"; + break; + case NumberRecord.sid: + NumberRecord numrec = (NumberRecord)record; + + thisRow = numrec.getRow(); + thisColumn = numrec.getColumn(); + + // Format + thisStr = formatListener.formatNumberDateCell(numrec); + break; + case RKRecord.sid: + RKRecord rkrec = (RKRecord)record; + + thisRow = rkrec.getRow(); + thisColumn = rkrec.getColumn(); + thisStr = ""; + break; + default: + break; + } + + // Handle new row + if (thisRow != -1 && thisRow != lastRowNumber) { + lastColumnNumber = -1; + } + + // Handle missing column + if (record instanceof MissingCellDummyRecord) { + MissingCellDummyRecord mc = (MissingCellDummyRecord)record; + thisRow = mc.getRow(); + thisColumn = mc.getColumn(); + thisStr = ""; + } + + // If we got something to print out, do so + if (thisStr != null) { + //if (thisColumn > 1) { + // // output.print(','); + //} + //if (thisStr != null) { + if (analysisContext.trim()) { + thisStr = thisStr.trim(); + } + if (!"".equals(thisStr)) { + notAllEmpty = true; + } + // } + // output.print(thisStr); + records.add(thisStr); + } + + // Update column and row count + if (thisRow > -1) { + lastRowNumber = thisRow; + } + if (thisColumn > -1) { + lastColumnNumber = thisColumn; + } + + // Handle end of row + if (record instanceof LastCellOfRowDummyRecord) { + thisRow = ((LastCellOfRowDummyRecord)record).getRow(); + // thisColumn = ((LastCellOfRowDummyRecord) + // record).getLastColumnNumber(); + // Columns are 0 based + if (lastColumnNumber == -1) { + lastColumnNumber = 0; + } + analysisContext.setCurrentRowNum(thisRow); + Sheet sheet = analysisContext.getCurrentSheet(); + + if ((sheet == null || sheet.getSheetNo() == sheetIndex) && notAllEmpty) { + notifyListeners(new OneRowAnalysisFinishEvent(copyList(records))); + } + // System.out.println(records); + records.clear(); + lastColumnNumber = -1; + notAllEmpty = false; + + } + } + + private List copyList(List data) { + if (data == null) { + return null; + } + List list = new ArrayList(); + for (String str : data) { + list.add(new String(str)); + } + return list; + + } + +} diff --git a/src/main/java/com/alibaba/excel/analysis/SaxAnalyserV07.java b/src/main/java/com/alibaba/excel/analysis/SaxAnalyserV07.java new file mode 100644 index 00000000..6c81bb32 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/SaxAnalyserV07.java @@ -0,0 +1,274 @@ +package com.alibaba.excel.analysis; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; + +import javax.xml.parsers.ParserConfigurationException; + +import com.alibaba.excel.analysis.v07.RowHandler; +import com.alibaba.excel.analysis.v07.XmlParserFactory; +import com.alibaba.excel.analysis.v07.XMLTempFile; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.util.FileUtil; + +import org.apache.poi.xssf.model.SharedStringsTable; +import org.apache.xmlbeans.XmlException; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * @author jipengfei + * @date 2017/08/27 + */ +public class SaxAnalyserV07 extends BaseSaxAnalyser { + + private SharedStringsTable sharedStringsTable; + + private List sharedStringList = new LinkedList(); + + private List sheetSourceList = new ArrayList(); + + private boolean use1904WindowDate = false; + + private final String path; + + private File tmpFile; + + private String workBookXMLFilePath; + + private String sharedStringXMLFilePath; + + public SaxAnalyserV07(AnalysisContext analysisContext) throws Exception { + this.analysisContext = analysisContext; + this.path = XMLTempFile.createPath(); + this.tmpFile = new File(XMLTempFile.getTmpFilePath(path)); + this.workBookXMLFilePath = XMLTempFile.getWorkBookFilePath(path); + this.sharedStringXMLFilePath = XMLTempFile.getSharedStringFilePath(path); + start(); + } + + @Override + protected void execute() { + try { + Sheet sheet = analysisContext.getCurrentSheet(); + if (!isAnalysisAllSheets(sheet)) { + if (this.sheetSourceList.size() <= sheet.getSheetNo()) { + return; + } + InputStream sheetInputStream = this.sheetSourceList.get(sheet.getSheetNo() - 1).getInputStream(); + parseXmlSource(sheetInputStream); + return; + } + int i = 0; + for (SheetSource sheetSource : this.sheetSourceList) { + i++; + this.analysisContext.setCurrentSheet(new Sheet(i)); + parseXmlSource(sheetSource.getInputStream()); + } + + } catch (Exception e) { + stop(); + throw new ExcelAnalysisException(e); + } finally { + } + + } + + private boolean isAnalysisAllSheets(Sheet sheet) { + if (sheet == null) { + return true; + } + if (sheet.getSheetNo() <= 0) { + return true; + } + return false; + } + + public void stop() { + FileUtil.deletefile(path); + } + + private void parseXmlSource(InputStream inputStream) { + try { + ContentHandler handler = new RowHandler(this, this.sharedStringsTable, this.analysisContext, + sharedStringList); + XmlParserFactory.parse(inputStream, handler); + inputStream.close(); + } catch (Exception e) { + try { + inputStream.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + throw new ExcelAnalysisException(e); + } + } + + public List getSheets() { + List sheets = new ArrayList(); + try { + int i = 1; + for (SheetSource sheetSource : this.sheetSourceList) { + Sheet sheet = new Sheet(i, 0); + sheet.setSheetName(sheetSource.getSheetName()); + i++; + sheets.add(sheet); + } + } catch (Exception e) { + stop(); + throw new ExcelAnalysisException(e); + } finally { + + } + + return sheets; + } + + + private void start() throws IOException, XmlException, ParserConfigurationException, SAXException { + + createTmpFile(); + + unZipTempFile(); + + initSharedStringsTable(); + + initUse1904WindowDate(); + + initSheetSourceList(); + + } + + private void createTmpFile() throws FileNotFoundException { + FileUtil.writeFile(tmpFile, analysisContext.getInputStream()); + } + + private void unZipTempFile() throws IOException { + FileUtil.doUnZip(path, tmpFile); + } + + private void initSheetSourceList() throws IOException, ParserConfigurationException, SAXException { + this.sheetSourceList = new ArrayList(); + InputStream workbookXml = new FileInputStream(this.workBookXMLFilePath); + XmlParserFactory.parse(workbookXml, new DefaultHandler() { + @Override + public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException { + if (qName.toLowerCase(Locale.US).equals("sheet")) { + String name = null; + int id = 0; + for (int i = 0; i < attrs.getLength(); i++) { + if (attrs.getLocalName(i).toLowerCase(Locale.US).equals("name")) { + name = attrs.getValue(i); + } else if (attrs.getLocalName(i).toLowerCase(Locale.US).equals("r:id")) { + id = Integer.parseInt(attrs.getValue(i).replaceAll("rId","")); + try { + InputStream inputStream = new FileInputStream(XMLTempFile.getSheetFilePath(path, id)); + sheetSourceList.add(new SheetSource(id, name, inputStream)); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + } + + } + } + + }); + workbookXml.close(); + Collections.sort(sheetSourceList); + } + + private void initUse1904WindowDate() throws IOException, XmlException { + InputStream workbookXml = new FileInputStream(workBookXMLFilePath); + WorkbookDocument ctWorkbook = WorkbookDocument.Factory.parse(workbookXml); + CTWorkbook wb = ctWorkbook.getWorkbook(); + CTWorkbookPr prefix = wb.getWorkbookPr(); + if (prefix != null) { + this.use1904WindowDate = prefix.getDate1904(); + } + this.analysisContext.setUse1904WindowDate(use1904WindowDate); + workbookXml.close(); + } + + private void initSharedStringsTable() throws IOException, ParserConfigurationException, SAXException { + + InputStream inputStream = new FileInputStream(this.sharedStringXMLFilePath); + //this.sharedStringsTable = new SharedStringsTable(); + //this.sharedStringsTable.readFrom(inputStream); + + XmlParserFactory.parse(inputStream, new DefaultHandler() { + @Override + public void characters(char[] ch, int start, int length) { + sharedStringList.add(new String(ch, start, length)); + } + + }); + inputStream.close(); + } + + private class SheetSource implements Comparable { + + private int id; + + private String sheetName; + + private InputStream inputStream; + + public SheetSource(int id, String sheetName, InputStream inputStream) { + this.id = id; + this.sheetName = sheetName; + this.inputStream = inputStream; + } + + public String getSheetName() { + return sheetName; + } + + public void setSheetName(String sheetName) { + this.sheetName = sheetName; + } + + public InputStream getInputStream() { + return inputStream; + } + + public void setInputStream(InputStream inputStream) { + this.inputStream = inputStream; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int compareTo(SheetSource o) { + if (o.id == this.id) { + return 0; + } else if (o.id > this.id) { + return 1; + } else { + return -1; + } + } + } + + +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/RowHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/RowHandler.java new file mode 100644 index 00000000..d237b82c --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/RowHandler.java @@ -0,0 +1,159 @@ +package com.alibaba.excel.analysis.v07; + +import java.util.Arrays; +import java.util.List; + +import com.alibaba.excel.annotation.FieldType; +import com.alibaba.excel.constant.ExcelXmlConstants; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventRegisterCenter; +import com.alibaba.excel.event.OneRowAnalysisFinishEvent; +import com.alibaba.excel.util.PositionUtils; + +import org.apache.poi.xssf.model.SharedStringsTable; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_VALUE_TAG; +import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_VALUE_TAG_1; +import static com.alibaba.excel.constant.ExcelXmlConstants.DIMENSION; +import static com.alibaba.excel.constant.ExcelXmlConstants.DIMENSION_REF; +import static com.alibaba.excel.constant.ExcelXmlConstants.ROW_TAG; + +/** + * @author jipengfei + * @date 2017/08/23 + */ +public class RowHandler extends DefaultHandler { + + private String currentCellIndex; + + private FieldType currentCellType; + + private int curRow; + + private int curCol; + + private String[] curRowContent = new String[20]; + + private String currentCellValue; + + private SharedStringsTable sst; + + private AnalysisContext analysisContext; + + private AnalysisEventRegisterCenter registerCenter; + + private List sharedStringList; + + public RowHandler(AnalysisEventRegisterCenter registerCenter, SharedStringsTable sst, + AnalysisContext analysisContext, List sharedStringList) { + this.registerCenter = registerCenter; + this.analysisContext = analysisContext; + this.sst = sst; + this.sharedStringList = sharedStringList; + + } + + @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; + } + //if ("6".equals(attributes.getValue("s"))) { + // // date + // currentCellType = FieldType.DATE; + //} + + } + } + + private void endCellValue(String name) throws SAXException { + // ensure size + if (curCol >= curRowContent.length) { + curRowContent = Arrays.copyOf(curRowContent, (int)(curCol * 1.5)); + } + if (CELL_VALUE_TAG.equals(name)) { + + switch (currentCellType) { + case STRING: + int idx = Integer.parseInt(currentCellValue); + currentCellValue = sharedStringList.get(idx); + currentCellType = FieldType.EMPTY; + break; + //case DATE: + // Date dateVal = HSSFDateUtil.getJavaDate(Double.parseDouble(currentCellValue), + // analysisContext.use1904WindowDate()); + // currentCellValue = TypeUtil.getDefaultDateString(dateVal); + // currentCellType = FieldType.EMPTY; + // break; + } + curRowContent[curCol] = currentCellValue; + } else if (CELL_VALUE_TAG_1.equals(name)) { + curRowContent[curCol] = currentCellValue; + } + } + + @Override + public void endElement(String uri, String localName, String name) throws SAXException { + + endRow(name); + endCellValue(name); + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + + currentCellValue += new String(ch, start, length); + + } + + private void setTotalRowCount(String name, Attributes attributes) { + if (DIMENSION.equals(name)) { + String d = attributes.getValue(DIMENSION_REF); + String totalStr = d.substring(d.indexOf(":") + 1, d.length()); + String c = totalStr.toUpperCase().replaceAll("[A-Z]", ""); + analysisContext.setTotalCount(Integer.parseInt(c)); + } + + } + + private void endRow(String name) { + if (name.equals(ROW_TAG)) { + registerCenter.notifyListeners(new OneRowAnalysisFinishEvent(Arrays.asList(curRowContent))); + curRowContent = new String[20]; + } + } + +} + diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XMLTempFile.java b/src/main/java/com/alibaba/excel/analysis/v07/XMLTempFile.java new file mode 100644 index 00000000..89b29a99 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/XMLTempFile.java @@ -0,0 +1,48 @@ +package com.alibaba.excel.analysis.v07; + +import java.io.File; +import java.security.SecureRandom; + +import com.alibaba.excel.util.EasyExcelTempFile; + +/** + * @author jipengfei + * @date 2017/10/13 + */ +public class XMLTempFile { + + private static final String TMP_FILE_NAME = "tmp.xlsx"; + + private static final String XL = "xl"; + + private static final String XML_WORKBOOK = "workbook.xml"; + + private static final String XML_SHARED_STRING = "sharedStrings.xml"; + + private static final String SHEET = "sheet"; + + private static final String WORK_SHEETS = "worksheets"; + + private static final SecureRandom random = new SecureRandom(); + + public static String getTmpFilePath(String path) { + return path + File.separator + TMP_FILE_NAME; + } + + public static String createPath() { + return EasyExcelTempFile.getEasyExcelTmpDir() + File.separator + random.nextLong(); + } + + public static String getWorkBookFilePath(String path) { + return path + File.separator + XL + File.separator + XML_WORKBOOK; + } + + public static String getSharedStringFilePath(String path) { + return path + File.separator + XL + File.separator + XML_SHARED_STRING; + } + + public static String getSheetFilePath(String path, int id) { + return path + File.separator + XL + File.separator + WORK_SHEETS + File.separator + SHEET + id + + ".xml"; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XmlParserFactory.java b/src/main/java/com/alibaba/excel/analysis/v07/XmlParserFactory.java new file mode 100644 index 00000000..36b392f7 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/XmlParserFactory.java @@ -0,0 +1,30 @@ +package com.alibaba.excel.analysis.v07; + +import java.io.IOException; +import java.io.InputStream; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +/** + * @author jipengfei + * @date 2017/10/13 + */ +public class XmlParserFactory { + + public static void parse(InputStream inputStream, ContentHandler contentHandler) + throws ParserConfigurationException, SAXException, IOException { + InputSource sheetSource = new InputSource(inputStream); + SAXParserFactory saxFactory = SAXParserFactory.newInstance(); + SAXParser saxParser = saxFactory.newSAXParser(); + XMLReader xmlReader = saxParser.getXMLReader(); + xmlReader.setContentHandler(contentHandler); + xmlReader.parse(sheetSource); + } +} diff --git a/src/main/java/com/alibaba/excel/annotation/ExcelColumnNum.java b/src/main/java/com/alibaba/excel/annotation/ExcelColumnNum.java new file mode 100644 index 00000000..01220980 --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/ExcelColumnNum.java @@ -0,0 +1,35 @@ +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 + * @date 2017/03/19 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelColumnNum { + + /** + * col num + * @return + */ + int value(); + + /** + * + * Default @see com.alibaba.TypeUtil + * if default is not meet you can set format + * + * @return + */ + String format() default ""; +} diff --git a/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java b/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java new file mode 100644 index 00000000..51617d7e --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java @@ -0,0 +1,38 @@ +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; + +/** + * @author jipengfei + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelProperty { + + /** + * 某列表头值 + * @return + */ + String[] value() default {""}; + + + /** + * 列顺序,越小越靠前 + * @return + */ + int index() default 99999; + + /** + * + * default @see com.alibaba.TypeUtil + * if default is not meet you can set format + * + * @return + */ + String format() default ""; +} diff --git a/src/main/java/com/alibaba/excel/annotation/FieldType.java b/src/main/java/com/alibaba/excel/annotation/FieldType.java new file mode 100644 index 00000000..e5dc48df --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/FieldType.java @@ -0,0 +1,12 @@ +package com.alibaba.excel.annotation; + +/** + * + * @author jipengfei + * @date 2017/03/15 + */ +public enum FieldType { + + STRING, INT, LONG, DATE, BOOLEAN, DOUBLE,EMPTY; + +} diff --git a/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java b/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java new file mode 100644 index 00000000..8403f9e3 --- /dev/null +++ b/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java @@ -0,0 +1,18 @@ +package com.alibaba.excel.constant; + +/** + * @author jipengfei + * @date 2017/08/24 + */ +public class ExcelXmlConstants { + public static final String DIMENSION = "dimension"; + public static final String DIMENSION_REF = "ref"; + public static final String POSITION = "r"; + + public static final String ROW_TAG = "row"; + public static final String CELL_TAG = "c"; + public static final String CELL_VALUE_TAG = "v"; + + public static final String CELL_VALUE_TAG_1 = "t"; + +} diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContext.java b/src/main/java/com/alibaba/excel/context/AnalysisContext.java new file mode 100644 index 00000000..e2631bcf --- /dev/null +++ b/src/main/java/com/alibaba/excel/context/AnalysisContext.java @@ -0,0 +1,139 @@ +package com.alibaba.excel.context; + +import java.io.InputStream; +import java.util.List; + +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.BaseRowModel; +import com.alibaba.excel.metadata.ExcelHeadProperty; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +/** + * 解析文件上下文 + * + * @author jipengfei + */ +public interface AnalysisContext { + + /** + * 返回用户自定义数据 + * + * @return 返回用户自定义数据 + */ + Object getCustom(); + + /** + * 返回当前Sheet + * + * @return current analysis sheet + */ + Sheet getCurrentSheet(); + + /** + * 设置当前解析的Sheet + * + * @param sheet + */ + void setCurrentSheet(Sheet sheet); + + /** + * 返回解析的Excel类型 + * + * @return excel type + */ + ExcelTypeEnum getExcelType(); + + /** + * 返回输入IO + * + * @return file io + */ + InputStream getInputStream(); + + /** + * 获取当前监听者 + * + * @return + */ + AnalysisEventListener getEventListener(); + + /** + * 获取当前行数 + * + * @return + */ + Integer getCurrentRowNum(); + + /** + * 设置当前行数 + * + * @param row + */ + void setCurrentRowNum(Integer row); + + /** + * 返回当前sheet共有多少行数据,仅限07版excel + * + * @return + */ + @Deprecated + Integer getTotalCount(); + + /** + * 设置总条数 + * + * @param totalCount + */ + void setTotalCount(Integer totalCount); + + /** + * 返回表头信息 + * + * @return + */ + ExcelHeadProperty getExcelHeadProperty(); + + /** + * 构建 ExcelHeadProperty + * + * @param clazz + * @param headOneRow + */ + void buildExcelHeadProperty(Class clazz, List headOneRow); + + /** + * 是否trim() + * + * @return + */ + boolean trim(); + + /** + * + */ + void setCurrentRowAnalysisResult(Object result); + + + /** + * + */ + Object getCurrentRowAnalysisResult(); + + /** + * + */ + void interrupt(); + + /** + * + * @return + */ + boolean use1904WindowDate(); + + /** + * + * @param use1904WindowDate + */ + void setUse1904WindowDate(boolean use1904WindowDate); +} diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java new file mode 100644 index 00000000..d4f8e6dd --- /dev/null +++ b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java @@ -0,0 +1,147 @@ +package com.alibaba.excel.context; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.metadata.BaseRowModel; +import com.alibaba.excel.metadata.ExcelHeadProperty; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +/** + * 解析Excel上线文默认实现 + * + * @author jipengfei + */ +public class AnalysisContextImpl implements AnalysisContext { + + private Object custom; + + private Sheet currentSheet; + + private ExcelTypeEnum excelType; + + private InputStream inputStream; + + private AnalysisEventListener eventListener; + + private Integer currentRowNum; + + private Integer totalCount; + + private ExcelHeadProperty excelHeadProperty; + + private boolean trim; + + private boolean use1904WindowDate = false; + + public void setUse1904WindowDate(boolean use1904WindowDate) { + this.use1904WindowDate = use1904WindowDate; + } + + public Object getCurrentRowAnalysisResult() { + return currentRowAnalysisResult; + } + + public void interrupt() { + throw new ExcelAnalysisException("interrupt error"); + } + + public boolean use1904WindowDate() { + return use1904WindowDate; + } + + public void setCurrentRowAnalysisResult(Object currentRowAnalysisResult) { + this.currentRowAnalysisResult = currentRowAnalysisResult; + } + + 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; + } + + public void setCurrentSheet(Sheet currentSheet) { + this.currentSheet = currentSheet; + if (currentSheet.getClazz() != null) { + buildExcelHeadProperty(currentSheet.getClazz(), null); + } + } + + public ExcelTypeEnum getExcelType() { + return excelType; + } + + public void setExcelType(ExcelTypeEnum excelType) { + this.excelType = excelType; + } + + public Object getCustom() { + return custom; + } + + public void setCustom(Object custom) { + this.custom = custom; + } + + public Sheet getCurrentSheet() { + return currentSheet; + } + + public InputStream getInputStream() { + return inputStream; + } + + public void setInputStream(InputStream inputStream) { + this.inputStream = inputStream; + } + + public AnalysisEventListener getEventListener() { + return eventListener; + } + + public void setEventListener(AnalysisEventListener eventListener) { + this.eventListener = eventListener; + } + + public Integer getCurrentRowNum() { + return this.currentRowNum; + } + + public void setCurrentRowNum(Integer row) { + this.currentRowNum = row; + } + + public Integer getTotalCount() { + return totalCount; + } + + public void setTotalCount(Integer totalCount) { + this.totalCount = totalCount; + } + + public ExcelHeadProperty getExcelHeadProperty() { + return this.excelHeadProperty; + } + + public void buildExcelHeadProperty(Class clazz, List headOneRow) { + if (this.excelHeadProperty == null && (clazz != null || headOneRow != null)) { + this.excelHeadProperty = new ExcelHeadProperty(clazz, new ArrayList>()); + } + if (this.excelHeadProperty.getHead() == null && headOneRow != null) { + this.excelHeadProperty.appendOneRow(headOneRow); + } + } + + public boolean trim() { + return this.trim; + } +} diff --git a/src/main/java/com/alibaba/excel/context/GenerateContext.java b/src/main/java/com/alibaba/excel/context/GenerateContext.java new file mode 100644 index 00000000..3f001c6d --- /dev/null +++ b/src/main/java/com/alibaba/excel/context/GenerateContext.java @@ -0,0 +1,75 @@ +package com.alibaba.excel.context; + +import java.io.OutputStream; + +import com.alibaba.excel.metadata.ExcelHeadProperty; +import com.alibaba.excel.metadata.Table; + +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; + +/** + * @author jipengfei + */ +public interface GenerateContext { + + + /** + * 返回当前sheet + * @return current analysis sheet + */ + Sheet getCurrentSheet(); + + /** + * + * 获取表头样式 + * @return + */ + CellStyle getCurrentHeadCellStyle(); + + /** + * 获取内容样式 + * @return + */ + CellStyle getCurrentContentStyle(); + + + /** + * 返回WorkBook + * @return + */ + Workbook getWorkbook(); + + /** + * 返回Io流 + * @return + */ + OutputStream getOutputStream(); + + /** + * 构建一个sheet + * @param sheet + */ + void buildCurrentSheet(com.alibaba.excel.metadata.Sheet sheet); + + /** + * 构建一个Table + * @param table + */ + void buildTable(Table table); + + /** + * 返回表头信息 + * @return + */ + ExcelHeadProperty getExcelHeadProperty(); + + /** + * + * @return + */ + boolean needHead(); +} + + diff --git a/src/main/java/com/alibaba/excel/context/GenerateContextImpl.java b/src/main/java/com/alibaba/excel/context/GenerateContextImpl.java new file mode 100644 index 00000000..8c05b48b --- /dev/null +++ b/src/main/java/com/alibaba/excel/context/GenerateContextImpl.java @@ -0,0 +1,231 @@ +package com.alibaba.excel.context; + +import java.io.OutputStream; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.alibaba.excel.metadata.BaseRowModel; +import com.alibaba.excel.metadata.CellRange; +import com.alibaba.excel.metadata.ExcelHeadProperty; +import com.alibaba.excel.metadata.Table; +import com.alibaba.excel.metadata.TableStyle; +import com.alibaba.excel.support.ExcelTypeEnum; + +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.VerticalAlignment; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; + +/** + * 生成Excel上下文 + * + * @author jipengfei + */ +public class GenerateContextImpl implements GenerateContext { + + private Sheet currentSheet; + + private String currentSheetName; + + private ExcelTypeEnum excelType; + + private Workbook workbook; + + private OutputStream outputStream; + + private Map sheetMap = new ConcurrentHashMap(); + + private Map tableMap = new ConcurrentHashMap(); + + private CellStyle defaultCellStyle; + + private CellStyle currentHeadCellStyle; + + private CellStyle currentContentCellStyle; + + private ExcelHeadProperty excelHeadProperty; + + private boolean needHead = true; + + public GenerateContextImpl(OutputStream out, ExcelTypeEnum excelType, boolean needHead) { + if (ExcelTypeEnum.XLS.equals(excelType)) { + this.workbook = new HSSFWorkbook(); + } else { + this.workbook = new SXSSFWorkbook(500); + } + this.outputStream = out; + this.defaultCellStyle = buildDefaultCellStyle(); + this.needHead = needHead; + } + + private CellStyle buildDefaultCellStyle() { + CellStyle newCellStyle = this.workbook.createCellStyle(); + Font font = this.workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short)14); + font.setBold(true); + newCellStyle.setFont(font); + newCellStyle.setWrapText(true); + newCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); + newCellStyle.setAlignment(HorizontalAlignment.CENTER); + newCellStyle.setLocked(true); + newCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + newCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + newCellStyle.setBorderBottom(BorderStyle.THIN); + newCellStyle.setBorderLeft(BorderStyle.THIN); + return newCellStyle; + } + + public void buildCurrentSheet(com.alibaba.excel.metadata.Sheet sheet) { + if (sheetMap.containsKey(sheet.getSheetNo())) { + this.currentSheet = sheetMap.get(sheet.getSheetNo()); + } else { + this.currentSheet = workbook.createSheet( + sheet.getSheetName() != null ? sheet.getSheetName() : sheet.getSheetNo() + ""); + this.currentSheet.setDefaultColumnWidth(20); + sheetMap.put(sheet.getSheetNo(), this.currentSheet); + buildHead(sheet.getHead(), sheet.getClazz()); + buildTableStyle(sheet.getTableStyle()); + if (needHead && excelHeadProperty != null) { + appendHeadToExcel(); + } + } + + } + + private void buildHead(List> head, Class clazz) { + if (head != null || clazz != null) { excelHeadProperty = new ExcelHeadProperty(clazz, head); } + } + + public void appendHeadToExcel() { + if (this.excelHeadProperty.getHead() != null && this.excelHeadProperty.getHead().size() > 0) { + List list = this.excelHeadProperty.getCellRangeModels(); + int n = currentSheet.getLastRowNum(); + if (n > 0) { + n = n + 4; + } + for (CellRange cellRangeModel : list) { + CellRangeAddress cra = new CellRangeAddress(cellRangeModel.getFirstRow() + n, + cellRangeModel.getLastRow() + n, + cellRangeModel.getFirstCol(), cellRangeModel.getLastCol()); + currentSheet.addMergedRegion(cra); + } + int i = n; + for (; i < this.excelHeadProperty.getRowNum() + n; i++) { + Row row = currentSheet.createRow(i); + addOneRowOfHeadDataToExcel(row, this.excelHeadProperty.getHeadByRowNum(i - n)); + } + } + } + + private void addOneRowOfHeadDataToExcel(Row row, List headByRowNum) { + if (headByRowNum != null && headByRowNum.size() > 0) { + for (int i = 0; i < headByRowNum.size(); i++) { + Cell cell = row.createCell(i); + cell.setCellStyle(this.getCurrentHeadCellStyle()); + cell.setCellValue(headByRowNum.get(i)); + } + } + } + + private void buildTableStyle(TableStyle tableStyle) { + if (tableStyle != null) { + CellStyle headStyle = buildDefaultCellStyle(); + if (tableStyle.getTableHeadFont() != null) { + Font font = this.workbook.createFont(); + font.setFontName(tableStyle.getTableHeadFont().getFontName()); + font.setFontHeightInPoints(tableStyle.getTableHeadFont().getFontHeightInPoints()); + font.setBold(tableStyle.getTableHeadFont().isBold()); + headStyle.setFont(font); + } + if (tableStyle.getTableHeadBackGroundColor() != null) { + headStyle.setFillForegroundColor(tableStyle.getTableHeadBackGroundColor().getIndex()); + } + this.currentHeadCellStyle = headStyle; + CellStyle contentStyle = buildDefaultCellStyle(); + if (tableStyle.getTableContentFont() != null) { + Font font = this.workbook.createFont(); + font.setFontName(tableStyle.getTableContentFont().getFontName()); + font.setFontHeightInPoints(tableStyle.getTableContentFont().getFontHeightInPoints()); + font.setBold(tableStyle.getTableContentFont().isBold()); + contentStyle.setFont(font); + } + if (tableStyle.getTableContentBackGroundColor() != null) { + contentStyle.setFillForegroundColor(tableStyle.getTableContentBackGroundColor().getIndex()); + } + this.currentContentCellStyle = contentStyle; + } + } + + public void buildTable(Table table) { + if (!tableMap.containsKey(table.getTableNo())) { + buildHead(table.getHead(), table.getClazz()); + tableMap.put(table.getTableNo(), table); + buildTableStyle(table.getTableStyle()); + if (needHead && excelHeadProperty != null) { + appendHeadToExcel(); + } + } + + } + + 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; + } + +} diff --git a/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java b/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java new file mode 100644 index 00000000..d055250c --- /dev/null +++ b/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java @@ -0,0 +1,30 @@ +package com.alibaba.excel.event; + +import com.alibaba.excel.context.AnalysisContext; + +/** + * 监听Excel解析每行数据 + * 不能单列,每次使用new一个 + * 不能单列,每次使用new一个 + * 不能单列,每次使用new一个 + * 重要事情说三遍 + * + * @author jipengfei + */ +public abstract class AnalysisEventListener { + + /** + * when analysis one row trigger invoke function + * + * @param object one row data + * @param context analysis context + */ + public abstract void invoke(T object, AnalysisContext context); + + /** + * if have something to do after all analysis + * + * @param context + */ + public abstract void doAfterAllAnalysed(AnalysisContext context); +} diff --git a/src/main/java/com/alibaba/excel/event/AnalysisEventRegisterCenter.java b/src/main/java/com/alibaba/excel/event/AnalysisEventRegisterCenter.java new file mode 100644 index 00000000..8f935f33 --- /dev/null +++ b/src/main/java/com/alibaba/excel/event/AnalysisEventRegisterCenter.java @@ -0,0 +1,29 @@ +package com.alibaba.excel.event; + + +/** + * 管理每个监听者 + * + * @author jipengfei + */ +public interface AnalysisEventRegisterCenter { + + /** + * 增加监听者 + * @param name + * @param listener + */ + void appendLister(String name, AnalysisEventListener listener); + + + /** + * 通知所有监听者 + * @param event + */ + void notifyListeners(OneRowAnalysisFinishEvent event); + + /** + * 清空所有监听者 + */ + void cleanAllListeners(); +} diff --git a/src/main/java/com/alibaba/excel/event/OneRowAnalysisFinishEvent.java b/src/main/java/com/alibaba/excel/event/OneRowAnalysisFinishEvent.java new file mode 100644 index 00000000..a9e9966d --- /dev/null +++ b/src/main/java/com/alibaba/excel/event/OneRowAnalysisFinishEvent.java @@ -0,0 +1,22 @@ +package com.alibaba.excel.event; + +/** + * @author jipengfei + * @date 2017/07/21 + */ +public class OneRowAnalysisFinishEvent { + + public OneRowAnalysisFinishEvent(Object data) { + this.data = data; + } + + private Object data; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/src/main/java/com/alibaba/excel/exception/ExcelAnalysisException.java b/src/main/java/com/alibaba/excel/exception/ExcelAnalysisException.java new file mode 100644 index 00000000..63614b51 --- /dev/null +++ b/src/main/java/com/alibaba/excel/exception/ExcelAnalysisException.java @@ -0,0 +1,24 @@ +package com.alibaba.excel.exception; + +/** + * Excel解析时候封装的异常 + * + * @author jipengfei + */ +public class ExcelAnalysisException extends RuntimeException { + + public ExcelAnalysisException() { + } + + public ExcelAnalysisException(String message) { + super(message); + } + + public ExcelAnalysisException(String message, Throwable cause) { + super(message, cause); + } + + public ExcelAnalysisException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/alibaba/excel/exception/ExcelGenerateException.java b/src/main/java/com/alibaba/excel/exception/ExcelGenerateException.java new file mode 100644 index 00000000..c31dd2b4 --- /dev/null +++ b/src/main/java/com/alibaba/excel/exception/ExcelGenerateException.java @@ -0,0 +1,21 @@ +package com.alibaba.excel.exception; + +/** + * 生成Excel封装的异常 + * @author jipengfei + */ +public class ExcelGenerateException extends RuntimeException { + + + public ExcelGenerateException(String message) { + super(message); + } + + public ExcelGenerateException(String message, Throwable cause) { + super(message, cause); + } + + public ExcelGenerateException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/BaseRowModel.java b/src/main/java/com/alibaba/excel/metadata/BaseRowModel.java new file mode 100644 index 00000000..744bc0a0 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/BaseRowModel.java @@ -0,0 +1,9 @@ +package com.alibaba.excel.metadata; + +/** + * Excel基础模型 + * @author jipengfei + */ +public class BaseRowModel { + +} diff --git a/src/main/java/com/alibaba/excel/metadata/CellRange.java b/src/main/java/com/alibaba/excel/metadata/CellRange.java new file mode 100644 index 00000000..7fac539b --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/CellRange.java @@ -0,0 +1,52 @@ +package com.alibaba.excel.metadata; + +/** + * @author jipengfei + * @date 2017/06/02 + */ +public class CellRange { + + private int firstRow; + private int lastRow; + private int firstCol; + private int lastCol; + + public CellRange(int firstRow, int lastRow, int firstCol, int lastCol) { + this.firstRow = firstRow; + this.lastRow = lastRow; + this.firstCol = firstCol; + this.lastCol = lastCol; + } + + public int getFirstRow() { + return firstRow; + } + + public void setFirstRow(int firstRow) { + this.firstRow = firstRow; + } + + public int getLastRow() { + return lastRow; + } + + public void setLastRow(int lastRow) { + this.lastRow = lastRow; + } + + public int getFirstCol() { + return firstCol; + } + + public void setFirstCol(int firstCol) { + this.firstCol = firstCol; + } + + public int getLastCol() { + return lastCol; + } + + public void setLastCol(int lastCol) { + this.lastCol = lastCol; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/ExcelColumnProperty.java b/src/main/java/com/alibaba/excel/metadata/ExcelColumnProperty.java new file mode 100644 index 00000000..82e554c3 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/ExcelColumnProperty.java @@ -0,0 +1,70 @@ +package com.alibaba.excel.metadata; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/** + * @author jipengfei + * @date 2017/05/31 + */ +public class ExcelColumnProperty implements Comparable { + + /** + * 列对应的Class field字段 + */ + private Field field; + + /** + * 列顺序 默认很大 + */ + private int index = 99999; + + /** + * 该列对应的表头 + */ + private List head = new ArrayList(); + + /** + * 日期类型format 如:"yyyy-MM-dd HH:mm:ss" + */ + private String format; + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public Field getField() { + return field; + } + + public void setField(Field field) { + this.field = field; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public List getHead() { + return head; + } + + public void setHead(List head) { + this.head = head; + } + + public int compareTo(ExcelColumnProperty o) { + int x = this.index; + int y = o.getIndex(); + return (x < y) ? -1 : ((x == y) ? 0 : 1); + } +} \ No newline at end of file diff --git a/src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java b/src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java new file mode 100644 index 00000000..2e188c8c --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java @@ -0,0 +1,253 @@ +package com.alibaba.excel.metadata; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.excel.annotation.ExcelColumnNum; +import com.alibaba.excel.annotation.ExcelProperty; + +/** + * 表头信息 + * + * @author jipengfei + * @date 2017/05/31 + */ +public class ExcelHeadProperty { + + /** + * 表头数据对应的Class + */ + private Class headClazz; + + /** + * 表头名称 + */ + private List> head = new ArrayList>(); + + /** + * Excel每列表头数据 + */ + private List columnPropertyList = new ArrayList(); + + /** + * key:Excel列号,value:表头数据 + */ + private Map excelColumnPropertyMap1 = new HashMap(); + + public ExcelHeadProperty(Class headClazz, List> head) { + this.headClazz = headClazz; + this.head = head; + initColumnProperties(); + } + + /** + * 初始化每列 + */ + private void initColumnProperties() { + if (this.headClazz != null) { + Field[] fields = this.headClazz.getDeclaredFields(); + List> headList = new ArrayList>(); + for (Field f : fields) { + initOneColumnProperty(f); + } + //对列排序 + Collections.sort(columnPropertyList); + if (head == null || head.size() == 0) { + for (ExcelColumnProperty excelColumnProperty : columnPropertyList) { + headList.add(excelColumnProperty.getHead()); + } + this.head = headList; + } + } + } + + /** + * 初始化一列 + * + * @param f + */ + private void initOneColumnProperty(Field f) { + ExcelProperty p = f.getAnnotation(ExcelProperty.class); + ExcelColumnProperty excelHeadProperty = null; + if (p != null) { + excelHeadProperty = new ExcelColumnProperty(); + excelHeadProperty.setField(f); + excelHeadProperty.setHead(Arrays.asList(p.value())); + excelHeadProperty.setIndex(p.index()); + excelHeadProperty.setFormat(p.format()); + excelColumnPropertyMap1.put(p.index(), excelHeadProperty); + } else { + ExcelColumnNum columnNum = f.getAnnotation(ExcelColumnNum.class); + if (columnNum != null) { + excelHeadProperty = new ExcelColumnProperty(); + excelHeadProperty.setField(f); + excelHeadProperty.setIndex(columnNum.value()); + excelHeadProperty.setFormat(columnNum.format()); + excelColumnPropertyMap1.put(columnNum.value(), excelHeadProperty); + } + } + if (excelHeadProperty != null) { + this.columnPropertyList.add(excelHeadProperty); + } + + } + + /** + * 将表头的一行数据,转换为一列一列形式,组成表头 + * + * @param row 表头中的一行数据 + */ + public void appendOneRow(List row) { + + for (int i = 0; i < row.size(); i++) { + List list; + if (head.size() <= i) { + list = new ArrayList(); + head.add(list); + } else { + list = head.get(0); + } + list.add(row.get(i)); + } + + } + + /** + * 根据Excel中的列号,获取Excel的表头信息 + * + * @param columnNum + * @return + */ + public ExcelColumnProperty getExcelColumnProperty(int columnNum) { + ExcelColumnProperty excelColumnProperty = excelColumnPropertyMap1.get(columnNum); + if (excelColumnProperty == null) { + if (head != null && head.size() > columnNum) { + List columnHead = head.get(columnNum); + for (ExcelColumnProperty columnProperty : columnPropertyList) { + if (headEquals(columnHead, columnProperty.getHead())) { + return columnProperty; + } + } + } + } + return excelColumnProperty; + } + + /** + * 判断表头是否相同 + * + * @param columnHead + * @param head + * @return + */ + private boolean headEquals(List columnHead, List head) { + boolean result = true; + if (columnHead == null || head == null || columnHead.size() != head.size()) { + return false; + } else { + for (int i = 0; i < head.size(); i++) { + if (!head.get(i).equals(columnHead.get(i))) { + result = false; + break; + } + } + } + return result; + } + + public Class getHeadClazz() { + return headClazz; + } + + public void setHeadClazz(Class headClazz) { + this.headClazz = headClazz; + } + + public List> getHead() { + return this.head; + } + + public void setHead(List> head) { + this.head = head; + } + + public List getColumnPropertyList() { + return columnPropertyList; + } + + public void setColumnPropertyList(List columnPropertyList) { + this.columnPropertyList = columnPropertyList; + } + + public List getCellRangeModels() { + List rangs = new ArrayList(); + for (int i = 0; i < head.size(); i++) { + List columnvalues = head.get(i); + for (int j = 0; j < columnvalues.size(); j++) { + int lastRow = getLastRangRow(j, columnvalues.get(j), columnvalues); + int lastColumn = getLastRangColumn(columnvalues.get(j), getHeadByRowNum(j), i); + if (lastRow >= 0 && lastColumn >= 0 && (lastRow > j || lastColumn > i)) { + rangs.add(new CellRange(j, lastRow, i, lastColumn)); + } + + } + } + return rangs; + } + + public List getHeadByRowNum(int rowNum) { + List l = new ArrayList(head.size()); + for (List list : head) { + if (list.size() > rowNum) { + l.add(list.get(rowNum)); + } else { + l.add(list.get(list.size() - 1)); + } + } + return l; + } + + /** + * @param value + * @param headByRowNum + * @param i + * @return + */ + private int getLastRangColumn(String value, List headByRowNum, int i) { + if (headByRowNum.indexOf(value) < i) { + return -1; + } else { + return headByRowNum.lastIndexOf(value); + } + } + + private int getLastRangRow(int j, String value, List columnvalue) { + + if (columnvalue.indexOf(value) < j) { + return -1; + } + if (value != null && value.equals(columnvalue.get(columnvalue.size() - 1))) { + return getRowNum() - 1; + } else { + return columnvalue.lastIndexOf(value); + } + } + + public int getRowNum() { + int headRowNum = 0; + for (List list : head) { + if (list != null && list.size() > 0) { + if (list.size() > headRowNum) { + headRowNum = list.size(); + } + } + } + return headRowNum; + } + +} diff --git a/src/main/java/com/alibaba/excel/metadata/Font.java b/src/main/java/com/alibaba/excel/metadata/Font.java new file mode 100644 index 00000000..aae38755 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/Font.java @@ -0,0 +1,49 @@ +package com.alibaba.excel.metadata; + +/** + * 字体样式 + * + * @author jipengfei + * @date 2017/05/24 + */ +public class Font { + + /** + * 字体名称,如:宋体、黑体 + */ + private String fontName; + + /** + * 字体大小 + */ + private short fontHeightInPoints; + + /** + * 是否加粗 + */ + private boolean bold; + + public String getFontName() { + return fontName; + } + + public void setFontName(String fontName) { + this.fontName = fontName; + } + + public short getFontHeightInPoints() { + return fontHeightInPoints; + } + + public void setFontHeightInPoints(short fontHeightInPoints) { + this.fontHeightInPoints = fontHeightInPoints; + } + + public boolean isBold() { + return bold; + } + + public void setBold(boolean bold) { + this.bold = bold; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/IndexValue.java b/src/main/java/com/alibaba/excel/metadata/IndexValue.java new file mode 100644 index 00000000..2be04275 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/IndexValue.java @@ -0,0 +1,39 @@ +package com.alibaba.excel.metadata; + +/** + * @author jipengfei + */ +public class IndexValue { + + private String v_index; + private String v_value; + + public IndexValue(String v_index, String v_value) { + super(); + this.v_index = v_index; + this.v_value = v_value; + } + + public String getV_index() { + return v_index; + } + + public void setV_index(String v_index) { + this.v_index = v_index; + } + + public String getV_value() { + return v_value; + } + + public void setV_value(String v_value) { + this.v_value = v_value; + } + + @Override + public String toString() { + return "IndexValue [v_index=" + v_index + ", v_value=" + v_value + "]"; + } + + +} diff --git a/src/main/java/com/alibaba/excel/metadata/Sheet.java b/src/main/java/com/alibaba/excel/metadata/Sheet.java new file mode 100644 index 00000000..82619979 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/Sheet.java @@ -0,0 +1,128 @@ +package com.alibaba.excel.metadata; + +import java.util.List; + +/** + * Sheet参数 + * + * @author jipengfei + */ +public class Sheet { + + /** + * 表头行数 + */ + private int headLineMun; + + /** + * sheet序号 + */ + private int sheetNo; + + /** + * 名称 可不填 + */ + private String sheetName; + + /** + * 对用的表头模型 + */ + private Class clazz; + + /** + * 对用的表头层级树,用于clazz不确定时候,动态生成表头 + */ + private List> head; + + /** + * + */ + private TableStyle tableStyle; + + public Sheet(int sheetNo) { + this.sheetNo = sheetNo; + } + + public Sheet(int sheetNo, int headLineMun) { + this.sheetNo = sheetNo; + this.headLineMun = headLineMun; + } + + public Sheet(int sheetNo, int headLineMun, Class clazz) { + this.sheetNo = sheetNo; + this.headLineMun = headLineMun; + this.clazz = clazz; + } + + public Sheet(int sheetNo, int headLineMun, Class clazz, String sheetName, + List> head) { + this.sheetNo = sheetNo; + this.clazz = clazz; + this.headLineMun = headLineMun; + this.sheetName = sheetName; + this.head = head; + } + + public List> getHead() { + return head; + } + + public void setHead(List> head) { + this.head = head; + } + + public Class getClazz() { + return clazz; + } + + public void setClazz(Class clazz) { + this.clazz = clazz; + if (headLineMun == 0) { + this.headLineMun = 1; + } + } + + public int getHeadLineMun() { + return headLineMun; + } + + public void setHeadLineMun(int headLineMun) { + this.headLineMun = headLineMun; + } + + public int getSheetNo() { + return sheetNo; + } + + public void setSheetNo(int sheetNo) { + this.sheetNo = sheetNo; + } + + public String getSheetName() { + return sheetName; + } + + public void setSheetName(String sheetName) { + this.sheetName = sheetName; + } + + public TableStyle getTableStyle() { + return tableStyle; + } + + public void setTableStyle(TableStyle tableStyle) { + this.tableStyle = tableStyle; + } + + @Override + public String toString() { + return "Sheet{" + + "headLineMun=" + headLineMun + + ", sheetNo=" + sheetNo + + ", sheetName='" + sheetName + '\'' + + ", clazz=" + clazz + + ", head=" + head + + ", tableStyle=" + tableStyle + + '}'; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/Table.java b/src/main/java/com/alibaba/excel/metadata/Table.java new file mode 100644 index 00000000..37afefc5 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/Table.java @@ -0,0 +1,65 @@ +package com.alibaba.excel.metadata; + +import java.util.List; + +/** + * @author jipengfei + * @date 2017/05/16 + */ +public class Table { + /** + * 对用的表头模型 + */ + private Class clazz; + + /** + * 对用的表头层级树,用于clazz不确定时候,动态生成表头 + */ + private List> head; + + /** + * 第几个table,用于和其他table区分 + */ + private Integer tableNo; + + /** + * 支持表格简单样式自定义 + */ + private TableStyle tableStyle; + + public TableStyle getTableStyle() { + return tableStyle; + } + + public void setTableStyle(TableStyle tableStyle) { + this.tableStyle = tableStyle; + } + + public Table(Integer tableNo) { + this.tableNo = tableNo; + } + + public Class getClazz() { + return clazz; + } + + public void setClazz(Class clazz) { + this.clazz = clazz; + } + + public List> getHead() { + return head; + } + + public void setHead(List> head) { + this.head = head; + } + + public Integer getTableNo() { + return tableNo; + } + + public void setTableNo(Integer tableNo) { + this.tableNo = tableNo; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/TableStyle.java b/src/main/java/com/alibaba/excel/metadata/TableStyle.java new file mode 100644 index 00000000..6618197e --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/TableStyle.java @@ -0,0 +1,62 @@ +package com.alibaba.excel.metadata; + +import org.apache.poi.ss.usermodel.IndexedColors; + +/** + * @author jipengfei + * @date 2017/05/24 + */ +public class TableStyle { + + /** + * 表头背景颜色 + */ + private IndexedColors tableHeadBackGroundColor; + + /** + * 表头字体样式 + */ + private Font tableHeadFont; + + /** + * 表格内容字体样式 + */ + private Font tableContentFont; + + /** + * 表格内容背景颜色 + */ + private IndexedColors tableContentBackGroundColor; + + public IndexedColors getTableHeadBackGroundColor() { + return tableHeadBackGroundColor; + } + + public void setTableHeadBackGroundColor(IndexedColors tableHeadBackGroundColor) { + this.tableHeadBackGroundColor = tableHeadBackGroundColor; + } + + public Font getTableHeadFont() { + return tableHeadFont; + } + + public void setTableHeadFont(Font tableHeadFont) { + this.tableHeadFont = tableHeadFont; + } + + public Font getTableContentFont() { + return tableContentFont; + } + + public void setTableContentFont(Font tableContentFont) { + this.tableContentFont = tableContentFont; + } + + public IndexedColors getTableContentBackGroundColor() { + return tableContentBackGroundColor; + } + + public void setTableContentBackGroundColor(IndexedColors tableContentBackGroundColor) { + this.tableContentBackGroundColor = tableContentBackGroundColor; + } +} diff --git a/src/main/java/com/alibaba/excel/modelbuild/ModelBuildEventListener.java b/src/main/java/com/alibaba/excel/modelbuild/ModelBuildEventListener.java new file mode 100644 index 00000000..607b8c52 --- /dev/null +++ b/src/main/java/com/alibaba/excel/modelbuild/ModelBuildEventListener.java @@ -0,0 +1,68 @@ +package com.alibaba.excel.modelbuild; + +import java.util.List; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelGenerateException; +import com.alibaba.excel.metadata.ExcelColumnProperty; +import com.alibaba.excel.metadata.ExcelHeadProperty; +import com.alibaba.excel.util.TypeUtil; + +import org.apache.commons.beanutils.BeanUtils; + +/** + * 监听POI Sax解析的每行结果 + * + * @author jipengfei + */ +public class ModelBuildEventListener extends AnalysisEventListener { + + + @Override + public void invoke(Object object, AnalysisContext context) { + + + if(context.getExcelHeadProperty() != null && context.getExcelHeadProperty().getHeadClazz()!=null ){ + Object resultModel = buildUserModel(context, (List)object); + context.setCurrentRowAnalysisResult(resultModel); + } + + } + + + + private Object buildUserModel(AnalysisContext context, List stringList) { + ExcelHeadProperty excelHeadProperty = context.getExcelHeadProperty(); + + Object resultModel; + try { + resultModel = excelHeadProperty.getHeadClazz().newInstance(); + } catch (Exception e) { + throw new ExcelGenerateException(e); + } + if (excelHeadProperty != null) { + for (int i = 0; i < stringList.size(); i++) { + ExcelColumnProperty columnProperty = excelHeadProperty.getExcelColumnProperty(i); + if (columnProperty != null) { + Object value = TypeUtil.convert(stringList.get(i), columnProperty.getField(), + columnProperty.getFormat(),context.use1904WindowDate()); + if (value != null) { + try { + BeanUtils.setProperty(resultModel, columnProperty.getField().getName(), value); + } catch (Exception e) { + throw new ExcelGenerateException( + columnProperty.getField().getName() + " can not set value " + value, e); + } + } + } + } + } + return resultModel; + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + + } +} diff --git a/src/main/java/com/alibaba/excel/parameter/AnalysisParam.java b/src/main/java/com/alibaba/excel/parameter/AnalysisParam.java new file mode 100644 index 00000000..5739f792 --- /dev/null +++ b/src/main/java/com/alibaba/excel/parameter/AnalysisParam.java @@ -0,0 +1,59 @@ +package com.alibaba.excel.parameter; + +import java.io.InputStream; + +import com.alibaba.excel.support.ExcelTypeEnum; + +/** + * 方便使用废弃Excel解析时候入参,直接将ExcelTypeEnum、InputStream、customContent传入{@link com.alibaba.excel.ExcelReader}的构造器 + * + * @author jipengfei + */ +@Deprecated +public class AnalysisParam { + + /** + * @see ExcelTypeEnum + */ + private ExcelTypeEnum excelTypeEnum; + + /** + * file in + */ + private InputStream in; + + /** + * user defined param to listener use + */ + private Object customContent; + + public AnalysisParam(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent) { + this.in = in; + this.excelTypeEnum = excelTypeEnum; + this.customContent = customContent; + } + + public ExcelTypeEnum getExcelTypeEnum() { + return excelTypeEnum; + } + + public void setExcelTypeEnum(ExcelTypeEnum excelTypeEnum) { + this.excelTypeEnum = excelTypeEnum; + } + + public Object getCustomContent() { + return customContent; + } + + public void setCustomContent(Object customContent) { + this.customContent = customContent; + } + + public InputStream getIn() { + return in; + } + + public void setIn(InputStream in) { + this.in = in; + } +} diff --git a/src/main/java/com/alibaba/excel/parameter/ExcelWriteParam.java b/src/main/java/com/alibaba/excel/parameter/ExcelWriteParam.java new file mode 100644 index 00000000..53665e86 --- /dev/null +++ b/src/main/java/com/alibaba/excel/parameter/ExcelWriteParam.java @@ -0,0 +1,47 @@ +package com.alibaba.excel.parameter; + +import java.io.OutputStream; + +import com.alibaba.excel.support.ExcelTypeEnum; + +/** + * 为方便使用废弃该入参。直接将outputStream,type传入{@link com.alibaba.excel.ExcelWriter}的构造器即可 + * + * @author jipengfei + * @date 2017/05/15 + */ +@Deprecated +public class ExcelWriteParam { + + /** + * 文件输出流 + */ + private OutputStream outputStream; + + /** + * Excel类型 + */ + private ExcelTypeEnum type; + + public ExcelWriteParam(OutputStream outputStream, ExcelTypeEnum type) { + this.outputStream = outputStream; + this.type = type; + + } + + public OutputStream getOutputStream() { + return outputStream; + } + + public void setOutputStream(OutputStream outputStream) { + this.outputStream = outputStream; + } + + public ExcelTypeEnum getType() { + return type; + } + + public void setType(ExcelTypeEnum type) { + this.type = type; + } +} diff --git a/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java b/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java new file mode 100644 index 00000000..623e530d --- /dev/null +++ b/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java @@ -0,0 +1,25 @@ +package com.alibaba.excel.support; + +/** + * 支持读写的数据格式 + * + * @author jipengfei + */ +public enum ExcelTypeEnum { + XLS(".xls"), + XLSX(".xlsx"); + // CSV(".csv"); + private String value; + + private ExcelTypeEnum(String value) { + this.setValue(value); + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/src/main/java/com/alibaba/excel/util/EasyExcelTempFile.java b/src/main/java/com/alibaba/excel/util/EasyExcelTempFile.java new file mode 100644 index 00000000..eb6584f3 --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/EasyExcelTempFile.java @@ -0,0 +1,62 @@ +package com.alibaba.excel.util; + +import java.io.File; + +/** + * 用于修复POI {@link org.apache.poi.util.DefaultTempFileCreationStrategy}在并发写,创建临时目录抛出异常的BUG。 + * + * @author jipengfei + * @date 2017/06/22 + */ +public class EasyExcelTempFile { + + private static final String JAVA_IO_TMPDIR = "java.io.tmpdir"; + + private static final String POIFILES = "poifiles"; + + private static final String EASY_EXCEL_FILES = "easyexcel"; + + /** + * 在创建ExcelBuilder后尝试创建临时目录,避免poi创建时候报错 + */ + public static void createPOIFilesDirectory() { + + String tmpDir = System.getProperty(JAVA_IO_TMPDIR); + if (tmpDir == null) { + throw new RuntimeException( + "Systems temporary directory not defined - set the -D" + JAVA_IO_TMPDIR + " jvm property!"); + } + File directory = new File(tmpDir, POIFILES); + if (!directory.exists()) { + syncCreatePOIFilesDirectory(directory); + } + + } + + /** + * 获取环境变量的配置 + */ + public static String getEasyExcelTmpDir() { + String tmpDir = System.getProperty(JAVA_IO_TMPDIR); + if (tmpDir == null) { + throw new RuntimeException( + "Systems temporary directory not defined - set the -D" + JAVA_IO_TMPDIR + " jvm property!"); + } + File directory = new File(tmpDir, EASY_EXCEL_FILES); + if (!directory.exists()) { + syncCreatePOIFilesDirectory(directory); + } + return tmpDir + File.separator + EASY_EXCEL_FILES; + } + + /** + * 如果directory 不存在则创建 + * + * @param directory + */ + private static synchronized void syncCreatePOIFilesDirectory(File directory) { + if (!directory.exists()) { + directory.mkdirs(); + } + } +} diff --git a/src/main/java/com/alibaba/excel/util/FileUtil.java b/src/main/java/com/alibaba/excel/util/FileUtil.java new file mode 100644 index 00000000..f4376589 --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/FileUtil.java @@ -0,0 +1,114 @@ +package com.alibaba.excel.util; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; + +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.compress.archivers.zip.ZipFile; +import org.apache.commons.compress.utils.IOUtils; + +/** + * @author jipengfei + * @date 2017/10/10 + */ +public class FileUtil { + + private static final int BUF = 4096; + + public static boolean writeFile(File file, InputStream stream) throws FileNotFoundException { + OutputStream o = null; + try { + makeDirs(file.getAbsolutePath()); + if (!file.exists()) { + file.createNewFile(); + } + + o = new FileOutputStream(file); + byte data[] = new byte[1024]; + int length = -1; + while ((length = stream.read(data)) != -1) { + o.write(data, 0, length); + } + o.flush(); + return true; + } catch (FileNotFoundException e) { + throw new RuntimeException("FileNotFoundException occurred. ", e); + } catch (IOException e) { + throw new RuntimeException("IOException occurred. ", e); + } finally { + try { + o.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public static boolean makeDirs(String filePath) { + String folderName = getFolderName(filePath); + if (folderName == null || "".equals(folderName)) { + return false; + } + File folder = new File(folderName); + return (folder.exists() && folder.isDirectory()) ? true : folder.mkdirs(); + } + + public static String getFolderName(String filePath) { + + if (filePath == null || "".equals(filePath)) { + return filePath; + } + int filePosi = filePath.lastIndexOf(File.separator); + return (filePosi == -1) ? "" : filePath.substring(0, filePosi); + } + + public static boolean doUnZip(String path, File file) throws IOException { + ZipFile zipFile = new ZipFile(file, "utf-8"); + Enumeration en = zipFile.getEntries(); + ZipArchiveEntry ze; + while (en.hasMoreElements()) { + ze = en.nextElement(); + File f = new File(path, ze.getName()); + if (ze.isDirectory()) { + f.mkdirs(); + continue; + } else { f.getParentFile().mkdirs(); } + + InputStream is = zipFile.getInputStream(ze); + OutputStream os = new FileOutputStream(f); + IOUtils.copy(is, os, BUF); + is.close(); + os.close(); + } + zipFile.close(); + return true; + } + + public static void deletefile(String delpath) { + File file = new File(delpath); + // 当且仅当此抽象路径名表示的文件存在且 是一个目录时,返回 true + if (!file.isDirectory()) { + file.delete(); + } else if (file.isDirectory()) { + String[] filelist = file.list(); + for (int i = 0; i < filelist.length; i++) { + File delfile = new File(delpath + File.separator + filelist[i]); + if (!delfile.isDirectory()) { + delfile.delete(); + } else if (delfile.isDirectory()) { + deletefile(delpath + File.separator + filelist[i]); + } + } + } + } + + public static void main(String[] args) { + System.out.println(File.separator); + } + +} diff --git a/src/main/java/com/alibaba/excel/util/IndexValueConverter.java b/src/main/java/com/alibaba/excel/util/IndexValueConverter.java new file mode 100644 index 00000000..af8ac7e1 --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/IndexValueConverter.java @@ -0,0 +1,74 @@ +package com.alibaba.excel.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import com.alibaba.excel.metadata.IndexValue; + +/** + * 去除空Cell + * @author jipengfei + * @date 2017/04/13 + */ +public class IndexValueConverter { + public static List converter(List i_list) { + + List tem = new ArrayList(); + + char[] start = {'@'}; + int j = 0; + for (; j < i_list.size(); j++) { + IndexValue currentIndexValue = i_list.get(j); + char[] currentIndex = currentIndexValue.getV_index().replaceAll("[0-9]", "").toCharArray(); + if (j > 0) { + start = i_list.get(j - 1).getV_index().replaceAll("[0-9]", "").toCharArray(); + } + int deep = subtraction26(currentIndex, start); + int k = 0; + for (; k < deep - 1; k++) { + tem.add(null); + } + tem.add(currentIndexValue.getV_value()); + } + return tem; + } + + private static int subtraction26(char[] currentIndex, char[] beforeIndex) { + int result = 0; + + Stack currentStack = new Stack(); + Stack berforStack = new Stack(); + + for (int i = 0; i < currentIndex.length; i++) { + currentStack.push(currentIndex[i]); + } + for (int i = 0; i < beforeIndex.length; i++) { + berforStack.push(beforeIndex[i]); + } + int i = 0; + char beforechar = '@'; + while (!currentStack.isEmpty()) { + char currentChar = currentStack.pop(); + if (!berforStack.isEmpty()) { + beforechar = berforStack.pop(); + } + int n = currentChar - beforechar; + if(n<0){ + n = n+26; + if(!currentStack.isEmpty()){ + char borrow = currentStack.pop(); + char newBorrow =(char)(borrow -1); + currentStack.push(newBorrow); + } + } + + + result += n * Math.pow(26, i); + i++; + beforechar='@'; + } + + return result; + } +} diff --git a/src/main/java/com/alibaba/excel/util/PositionUtils.java b/src/main/java/com/alibaba/excel/util/PositionUtils.java new file mode 100644 index 00000000..f5f084ac --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/PositionUtils.java @@ -0,0 +1,29 @@ +package com.alibaba.excel.util; + +/** + * @author jipengfei + * @date 2017/08/27 + */ +public class PositionUtils { + + public static int getRow(String currentCellIndex) { + int row = 0; + if (currentCellIndex != null) { + String rowStr = currentCellIndex.replaceAll("[A-Z]", "").replaceAll("[a-z]", ""); + row = Integer.parseInt(rowStr)-1; + } + return row; + } + + public static int getCol(String currentCellIndex) { + int col = 0; + if (currentCellIndex != null) { + + char[] currentIndex = currentCellIndex.replaceAll("[0-9]", "").toCharArray(); + for (int i = 0; i < currentIndex.length; i++) { + col += (currentIndex[i] - '@') * Math.pow(26, (currentIndex.length - i - 1)); + } + } + return col-1; + } +} diff --git a/src/main/java/com/alibaba/excel/util/TypeUtil.java b/src/main/java/com/alibaba/excel/util/TypeUtil.java new file mode 100644 index 00000000..79975224 --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/TypeUtil.java @@ -0,0 +1,142 @@ +package com.alibaba.excel.util; + +import java.lang.reflect.Field; +import java.math.BigDecimal; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.poi.hssf.usermodel.HSSFDateUtil; + +/** + * 类型转换工具类 + * + * @author jipengfei + * @date 2017/03/15 + */ +public class TypeUtil { + + private static List DATE_FORMAT_LIST = new ArrayList(4); + + static { + DATE_FORMAT_LIST.add(new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")); + DATE_FORMAT_LIST.add(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); + } + + public static Object convert(String value, Field field, String format, boolean us) { + if (isNotEmpty(value)) { + if (String.class.equals(field.getType())) { + return value; + } + if (Integer.class.equals(field.getType()) || int.class.equals(field.getType())) { + return Integer.parseInt(value); + } + if (Double.class.equals(field.getType()) || double.class.equals(field.getType())) { + return Double.parseDouble(value); + } + if (Boolean.class.equals(field.getType()) || boolean.class.equals(field.getType())) { + String valueLower = value.toLowerCase(); + if (valueLower.equals("true") || valueLower.equals("false")) { + return Boolean.parseBoolean(value.toLowerCase()); + } + Integer integer = Integer.parseInt(value); + if (integer == 0) { + return false; + } else { + return true; + } + } + if (Long.class.equals(field.getType()) || long.class.equals(field.getType())) { + return Long.parseLong(value); + } + if (Date.class.equals(field.getType())) { + if (value.contains("-") || value.contains("/") || value.contains(":")) { + return getSimpleDateFormatDate(value, format); + } else { + Double d = Double.parseDouble(value); + return HSSFDateUtil.getJavaDate(d, us); + } + } + if (BigDecimal.class.equals(field.getType())) { + return new BigDecimal(value); + } + + } + return null; + } + + public static String getDefaultDateString(Date date) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return simpleDateFormat.format(date); + + } + + public static Date getSimpleDateFormatDate(String value, String format) { + if (isNotEmpty(value)) { + Date date = null; + if (isNotEmpty(format)) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); + try { + date = simpleDateFormat.parse(value); + return date; + } catch (ParseException e) { + } + } + for (SimpleDateFormat dateFormat : DATE_FORMAT_LIST) { + try { + date = dateFormat.parse(value); + } catch (ParseException e) { + } + if (date != null) { + break; + } + } + + return date; + + } + return null; + + } + + private static Boolean isNotEmpty(String value) { + if (value == null) { + return false; + } + if (value.trim().equals("")) { + return false; + } + return true; + + } + + public static String formatFloat(String value) { + if (value.contains(".")) { + if (isNumeric(value)) { + try { + BigDecimal decimal = new BigDecimal(value); + BigDecimal setScale = decimal.setScale(10, BigDecimal.ROUND_HALF_DOWN).stripTrailingZeros(); + return setScale.toPlainString(); + } catch (Exception e) { + } + } + } + return value; + } + + public static final Pattern pattern = Pattern.compile("[\\+\\-]?[\\d]+([\\.][\\d]*)?([Ee][+-]?[\\d]+)?$"); + + private static boolean isNumeric(String str) { + Matcher isNum = pattern.matcher(str); + if (!isNum.matches()) { + return false; + } + return true; + } + + +} diff --git a/src/main/java/com/alibaba/excel/write/ExcelBuilder.java b/src/main/java/com/alibaba/excel/write/ExcelBuilder.java new file mode 100644 index 00000000..63d373f0 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/ExcelBuilder.java @@ -0,0 +1,54 @@ +package com.alibaba.excel.write; + +import java.io.OutputStream; +import java.util.List; + +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.metadata.Table; +import com.alibaba.excel.support.ExcelTypeEnum; + +/** + * Excel构建器 + * + * @author jipengfei + */ +public interface ExcelBuilder { + + /** + * 初始化Excel构造器 + * + * @param out 文件输出流 + * @param excelType 输出Excel类型,建议使用07版xlsx(性能,内存消耗,cpu使用都远低于03版xls) + * @param needHead 是否需要将表头写入Excel + */ + void init(OutputStream out, ExcelTypeEnum excelType, boolean needHead); + + /** + * 向Excel增加的内容 + * + * @param data 数据格式 {@link List < String >} 或{@link List } + */ + void addContent(List data); + + /** + * 向Excel增加的内容 + * + * @param data 数据格式 {@link List < String >} 或{@link List } + * @param sheetParam 数据写到某个sheet中 + */ + void addContent(List data, Sheet sheetParam); + + /** + * 向Excel增加的内容 + * + * @param data 数据格式 {@link List < String >} 或{@link List } + * @param sheetParam 数据写到某个sheet中 + * @param table 写到某个sheet的某个Table + */ + void addContent(List data, Sheet sheetParam, Table table); + + /** + * 关闭资源 + */ + void finish(); +} diff --git a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java new file mode 100644 index 00000000..9d306cc7 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java @@ -0,0 +1,109 @@ +package com.alibaba.excel.write; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +import com.alibaba.excel.context.GenerateContext; +import com.alibaba.excel.context.GenerateContextImpl; +import com.alibaba.excel.metadata.ExcelColumnProperty; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.metadata.Table; +import com.alibaba.excel.support.ExcelTypeEnum; +import com.alibaba.excel.util.EasyExcelTempFile; + +import org.apache.commons.beanutils.BeanUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; + +/** + * @author jipengfei + * @date 2017/05/27 + */ +public class ExcelBuilderImpl implements ExcelBuilder { + + private GenerateContext context; + + public void init(OutputStream out, ExcelTypeEnum excelType, boolean needHead) { + //初始化时候创建临时缓存目录,用于规避POI在并发写bug + EasyExcelTempFile.createPOIFilesDirectory(); + + context = new GenerateContextImpl(out, excelType, needHead); + } + + public void addContent(List data) { + if (data != null && data.size() > 0) { + int rowNum = context.getCurrentSheet().getLastRowNum(); + if (rowNum == 0) { + Row row = context.getCurrentSheet().getRow(0); + if(row ==null) { + if (context.getExcelHeadProperty() == null || !context.needHead()) { + rowNum = -1; + } + } + } + for (int i = 0; i < data.size(); i++) { + int n = i + rowNum + 1; + addOneRowOfDataToExcel(data.get(i), n); + } + } + } + + public void addContent(List data, Sheet sheetParam) { + context.buildCurrentSheet(sheetParam); + addContent(data); + } + + public void addContent(List data, Sheet sheetParam, Table table) { + context.buildCurrentSheet(sheetParam); + context.buildTable(table); + addContent(data); + } + + public void finish() { + try { + context.getWorkbook().write(context.getOutputStream()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void addOneRowOfDataToExcel(List oneRowData, Row row) { + if (oneRowData != null && oneRowData.size() > 0) { + for (int i = 0; i < oneRowData.size(); i++) { + Cell cell = row.createCell(i); + cell.setCellStyle(context.getCurrentContentStyle()); + cell.setCellValue(oneRowData.get(i)); + } + } + } + + private void addOneRowOfDataToExcel(Object oneRowData, Row row) { + int i = 0; + for (ExcelColumnProperty excelHeadProperty : context.getExcelHeadProperty().getColumnPropertyList()) { + Cell cell = row.createCell(i); + cell.setCellStyle(context.getCurrentContentStyle()); + String cellValue = null; + try { + cellValue = BeanUtils.getProperty(oneRowData, excelHeadProperty.getField().getName()); + } catch (Exception e) { + e.printStackTrace(); + } + if (cellValue != null) { + cell.setCellValue(cellValue); + } else { + cell.setCellValue(""); + } + i++; + } + } + + private void addOneRowOfDataToExcel(Object oneRowData, int n) { + Row row = context.getCurrentSheet().createRow(n); + if (oneRowData instanceof List) { + addOneRowOfDataToExcel((List)oneRowData, row); + } else { + addOneRowOfDataToExcel(oneRowData, row); + } + } +} diff --git a/src/test/java/function/listener/ExcelListener.java b/src/test/java/function/listener/ExcelListener.java new file mode 100644 index 00000000..dc593204 --- /dev/null +++ b/src/test/java/function/listener/ExcelListener.java @@ -0,0 +1,97 @@ +package function.listener; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.Sheet; + +/** + * Created by jipengfei on 17/3/14. + * 解析监听器, + * 每解析一行会回调invoke()方法。 + * 整个excel解析结束会执行doAfterAllAnalysed()方法 + * + * 下面只是我写的一个样例而已,可以根据自己的逻辑修改该类。 + * + * @author jipengfei + * @date 2017/03/14 + */ +public class ExcelListener extends AnalysisEventListener { + + //自定义用于暂时存储data。 + //可以通过实例获取该值 + private List datas = new ArrayList(); + Sheet sheet; + + private ExcelWriter writer; + + + public void invoke(Object object, AnalysisContext context) { + // context.interrupt(); + + System.out.println("当前表格数" + context.getCurrentSheet().getSheetNo() + " 当前行:" + context.getCurrentRowNum()); + System.out.println(object); + datas.add(object);//数据存储到list,供批量处理,或后续自己业务逻辑处理。 + List> ll = new ArrayList>(); + ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); + ObjectOutputStream out = null; + try { + out = new ObjectOutputStream(byteOut); + out.writeObject(object); + ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); + ObjectInputStream in = new ObjectInputStream(byteIn); + + List dest = (List)in.readObject(); + ll.add(dest); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + + // writer.write0(ll, sheet); + doSomething(object);//根据自己业务做处理 + + } + + private void doSomething(Object object) { + //1、入库调用接口 + } + + public void doAfterAllAnalysed(AnalysisContext context) { + // writer.finish(); + // datas.clear();//解析结束销毁不用的资源 + } + + public List getDatas() { + return datas; + } + + public void setDatas(List datas) { + this.datas = datas; + } + + public Sheet getSheet() { + return sheet; + } + + public void setSheet(Sheet sheet) { + this.sheet = sheet; + } + + public ExcelWriter getWriter() { + return writer; + } + + public void setWriter(ExcelWriter writer) { + this.writer = writer; + } +} diff --git a/src/test/java/function/model/ExcelPropertyIndexModel.java b/src/test/java/function/model/ExcelPropertyIndexModel.java new file mode 100644 index 00000000..0009615f --- /dev/null +++ b/src/test/java/function/model/ExcelPropertyIndexModel.java @@ -0,0 +1,88 @@ +package function.model; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.metadata.BaseRowModel; + +/** + * @author jipengfei + * @date 2017/05/31 + */ +public class ExcelPropertyIndexModel extends BaseRowModel { + + @ExcelProperty(value = "姓名" ,index = 0) + private String name; + + @ExcelProperty(value = "年龄",index = 1) + private String age; + + @ExcelProperty(value = "邮箱",index = 2) + private String email; + + @ExcelProperty(value = "地址",index = 3) + private String address; + + @ExcelProperty(value = "性别",index = 4) + private String sax; + + @ExcelProperty(value = "高度",index = 5) + private String heigh; + + @ExcelProperty(value = "备注",index = 6) + private String last; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAge() { + return age; + } + + public void setAge(String age) { + this.age = age; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getSax() { + return sax; + } + + public void setSax(String sax) { + this.sax = sax; + } + + public String getHeigh() { + return heigh; + } + + public void setHeigh(String heigh) { + this.heigh = heigh; + } + + public String getLast() { + return last; + } + + public void setLast(String last) { + this.last = last; + } +} diff --git a/src/test/java/function/model/LoanInfo.java b/src/test/java/function/model/LoanInfo.java new file mode 100644 index 00000000..f0b7f055 --- /dev/null +++ b/src/test/java/function/model/LoanInfo.java @@ -0,0 +1,132 @@ +package function.model; + +import java.math.BigDecimal; +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.metadata.BaseRowModel; + +/** + * Created by jipengfei on 17/3/28. + * + * @author jipengfei + * @date 2017/03/28 + */ +public class LoanInfo extends BaseRowModel implements Comparable { + @ExcelProperty(index = 0) + private String bankLoanId; + + @ExcelProperty(index = 1) + private Long customerId; + + @ExcelProperty(index = 2,format = "yyyy/MM/dd") + private Date loanDate; + + @ExcelProperty(index = 3) + private BigDecimal quota; + + @ExcelProperty(index = 4) + private String bankInterestRate; + + @ExcelProperty(index = 5) + private Integer loanTerm; + + @ExcelProperty(index = 6,format = "yyyy/MM/dd") + private Date loanEndDate; + + @ExcelProperty(index = 7) + private Date interestPerMonth; + + + + // public String getLoanName() { + // return loanName; + // } + // + // public void setLoanName(String loanName) { + // this.loanName = loanName; + // } + + public Date getLoanDate() { + return loanDate; + } + + public void setLoanDate(Date loanDate) { + this.loanDate = loanDate; + } + + public BigDecimal getQuota() { + return quota; + } + + public void setQuota(BigDecimal quota) { + this.quota = quota; + } + + public String getBankInterestRate() { + return bankInterestRate; + } + + public void setBankInterestRate(String bankInterestRate) { + this.bankInterestRate = bankInterestRate; + } + + public Integer getLoanTerm() { + return loanTerm; + } + + public void setLoanTerm(Integer loanTerm) { + this.loanTerm = loanTerm; + } + + public Date getLoanEndDate() { + return loanEndDate; + } + + public void setLoanEndDate(Date loanEndDate) { + this.loanEndDate = loanEndDate; + } + + public Date getInterestPerMonth() { + return interestPerMonth; + } + + public void setInterestPerMonth(Date interestPerMonth) { + this.interestPerMonth = interestPerMonth; + } + + public String getBankLoanId() { + return bankLoanId; + } + + public void setBankLoanId(String bankLoanId) { + this.bankLoanId = bankLoanId; + } + + public Long getCustomerId() { + return customerId; + } + + public void setCustomerId(Long customerId) { + this.customerId = customerId; + } + + @Override + public String toString() { + return "ExcelLoanInfo{" + + "bankLoanId='" + bankLoanId + '\'' + + ", customerId='" + customerId + '\'' + + ", loanDate=" + loanDate + + ", quota=" + quota + + ", bankInterestRate=" + bankInterestRate + + ", loanTerm=" + loanTerm + + ", loanEndDate=" + loanEndDate + + ", interestPerMonth=" + interestPerMonth + + '}'; + } + + public int compareTo(LoanInfo info) { + boolean before = this.getLoanDate().before(info.getLoanDate()); + return before ? 1 : 0; + } +} \ No newline at end of file diff --git a/src/test/java/function/model/MultiLineHeadExcelModel.java b/src/test/java/function/model/MultiLineHeadExcelModel.java new file mode 100644 index 00000000..5f0317ab --- /dev/null +++ b/src/test/java/function/model/MultiLineHeadExcelModel.java @@ -0,0 +1,127 @@ +package function.model; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.metadata.BaseRowModel; + +/** + * Created by jipengfei on 17/2/19. + */ +public class MultiLineHeadExcelModel extends BaseRowModel { + + @ExcelProperty(value = {"表头1","表头1","表头31"},index = 0) + private String p1; + + @ExcelProperty(value = {"表头1","表头1","表头32"},index = 1) + private String p2; + + @ExcelProperty(value = {"表头3","表头3","表头3"},index = 2) + private int p3; + + @ExcelProperty(value = {"表头4","表头4","表头4"},index = 3) + private long p4; + + @ExcelProperty(value = {"表头5","表头51","表头52"},index = 4) + private String p5; + + @ExcelProperty(value = {"表头6","表头61","表头611"},index = 5) + private String p6; + + @ExcelProperty(value = {"表头6","表头61","表头612"},index = 6) + private String p7; + + @ExcelProperty(value = {"表头6","表头62","表头621"},index = 7) + private String p8; + + @ExcelProperty(value = {"表头6","表头62","表头622"},index = 8) + private String p9; + + public String getP1() { + return p1; + } + + public void setP1(String p1) { + this.p1 = p1; + } + + public String getP2() { + return p2; + } + + public void setP2(String p2) { + this.p2 = p2; + } + + public int getP3() { + return p3; + } + + public void setP3(int p3) { + this.p3 = p3; + } + + public long getP4() { + return p4; + } + + public void setP4(long p4) { + this.p4 = p4; + } + + public String getP5() { + return p5; + } + + public void setP5(String p5) { + this.p5 = p5; + } + + public String getP6() { + return p6; + } + + public void setP6(String p6) { + this.p6 = p6; + } + + public String getP7() { + return p7; + } + + public void setP7(String p7) { + this.p7 = p7; + } + + public String getP8() { + return p8; + } + + public void setP8(String p8) { + this.p8 = p8; + } + + public String getP9() { + return p9; + } + + public void setP9(String p9) { + this.p9 = p9; + } + + public static void main(String[] args) { + Class clazz = MultiLineHeadExcelModel.class; + Field[] fields = clazz.getDeclaredFields(); + List> head = new ArrayList>(); + for (int i = 0; i < fields.length ; i++) { + Field f = fields[i]; + ExcelProperty p = f.getAnnotation(ExcelProperty.class); + String[] value =p.value(); + head.add(Arrays.asList(value)); + } + System.out.println(head); + } +} diff --git a/src/test/java/function/model/NoAnnModel.java b/src/test/java/function/model/NoAnnModel.java new file mode 100644 index 00000000..0393eb11 --- /dev/null +++ b/src/test/java/function/model/NoAnnModel.java @@ -0,0 +1,44 @@ +package function.model; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.metadata.BaseRowModel; + +/** + * @author jipengfei + * @date 2017/05/16 + */ +public class NoAnnModel extends BaseRowModel { + + @ExcelProperty(index = 0) + private String p1; + + @ExcelProperty(index = 1) + private String p2; + + @ExcelProperty(index = 2) + private String p3; + + public String getP1() { + return p1; + } + + public void setP1(String p1) { + this.p1 = p1; + } + + public String getP2() { + return p2; + } + + public void setP2(String p2) { + this.p2 = p2; + } + + public String getP3() { + return p3; + } + + public void setP3(String p3) { + this.p3 = p3; + } +} diff --git a/src/test/java/function/model/OneRowHeadExcelModel.java b/src/test/java/function/model/OneRowHeadExcelModel.java new file mode 100644 index 00000000..9a879352 --- /dev/null +++ b/src/test/java/function/model/OneRowHeadExcelModel.java @@ -0,0 +1,270 @@ +package function.model; + +import com.alibaba.excel.annotation.ExcelColumnNum; +import com.alibaba.excel.metadata.BaseRowModel; + +/** + * Created by jipengfei on 17/2/18. + */ +public class OneRowHeadExcelModel extends BaseRowModel { + + @ExcelColumnNum(value = 0) + private String p1; + + @ExcelColumnNum(1) + private String p2; + + @ExcelColumnNum(2) + private int p3; + + @ExcelColumnNum(3) + private long p4; + + @ExcelColumnNum(4) + private String p5; + + @ExcelColumnNum(5) + private String p6; + + @ExcelColumnNum(6) + private String p7; + + @ExcelColumnNum(7) + private String p8; + + @ExcelColumnNum(8) + private String p9; + + @ExcelColumnNum(9) + private String p10; + + @ExcelColumnNum(10) + private String p11; + + @ExcelColumnNum(11) + private String p12; + + @ExcelColumnNum(12) + private String p13; + + @ExcelColumnNum(13) + private String p14; + + @ExcelColumnNum(14) + private String p15; + + @ExcelColumnNum(15) + private String p16; + + @ExcelColumnNum(16) + private String p17; + + @ExcelColumnNum(17) + private String p18; + + @ExcelColumnNum(18) + private String p19; + + @ExcelColumnNum(19) + private String p20; + + @ExcelColumnNum(20) + private String p21; + + + + public String getP2() { + return p2; + } + + public void setP2(String p2) { + this.p2 = p2; + } + + public int getP3() { + return p3; + } + + public void setP3(int p3) { + this.p3 = p3; + } + + public long getP4() { + return p4; + } + + public void setP4(long p4) { + this.p4 = p4; + } + + public String getP5() { + return p5; + } + + public void setP5(String p5) { + this.p5 = p5; + } + + public String getP6() { + return p6; + } + + public void setP6(String p6) { + this.p6 = p6; + } + + public String getP7() { + return p7; + } + + public void setP7(String p7) { + this.p7 = p7; + } + + public String getP8() { + return p8; + } + + public void setP8(String p8) { + this.p8 = p8; + } + + public String getP9() { + return p9; + } + + public void setP9(String p9) { + this.p9 = p9; + } + + public String getP10() { + return p10; + } + + public void setP10(String p10) { + this.p10 = p10; + } + + public String getP11() { + return p11; + } + + public void setP11(String p11) { + this.p11 = p11; + } + + public String getP12() { + return p12; + } + + public void setP12(String p12) { + this.p12 = p12; + } + + public String getP13() { + return p13; + } + + public void setP13(String p13) { + this.p13 = p13; + } + + public String getP14() { + return p14; + } + + public void setP14(String p14) { + this.p14 = p14; + } + + public String getP15() { + return p15; + } + + public void setP15(String p15) { + this.p15 = p15; + } + + public String getP16() { + return p16; + } + + public void setP16(String p16) { + this.p16 = p16; + } + + public String getP17() { + return p17; + } + + public void setP17(String p17) { + this.p17 = p17; + } + + public String getP18() { + return p18; + } + + public void setP18(String p18) { + this.p18 = p18; + } + + public String getP19() { + return p19; + } + + public void setP19(String p19) { + this.p19 = p19; + } + + public String getP20() { + return p20; + } + + public void setP20(String p20) { + this.p20 = p20; + } + + public String getP21() { + return p21; + } + + public void setP21(String p21) { + this.p21 = p21; + } + + public String getP1() { + return p1; + } + + public void setP1(String p1) { + this.p1 = p1; + } + + @Override + public String toString() { + return "OneRowHeadExcelModel{" + + "p1='" + p1 + '\'' + + ", p2='" + p2 + '\'' + + ", p3=" + p3 + + ", p4=" + p4 + + ", p5='" + p5 + '\'' + + ", p6='" + p6 + '\'' + + ", p7='" + p7 + '\'' + + ", p8='" + p8 + '\'' + + ", p9='" + p9 + '\'' + + ", p10='" + p10 + '\'' + + ", p11='" + p11 + '\'' + + ", p12='" + p12 + '\'' + + ", p13='" + p13 + '\'' + + ", p14='" + p14 + '\'' + + ", p15='" + p15 + '\'' + + ", p16='" + p16 + '\'' + + ", p17='" + p17 + '\'' + + ", p18='" + p18 + '\'' + + ", p19='" + p19 + '\'' + + ", p20='" + p20 + '\'' + + ", p21='" + p21 + '\'' + + '}'; + } +} diff --git a/src/test/java/function/model/TestModel3.java b/src/test/java/function/model/TestModel3.java new file mode 100644 index 00000000..e87a4ffb --- /dev/null +++ b/src/test/java/function/model/TestModel3.java @@ -0,0 +1,354 @@ +package function.model; + +import com.alibaba.excel.annotation.ExcelColumnNum; +import com.alibaba.excel.metadata.BaseRowModel; + +/** + * Created by jipengfei on 17/3/19. + * + * @author jipengfei + * @date 2017/03/19 + */ +public class TestModel3 extends BaseRowModel { + + @ExcelColumnNum(0) + private String p1; + + @ExcelColumnNum(1) + private String p2; + + @ExcelColumnNum(2) + private String p3; + + @ExcelColumnNum(3) + private String p4; + + @ExcelColumnNum(4) + private String p5; + + @ExcelColumnNum(5) + private String p6; + + @ExcelColumnNum(6) + private String p7; + + @ExcelColumnNum(7) + private String p8; + + @ExcelColumnNum(8) + private String p9; + + @ExcelColumnNum(9) + private String p10; + + @ExcelColumnNum(10) + private String p11; + + @ExcelColumnNum(11) + private String p12; + + @ExcelColumnNum(12) + private String p13; + + @ExcelColumnNum(13) + private String p14; + + @ExcelColumnNum(14) + private String p15; + + @ExcelColumnNum(15) + private String p16; + + @ExcelColumnNum(16) + private String p17; + + @ExcelColumnNum(17) + private String p18; + + @ExcelColumnNum(18) + private String p19; + + @ExcelColumnNum(19) + private String p20; + + @ExcelColumnNum(20) + private String p21; + + @ExcelColumnNum(21) + private String p22; + + @ExcelColumnNum(22) + private String p23; + + @ExcelColumnNum(23) + private String p24; + + @ExcelColumnNum(24) + private String p25; + + @ExcelColumnNum(25) + private String p26; + + @ExcelColumnNum(26) + private String p27; + + @ExcelColumnNum(27) + private String p28; + + @ExcelColumnNum(28) + private String p29; + + @ExcelColumnNum(29) + private String p30; + + @ExcelColumnNum(30) + private String p31; + + public String getP28() { + return p28; + } + + public String getP30() { + return p30; + } + + public void setP30(String p30) { + this.p30 = p30; + } + + public String getP31() { + return p31; + } + + public void setP31(String p31) { + this.p31 = p31; + } + + public void setP28(String p28) { + this.p28 = p28; + } + + public String getP29() { + return p29; + } + + public void setP29(String p29) { + this.p29 = p29; + } + + public String getP1() { + return p1; + } + + public void setP1(String p1) { + this.p1 = p1; + } + + public String getP2() { + return p2; + } + + public void setP2(String p2) { + this.p2 = p2; + } + + public String getP3() { + return p3; + } + + public void setP3(String p3) { + this.p3 = p3; + } + + public String getP4() { + return p4; + } + + public void setP4(String p4) { + this.p4 = p4; + } + + public String getP5() { + return p5; + } + + public void setP5(String p5) { + this.p5 = p5; + } + + public String getP6() { + return p6; + } + + public void setP6(String p6) { + this.p6 = p6; + } + + public String getP7() { + return p7; + } + + public void setP7(String p7) { + this.p7 = p7; + } + + public String getP8() { + return p8; + } + + public void setP8(String p8) { + this.p8 = p8; + } + + public String getP9() { + return p9; + } + + public void setP9(String p9) { + this.p9 = p9; + } + + public String getP10() { + return p10; + } + + public void setP10(String p10) { + this.p10 = p10; + } + + public String getP11() { + return p11; + } + + public void setP11(String p11) { + this.p11 = p11; + } + + public String getP12() { + return p12; + } + + public void setP12(String p12) { + this.p12 = p12; + } + + public String getP13() { + return p13; + } + + public void setP13(String p13) { + this.p13 = p13; + } + + public String getP14() { + return p14; + } + + public void setP14(String p14) { + this.p14 = p14; + } + + public String getP15() { + return p15; + } + + public void setP15(String p15) { + this.p15 = p15; + } + + public String getP16() { + return p16; + } + + public void setP16(String p16) { + this.p16 = p16; + } + + public String getP17() { + return p17; + } + + public void setP17(String p17) { + this.p17 = p17; + } + + public String getP18() { + return p18; + } + + public void setP18(String p18) { + this.p18 = p18; + } + + public String getP19() { + return p19; + } + + public void setP19(String p19) { + this.p19 = p19; + } + + public String getP20() { + return p20; + } + + public void setP20(String p20) { + this.p20 = p20; + } + + public String getP21() { + return p21; + } + + public void setP21(String p21) { + this.p21 = p21; + } + + public String getP22() { + return p22; + } + + public void setP22(String p22) { + this.p22 = p22; + } + + public String getP23() { + return p23; + } + + public void setP23(String p23) { + this.p23 = p23; + } + + public String getP24() { + return p24; + } + + public void setP24(String p24) { + this.p24 = p24; + } + + public String getP25() { + return p25; + } + + public void setP25(String p25) { + this.p25 = p25; + } + + public String getP26() { + return p26; + } + + public void setP26(String p26) { + this.p26 = p26; + } + + public String getP27() { + return p27; + } + + public void setP27(String p27) { + this.p27 = p27; + } +} diff --git a/src/test/java/function/read/ExelAllDataTypeTest.java b/src/test/java/function/read/ExelAllDataTypeTest.java new file mode 100644 index 00000000..64d2089b --- /dev/null +++ b/src/test/java/function/read/ExelAllDataTypeTest.java @@ -0,0 +1,47 @@ +package function.read; + +import java.io.IOException; +import java.io.InputStream; + +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +import function.listener.ExcelListener; +import junit.framework.TestCase; +import org.junit.Test; + +/** + * Created by jipengfei on 17/3/15. + * + * @author jipengfei + * @date 2017/03/15 + */ +public class ExelAllDataTypeTest extends TestCase { + // 创建没有自定义模型,没有sheet的解析器,默认解析所有sheet解析结果以List的方式通知监听者 + @Test + public void testExcel2007WithReflectModel() { + InputStream inputStream = getInputStream("test2.xlsx"); + + try { + // 解析每行结果在listener中处理 + AnalysisEventListener listener = new ExcelListener(); + + new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, listener).read(new Sheet(1, 1,null)); + }catch (Exception e){ + }finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + + private InputStream getInputStream(String fileName) { + return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); + + } +} diff --git a/src/test/java/function/read/NumTest3.java b/src/test/java/function/read/NumTest3.java new file mode 100644 index 00000000..38710027 --- /dev/null +++ b/src/test/java/function/read/NumTest3.java @@ -0,0 +1,46 @@ +package function.read; + +import java.io.IOException; +import java.io.InputStream; + +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +import function.listener.ExcelListener; +import function.model.TestModel3; +import org.junit.Test; + +/** + * Created by jipengfei on 17/3/19. + * + * @author jipengfei + * @date 2017/03/19 + */ +public class NumTest3 { + + @Test + public void testExcel2007WithReflectModel() { + InputStream inputStream = getInputStream("test3.xlsx"); + try { + AnalysisEventListener listener = new ExcelListener(); + + new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, listener).read(new Sheet(1, 1, TestModel3.class)); + } catch (Exception e) { + + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + + private InputStream getInputStream(String fileName) { + return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); + + } +} diff --git a/src/test/java/function/read/ReadSheets.java b/src/test/java/function/read/ReadSheets.java new file mode 100644 index 00000000..2b2dd13e --- /dev/null +++ b/src/test/java/function/read/ReadSheets.java @@ -0,0 +1,83 @@ +package function.read; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +import function.listener.ExcelListener; +import org.junit.Test; + +/** + * Created by jipengfei on 17/3/22. + * + * @author jipengfei + * @date 2017/03/22 + */ +public class ReadSheets { + @Test + public void ReadSheets2007() { + InputStream inputStream = getInputStream("2007NoModelMultipleSheet.xlsx"); + try { + ExcelListener listener = new ExcelListener(); + listener.setSheet(new Sheet(1)); + ExcelWriter excelWriter = new ExcelWriter(new FileOutputStream("/Users/jipengfei/77.xlsx"), ExcelTypeEnum.XLSX,false); + listener.setWriter(excelWriter); + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, listener); + List sheets = reader.getSheets(); + System.out.println(sheets); + for (Sheet sheet:sheets) { + sheet.setHeadLineMun(1); + reader.read(sheet); + } + // reader.read(new Sheet(1)); + excelWriter.finish(); + + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Test + public void ReadSheets2003() { + InputStream inputStream = getInputStream("2003.xls"); + try { + AnalysisEventListener listener = new ExcelListener(); + + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLS, null, listener); + reader.read(); + List sheets = reader.getSheets(); + System.out.println(sheets); + for (Sheet sheet:sheets) { + sheet.setHeadLineMun(1); + reader.read(sheet); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + + private InputStream getInputStream(String fileName) { + return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); + + } +} diff --git a/src/test/java/function/read/XLSX2007FunctionTest.java b/src/test/java/function/read/XLSX2007FunctionTest.java new file mode 100644 index 00000000..bf75a398 --- /dev/null +++ b/src/test/java/function/read/XLSX2007FunctionTest.java @@ -0,0 +1,140 @@ +package function.read; + +import java.io.IOException; +import java.io.InputStream; + +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +import function.listener.ExcelListener; +import function.model.OneRowHeadExcelModel; +import junit.framework.TestCase; +import org.junit.Test; + +/** + * Created by jipengfei on 17/2/18. + */ +public class XLSX2007FunctionTest extends TestCase { + + //创建没有自定义模型,没有sheet的解析器,默认解析所有sheet解析结果以List的方式通知监听者 + @Test + public void testExcel2007NoModel() { + InputStream inputStream = getInputStream("2007NoModelBigFile.xlsx"); + try { + // 解析每行结果在listener中处理 + AnalysisEventListener listener = new ExcelListener(); + + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, listener); + + reader.read(); + } catch (Exception e) { + e.printStackTrace(); + + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + @Test + public void testExcel2007NoModel2() { + InputStream inputStream = getInputStream("test4.xlsx"); + try { + // 解析每行结果在listener中处理 + AnalysisEventListener listener = new ExcelListener(); + + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, listener); + + reader.read(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + //创建没有自定义模型,但有规定sheet解析器,解析结果以List的方式通知监听者 + @Test + public void testExcel2007WithSheet() { + InputStream inputStream = getInputStream("111.xlsx"); + + try { + // 解析每行结果在listener中处理 + AnalysisEventListener listener = new ExcelListener(); + + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, listener); + reader.read(new Sheet(1, 0)); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + + //创建需要反射映射模型的解析器,解析结果List Object为自定义的模型 + @Test + public void testExcel2007WithReflectModel() { + InputStream inputStream = getInputStream("2007.xlsx"); + try { + + // 解析每行结果在listener中处理 + AnalysisEventListener listener = new ExcelListener(); + + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, listener); + + reader.read(new Sheet(1, 1, OneRowHeadExcelModel.class)); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + + @Test + public void testExcel2007MultHeadWithReflectModel() { + InputStream inputStream = getInputStream("2007_1.xlsx"); + + try { + + // 解析每行结果在listener中处理 + AnalysisEventListener listener = new ExcelListener(); + + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, listener); + + reader.read(new Sheet(1, 4, OneRowHeadExcelModel.class)); + + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + + private InputStream getInputStream(String fileName) { + return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); + + } +} diff --git a/src/test/java/function/write/ExcelWriteIndexTest.java b/src/test/java/function/write/ExcelWriteIndexTest.java new file mode 100644 index 00000000..88c88b67 --- /dev/null +++ b/src/test/java/function/write/ExcelWriteIndexTest.java @@ -0,0 +1,117 @@ +package function.write; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +import function.model.ExcelPropertyIndexModel; +import function.model.MultiLineHeadExcelModel; +import org.junit.Test; + +/** + * 测试{@link ExcelProperty#index()} + * + * @author jipengfei + * @date 2017/05/31 + */ +public class ExcelWriteIndexTest { + + @Test + public void test1() throws FileNotFoundException { + OutputStream out = new FileOutputStream("/Users/jipengfei/78.xlsx"); + try { + ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX); + //写第一个sheet, sheet1 数据全是List 无模型映射关系 + Sheet sheet1 = new Sheet(1, 0,ExcelPropertyIndexModel.class); + writer.write(getData(), sheet1); + writer.finish(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + @Test + public void test2() throws FileNotFoundException { + OutputStream out = new FileOutputStream("/Users/jipengfei/79.xlsx"); + try { + ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX); + //写第一个sheet, sheet1 数据全是List 无模型映射关系 + Sheet sheet1 = new Sheet(1, 3,MultiLineHeadExcelModel.class); + writer.write(getModeldatas(), sheet1); + writer.finish(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public List getData() { + List datas = new ArrayList(); + ExcelPropertyIndexModel model = new ExcelPropertyIndexModel(); + model.setAddress("杭州"); + model.setAge("11"); + model.setEmail("7827323@qq.com"); + model.setSax("男"); + model.setHeigh("1123"); + datas.add(model); + return datas; + } + private List getModeldatas() { + List MODELS = new ArrayList(); + MultiLineHeadExcelModel model1 = new MultiLineHeadExcelModel(); + model1.setP1("111"); + model1.setP2("222"); + model1.setP3(33); + model1.setP4(44); + model1.setP5("555"); + model1.setP6("666"); + model1.setP7("777"); + model1.setP8("888"); + + MultiLineHeadExcelModel model2 = new MultiLineHeadExcelModel(); + model2.setP1("111"); + model2.setP2("111"); + model2.setP3(11); + model2.setP4(9); + model2.setP5("111"); + model2.setP6("111"); + model2.setP7("111"); + model2.setP8("111"); + + MultiLineHeadExcelModel model3 = new MultiLineHeadExcelModel(); + model3.setP1("111"); + model3.setP2("111"); + model3.setP3(11); + model3.setP4(9); + model3.setP5("111"); + model3.setP6("111"); + model3.setP7("111"); + model3.setP8("111"); + + MODELS.add(model1); + MODELS.add(model2); + MODELS.add(model3); + + return MODELS; + + } + +} diff --git a/src/test/java/function/write/ExcelWriteTest.java b/src/test/java/function/write/ExcelWriteTest.java new file mode 100644 index 00000000..b50f3737 --- /dev/null +++ b/src/test/java/function/write/ExcelWriteTest.java @@ -0,0 +1,246 @@ +package function.write; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.metadata.Font; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.metadata.Table; +import com.alibaba.excel.metadata.TableStyle; +import com.alibaba.excel.support.ExcelTypeEnum; + +import function.model.MultiLineHeadExcelModel; +import function.model.NoAnnModel; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.junit.Test; + +/** + * + * 测试Excel写多个表格 + * @author jipengfei + * @date 2017/05/16 + */ +public class ExcelWriteTest { + + /** + * 一个sheet一张表 + * + * @throws FileNotFoundException + */ + @Test + public void test1() throws FileNotFoundException { + + OutputStream out = new FileOutputStream("/Users/jipengfei/77.xlsx"); + try { + ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX,true); + //写第一个sheet, sheet1 数据全是List 无模型映射关系 + Sheet sheet1 = new Sheet(1, 0); + sheet1.setSheetName("第一个sheet"); + writer.write0(getListString(), sheet1); + + //写第二个sheet sheet2 模型上打有表头的注解,合并单元格 + Sheet sheet2 = new Sheet(2, 3, MultiLineHeadExcelModel.class, "第二个sheet", null); + sheet2.setTableStyle(getTableStyle1()); + writer.write(getModeldatas(), sheet2); + + //写sheet3 模型上没有注解,表头数据动态传入 + List> head = new ArrayList>(); + List headCoulumn1 = new ArrayList(); + List headCoulumn2 = new ArrayList(); + List headCoulumn3 = new ArrayList(); + headCoulumn1.add("第一列"); + headCoulumn2.add("第二列"); + headCoulumn3.add("第三列"); + head.add(headCoulumn1); + head.add(headCoulumn2); + head.add(headCoulumn3); + Sheet sheet3 = new Sheet(3, 1, NoAnnModel.class, "第三个sheet", head); + writer.write(getNoAnnModels(), sheet3); + writer.finish(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 一个sheet多张表 + * + * @throws FileNotFoundException + */ + @Test + public void test2() throws FileNotFoundException { + OutputStream out = new FileOutputStream("/Users/jipengfei/77.xlsx"); + try { + ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX,false); + + //写sheet1 数据全是List 无模型映射关系 + Sheet sheet1 = new Sheet(1, 0); + sheet1.setSheetName("第一个sheet"); + Table table1 = new Table(1); + writer.write0(getListString(), sheet1, table1); + writer.write0(getListString(), sheet1, table1); + + //写sheet2 模型上打有表头的注解 + Table table2 = new Table(2); + table2.setTableStyle(getTableStyle1()); + table2.setClazz(MultiLineHeadExcelModel.class); + writer.write(getModeldatas(), sheet1, table2); + + //写sheet3 模型上没有注解,表头数据动态传入,此情况下模型field顺序与excel现实顺序一致 + List> head = new ArrayList>(); + List headCoulumn1 = new ArrayList(); + List headCoulumn2 = new ArrayList(); + List headCoulumn3 = new ArrayList(); + headCoulumn1.add("第一列"); + headCoulumn2.add("第二列"); + headCoulumn3.add("第三列"); + head.add(headCoulumn1); + head.add(headCoulumn2); + head.add(headCoulumn3); + Table table3 = new Table(3); + table3.setHead(head); + table3.setClazz(NoAnnModel.class); + table3.setTableStyle(getTableStyle2()); + writer.write(getNoAnnModels(), sheet1, table3); + writer.write(getNoAnnModels(), sheet1, table3); + + writer.finish(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private List> getListString() { + List list = new ArrayList(); + list.add("ooo1"); + list.add("ooo2"); + list.add("ooo3"); + list.add("ooo4"); + List list1 = new ArrayList(); + list1.add("ooo1"); + list1.add("ooo2"); + list1.add("ooo3"); + list1.add("ooo4"); + List> ll = new ArrayList>(); + ll.add(list); + ll.add(list1); + return ll; + } + + private List getModeldatas() { + List MODELS = new ArrayList(); + MultiLineHeadExcelModel model1 = new MultiLineHeadExcelModel(); + model1.setP1("111"); + model1.setP2("222"); + model1.setP3(33); + model1.setP4(44); + model1.setP5("555"); + model1.setP6("666"); + model1.setP7("777"); + model1.setP8("888"); + + MultiLineHeadExcelModel model2 = new MultiLineHeadExcelModel(); + model2.setP1("111"); + model2.setP2("111"); + model2.setP3(11); + model2.setP4(9); + model2.setP5("111"); + model2.setP6("111"); + model2.setP7("111"); + model2.setP8("111"); + + MultiLineHeadExcelModel model3 = new MultiLineHeadExcelModel(); + model3.setP1("111"); + model3.setP2("111"); + model3.setP3(11); + model3.setP4(9); + model3.setP5("111"); + model3.setP6("111"); + model3.setP7("111"); + model3.setP8("111"); + + MODELS.add(model1); + MODELS.add(model2); + MODELS.add(model3); + + return MODELS; + + } + + private List getNoAnnModels() { + List MODELS = new ArrayList(); + NoAnnModel model1 = new NoAnnModel(); + model1.setP1("111"); + model1.setP2("111"); + + NoAnnModel model2 = new NoAnnModel(); + model2.setP1("111"); + model2.setP2("111"); + model2.setP3("22"); + + NoAnnModel model3 = new NoAnnModel(); + model3.setP1("111"); + model3.setP2("111"); + model3.setP3("111"); + + MODELS.add(model1); + MODELS.add(model2); + MODELS.add(model3); + + return MODELS; + + } + + private TableStyle getTableStyle1() { + TableStyle tableStyle = new TableStyle(); + Font headFont = new Font(); + headFont.setBold(true); + headFont.setFontHeightInPoints((short)22); + headFont.setFontName("楷体"); + tableStyle.setTableHeadFont(headFont); + tableStyle.setTableHeadBackGroundColor(IndexedColors.BLUE); + + Font contentFont = new Font(); + contentFont.setBold(true); + contentFont.setFontHeightInPoints((short)22); + contentFont.setFontName("黑体"); + tableStyle.setTableContentFont(contentFont); + tableStyle.setTableContentBackGroundColor(IndexedColors.GREEN); + return tableStyle; + } + + private TableStyle getTableStyle2() { + TableStyle tableStyle = new TableStyle(); + Font headFont = new Font(); + headFont.setBold(true); + headFont.setFontHeightInPoints((short)22); + headFont.setFontName("宋体"); + tableStyle.setTableHeadFont(headFont); + tableStyle.setTableHeadBackGroundColor(IndexedColors.BLUE); + + Font contentFont = new Font(); + contentFont.setBold(true); + contentFont.setFontHeightInPoints((short)10); + contentFont.setFontName("黑体"); + tableStyle.setTableContentFont(contentFont); + tableStyle.setTableContentBackGroundColor(IndexedColors.RED); + return tableStyle; + } +} diff --git a/src/test/java/function/write/ExcelWriteTest1.java b/src/test/java/function/write/ExcelWriteTest1.java new file mode 100644 index 00000000..3bc5d658 --- /dev/null +++ b/src/test/java/function/write/ExcelWriteTest1.java @@ -0,0 +1,108 @@ +package function.write; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +import function.listener.ExcelListener; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.xssf.streaming.SXSSFSheet; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.junit.Test; + +/** + * @author jipengfei + * @date 2017/08/15 + */ +public class ExcelWriteTest1 { + + @Test + public void test(){ + OutputStream out = null; + try { + out = new FileOutputStream("/Users/jipengfei/79.xlsx"); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + try { + ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX, false); + + //写sheet1 数据全是List 无模型映射关系 + Sheet sheet1 = new Sheet(1, 0); + sheet1.setSheetName("第一个sheet"); + List list = new ArrayList(); + list.add("1");list.add("2");list.add("3"); + List list1 = new ArrayList(); + list1.add("1");list1.add("2");list1.add("3"); + List> lll = new ArrayList>(); + lll.add(list); + writer.write0(lll,sheet1); + writer.write0(lll,sheet1); + writer.finish(); + }catch (Exception e){ + e.printStackTrace(); + } + } + + @Test + public void testWriteAndRead(){ + OutputStream out = null; + try { + out = new FileOutputStream("/Users/jipengfei/79.xlsx"); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + try { + SXSSFWorkbook wb = new SXSSFWorkbook(10000); + SXSSFSheet sheet = wb.createSheet("11111"); + Row row = sheet.createRow(0); + Cell cell1 = row.createCell(0); + cell1.setCellValue("1111"); + Cell cell2 = row.createCell(1); + cell2.setCellValue("22222"); + Cell cell3 = row.createCell(2); + cell3.setCellValue("33333"); + + + + Row row1 = sheet.createRow(1); + Cell cell21 = row1.createCell(0); + cell21.setCellValue("444"); + Cell cell22 = row1.createCell(1); + cell22.setCellValue("555"); + Cell cell23 = row1.createCell(2); + cell23.setCellValue("666"); + wb.write(out); + out.close(); + + + + + InputStream inputStream = new FileInputStream("/Users/jipengfei/79.xlsx"); + + AnalysisEventListener listener = new ExcelListener(); + + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, listener); + reader.read(new Sheet(1)); + + }catch (Exception e){ + e.printStackTrace(); + } + } + + private InputStream getInputStream(String fileName) { + return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); + + } +} diff --git a/src/test/java/javamodel/ExcelRowJavaModel.java b/src/test/java/javamodel/ExcelRowJavaModel.java new file mode 100644 index 00000000..e3b778cf --- /dev/null +++ b/src/test/java/javamodel/ExcelRowJavaModel.java @@ -0,0 +1,128 @@ +package javamodel; + +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.metadata.BaseRowModel; + +/** + * Created by jipengfei on 17/3/15. + * + * @author jipengfei + * @date 2017/03/15 + */ +public class ExcelRowJavaModel extends BaseRowModel { + @ExcelProperty(index = 0,value = "银行放款编号") + private int num; + + @ExcelProperty(index = 1,value = "code") + private Long code; + + @ExcelProperty(index = 2,value = "银行存放期期") + private Date endTime; + + @ExcelProperty(index = 3,value = "测试1") + private Double money; + + @ExcelProperty(index = 4,value = "测试2") + private String times; + + @ExcelProperty(index = 5,value = "测试3") + private int activityCode; + + @ExcelProperty(index = 6,value = "测试4") + private Date date; + + @ExcelProperty(index = 7,value = "测试5") + private Double lx; + + @ExcelProperty(index = 8,value = "测试6") + private String name; + + public int getNum() { + return num; + } + + public void setNum(int num) { + this.num = num; + } + + public Long getCode() { + return code; + } + + public void setCode(Long code) { + this.code = code; + } + + public Date getEndTime() { + return endTime; + } + + public void setEndTime(Date endTime) { + this.endTime = endTime; + } + + public Double getMoney() { + return money; + } + + public void setMoney(Double money) { + this.money = money; + } + + public String getTimes() { + return times; + } + + public void setTimes(String times) { + this.times = times; + } + + public int getActivityCode() { + return activityCode; + } + + public void setActivityCode(int activityCode) { + this.activityCode = activityCode; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public Double getLx() { + return lx; + } + + public void setLx(Double lx) { + this.lx = lx; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return "ExcelRowJavaModel{" + + "num=" + num + + ", code=" + code + + ", endTime=" + endTime + + ", money=" + money + + ", times='" + times + '\'' + + ", activityCode=" + activityCode + + ", date=" + date + + ", lx=" + lx + + ", name='" + name + '\'' + + '}'; + } +} diff --git a/src/test/java/javamodel/ExcelRowJavaModel1.java b/src/test/java/javamodel/ExcelRowJavaModel1.java new file mode 100644 index 00000000..764270ec --- /dev/null +++ b/src/test/java/javamodel/ExcelRowJavaModel1.java @@ -0,0 +1,130 @@ +package javamodel; + +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.metadata.BaseRowModel; + +/** + * Created by jipengfei on 17/3/15. + * + * @author jipengfei + * @date 2017/03/15 + */ +public class ExcelRowJavaModel1 extends BaseRowModel { + + @ExcelProperty(index = 0,value = "银行放款编号") + private int num; + + @ExcelProperty(index = 1,value = "code") + private Long code; + + @ExcelProperty(index = 2,value = "银行存放期期") + private Date endTime; + + @ExcelProperty(index = 3,value = "测试1") + private Double money; + + @ExcelProperty(index = 4,value = "测试2") + private String times; + + @ExcelProperty(index = 5,value = "测试3") + private int activityCode; + + @ExcelProperty(index = 6,value = "测试4") + private Date date; + + @ExcelProperty(index = 7,value = "测试5") + private Double lx; + + @ExcelProperty(index = 8,value = "测试6") + private String name; + + + public int getNum() { + return num; + } + + public void setNum(int num) { + this.num = num; + } + + public Long getCode() { + return code; + } + + public void setCode(Long code) { + this.code = code; + } + + public Date getEndTime() { + return endTime; + } + + public void setEndTime(Date endTime) { + this.endTime = endTime; + } + + public Double getMoney() { + return money; + } + + public void setMoney(Double money) { + this.money = money; + } + + public String getTimes() { + return times; + } + + public void setTimes(String times) { + this.times = times; + } + + public int getActivityCode() { + return activityCode; + } + + public void setActivityCode(int activityCode) { + this.activityCode = activityCode; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public Double getLx() { + return lx; + } + + public void setLx(Double lx) { + this.lx = lx; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return "ExcelRowJavaModel{" + + "num=" + num + + ", code=" + code + + ", endTime=" + endTime + + ", money=" + money + + ", times='" + times + '\'' + + ", activityCode=" + activityCode + + ", date=" + date + + ", lx=" + lx + + ", name='" + name + '\'' + + '}'; + } +} diff --git a/src/test/java/read/v03/XLS2003FunctionTest.java b/src/test/java/read/v03/XLS2003FunctionTest.java new file mode 100644 index 00000000..ab10f7da --- /dev/null +++ b/src/test/java/read/v03/XLS2003FunctionTest.java @@ -0,0 +1,88 @@ +package read.v03; + +import java.io.IOException; +import java.io.InputStream; + +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +import function.listener.ExcelListener; +import function.model.LoanInfo; +import junit.framework.TestCase; +import org.junit.Test; + +/** + * Created by jipengfei on 17/2/19. + */ +public class XLS2003FunctionTest extends TestCase { + + @Test + public void testExcel2003NoModel() { + InputStream inputStream = getInputStream("loan1.xls"); + try { + // 解析每行结果在listener中处理 + ExcelListener listener = new ExcelListener(); + + ExcelReader excelReader = new ExcelReader(inputStream, ExcelTypeEnum.XLS, null, listener); + excelReader.read(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Test + public void testExcel2003WithSheet() { + InputStream inputStream = getInputStream("loan1.xls"); + try { + // 解析每行结果在listener中处理 + ExcelListener listener = new ExcelListener(); + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLS, null, listener); + reader.read(new Sheet(1, 1)); + + System.out.println(listener.getDatas()); + } catch (Exception e) { +e.printStackTrace(); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Test + public void testExcel2003WithReflectModel() { + InputStream inputStream = getInputStream("loan1.xls"); + try { + // 解析每行结果在listener中处理 + AnalysisEventListener listener = new ExcelListener(); + + ExcelReader excelReader = new ExcelReader(inputStream, ExcelTypeEnum.XLS, null, listener); + + excelReader.read(new Sheet(1, 2, LoanInfo.class)); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + + private InputStream getInputStream(String fileName) { + return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); + + } +} diff --git a/src/test/java/read/v07/Read2007MeanWhileWrite.java b/src/test/java/read/v07/Read2007MeanWhileWrite.java new file mode 100644 index 00000000..10ecc615 --- /dev/null +++ b/src/test/java/read/v07/Read2007MeanWhileWrite.java @@ -0,0 +1,92 @@ +package read.v07; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +import javamodel.ExcelRowJavaModel; +import javamodel.ExcelRowJavaModel1; +import org.junit.Test; +import read.v07.listener.Excel2007NoJavaModelAnalysisListener; +import read.v07.listener.Excel2007WithJavaModelAnalysisListener; + +/** + * @author jipengfei + * @date 2017/08/27 + */ +public class Read2007MeanWhileWrite { + + @Test + public void noModel() { + + InputStream inputStream = getInputStream("2007NoModelMultipleSheet.xlsx"); + try { + Excel2007NoJavaModelAnalysisListener listener = new Excel2007NoJavaModelAnalysisListener(); + ExcelWriter excelWriter = new ExcelWriter(new FileOutputStream("/Users/jipengfei/77.xlsx"), + ExcelTypeEnum.XLSX, false); + listener.setExcelWriter(excelWriter); + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, listener); + List sheets = reader.getSheets(); + System.out.println(sheets); + for (Sheet sheet : sheets) { + sheet.setHeadLineMun(1); + reader.read(sheet); + } + excelWriter.finish(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Test + public void withModel() { + + InputStream inputStream = getInputStream("2007WithModelMultipleSheet.xlsx"); + try { + Excel2007WithJavaModelAnalysisListener listener = new Excel2007WithJavaModelAnalysisListener(); + ExcelWriter excelWriter = new ExcelWriter(new FileOutputStream("/Users/jipengfei/78.xlsx"), + ExcelTypeEnum.XLSX, true); + listener.setExcelWriter(excelWriter); + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, listener); + List sheets = reader.getSheets(); + for (Sheet sheet : sheets) { + sheet.setHeadLineMun(1); + if (sheet.getSheetNo() == 1) { + sheet.setHeadLineMun(2); + sheet.setClazz(ExcelRowJavaModel.class); + } + if (sheet.getSheetNo() == 2) { + sheet.setHeadLineMun(1); + sheet.setClazz(ExcelRowJavaModel1.class); + } + reader.read(sheet); + } + excelWriter.finish(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private InputStream getInputStream(String fileName) { + return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); + + } +} diff --git a/src/test/java/read/v07/Read2007Xlsx.java b/src/test/java/read/v07/Read2007Xlsx.java new file mode 100644 index 00000000..b30baeec --- /dev/null +++ b/src/test/java/read/v07/Read2007Xlsx.java @@ -0,0 +1,344 @@ +package read.v07; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.support.ExcelTypeEnum; + +import javamodel.ExcelRowJavaModel; +import javamodel.ExcelRowJavaModel1; +import org.junit.Test; + +/** + * @author jipengfei + * @date 2017/08/27 + */ +public class Read2007Xlsx { + //创建没有自定义模型,没有sheet的解析器,默认解析所有sheet解析结果以List的方式通知监听者 + @Test + public void noModel() { + InputStream inputStream = getInputStream("2007NoModelBigFile.xlsx"); + try { + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, + new AnalysisEventListener>() { + @Override + public void invoke(List object, AnalysisContext context) { + System.out.println( + "当前sheet:" + context.getCurrentSheet().getSheetNo() + " 当前行:" + context.getCurrentRowNum() + + " data:" + object); + + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + } + }); + + reader.read(); + } catch (Exception e) { + e.printStackTrace(); + + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Test + public void withJavaModel() { + InputStream inputStream = getInputStream("2007WithModel.xlsx"); + try { + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, + new AnalysisEventListener() { + @Override + public void invoke(ExcelRowJavaModel object, AnalysisContext context) { + System.out.println( + "当前sheet:" + context.getCurrentSheet().getSheetNo() + " 当前行:" + context.getCurrentRowNum() + + " data:" + object); + + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + } + }); + + reader.read(new Sheet(1, 2, ExcelRowJavaModel.class)); + } catch (Exception e) { + e.printStackTrace(); + + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + //创建没有自定义模型,没有sheet的解析器,默认解析所有sheet解析结果以List的方式通知监听者 + @Test + public void noModelMultipleSheet() { + InputStream inputStream = getInputStream("2007NoModelMultipleSheet.xlsx"); + try { + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, + new AnalysisEventListener>() { + @Override + public void invoke(List object, AnalysisContext context) { + System.out.println( + "当前sheet:" + context.getCurrentSheet().getSheetNo() + " 当前行:" + context.getCurrentRowNum() + + " data:" + object); + + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + } + }); + + reader.read(); + } catch (Exception e) { + e.printStackTrace(); + + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Test + public void withModelMultipleSheet() { + InputStream inputStream = getInputStream("2007WithModelMultipleSheet.xlsx"); + try { + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, + new AnalysisEventListener() { + @Override + public void invoke(Object object, AnalysisContext context) { + ExcelRowJavaModel obj = null; + if (context.getCurrentSheet().getSheetNo() == 1) { + obj = (ExcelRowJavaModel)object; + } + if (context.getCurrentSheet().getSheetNo() == 2) { + obj = (ExcelRowJavaModel)object; + } + System.out.println( + "当前sheet:" + context.getCurrentSheet().getSheetNo() + " 当前行:" + context.getCurrentRowNum() + + " data:" + obj); + + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + + } + }); + + reader.read(new Sheet(1, 2, ExcelRowJavaModel.class)); + reader.read(new Sheet(2, 1, ExcelRowJavaModel1.class)); + + } catch (Exception e) { + e.printStackTrace(); + + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + //读取shets + @Test + public void getSheets() { + InputStream inputStream = getInputStream("2007NoModelMultipleSheet.xlsx"); + try { + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, + new AnalysisEventListener>() { + @Override + public void invoke(List object, AnalysisContext context) { + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + } + }); + + List sheets = reader.getSheets(); + System.out.println(sheets); + } catch (Exception e) { + e.printStackTrace(); + + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + //获取sheet后再单独一个sheet解析 + @Test + public void getSheetsAndAnalysisNoModel() { + InputStream inputStream = getInputStream("2007NoModelMultipleSheet.xlsx"); + try { + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, + new AnalysisEventListener>() { + @Override + public void invoke(List object, AnalysisContext context) { + System.out.println( + "当前sheet:" + context.getCurrentSheet().getSheetNo() + " 当前行:" + context.getCurrentRowNum() + + " data:" + object); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + } + }); + + List sheets = reader.getSheets(); + System.out.println(sheets); + for (Sheet sheet : sheets) { + reader.read(sheet); + } + + } catch (Exception e) { + e.printStackTrace(); + + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 获取所有sheet后遍历解析,解析结果含有java模型 + */ + @Test + public void getSheetsAndAnalysisWithModel() { + InputStream inputStream = getInputStream("2007WithModelMultipleSheet.xlsx"); + try { + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, + new AnalysisEventListener() { + @Override + public void invoke(Object object, AnalysisContext context) { + ExcelRowJavaModel obj = null; + if (context.getCurrentSheet().getSheetNo() == 1) { + obj = (ExcelRowJavaModel)object; + } + if (context.getCurrentSheet().getSheetNo() == 2) { + obj = (ExcelRowJavaModel)object; + } + System.out.println( + "当前sheet:" + context.getCurrentSheet().getSheetNo() + " 当前行:" + context.getCurrentRowNum() + + " data:" + obj); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + } + }); + + List sheets = reader.getSheets(); + System.out.println(sheets); + for (Sheet sheet : sheets) { + if (sheet.getSheetNo() == 1) { + sheet.setHeadLineMun(2); + sheet.setClazz(ExcelRowJavaModel.class); + } + if (sheet.getSheetNo() == 2) { + sheet.setHeadLineMun(1); + sheet.setClazz(ExcelRowJavaModel1.class); + } + reader.read(sheet); + } + + } catch (Exception e) { + e.printStackTrace(); + + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 解析过程中断,不再解析(比如解析到某一行出错了,后面不需要再解析了) + */ + @Test + public void interrupt() { + InputStream inputStream = getInputStream("2007WithModelMultipleSheet.xlsx"); + try { + ExcelReader reader = new ExcelReader(inputStream, ExcelTypeEnum.XLSX, null, + new AnalysisEventListener() { + @Override + public void invoke(Object object, AnalysisContext context) { + context.interrupt(); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + } + }); + + List sheets = reader.getSheets(); + System.out.println(sheets); + for (Sheet sheet : sheets) { + if (sheet.getSheetNo() == 1) { + sheet.setHeadLineMun(2); + sheet.setClazz(ExcelRowJavaModel.class); + } + if (sheet.getSheetNo() == 2) { + sheet.setHeadLineMun(1); + sheet.setClazz(ExcelRowJavaModel1.class); + } + reader.read(sheet); + } + + } catch (Exception e) { + e.printStackTrace(); + + } finally { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + private InputStream getInputStream(String fileName) { + return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); + + } + + public static void main(String[] args) { + List mm = new ArrayList(); + mm.add(null); + mm.add(null); + mm.add(null); + mm.add(null); + mm.removeAll(Collections.singleton(null)); + + System.out.println(mm); + } +} diff --git a/src/test/java/read/v07/listener/Excel2007NoJavaModelAnalysisListener.java b/src/test/java/read/v07/listener/Excel2007NoJavaModelAnalysisListener.java new file mode 100644 index 00000000..a0663c7e --- /dev/null +++ b/src/test/java/read/v07/listener/Excel2007NoJavaModelAnalysisListener.java @@ -0,0 +1,37 @@ +package read.v07.listener; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; + +/** + * @author jipengfei + * @date 2017/08/27 + */ +public class Excel2007NoJavaModelAnalysisListener extends AnalysisEventListener { + + private ExcelWriter excelWriter; + + public ExcelWriter getExcelWriter() { + return excelWriter; + } + + public void setExcelWriter(ExcelWriter excelWriter) { + this.excelWriter = excelWriter; + } + + public void invoke(Object object, AnalysisContext context) { + List> ll = new ArrayList>(); + ll.add((List)object); + System.out.println(object); + excelWriter.write0(ll,context.getCurrentSheet()); + } + + public void doAfterAllAnalysed(AnalysisContext context) { + + } + +} diff --git a/src/test/java/read/v07/listener/Excel2007WithJavaModelAnalysisListener.java b/src/test/java/read/v07/listener/Excel2007WithJavaModelAnalysisListener.java new file mode 100644 index 00000000..1343b4a0 --- /dev/null +++ b/src/test/java/read/v07/listener/Excel2007WithJavaModelAnalysisListener.java @@ -0,0 +1,42 @@ +package read.v07.listener; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.BaseRowModel; +import com.alibaba.excel.metadata.Sheet; + +import javamodel.ExcelRowJavaModel; + +/** + * @author jipengfei + * @date 2017/08/27 + */ +public class Excel2007WithJavaModelAnalysisListener extends AnalysisEventListener { + + private ExcelWriter excelWriter; + + public ExcelWriter getExcelWriter() { + return excelWriter; + } + + public void setExcelWriter(ExcelWriter excelWriter) { + this.excelWriter = excelWriter; + } + + public void invoke(Object object, AnalysisContext context) { + List< BaseRowModel> ll = new ArrayList(); + ll.add((BaseRowModel)object); + Sheet sheet = context.getCurrentSheet(); + sheet.setClazz(ExcelRowJavaModel.class); + excelWriter.write(ll,sheet); + } + + public void doAfterAllAnalysed(AnalysisContext context) { + + } + +} diff --git a/src/test/resources/111.xlsx b/src/test/resources/111.xlsx new file mode 100644 index 00000000..b5efcd91 Binary files /dev/null and b/src/test/resources/111.xlsx differ diff --git a/src/test/resources/1111.xlsx b/src/test/resources/1111.xlsx new file mode 100644 index 00000000..a062def1 Binary files /dev/null and b/src/test/resources/1111.xlsx differ diff --git a/src/test/resources/2003.xls b/src/test/resources/2003.xls new file mode 100644 index 00000000..cef6344c Binary files /dev/null and b/src/test/resources/2003.xls differ diff --git a/src/test/resources/2007.xlsx b/src/test/resources/2007.xlsx new file mode 100644 index 00000000..fe19ea0f Binary files /dev/null and b/src/test/resources/2007.xlsx differ diff --git a/src/test/resources/2007NoModelBigFile.xlsx b/src/test/resources/2007NoModelBigFile.xlsx new file mode 100644 index 00000000..5d5a5c17 Binary files /dev/null and b/src/test/resources/2007NoModelBigFile.xlsx differ diff --git a/src/test/resources/2007NoModelMultipleSheet.xlsx b/src/test/resources/2007NoModelMultipleSheet.xlsx new file mode 100644 index 00000000..48fb8703 Binary files /dev/null and b/src/test/resources/2007NoModelMultipleSheet.xlsx differ diff --git a/src/test/resources/2007WithModel.xlsx b/src/test/resources/2007WithModel.xlsx new file mode 100644 index 00000000..73ab8065 Binary files /dev/null and b/src/test/resources/2007WithModel.xlsx differ diff --git a/src/test/resources/2007WithModelMultipleSheet.xlsx b/src/test/resources/2007WithModelMultipleSheet.xlsx new file mode 100644 index 00000000..0c601093 Binary files /dev/null and b/src/test/resources/2007WithModelMultipleSheet.xlsx differ diff --git a/src/test/resources/2007_1.xlsx b/src/test/resources/2007_1.xlsx new file mode 100644 index 00000000..5aaf0f0a Binary files /dev/null and b/src/test/resources/2007_1.xlsx differ diff --git a/src/test/resources/77.xlsx b/src/test/resources/77.xlsx new file mode 100644 index 00000000..f746d399 Binary files /dev/null and b/src/test/resources/77.xlsx differ diff --git a/update.md b/update.md new file mode 100644 index 00000000..9621cf49 --- /dev/null +++ b/update.md @@ -0,0 +1,39 @@ +# 1.0.1 + +完善测试用例,防止歧义,模型字段映射不上时候有抛异常,改为提醒。 + +# 1.0.2 + +修复拿到一行数据后,存到list中,但最后处理时候变为空的bug。 + +# 1.0.3 + +修复无@ExcelProperty标注的多余字段时候报错。 + +# 1.0.4 + +修复日期类型转换时候数字问题。基础模型支持字段类型int,long,double,boolean,date,string + +# 1.0.5 + +优化类型转换的性能。 + +# 1.0.6 + +增加@ExcelColumnNum,修复字符串前后空白,增加过滤功能。 +# 1.0.8 + +如果整行excel数据全部为空,则不解析返回。完善多sheet的解析。 + +# 1.0.9 + +修复excel超过16列被覆盖的问题,修复数据只有一行时候无法透传的bug。 + + +# 1.2.1 + +修复POI在大并发情况下创建临时目录失败的bug + +# 1.2.4 + +修复read()方法存在的bug