├── .gitignore ├── .rultor.yml ├── .travis.yml ├── LICENSE ├── README.md ├── docs ├── .nojekyll ├── README.md ├── _coverpage.md ├── _media │ └── logo.svg ├── favicon.ico ├── index.html └── old-version.md ├── pom.xml └── src ├── main └── java │ └── io │ └── github │ └── biezhi │ └── excel │ └── plus │ ├── Constant.java │ ├── Reader.java │ ├── Writer.java │ ├── annotation │ └── ExcelColumn.java │ ├── conveter │ ├── BigIntConverter.java │ ├── BooleanConverter.java │ ├── ByteConverter.java │ ├── Converter.java │ ├── ConverterCache.java │ ├── DateConverter.java │ ├── DecimalConverter.java │ ├── DoubleConverter.java │ ├── FloatConverter.java │ ├── IntConverter.java │ ├── LocalDateConverter.java │ ├── LocalDateTimeConverter.java │ ├── LongConverter.java │ ├── NullConverter.java │ ├── NumberConverter.java │ ├── ShortConverter.java │ └── StringConverter.java │ ├── enums │ └── ExcelType.java │ ├── exception │ ├── ConverterException.java │ ├── ExcelPlusException.java │ ├── ReaderException.java │ └── WriterException.java │ ├── reader │ ├── ExcelReader.java │ ├── ReaderConverter.java │ ├── ReaderFactory.java │ ├── ReaderWith2003.java │ ├── ReaderWith2007.java │ ├── ReaderWithCSV.java │ ├── SheetToCSV.java │ └── XLSXDataFormatter.java │ ├── types │ ├── Result.java │ ├── RowPredicate.java │ ├── StyleConsumer.java │ └── Valid.java │ ├── util │ ├── ExcelUtil.java │ └── StringUtil.java │ └── writer │ ├── ExcelWriter.java │ ├── ResponseWrapper.java │ ├── WriterWith2003.java │ ├── WriterWith2007.java │ └── WriterWithCSV.java └── test ├── java └── io │ └── github │ └── biezhi │ └── excel │ └── plus │ ├── BaseTest.java │ ├── ReaderTest.java │ ├── WriterTest.java │ ├── converter │ ├── BigIntConverterTest.java │ ├── BooleanConverterTest.java │ ├── ByteConverterTest.java │ ├── ConverterCacheTest.java │ ├── DateConverterTest.java │ ├── DecimalConverterTest.java │ ├── DoubleConverterTest.java │ ├── FloatConverterTest.java │ ├── IntConverterTest.java │ ├── LocalDateConverterTest.java │ ├── LocalDateTimeConverterTest.java │ ├── LongConverterTest.java │ ├── NullConverterTest.java │ ├── ShortConverterTest.java │ ├── StringConverterTest.java │ └── TestStatusConv.java │ ├── examples │ ├── Excel2003Test.java │ ├── ReaderExample.java │ └── WriterExample.java │ ├── model │ ├── Book.java │ ├── Financial.java │ ├── Member.java │ ├── PerformanceTestModel.java │ ├── Sample.java │ └── StatusConverter.java │ ├── reader │ └── ReaderFactoryTest.java │ ├── util │ ├── ExcelUtilTest.java │ └── StringUtilTest.java │ └── writer │ └── ResponseWrapperTest.java └── resources ├── FinancialSample.xlsx ├── SampleData.xls ├── SampleData.xlsx ├── book.csv └── template.xlsx /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Maven template 3 | target/ 4 | pom.xml.tag 5 | pom.xml.releaseBackup 6 | pom.xml.versionsBackup 7 | pom.xml.next 8 | release.properties 9 | dependency-reduced-pom.xml 10 | buildNumber.properties 11 | .mvn/timing.properties 12 | 13 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 14 | !/.mvn/wrapper/maven-wrapper.jar 15 | ### JetBrains template 16 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 17 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 18 | 19 | # User-specific stuff: 20 | .idea/**/workspace.xml 21 | .idea/**/tasks.xml 22 | .idea/dictionaries 23 | 24 | # Sensitive or high-churn files: 25 | .idea/**/dataSources/ 26 | .idea/**/dataSources.ids 27 | .idea/**/dataSources.xml 28 | .idea/**/dataSources.local.xml 29 | .idea/**/sqlDataSources.xml 30 | .idea/**/dynamic.xml 31 | .idea/**/uiDesigner.xml 32 | 33 | # Gradle: 34 | .idea/**/gradle.xml 35 | .idea/**/libraries 36 | 37 | # CMake 38 | cmake-build-debug/ 39 | 40 | # Mongo Explorer plugin: 41 | .idea/**/mongoSettings.xml 42 | 43 | ## File-based project format: 44 | *.iws 45 | 46 | ## Plugin-specific files: 47 | 48 | # IntelliJ 49 | out/ 50 | 51 | # mpeltonen/sbt-idea plugin 52 | .idea_modules/ 53 | 54 | # JIRA plugin 55 | atlassian-ide-plugin.xml 56 | 57 | # Cursive Clojure plugin 58 | .idea/replstate.xml 59 | 60 | # Crashlytics plugin (for Android Studio and IntelliJ) 61 | com_crashlytics_export_strings.xml 62 | crashlytics.properties 63 | crashlytics-build.properties 64 | fabric.properties 65 | ### Eclipse template 66 | 67 | .metadata 68 | bin/ 69 | tmp/ 70 | *.tmp 71 | *.bak 72 | *.swp 73 | *~.nib 74 | local.properties 75 | .settings/ 76 | .loadpath 77 | .recommenders 78 | 79 | # External tool builders 80 | .externalToolBuilders/ 81 | 82 | # Locally stored "Eclipse launch configurations" 83 | *.launch 84 | 85 | # PyDev specific (Python IDE for Eclipse) 86 | *.pydevproject 87 | 88 | # CDT-specific (C/C++ Development Tooling) 89 | .cproject 90 | 91 | # Java annotation processor (APT) 92 | .factorypath 93 | 94 | # PDT-specific (PHP Development Tools) 95 | .buildpath 96 | 97 | # sbteclipse plugin 98 | .target 99 | 100 | # Tern plugin 101 | .tern-project 102 | 103 | # TeXlipse plugin 104 | .texlipse 105 | 106 | # STS (Spring Tool Suite) 107 | .springBeans 108 | 109 | # Code Recommenders 110 | .recommenders/ 111 | 112 | # Scala IDE specific (Scala & Java development for Eclipse) 113 | .cache-main 114 | .scala_dependencies 115 | .worksheet 116 | .vscode 117 | .idea 118 | *.iml -------------------------------------------------------------------------------- /.rultor.yml: -------------------------------------------------------------------------------- 1 | release: 2 | script: | 3 | mvn versions:set "-DnewVersion=${tag}" 4 | git commit -am "${tag}" 5 | mvn clean deploy -Pqulice -Psonatype -Pexcel-plus --settings /home/r/settings.xml -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | sudo: false 3 | 4 | jdk: 5 | - openjdk8 6 | 7 | notifications: 8 | email: false 9 | 10 | script: "mvn cobertura:cobertura" 11 | 12 | after_success: 13 | - bash <(curl -s https://codecov.io/bash) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # excel-plus 2 | 3 | Easier to read and generate an excel file, supports `XLSX`、`XLS`、`CSV`. 4 | 5 | [![EO principles respected here](http://www.elegantobjects.org/badge.svg)](http://www.elegantobjects.org) 6 | [![DevOps By Rultor.com](http://www.rultor.com/b/hellokaton/excel-plus)](http://www.rultor.com/p/hellokaton/excel-plus) 7 | 8 | 9 | [![](https://img.shields.io/travis/hellokaton/excel-plus.svg)](https://travis-ci.org/hellokaton/excel-plus) 10 | [![Javadocs](http://javadoc.io/badge/io.github.biezhi/excel-plus.svg)](http://javadoc.io/doc/io.github.biezhi/excel-plus) 11 | [![](https://img.shields.io/maven-central/v/io.github.biezhi/excel-plus.svg)](https://search.maven.org/search?q=excel-plus) 12 | [![](https://img.shields.io/badge/license-Apache2-FF0080.svg)](https://github.com/hellokaton/excel-plus/blob/master/LICENSE) 13 | 14 | [![codecov](https://codecov.io/gh/hellokaton/excel-plus/branch/master/graph/badge.svg)](https://codecov.io/gh/hellokaton/excel-plus) 15 | [![SonarQube](https://img.shields.io/badge/sonar-ok-green.svg)](https://sonarcloud.io/dashboard/index/io.github.biezhi:excel-plus) 16 | 17 | 中文文档 18 | 19 | # Feature 20 | 21 | - Easy to use 22 | - Annotation driven 23 | - Based java 8 24 | - Support `xls`、`xlsx`、`csv` 25 | - Support export by template 26 | - Support custom column style 27 | - High performance, only 30 seconds to read or write `1,000,000` lines 28 | 29 | # Usage 30 | 31 | **How to use**. Latest version here 32 | 33 | ```xml 34 | 35 | io.github.biezhi 36 | excel-plus 37 | 1.0.8 38 | 39 | ``` 40 | 41 | snapshot version 42 | 43 | ```xml 44 | 45 | 46 | snapshots-repo 47 | https://oss.sonatype.org/content/repositories/snapshots 48 | 49 | false 50 | 51 | 52 | true 53 | 54 | 55 | 56 | 57 | 58 | 59 | io.github.biezhi 60 | excel-plus 61 | 1.0.8-SNAPSHOT 62 | 63 | 64 | ``` 65 | 66 | **Read excel as List** 67 | 68 | ![](https://i.loli.net/2018/12/14/5c1290880509b.png) 69 | 70 | ```java 71 | public class Member { 72 | 73 | @ExcelColumn(title = "卡号", index = 0) 74 | private Long cardNo; 75 | 76 | @ExcelColumn(title = "卡类型", index = 1) 77 | private String cardType; 78 | 79 | @ExcelColumn(title = "领用状态", index = 2) 80 | private String requisitionStatus; 81 | 82 | @ExcelColumn(title = "状态", index = 3) 83 | private String status; 84 | 85 | @ExcelColumn(title = "余额(元)", index = 6) 86 | private BigDecimal amount; 87 | 88 | @ExcelColumn(title = "会员", index = 7) 89 | private String nickname; 90 | 91 | @ExcelColumn(title = "性别", index = 9) 92 | private String gender; 93 | 94 | @ExcelColumn(title = "手机", index = 10) 95 | private String mobile; 96 | 97 | @ExcelColumn(title = "发卡日期", index = 14, datePattern = "M/d/yyyy HH:mm") 98 | private Date sendCardTime; 99 | 100 | // getter setter 省略 101 | } 102 | ``` 103 | 104 | ```java 105 | List members = Reader.create(Member.class) 106 | .from(new File("members.xlsx")) 107 | .start(1) 108 | .asList(); 109 | ``` 110 | 111 | **Write excel as file** 112 | 113 | ```java 114 | public class Book { 115 | 116 | @ExcelColumn(title = "书名", index = 0) 117 | private String title; 118 | 119 | @ExcelColumn(title = "作者", index = 1) 120 | private String author; 121 | 122 | @ExcelColumn(title = "售价", index = 2) 123 | private Double price; 124 | 125 | @ExcelColumn(title = "出版日期", index = 3, datePattern = "yyyy年M月") 126 | private LocalDate publishDate; 127 | 128 | // getter setter 省略 129 | } 130 | ``` 131 | 132 | ```java 133 | Writer.create() 134 | .withRows(books) 135 | .headerTitle("书籍列表 V1") 136 | .to(new File("book.xlsx")); 137 | ``` 138 | 139 | ![](https://i.loli.net/2018/12/14/5c1292b23b66f.png) 140 | 141 | Code See [here](https://github.com/hellokaton/excel-plus/blob/master/src/test/java/io/github/biezhi/excel/plus/examples/WriterExample.java#L145) 142 | 143 | **Browser download** 144 | 145 | ```java 146 | Writer.create() 147 | .withRows(orders) 148 | .to(ResponseWrapper.create(HttpServletResponse, "order-list.xls")); 149 | ``` 150 | 151 | # Examples 152 | 153 | See [here](https://github.com/hellokaton/excel-plus/blob/master/src/test/java/io/github/biezhi/excel/plus/examples) 154 | 155 | # Thanks 156 | 157 | - [ydq](https://github.com/ydq) 158 | 159 | # License 160 | 161 | [Apache2](https://github.com/hellokaton/excel-plus/blob/master/LICENSE) 162 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellokaton/excel-plus/96630e6d2fa9700890ba15c37e63aee98898bbc8/docs/.nojekyll -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Excel Plus 2 | 3 | ## 它是什么? 4 | 5 | `excel-plus` 是基于 [Apache POI](https://poi.apache.org/) 框架的一款扩展封装小库,让我们在开发中更快速的完成导入导出的需求。 6 | 尽管很多人会提出 `poi` 能干这事儿为什么还要封装一层呢? 7 | 8 | `excel-plus`很大程度上简化了代码、让使用者更轻松的 9 | **读**、**写** Excel 文档,也不用去关心格式兼容等问题,很多时候我们在代码中会写很多的 `for` 循环,各种 `getXXXIndex` 10 | 来获取行或列让代码变的更臃肿。多个项目之间打一枪换一个地方,代码 Copy 来 Copy 去十分凌乱, 11 | 如果你也在开发中遇到类似的问题,那么 `excel-plus` 是你值得一试的工具。 12 | 13 | ## 不是什么 14 | 15 | `excel-plus` 不是万能的,比如你想合并某几列,或者让第三行的某一列设置样式或特殊格式, 16 | 很抱歉它是做不到的,因为这让事情复杂化了,即便支持也会像原始的 POI API 一样让人痛恶。 17 | 如果真的需要,你可能需要在网络上寻找一些 `Utils` 结尾的工具类自行编写了,祝你好运 :P 18 | 19 | > 如果你在使用过程中遇到什么问题或者建议可以发一个 [issue](https://github.com/biezhi/excel-plus/issues/new) 告诉我 20 | 21 | ## 特性 22 | 23 | - 基于 Java 8 开发 24 | - 简洁的 API 操作 25 | - 注解驱动 26 | - 高性能低损耗 27 | - 可配置列顺序 28 | - 支持按模板导出 29 | - 支持过滤行数据 30 | - 支持数据类型转换 31 | - 支持自定义列样式 32 | - 支持读取时校验 33 | - 支持一行代码下载 Excel 文件 34 | - 支持 Excel 2003、2007、CSV 格式 35 | 36 | # 快速开始 37 | 38 | ## 引入依赖 39 | 40 | 加入以下 `maven` 依赖到你的 `pom.xml` 文件中,该项目使用的 `poi` 版本是 [4.0.1](https://mvnrepository.com/artifact/org.apache.poi/poi/4.0.1), 41 | 如果你的项目已经存在,请注意删除或者排除依赖。 42 | 43 | ```xml 44 | 45 | io.github.biezhi 46 | excel-plus 47 | 1.0.8 48 | 49 | ``` 50 | 51 | 也可以使用快照版本,最新的 bug 修复和功能更新都在这里 52 | 53 | ```xml 54 | 55 | 56 | snapshots-repo 57 | https://oss.sonatype.org/content/repositories/snapshots 58 | 59 | false 60 | 61 | 62 | true 63 | 64 | 65 | 66 | 67 | 68 | io.github.biezhi 69 | excel-plus 70 | 1.0.8-SNAPSHOT 71 | 72 | ``` 73 | 74 | > **注意**:这里的版本号请使用 `maven` 仓库较新版本,可在 Github 的 README 中看到。 75 | 76 | ## 读取和写入 77 | 78 | 下面是我们的 Java 模型类,用于存储 Excel 的行数据。 79 | 80 | ```java 81 | public class Sample { 82 | 83 | @ExcelColumn(index = 0, datePattern = "M/d/yy") 84 | private LocalDate date; 85 | 86 | @ExcelColumn(index = 1) 87 | private String location; 88 | 89 | @ExcelColumn(index = 4) 90 | private int proportion; 91 | 92 | @ExcelColumn(index = 5) 93 | private double ss; 94 | 95 | @ExcelColumn(index = 6) 96 | private BigDecimal amount; 97 | 98 | // getter setter 省略 99 | } 100 | ``` 101 | 102 | 这是一个简单的模型类,使用 `@ExcelColumn` 来匹配 Excel 中的列关系,这个表格的数据在 [这里](https://github.com/biezhi/excel-plus/blob/v1.0/src/test/resources/SampleData.xlsx)。 103 | 104 | 测试的 Excel 文档中有很多个 `Sheet`,我们只需读取名为 `SalesOrders` 的就可以了,其他的不关心。 105 | 106 | ```java 107 | List samples = Reader.create(Sample.class) 108 | .from(new File("SampleData.xlsx")) 109 | .sheet("SalesOrders") 110 | .start(1) 111 | .asList(); 112 | ``` 113 | 114 | 这样就可以读取到了,非常简单! 115 | 116 | > 这里设置 `start` 为 1 的原因: 117 | > 1. 读取行的索引总是从 0 开始 118 | > 2. 这个表格中索引为 0 的行是列信息,故从索引为 1 的开始读取 119 | 120 | 接下来试试写入一个表格到磁盘上吧 :) 121 | 122 | ```java 123 | List samples = new ArrayList<>(); 124 | // 这里的数据需自行准备 125 | Writer.create() 126 | .headerTitle("一份简单的Excel表格") 127 | .withRows(samples) 128 | .to(new File("sample_test.xlsx")); 129 | ``` 130 | 131 | 此时看看本地是否产生了一个名为 `sample_test.xlsx` 的 Excel 表格。 132 | 133 | # 进阶使用 134 | 135 | 读取 Excel 文档通过 `Reader` API 来完成,你只需要创建一个 Reader 对象,就可以读取文档了。 136 | 137 | > 导入包的时候注意是 `io.github.biezhi.excel.plus.Reader` 138 | 139 | ## 创建 Reader 140 | 141 | 创建 Reader 的方式可以通过构造函数或者工厂方法,我们建议你这样使用: 142 | 143 | ```java 144 | Reader.create(Sample.class); 145 | ``` 146 | 147 | 这里是 `Sample.class` 是一个 Java 中的类型,它和 Excel 的行进行绑定,通过 `@ExcelColumn` 来表示列关系。 148 | 149 | ## 读取指定的 Sheet 150 | 151 | 有些时候在一个 Excel 文档中有多个 Sheet,默认这个库会读取第一个,也就是 `index` 为 0 的 Sheet。 152 | 如果你想读取其他的 `excel-plus` 提供了 API 帮助你。 153 | 154 | ```java 155 | Reader.create(Sample.class) 156 | .from(new File("SampleData.xlsx")) 157 | .sheet(1) 158 | ``` 159 | 160 | 这样会读取 `index` 为 1 的 Sheet,如果你想按名称读取可以参考如下代码 161 | 162 | ```java 163 | Reader.create(Sample.class) 164 | .from(new File("SampleData.xlsx")) 165 | .sheet("sheetName") 166 | ``` 167 | 168 | ## 从指定行开始读取 169 | 170 | 默认情况,`Reader` 会从索引为 2 的行开始读取,有些时候我们的表格并非有表头或者标题,所以需要重新设置开始读取的行。 171 | 这里设置的是一个索引值,假设 Excel 中只有 2 行数据,没有其他的,那么可以这样设置: 172 | 173 | ```java 174 | Reader.create(Sample.class) 175 | .from(new File("SampleData.xlsx")) 176 | .start(0) 177 | ``` 178 | 179 | 如果数据行上面有一行列头显示,我们就可以从索引为 1 的行开始读取 180 | 181 | ```java 182 | Reader.create(Sample.class) 183 | .from(new File("SampleData.xlsx")) 184 | .start(1) 185 | ``` 186 | 187 | ## 从 InputStream 读取 188 | 189 | 大多数情况下 Excel 以文件的形式存在,在某些特殊情况下可能是一个 `InputStream`,`excel-plus` 也支持从流中读取文档数据。 190 | 但你要记住,`File` 参数形式的效率会更高,因为内部的一些判断和 POI 本身的机制导致。 191 | 192 | ```java 193 | Reader.create(Sample.class) 194 | .from(YOU_INPUT_STREAM) 195 | ``` 196 | 197 | ## 读取结果过滤 198 | 199 | 有时候我们需要对读取的行数据做一下过滤,这时候就可以使用 `filter` 函数来筛选出合适的数据项。 200 | 201 | ```java 202 | List samples = Reader.create(Sample.class) 203 | .from(new File(classPath() + "/SampleData.xlsx")) 204 | .sheet("SalesOrders") 205 | .startRow(1) 206 | .asStream() 207 | .filter(sample -> sample.getAmount().intValue() > 1000) 208 | .collect(toList()); 209 | 210 | ``` 211 | 212 | ## 读取 CSV 文档 213 | 214 | 为了方便,我们也支持直接读取一份 CSV 文档,使用方式和前面没有差异,只是在 `from` 的时候文件名不同了而已。 215 | 216 | --- 217 | 218 | 写入一份 Excel 文档通过使用 `Writer` API 来完成,创建一个 Writer 对象就可以操作 Excel 写入了。 219 | 220 | > 导入包的时候注意是 `io.github.biezhi.excel.plus.Writer` 221 | 222 | ## 创建 Writer 223 | 224 | 你可以通过使用构造函数的方式或者工厂方法来创建一个 Writer 对象,下面的方式更简洁: 225 | 226 | ```java 227 | Writer.create(); 228 | ``` 229 | 230 | 默认情况下创建的 Writer 对象会写入一个 `XLSX` 格式的 Excel 文档,如果你要写入一份 `XLS` 或者 `CSV` 文档的话可以修改入参 231 | 232 | ```java 233 | Writer.create(ExcelType.XLS); 234 | Writer.create(ExcelType.CSV); 235 | ``` 236 | 237 | ## 自定义写入 Sheet 238 | 239 | 默认写入一份 Excel 文档的 Sheet 名称是 `Sheet0`,如果你在意这个名字的话可以修改它。 240 | 241 | ```java 242 | Writer.create().sheet("my_sheet"); 243 | ``` 244 | 245 | ## 设置标题 246 | 247 | 设置标题是一个可选项,如果你想在写入 Excel 的时候加入一个大标题,如 “2018 年 5 月 书籍 TOP 10”。 248 | 249 | ```java 250 | Writer.create().headerTitle("2018 年 5 月 书籍 TOP 10"); 251 | ``` 252 | 253 | 该标题在 Excel 文档生成后显示在第一行,自动合并为一列。 254 | 255 | ## 从指定行开始写入 256 | 257 | 这一选项不建议使用,默认是通过是否设置标题来计算得出的,如果你愿意中间空一些行再写入的话可以设置。 258 | 259 | ```java 260 | Writer.create().start(4); 261 | ``` 262 | 263 | 这将从索引为 4 的行开始写入。 264 | 265 | ## 自定义写入样式 266 | 267 | 大多数情况下我们是无需设置样式的,在 `excel-plus` 中提供了设置表头和列的样式 API。 268 | 在某些需求下可能需要设置字体大小、颜色、居中等,你可以像下面的代码这样干。 269 | 如果你对样式的操作不熟悉可以参考 POI 的列设置 [文档](https://poi.apache.org/spreadsheet/quick-guide.html#Creating+Date+Cells)。 270 | 271 | ```java 272 | Writer.create() 273 | .headerTitle("一份自定义样式的Excel表格") 274 | .withRows(buildData()) 275 | .titleStyle((wb, style) -> { 276 | Font font = wb.createFont(); 277 | font.setFontHeightInPoints((short) 40); 278 | font.setColor(HSSFColor.HSSFColorPredefined.RED.getIndex()); 279 | style.setFont(font); 280 | }) 281 | .headerStyle((wb, style) -> { 282 | Font font = wb.createFont(); 283 | font.setFontHeightInPoints((short) 20); 284 | font.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex()); 285 | style.setFont(font); 286 | }) 287 | .cellStyle((wb, style) -> { 288 | Font font = wb.createFont(); 289 | font.setFontHeightInPoints((short) 20); 290 | font.setColor(HSSFColor.HSSFColorPredefined.BLUE.getIndex()); 291 | style.setFont(font); 292 | }) 293 | .to(new File(fileName)); 294 | ``` 295 | 296 | ## 通过 Servlet 下载 297 | 298 | 为了方便我们将查询的数据直接输出到浏览器弹出下载,`excel-plus` 也做了一点 _手脚_ 让你一行代码就可以搞定。 299 | 如果你使用的是基于 `servlet` 的应用可以使用如下方式。 300 | 301 | ```java 302 | Writer.create() 303 | ... 304 | .to(ResponseWrapper.createXLSX(servletResponse, "xxx表格.xlsx")) 305 | ``` 306 | 307 | 只需要将 `HttpServletResponse` 对象传入,并输入导出的文件名称,其他的都见鬼去吧。 308 | 309 | ## 使用模板导出 310 | 311 | 有时候我们需要导出的 Excel 表格样式比较复杂,可以事先设置好一个模板表格,数据为空, 312 | 由程序向模板中填入数据,然后导出即可,这样就满足了美观的需求。 313 | 314 | ```java 315 | Writer.create() 316 | .withTemplate(classPath() + "/template.xls") 317 | .withRows(buildData()) 318 | .to(new File(fileName)); 319 | ``` 320 | 321 | > 需要注意的是这里的 `template.xls` 位于 `classpath` 路径下。 322 | 323 | # API 概览 324 | 325 | ## 核心对象 326 | 327 | - `Reader`: 用于读取一份 Excel 文档 328 | - `Writer`: 用于写入一份 Excel 文档 329 | - `Converter`: 数据类型转换的顶层接口,处理自定义的读取、写入规则 330 | 331 | ## Reader 332 | 333 | - `create(Class)`:创建指定类型的 Reader 334 | - `from(File)`:从文件中读取 335 | - `from(InputStream)`:从 InputStream 中读取 336 | - `startRow(int)`:设置从第几行开始读,索引从 0 开始 337 | - `sheet(int)`:要读取的 sheet 索引,默认为 0 338 | - `sheet(String)`:要读取的 sheet 名称,如果设置则不会根据 sheetIndex 读取 339 | - `asStream()`:将读取结果存储在 Stream 中返回 340 | - `asList()`:将读取结果存储在 List 中返回 341 | 342 | ## Writer 343 | 344 | - `Writer(ExcelType)`:构造函数,写入什么类型的文件,支持 XLSX、XLS、CSV 格式 345 | - `withRows(Collection)`:写入的数据,该方法接收一个集合 346 | - `sheet(String)`:写入的 Sheet 名称,默认为 `Sheet0` 347 | - `startRow(int)`:从第几行开始写入,索引从 0 开始,默认是计算出的,建议不设置 348 | - `headerTitle(String)`:Sheet 的大标题,可选项 349 | - `titleStyle(BiConsumer)`:自定义标题样式 350 | - `headerStyle(BiConsumer)`:自定义列头样式 351 | - `cellStyle(BiConsumer)`:自定义行中的单元格样式 352 | - `withTemplate(File)`:根据模板文件创建 Excel 353 | - `bufferSize(int)`:写入一个 XLSX 格式的文件时缓冲大小,默认为 100,建议不修改 354 | - `withRaw()`:自定义写入行,启用该配置后不会根据集合数据写 Excel 355 | - `createRow(int)`:`withRaw` 启用后可使用该 API,用于自定义创建 `Row` 和 `Cell` 356 | - `isAppend(boolean)`: 默认为false,设置为true文件写入将使用追加而不是覆盖 357 | - `to(File)`:写入 Excel 文档到文件 358 | - `to(OutputStream)`:写入 Excel 文档到 OutputStream 359 | 360 | ## 注解使用 361 | 362 | 通过使用注解来配置如何读取、写入 Excel 文档。 363 | 364 | @ExcelColumn 注解 365 | 366 | | 选项 | 默认值 | 描述 | 367 | |-------------|----------------------|--------------------------------------------------------------------| 368 | | `index` | `-1` | 用于标识 Excel 中的列索引,从 0 开始,该选项适用于读取或写入 Excel | 369 | | `title` | `""` | 导出 Excel 时的列名称,如:状态、姓名、手机号 | 370 | | `datePattern` | `""` | 日期格式化的 `pattern`,对 `Date`、`LocalDate`、`LocalDateTime` 生效 | 371 | | `converter` | `NullConverter.class` | 数据类型转换的类 Class,实现自 Converter 接口,实现类需提供无参构造函数 | 372 | | `width` | `-1` | 导出为 Excel 时的列宽度,建议以 `字符数 * 256` 为基准进行设置 | 373 | 374 | # 常见问题 375 | 376 | 在使用过程中遇到什么问题或者建议可以发一个 [issue](https://github.com/biezhi/excel-plus/issues/new) 377 | 378 | # 版本更新 379 | 380 | v1.0-SNAPSHOT 381 | 382 | 1. 修复性能问题 383 | 2. 重构部分 API 384 | 3. 简化代码 385 | -------------------------------------------------------------------------------- /docs/_coverpage.md: -------------------------------------------------------------------------------- 1 | excel-plus 2 | 3 | > 提高生产力的 Excel 操作库 4 | 5 | - 支持按模板导出 6 | - 支持自定义导出样式 7 | - 注解驱动 Excel 行到 Java 字段 8 | - [更多特性](#特性) 9 | 10 | [GitHub](https://github.com/biezhi/excel-plus) 11 | [快速开始](#快速开始) 12 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellokaton/excel-plus/96630e6d2fa9700890ba15c37e63aee98898bbc8/docs/favicon.ico -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Excel Plus - 提高生产力的 Excel 操作库 6 | 7 | 8 | 9 | 10 | 11 | 12 | 16 |
17 | 18 | 19 | 20 | 21 | 30 | 31 | -------------------------------------------------------------------------------- /docs/old-version.md: -------------------------------------------------------------------------------- 1 | # Excel Plus 2 | 3 | ## 它是什么? 4 | 5 | `excel-plus` 是基于 [Apache POI](https://poi.apache.org/) 框架的一款扩展封装小库,让我们在开发中更快速的完成导入导出的需求。 6 | 尽管很多人会提出 `poi` 能干这事儿为什么还要封装一层呢? 7 | 8 | `excel-plus`很大程度上简化了代码、让使用者更轻松的 9 | 读、写 Excel 文档,也不用去关心格式兼容等问题,很多时候我们在代码中会写很多的 `for` 循环,各种 `getXXXIndex` 10 | 来获取行或列让代码变的更臃肿。多个项目之间打一枪换一个地方,代码 Copy 来 Copy 去十分凌乱, 11 | 如果你也在开发中遇到类似的问题,那么 `excel-plus` 是你值得一试的工具。 12 | 13 | ## 不是什么 14 | 15 | `excel-plus` 不是万能的,比如你想合并某几列,或者让第三行的某一列设置样式或特殊格式, 16 | 很抱歉它是做不到的,因为这让事情复杂化了,即便支持也会像原始的 POI API 一样让人痛恶。 17 | 如果真的需要,你可能需要在网络上寻找一些 `Utils` 结尾的工具类自行编写了,祝你好运 :P 18 | 19 | > 如果你在使用过程中遇到什么问题或者建议可以发一个 [issue](https://github.com/biezhi/excel-plus/issues/new) 告诉我 20 | 21 | ## 特性 22 | 23 | - 基于 Java 8 开发 24 | - 简洁的 API 操作 25 | - 注解驱动 26 | - 可配置列顺序 27 | - 支持按模板导出 28 | - 支持过滤行数据 29 | - 支持校验行数据 30 | - 支持数据类型转换 31 | - 支持自定义列样式 32 | - 支持一行代码下载 Excel 文件 33 | - 支持 Excel 2003、2007、CSV 格式 34 | 35 | # 快速开始 36 | 37 | ## 引入依赖 38 | 39 | 加入以下 `maven` 依赖到你的 `pom.xml` 文件中,该项目使用的 `poi` 版本是 **3.17**, 40 | 如果你的项目已经存在,请注意删除或者排除依赖。 41 | 42 | ```xml 43 | 44 | io.github.biezhi 45 | excel-plus 46 | 0.1.6.RELEASE 47 | 48 | ``` 49 | 50 | > **注意**:这里的版本号请使用 `maven` 仓库较新版本,可在 Github 的 README 中看到。 51 | 52 | ## 导入导出 53 | 54 | 下面是我们的 Java 模型类,用于存储 Excel 的行数据。 55 | 56 | ```java 57 | // 卡密 Model 58 | public class CardSecret { 59 | 60 | @ExcelField(order = 0, columnName = "运营商类型", 61 | convertType = CardTypeConverter.class) 62 | private Integer cardType; 63 | 64 | @ExcelField(order = 1, columnName = "卡密") 65 | private String secret; 66 | 67 | @ExcelField(order = 2, columnName = "面额") 68 | private BigDecimal amount; 69 | 70 | @ExcelField(order = 3, columnName = "过期时间", datePattern = "yyyy年MM月dd日") 71 | private Date expiredDate; 72 | 73 | // 可跳过索引为 4 的列 74 | @ExcelField(order = 5, columnName = "使用情况", convertType = UsedTypeConverter.class) 75 | private Boolean used; 76 | 77 | // getter setter 省略 78 | } 79 | ``` 80 | 81 | 这里的 `cardType` 是数据库中存储的运营商类型,1对应的是**移动**,其他对应的是**联通**。 82 | 这时候我们需要编写一个转换器将数字类型的结果转换为Excel中语义化的中文。 83 | 84 | ```java 85 | // 运营商类型转换器 86 | public class CardTypeConverter implements Converter { 87 | 88 | @Override 89 | public String write(Integer value) { 90 | return value.equals(1) ? "联通" : "移动"; 91 | } 92 | 93 | @Override 94 | public Integer read(String value) { 95 | return value.equals("联通") ? 1 : 2; 96 | } 97 | } 98 | ``` 99 | 100 | 使用 `ExcelPlus` 导出卡密列表。 101 | 102 | ```java 103 | ExcelPlus excelPlus = new ExcelPlus(); 104 | List cardSecrets = new ArrayList<>(); 105 | cardSecrets.add(new CardSecret(1, "vlfdzepjmlz2y43z7er4", new BigDecimal("20"), false)); 106 | cardSecrets.add(new CardSecret(2, "rasefq2rzotsmx526z6g", new BigDecimal("10"), false)); 107 | cardSecrets.add(new CardSecret(2, "2ru44qut6neykb2380wt", new BigDecimal("50"), true)); 108 | cardSecrets.add(new CardSecret(1, "srcb4c9fdqzuykd6q4zl", new BigDecimal("15"), false)); 109 | 110 | excelPlus.export(cardSecrets).writeAsFile(new File("卡密列表.xlsx")); 111 | ``` 112 | 113 | 这样就完成了一个列表数据导出为 Excel 的例子,通常我们的数据都是从数据库查询出来的。 114 | 下面这个例子是从Excel 中读取数据到 Java List 容器,如果你想存储在 Set 里我相信你可以做到。 115 | 116 | ```java 117 | Reader reader = Reader.create().excelFile(new File("卡密列表.xlsx")); 118 | List cardList = excelPlus.read(CardSecret.class, reader).asList(); 119 | ``` 120 | 121 | 没错,就是这么简单!如果有更加复杂或自定义的需求可以看下面的进阶使用。 122 | 123 | # 进阶使用 124 | 125 | ## 读取过滤 126 | 127 | 有时候我们需要对读取的行数据做一下过滤,这时候就可以使用 `filter` 函数来筛选出合适的数据项。 128 | 129 | ```java 130 | excelPlus.read(CardSecret.class, reader) 131 | .filter(cardSecret -> !cardSecret.getSecret().isEmpty()) 132 | .asList(); 133 | ``` 134 | 135 | ## 读取校验 136 | 137 | 有一种场景是当 Excel 中的某一行或者几行数据不满足条件时候,我们记录下这些异常数据,并提示给调用方(比如 Web 浏览器)。 138 | 下面这个示例校验每行数据中的 `amount` 是否 `< 20`,如果满足则返回一个校验失败的错误信息,然后我们将错误内容输出到控制台, 139 | 实际工作中你可能将它们交由前端处理。 140 | 141 | ```java 142 | ReaderResult result = excelPlus.read(new File("卡密列表.xls"), CardSecret.class) 143 | .valid((index, cardSecret) -> { 144 | if(!cardSecret.getUsed()){ 145 | return ValidRow.ok(); 146 | } 147 | return ValidRow.fail("已经被使用"); 148 | }); 149 | 150 | if (!result.isValid()) { 151 | result.errors().forEach(System.out::println); 152 | } else { 153 | System.out.println(result.asList().size()); 154 | } 155 | ``` 156 | 157 | > 当然你可以将 `valid` 校验代码块封装一下看起来更流畅 :P 158 | 159 | ## 导出样式 160 | 161 | 大多数情况下我们是无需设置样式的,在 `excel-plus` 中提供了设置表头和列的样式 API。 162 | 在某些需求下可能需要设置字体大小、颜色、居中等,你可以像下面的代码这样干。 163 | 如果你对样式的操作不熟悉可以参考 POI 的列设置[文档](https://poi.apache.org/spreadsheet/quick-guide.html#Creating+Date+Cells)。 164 | 165 | ```java 166 | // 构建数据 167 | List cardSecrets = this.buildCardSecrets(); 168 | 169 | Exporter exporter = Exporter.create(cardSecrets); 170 | exporter.headerStyle(workbook -> { 171 | CellStyle headerStyle = workbook.createCellStyle(); 172 | headerStyle.setAlignment(HorizontalAlignment.LEFT); 173 | 174 | headerStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.WHITE.getIndex()); 175 | headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); 176 | 177 | Font headerFont = workbook.createFont(); 178 | headerFont.setFontHeightInPoints((short) 12); 179 | headerFont.setBold(true); 180 | headerStyle.setFont(headerFont); 181 | return headerStyle; 182 | }); 183 | 184 | excelPlus.export(exporter) 185 | .writeAsFile(new File("卡密列表.xlsx")); 186 | ``` 187 | 188 | ## 浏览器下载 189 | 190 | 为了方便我们将数据库查询的数据直接输出到浏览器弹出下载,`excel-plus` 也做了一点 _手脚_ 让你一行代码就可以搞定。 191 | 192 | ```java 193 | excelPlus.export(exporter) 194 | .writeAsResponse(ResponseWrapper.create(servletResponse, "xxx表格.xls")) 195 | ``` 196 | 197 | 只需要将 `HttpServletResponse` 对象传入,并输入导出的文件名称,其他的都见鬼去吧。 198 | 199 | ## 模板导出 200 | 201 | 有时候我们需要导出的 Excel 表格样式比较复杂,可以事先设置好一个模板表格,数据为空, 202 | 由程序向模板中填入数据,然后导出即可,这样就满足了美观的需求。 203 | 204 | ```java 205 | List cardSecrets = this.buildCardSecrets(); 206 | excelPlus.export(Exporter.create(cardSecrets).byTemplate("tpl.xls")).writeAsFile(new File("template_rows.xls")); 207 | ``` 208 | 209 | > 需要注意的是这里的 `tpl.xls` 位于 `classpath` 路径下。 210 | 211 | # API 介绍 212 | 213 | ## 核心对象 214 | 215 | - `ExcelPlus`: 用于操作读取或导出 Excel 文档的类 216 | - `Converter`: 数据类型转换的顶层接口 217 | - `ReaderResult`: 存储读取到的列表,包含校验不通过的消息 218 | - `Exporter`: 用于存储导出 Excel 文档时的配置,如样式、模板位置等 219 | 220 | ## 注解使用 221 | 222 | 该项目中有 4 个注解,分别是 `ExcelField`、`ExcelSheet`、`ReadField`、`WriteField`。 223 | 正常情况下你只会用到第一个注解,下面解释一下 `@ExcelField`。 224 | 225 | @ExcelField 注解 226 | 227 | | 选项 | 默认值 | 描述 | 228 | |-------------|----------------------|--------------------------------------------------------------------| 229 | | `order` | -1 | 用于标识 Excel 中的列索引,从 0 开始,该选项适用于读取或写入 Excel | 230 | | `columnName` | 必选 | 导出Excel时的列名称,如:状态、姓名、手机号 | 231 | | `datePattern` | 空 | 日期格式化的 `pattern`,对 `Date`、`LocalDate`、`LocalDateTime` 生效 | 232 | | `convertType` | `EmptyConverter.class` | 数据类型转换的类 Class,实现自 Converter 接口,实现类需有无参构造函数 | 233 | 234 | > `@ReadField` 和 `@WriteField` 是针对读取和写入的顺序不一致、日期格式不一致时的覆盖型注解,一般用不到。 235 | 236 | @ExcelSheet 注解 237 | 238 | 用于标识导出的工作表名称,默认是 `Sheet0`,无特殊需求用不到。 239 | 240 | # 常见问题 241 | 242 | 等你有了我就写上来行不? 243 | 244 | 在使用过程中遇到什么问题或者建议可以发一个 [issue](https://github.com/biezhi/excel-plus/issues/new) 245 | 246 | # 版本更新 247 | 248 | v0.1.2 249 | 250 | 1. 导出数字支持 251 | 2. 修复日期格式化 bug 252 | 3. 修复列索引错误 253 | 254 | v0.1.1 255 | 256 | 1. 优化读取性能 257 | 2. 重构 POI 读取方式 258 | 259 | v0.0.4 260 | 261 | 1. 添加 `sheetName` 方法在运行时读取工作表 262 | 2. 添加 `sheetIndex` 方法在运行时读取工作表 263 | 264 | v0.0.3 265 | 266 | 1. 修复自定义 `SheetName` 读取失败 267 | 268 | v0.0.2 269 | 270 | 1. 添加验证行记录各项指标 271 | 2. 区分验证成功和失败行 272 | 3. 可配置是否添加到验证成功行 273 | 4. 取消 `columnName` 选项为必选 274 | 275 | v0.0.1 276 | 277 | - 发布第一个版本 278 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | io.github.biezhi 8 | excel-plus 9 | 1.0.8 10 | excel-plus 11 | https://biezhi.github.io/excel-plus 12 | excel read and write framework 13 | 14 | 15 | 16 | The Apache Software License, Version 2.0 17 | http://www.apache.org/licenses/LICENSE-2.0.txt 18 | 19 | 20 | 21 | 22 | biezhi 23 | biezhi.me@gmail.com 24 | 25 | 26 | 27 | scm:git@github.com:biezhi/excel-plus.git 28 | scm:git@github.com:biezhi/excel-plus.git 29 | git@github.com:biezhi/excel-plus.git 30 | 31 | 32 | 33 | 5.4.0 34 | 35 | 36 | 37 | 38 | org.slf4j 39 | slf4j-api 40 | 1.7.25 41 | compile 42 | 43 | 44 | org.apache.poi 45 | poi 46 | ${poi.version} 47 | 48 | 49 | org.apache.poi 50 | poi-ooxml 51 | ${poi.version} 52 | 53 | 54 | javax.servlet 55 | javax.servlet-api 56 | 3.0.1 57 | compile 58 | 59 | 60 | org.projectlombok 61 | lombok 62 | 1.16.18 63 | compile 64 | 65 | 66 | ch.qos.logback 67 | logback-classic 68 | 1.2.3 69 | test 70 | 71 | 72 | junit 73 | junit 74 | 4.13.1 75 | test 76 | 77 | 78 | 79 | 80 | 81 | 82 | org.apache.maven.plugins 83 | maven-compiler-plugin 84 | 85 | 1.8 86 | 1.8 87 | 88 | 89 | 90 | org.codehaus.mojo 91 | cobertura-maven-plugin 92 | 2.7 93 | 94 | 95 | html 96 | xml 97 | 98 | 99 | 100 | io.github.biezhi.excel.plus.annotation.* 101 | io.github.biezhi.excel.plus.exception.* 102 | 103 | 104 | io/github/biezhi/excel/plus/annotation/*.class 105 | io/github/biezhi/excel/plus/exception/*.class 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | release 117 | 118 | 119 | oss 120 | 121 | https://oss.sonatype.org/content/repositories/snapshots/ 122 | 123 | 124 | 125 | oss 126 | 127 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | org.apache.maven.plugins 136 | maven-source-plugin 137 | 2.4 138 | 139 | 140 | package 141 | 142 | jar-no-fork 143 | 144 | 145 | 146 | 147 | 148 | 149 | org.apache.maven.plugins 150 | maven-javadoc-plugin 151 | 2.10.2 152 | 153 | UTF-8 154 | UTF-8 155 | 156 | 157 | 158 | package 159 | 160 | jar 161 | 162 | 163 | -Xdoclint:none 164 | 165 | 166 | 167 | 168 | 169 | 170 | org.apache.maven.plugins 171 | maven-gpg-plugin 172 | 1.6 173 | 174 | 175 | sign-artifacts 176 | verify 177 | 178 | sign 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | snapshots 188 | 189 | 190 | oss 191 | 192 | https://oss.sonatype.org/content/repositories/snapshots/ 193 | 194 | 195 | 196 | oss 197 | 198 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | org.apache.maven.plugins 207 | maven-source-plugin 208 | 2.4 209 | 210 | 211 | package 212 | 213 | jar-no-fork 214 | 215 | 216 | 217 | 218 | 219 | 220 | org.apache.maven.plugins 221 | maven-surefire-plugin 222 | 2.17 223 | 224 | true 225 | 226 | 227 | 228 | 229 | org.apache.maven.plugins 230 | maven-gpg-plugin 231 | 1.6 232 | 233 | 234 | sign-artifacts 235 | verify 236 | 237 | sign 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/Constant.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus; 17 | 18 | import org.apache.poi.hssf.util.HSSFColor; 19 | import org.apache.poi.ss.usermodel.*; 20 | 21 | /** 22 | * Excel plus constant 23 | * 24 | * @author biezhi 25 | * @date 2018/12/12 26 | */ 27 | public interface Constant { 28 | 29 | /** 30 | * The default worksheet name. 31 | */ 32 | String DEFAULT_SHEET_NAME = "Sheet0"; 33 | String DEFAULT_FONT_NAME = "SimHei"; 34 | int DEFAULT_COLUMN_WIDTH = 20 * 256; 35 | 36 | String XLSX_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; 37 | String XLS_CONTENT_TYPE = "application/vnd.ms-excel"; 38 | 39 | static CellStyle defaultTitleStyle(Workbook workbook) { 40 | CellStyle style = workbook.createCellStyle(); 41 | 42 | style.setAlignment(HorizontalAlignment.CENTER); 43 | style.setVerticalAlignment(VerticalAlignment.CENTER); 44 | 45 | style.setBorderTop(BorderStyle.THIN); 46 | style.setBorderRight(BorderStyle.THIN); 47 | style.setBorderBottom(BorderStyle.THIN); 48 | style.setBorderLeft(BorderStyle.THIN); 49 | 50 | style.setFillForegroundColor(HSSFColor.HSSFColorPredefined.WHITE.getIndex()); 51 | style.setFillPattern(FillPatternType.SOLID_FOREGROUND); 52 | 53 | Font font = workbook.createFont(); 54 | font.setFontHeightInPoints((short) 20); 55 | font.setBold(true); 56 | font.setFontName(DEFAULT_FONT_NAME); 57 | style.setFont(font); 58 | return style; 59 | } 60 | 61 | /** 62 | * The default Excel header style. 63 | * 64 | * @param workbook Excel workbook 65 | * @return header row cell style 66 | */ 67 | static CellStyle defaultHeaderStyle(Workbook workbook) { 68 | CellStyle headerStyle = workbook.createCellStyle(); 69 | 70 | headerStyle.setAlignment(HorizontalAlignment.CENTER); 71 | headerStyle.setVerticalAlignment(VerticalAlignment.CENTER); 72 | headerStyle.setBorderTop(BorderStyle.THIN); 73 | headerStyle.setBorderRight(BorderStyle.THIN); 74 | headerStyle.setBorderBottom(BorderStyle.THIN); 75 | headerStyle.setBorderLeft(BorderStyle.THIN); 76 | 77 | headerStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.WHITE.getIndex()); 78 | headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); 79 | 80 | Font font = workbook.createFont(); 81 | font.setFontHeightInPoints(Short.parseShort("16")); 82 | font.setBold(true); 83 | font.setFontName(DEFAULT_FONT_NAME); 84 | headerStyle.setFont(font); 85 | return headerStyle; 86 | } 87 | 88 | /** 89 | * The default Excel column style. 90 | * 91 | * @param workbook Excel workbook 92 | * @return row column cell style 93 | */ 94 | static CellStyle defaultColumnStyle(Workbook workbook) { 95 | CellStyle cellStyle = workbook.createCellStyle(); 96 | cellStyle.setAlignment(HorizontalAlignment.CENTER); 97 | cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); 98 | cellStyle.setBorderTop(BorderStyle.THIN); 99 | cellStyle.setBorderRight(BorderStyle.THIN); 100 | cellStyle.setBorderBottom(BorderStyle.THIN); 101 | cellStyle.setBorderLeft(BorderStyle.THIN); 102 | cellStyle.setWrapText(true); 103 | 104 | cellStyle.setDataFormat((short) 0); 105 | 106 | Font font = workbook.createFont(); 107 | font.setFontName(DEFAULT_FONT_NAME); 108 | font.setFontHeightInPoints(Short.parseShort("14")); 109 | 110 | cellStyle.setFont(font); 111 | return cellStyle; 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/Reader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus; 17 | 18 | import io.github.biezhi.excel.plus.exception.ReaderException; 19 | import io.github.biezhi.excel.plus.reader.ReaderFactory; 20 | import io.github.biezhi.excel.plus.types.Result; 21 | import io.github.biezhi.excel.plus.util.StringUtil; 22 | 23 | import java.io.File; 24 | import java.io.InputStream; 25 | import java.nio.charset.Charset; 26 | import java.nio.charset.StandardCharsets; 27 | import java.util.List; 28 | import java.util.stream.Stream; 29 | 30 | import static java.util.stream.Collectors.toList; 31 | 32 | /** 33 | * ExcelPlus Reader 34 | *

35 | * Used to read Excel documents 36 | * 37 | * @author biezhi 38 | * @date 2018-12-11 39 | */ 40 | public class Reader { 41 | 42 | /** 43 | * Java entity type to which the Excel row is mapped 44 | */ 45 | private Class modelType; 46 | 47 | /** 48 | * The index of the sheet to be read, default is 0 49 | */ 50 | private int sheetIndex; 51 | 52 | /** 53 | * Sheet name to be read, sheet does not take effect if sheet is configured 54 | */ 55 | private String sheetName; 56 | 57 | /** 58 | * Reading data from the first few lines should start with an index that really has data, 59 | * otherwise an error will occur. please confirm that the parameter is correct when reading. 60 | *

61 | * Index starts at 0 instead of 1. 62 | */ 63 | private int startRow = 2; 64 | 65 | /** 66 | * Read a excel row from a file 67 | */ 68 | private File fromFile; 69 | 70 | /** 71 | * Read a excel row from a InputStream 72 | */ 73 | private InputStream fromStream; 74 | 75 | private Charset charset = StandardCharsets.UTF_8; 76 | 77 | public Reader(Class modelType) { 78 | this.modelType = modelType; 79 | } 80 | 81 | public static Reader create(Class modelType) { 82 | return new Reader<>(modelType); 83 | } 84 | 85 | public static Reader create(Class modelType, File fromFile) { 86 | return new Reader<>(modelType).from(fromFile); 87 | } 88 | 89 | public static Reader create(Class modelType, InputStream fromStream) { 90 | return new Reader<>(modelType).from(fromStream); 91 | } 92 | 93 | /** 94 | * Read row data from an Excel file 95 | * 96 | * @param fromFile excel file object 97 | * @return Reader 98 | */ 99 | public Reader from(File fromFile) { 100 | if (null == fromFile || !fromFile.exists()) { 101 | throw new IllegalArgumentException("excel file must be exist"); 102 | } 103 | this.fromFile = fromFile; 104 | return this; 105 | } 106 | 107 | /** 108 | * Read row data from an InputStream 109 | * 110 | * @param fromStream excel InputStream 111 | * @return Reader 112 | */ 113 | public Reader from(InputStream fromStream) { 114 | this.fromStream = fromStream; 115 | return this; 116 | } 117 | 118 | /** 119 | * Set the reading from the first few lines, the index starts from 0 120 | * 121 | * @param startRow start row index 122 | * @return Reader 123 | */ 124 | public Reader start(int startRow) { 125 | if (startRow < 0) { 126 | throw new IllegalArgumentException("start cannot be less than 0"); 127 | } 128 | this.startRow = startRow; 129 | return this; 130 | } 131 | 132 | /** 133 | * The setting is read from the first sheet, the default is 0 134 | * 135 | * @param sheetIndex sheet index 136 | * @return Reader 137 | */ 138 | public Reader sheet(int sheetIndex) { 139 | if (sheetIndex < 0) { 140 | throw new IllegalArgumentException("sheet cannot be less than 0"); 141 | } 142 | this.sheetIndex = sheetIndex; 143 | return this; 144 | } 145 | 146 | /** 147 | * Set the name of the sheet to be read. If you set the name, sheet will be invalid. 148 | * 149 | * @param sheetName sheet name 150 | * @return 151 | */ 152 | public Reader sheet(String sheetName) { 153 | if (StringUtil.isEmpty(sheetName)) { 154 | throw new IllegalArgumentException("sheet cannot be empty"); 155 | } 156 | this.sheetName = sheetName; 157 | return this; 158 | } 159 | 160 | public Reader charset(Charset charset){ 161 | this.charset = charset; 162 | return this; 163 | } 164 | 165 | /** 166 | * Return the read result as a Stream 167 | * 168 | * @return Stream 169 | * @throws ReaderException Thrown when an exception occurs during reading 170 | */ 171 | public Stream asStream() { 172 | if (modelType == null) { 173 | throw new IllegalArgumentException("modelType can be not null"); 174 | } 175 | 176 | if (fromFile == null && fromStream == null) { 177 | throw new IllegalArgumentException("Excel source not is null"); 178 | } 179 | 180 | if (fromFile != null) { 181 | return ReaderFactory.readByFile(this); 182 | } else { 183 | return ReaderFactory.readByStream(this); 184 | } 185 | } 186 | 187 | /** 188 | * Convert the read result to a List 189 | * 190 | * @return List 191 | * @throws ReaderException Thrown when an exception occurs during reading 192 | */ 193 | public List asList() throws ReaderException { 194 | Stream stream = this.asStream(); 195 | return stream.collect(toList()); 196 | } 197 | 198 | public Result asResult() throws ReaderException { 199 | return new Result<>(asList()); 200 | } 201 | 202 | public InputStream fromStream() { 203 | return this.fromStream; 204 | } 205 | 206 | public File fromFile() { 207 | return fromFile; 208 | } 209 | 210 | public Class modelType() { 211 | return modelType; 212 | } 213 | 214 | public int sheetIndex() { 215 | return this.sheetIndex; 216 | } 217 | 218 | public String sheetName() { 219 | return this.sheetName; 220 | } 221 | 222 | public int startRow() { 223 | return this.startRow; 224 | } 225 | 226 | public Charset charset(){ 227 | return this.charset; 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/annotation/ExcelColumn.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.annotation; 17 | 18 | import io.github.biezhi.excel.plus.conveter.Converter; 19 | import io.github.biezhi.excel.plus.conveter.NullConverter; 20 | 21 | import java.lang.annotation.ElementType; 22 | import java.lang.annotation.Retention; 23 | import java.lang.annotation.RetentionPolicy; 24 | import java.lang.annotation.Target; 25 | 26 | /** 27 | * @author biezhi 28 | * @date 2018-12-11 29 | */ 30 | @Retention(RetentionPolicy.RUNTIME) 31 | @Target(ElementType.FIELD) 32 | public @interface ExcelColumn { 33 | 34 | String title() default ""; 35 | 36 | int index() default -1; 37 | 38 | String datePattern() default ""; 39 | 40 | Class converter() default NullConverter.class; 41 | 42 | int width() default -1; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/BigIntConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | import io.github.biezhi.excel.plus.exception.ConverterException; 19 | import io.github.biezhi.excel.plus.util.StringUtil; 20 | 21 | import java.math.BigInteger; 22 | 23 | /** 24 | * BigInteger to string converter 25 | * 26 | * @author biezhi 27 | * @date 2018-12-12 28 | */ 29 | public class BigIntConverter extends NumberConverter implements Converter { 30 | 31 | @Override 32 | public BigInteger stringToR(String value) throws ConverterException { 33 | try { 34 | value = replaceComma(value); 35 | if (StringUtil.isEmpty(value)) { 36 | return null; 37 | } 38 | return new BigInteger(value); 39 | } catch (Exception e){ 40 | throw new ConverterException("convert [" + value + "] to BigInteger error", e); 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/BooleanConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | /** 19 | * Boolean to string converter 20 | * 21 | * @author biezhi 22 | * @date 2018-12-12 23 | */ 24 | public class BooleanConverter implements Converter { 25 | 26 | @Override 27 | public Boolean stringToR(String value) { 28 | return Boolean.parseBoolean(value); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/ByteConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | import io.github.biezhi.excel.plus.exception.ConverterException; 19 | 20 | /** 21 | * Byte to string converter 22 | * 23 | * @author biezhi 24 | * @date 2018-12-12 25 | */ 26 | public class ByteConverter implements Converter { 27 | 28 | @Override 29 | public Byte stringToR(String value) throws ConverterException { 30 | try { 31 | return Byte.parseByte(value); 32 | } catch (Exception e){ 33 | throw new ConverterException("convert [" + value + "] to Byte error", e); 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/Converter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | import io.github.biezhi.excel.plus.exception.ConverterException; 19 | 20 | /** 21 | * @author biezhi 22 | * @date 2018-12-12 23 | */ 24 | public interface Converter { 25 | 26 | R stringToR(String value) throws ConverterException; 27 | 28 | default java.lang.String toString(R fieldValue) throws ConverterException { 29 | if (null == fieldValue) { 30 | return null; 31 | } 32 | return fieldValue.toString(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/ConverterCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | import io.github.biezhi.excel.plus.annotation.ExcelColumn; 19 | import lombok.experimental.UtilityClass; 20 | 21 | import java.lang.reflect.Field; 22 | import java.math.BigDecimal; 23 | import java.math.BigInteger; 24 | import java.time.LocalDate; 25 | import java.time.LocalDateTime; 26 | import java.util.Date; 27 | import java.util.HashMap; 28 | import java.util.Map; 29 | 30 | /** 31 | * @author biezhi 32 | * @date 2018-12-12 33 | */ 34 | @UtilityClass 35 | public class ConverterCache { 36 | 37 | private static final Map, Converter> CONVERTER_MAP = new HashMap<>(64); 38 | 39 | static { 40 | CONVERTER_MAP.put(StringConverter.class, new StringConverter()); 41 | CONVERTER_MAP.put(IntConverter.class, new IntConverter()); 42 | CONVERTER_MAP.put(LongConverter.class, new LongConverter()); 43 | CONVERTER_MAP.put(ShortConverter.class, new ShortConverter()); 44 | CONVERTER_MAP.put(ByteConverter.class, new ByteConverter()); 45 | CONVERTER_MAP.put(BooleanConverter.class, new BooleanConverter()); 46 | CONVERTER_MAP.put(DoubleConverter.class, new DoubleConverter()); 47 | CONVERTER_MAP.put(FloatConverter.class, new FloatConverter()); 48 | CONVERTER_MAP.put(DecimalConverter.class, new DecimalConverter()); 49 | CONVERTER_MAP.put(BigIntConverter.class, new BigIntConverter()); 50 | } 51 | 52 | public static void addConvert(Converter converter) { 53 | if (null != converter) { 54 | CONVERTER_MAP.put(converter.getClass(), converter); 55 | } 56 | } 57 | 58 | public static Converter getConvert( 59 | Class type) { 60 | return CONVERTER_MAP.get(type); 61 | } 62 | 63 | public static Converter computeConvert(Field field) throws Exception { 64 | if (null == field) { 65 | return null; 66 | } 67 | 68 | Class fieldType = field.getType(); 69 | 70 | ExcelColumn column = field.getAnnotation(ExcelColumn.class); 71 | if (null != column && !NullConverter.class.equals(column.converter())) { 72 | return column.converter().newInstance(); 73 | } 74 | 75 | if (fieldType.equals(String.class)) { 76 | return ConverterCache.getConvert(StringConverter.class); 77 | } else if (fieldType.equals(int.class) || fieldType.equals(Integer.class)) { 78 | return ConverterCache.getConvert(IntConverter.class); 79 | } else if (fieldType.equals(long.class) || fieldType.equals(Long.class)) { 80 | return ConverterCache.getConvert(LongConverter.class); 81 | } else if (fieldType.equals(double.class) || fieldType.equals(Double.class)) { 82 | return ConverterCache.getConvert(DoubleConverter.class); 83 | } else if (fieldType.equals(float.class) || fieldType.equals(Float.class)) { 84 | return ConverterCache.getConvert(FloatConverter.class); 85 | } else if (fieldType.equals(short.class) || fieldType.equals(Short.class)) { 86 | return ConverterCache.getConvert(ShortConverter.class); 87 | } else if (fieldType.equals(byte.class) || fieldType.equals(Byte.class)) { 88 | return ConverterCache.getConvert(ByteConverter.class); 89 | } else if (fieldType.equals(boolean.class) || fieldType.equals(Boolean.class)) { 90 | return ConverterCache.getConvert(BooleanConverter.class); 91 | } else if (fieldType.equals(BigInteger.class)) { 92 | return ConverterCache.getConvert(BigIntConverter.class); 93 | } else if (fieldType.equals(BigDecimal.class)) { 94 | return ConverterCache.getConvert(DecimalConverter.class); 95 | } else if (fieldType.equals(Date.class)) { 96 | String pattern = field.getAnnotation(ExcelColumn.class).datePattern(); 97 | return new DateConverter(pattern); 98 | } else if (fieldType.equals(LocalDate.class)) { 99 | String pattern = field.getAnnotation(ExcelColumn.class).datePattern(); 100 | return new LocalDateConverter(pattern); 101 | } else if (fieldType.equals(LocalDateTime.class)) { 102 | String pattern = field.getAnnotation(ExcelColumn.class).datePattern(); 103 | return new LocalDateTimeConverter(pattern); 104 | } 105 | return null; 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/DateConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | import io.github.biezhi.excel.plus.exception.ConverterException; 19 | 20 | import java.text.DateFormat; 21 | import java.text.SimpleDateFormat; 22 | import java.util.Date; 23 | 24 | /** 25 | * Date to string converter 26 | * 27 | * @author biezhi 28 | * @date 2018-12-12 29 | */ 30 | public class DateConverter implements Converter { 31 | 32 | private ThreadLocal df; 33 | 34 | public DateConverter(String pattern) { 35 | this.df = ThreadLocal.withInitial(() -> new SimpleDateFormat(pattern)); 36 | } 37 | 38 | @Override 39 | public Date stringToR(String value) throws ConverterException { 40 | try { 41 | if(null == value){ 42 | return null; 43 | } 44 | return df.get().parse(value); 45 | } catch (Exception e) { 46 | throw new ConverterException("convert [" + value + "] to Date error", e); 47 | } 48 | } 49 | 50 | @Override 51 | public String toString(Date date) throws ConverterException { 52 | try { 53 | if(null == date){ 54 | return null; 55 | } 56 | return df.get().format(date); 57 | } catch (Exception e) { 58 | throw new ConverterException("convert [" + date + "] to String error", e); 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/DecimalConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | import io.github.biezhi.excel.plus.exception.ConverterException; 19 | import io.github.biezhi.excel.plus.util.StringUtil; 20 | 21 | import java.math.BigDecimal; 22 | 23 | /** 24 | * BigDecimal to string converter 25 | * 26 | * @author biezhi 27 | * @date 2018-12-12 28 | */ 29 | public class DecimalConverter extends NumberConverter implements Converter { 30 | 31 | @Override 32 | public BigDecimal stringToR(String value) throws ConverterException { 33 | try { 34 | value = super.replaceComma(value); 35 | if (StringUtil.isEmpty(value)) { 36 | return null; 37 | } 38 | return new BigDecimal(value); 39 | } catch (Exception e){ 40 | throw new ConverterException("convert [" + value + "] to BigDecimal error", e); 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/DoubleConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | import io.github.biezhi.excel.plus.exception.ConverterException; 19 | import io.github.biezhi.excel.plus.util.StringUtil; 20 | 21 | /** 22 | * Double to string converter 23 | * 24 | * @author biezhi 25 | * @date 2018-12-12 26 | */ 27 | public class DoubleConverter extends NumberConverter implements Converter { 28 | 29 | @Override 30 | public Double stringToR(String value) throws ConverterException { 31 | try { 32 | value = super.replaceComma(value); 33 | if (StringUtil.isEmpty(value)) { 34 | return null; 35 | } 36 | return Double.parseDouble(value); 37 | } catch (Exception e){ 38 | throw new ConverterException("convert [" + value + "] to Double error", e); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/FloatConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | import io.github.biezhi.excel.plus.exception.ConverterException; 19 | import io.github.biezhi.excel.plus.util.StringUtil; 20 | 21 | /** 22 | * Float to string converter 23 | * 24 | * @author biezhi 25 | * @date 2018-12-12 26 | */ 27 | public class FloatConverter extends NumberConverter implements Converter { 28 | 29 | @Override 30 | public Float stringToR(String value) throws ConverterException { 31 | try { 32 | value = super.replaceComma(value); 33 | if (StringUtil.isEmpty(value)) { 34 | return null; 35 | } 36 | return Float.parseFloat(value); 37 | } catch (Exception e){ 38 | throw new ConverterException("convert [" + value + "] to Float error", e); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/IntConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | import io.github.biezhi.excel.plus.exception.ConverterException; 19 | import io.github.biezhi.excel.plus.util.StringUtil; 20 | 21 | /** 22 | * Integer to string converter 23 | * 24 | * @author biezhi 25 | * @date 2018-12-12 26 | */ 27 | public class IntConverter extends NumberConverter implements Converter { 28 | 29 | @Override 30 | public Integer stringToR(String value) throws ConverterException { 31 | try { 32 | value = super.replaceComma(value); 33 | if (StringUtil.isEmpty(value)) { 34 | return null; 35 | } 36 | 37 | return Integer.parseInt(value); 38 | } catch (Exception e) { 39 | throw new ConverterException("convert [" + value + "] to Integer error", e); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/LocalDateConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | import io.github.biezhi.excel.plus.exception.ConverterException; 19 | 20 | import java.time.LocalDate; 21 | import java.time.LocalDateTime; 22 | import java.time.YearMonth; 23 | import java.time.format.DateTimeFormatter; 24 | import java.time.format.DateTimeParseException; 25 | 26 | /** 27 | * LocalDate to string converter 28 | * 29 | * @author biezhi 30 | * @date 2018-12-12 31 | */ 32 | public class LocalDateConverter implements Converter { 33 | 34 | private DateTimeFormatter formatter; 35 | 36 | public LocalDateConverter(String pattern) { 37 | this.formatter = DateTimeFormatter.ofPattern(pattern); 38 | } 39 | 40 | @Override 41 | public LocalDate stringToR(String value) throws ConverterException { 42 | try { 43 | if(null == value){ 44 | return null; 45 | } 46 | return LocalDate.parse(value, formatter); 47 | } catch (DateTimeParseException e) { 48 | try { 49 | YearMonth ym = YearMonth.parse(value, formatter); 50 | return ym.atDay(1); 51 | } catch (Exception e2) { 52 | throw new ConverterException("convert [" + value + "] to LocalDate error", e2); 53 | } 54 | } catch (Exception e) { 55 | throw new ConverterException("convert [" + value + "] to LocalDate error", e); 56 | } 57 | } 58 | 59 | @Override 60 | public String toString(LocalDate localDate) { 61 | if(null == localDate){ 62 | return null; 63 | } 64 | return localDate.format(formatter); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/LocalDateTimeConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | import io.github.biezhi.excel.plus.exception.ConverterException; 19 | 20 | import java.time.LocalDateTime; 21 | import java.time.format.DateTimeFormatter; 22 | 23 | /** 24 | * LocalDateTime to string converter 25 | * 26 | * @author biezhi 27 | * @date 2018-12-12 28 | */ 29 | public class LocalDateTimeConverter implements Converter { 30 | 31 | private DateTimeFormatter formatter; 32 | 33 | public LocalDateTimeConverter(String pattern) { 34 | this.formatter = DateTimeFormatter.ofPattern(pattern); 35 | } 36 | 37 | @Override 38 | public LocalDateTime stringToR(String value) throws ConverterException { 39 | try { 40 | if (null == value) { 41 | return null; 42 | } 43 | return LocalDateTime.parse(value, formatter); 44 | } catch (Exception e) { 45 | throw new ConverterException("convert [" + value + "] to LocalDateTime error", e); 46 | } 47 | } 48 | 49 | @Override 50 | public String toString(LocalDateTime localDateTime) { 51 | if (null == localDateTime) { 52 | return null; 53 | } 54 | return localDateTime.format(formatter); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/LongConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | import io.github.biezhi.excel.plus.exception.ConverterException; 19 | import io.github.biezhi.excel.plus.util.StringUtil; 20 | 21 | /** 22 | * Long to string converter 23 | * 24 | * @author biezhi 25 | * @date 2018-12-12 26 | */ 27 | public class LongConverter extends NumberConverter implements Converter { 28 | 29 | @Override 30 | public Long stringToR(String value) throws ConverterException { 31 | try { 32 | value = super.replaceComma(value); 33 | if (StringUtil.isEmpty(value)) { 34 | return null; 35 | } 36 | return Long.parseLong(value); 37 | } catch (Exception e){ 38 | throw new ConverterException("convert [" + value + "] to Long error", e); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/NullConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | /** 19 | * NullConverter 20 | * 21 | * @author biezhi 22 | * @date 2018-12-12 23 | */ 24 | public final class NullConverter implements Converter { 25 | 26 | @Override 27 | public Object stringToR(String value) { 28 | throw new RuntimeException("Not accessible here"); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/NumberConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | import io.github.biezhi.excel.plus.util.StringUtil; 19 | 20 | public abstract class NumberConverter { 21 | 22 | String replaceComma(String value) { 23 | if (StringUtil.isEmpty(value)) { 24 | return null; 25 | } 26 | value = value.replaceAll(",", ""); 27 | if(value.endsWith(".0")){ 28 | return value.substring(0, value.length() - 2); 29 | } 30 | return value; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/ShortConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | import io.github.biezhi.excel.plus.exception.ConverterException; 19 | import io.github.biezhi.excel.plus.util.StringUtil; 20 | 21 | /** 22 | * Short to string converter 23 | * 24 | * @author biezhi 25 | * @date 2018-12-12 26 | */ 27 | public class ShortConverter extends NumberConverter implements Converter { 28 | 29 | @Override 30 | public Short stringToR(String value) throws ConverterException { 31 | try { 32 | value = super.replaceComma(value); 33 | if (StringUtil.isEmpty(value)) { 34 | return null; 35 | } 36 | return Short.parseShort(value); 37 | } catch (Exception e) { 38 | throw new ConverterException("convert [" + value + "] to Integer error", e); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/conveter/StringConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.conveter; 17 | 18 | /** 19 | * String to string 20 | * 21 | * @author biezhi 22 | * @date 2018-12-12 23 | */ 24 | public class StringConverter implements Converter { 25 | 26 | @Override 27 | public String stringToR(String value) { 28 | return value; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/enums/ExcelType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.enums; 17 | 18 | /** 19 | * ExcelType 20 | * 21 | * @author biezhi 22 | * @date 2018-12-11 23 | */ 24 | public enum ExcelType { 25 | 26 | XLSX, XLS, CSV 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/exception/ConverterException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.exception; 17 | 18 | /** 19 | * ConverterException 20 | * 21 | * @author biezhi 22 | * @date 2018-12-11 23 | */ 24 | public class ConverterException extends ExcelPlusException { 25 | 26 | public ConverterException() { 27 | } 28 | 29 | public ConverterException(String message) { 30 | super(message); 31 | } 32 | 33 | public ConverterException(String message, Throwable cause) { 34 | super(message, cause); 35 | } 36 | 37 | public ConverterException(Throwable cause) { 38 | super(cause); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/exception/ExcelPlusException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.exception; 17 | 18 | /** 19 | * ExcelPlusException 20 | * 21 | * @author biezhi 22 | * @date 2018-12-11 23 | */ 24 | public class ExcelPlusException extends Exception { 25 | 26 | public ExcelPlusException() { 27 | } 28 | 29 | public ExcelPlusException(String message) { 30 | super(message); 31 | } 32 | 33 | public ExcelPlusException(String message, Throwable cause) { 34 | super(message, cause); 35 | } 36 | 37 | public ExcelPlusException(Throwable cause) { 38 | super(cause); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/exception/ReaderException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.exception; 17 | 18 | /** 19 | * ReaderException 20 | * 21 | * @author biezhi 22 | * @date 2018-12-11 23 | */ 24 | public class ReaderException extends RuntimeException { 25 | 26 | public ReaderException() { 27 | } 28 | 29 | public ReaderException(String message) { 30 | super(message); 31 | } 32 | 33 | public ReaderException(String message, Throwable cause) { 34 | super(message, cause); 35 | } 36 | 37 | public ReaderException(Throwable cause) { 38 | super(cause); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/exception/WriterException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.exception; 17 | 18 | /** 19 | * WriterException 20 | * 21 | * @author biezhi 22 | * @date 2018-12-11 23 | */ 24 | public class WriterException extends ExcelPlusException { 25 | 26 | public WriterException() { 27 | } 28 | 29 | public WriterException(String message) { 30 | super(message); 31 | } 32 | 33 | public WriterException(String message, Throwable cause) { 34 | super(message, cause); 35 | } 36 | 37 | public WriterException(Throwable cause) { 38 | super(cause); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/reader/ExcelReader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.reader; 17 | 18 | import io.github.biezhi.excel.plus.Reader; 19 | import io.github.biezhi.excel.plus.exception.ReaderException; 20 | 21 | import java.util.stream.Stream; 22 | 23 | /** 24 | * Excel Reader 25 | * 26 | * @author biezhi 27 | * @date 2018-12-11 28 | */ 29 | public interface ExcelReader { 30 | 31 | Stream readExcel(Reader reader) throws ReaderException; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/reader/ReaderConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.reader; 17 | 18 | import io.github.biezhi.excel.plus.annotation.ExcelColumn; 19 | import io.github.biezhi.excel.plus.conveter.Converter; 20 | import io.github.biezhi.excel.plus.conveter.ConverterCache; 21 | import io.github.biezhi.excel.plus.conveter.NullConverter; 22 | import io.github.biezhi.excel.plus.exception.ConverterException; 23 | import lombok.extern.slf4j.Slf4j; 24 | import org.apache.poi.ss.usermodel.Cell; 25 | import org.apache.poi.ss.usermodel.CellType; 26 | import org.apache.poi.ss.usermodel.DateUtil; 27 | import org.apache.poi.ss.usermodel.Row; 28 | 29 | import java.lang.reflect.Field; 30 | import java.util.HashMap; 31 | import java.util.Map; 32 | 33 | /** 34 | * ReaderConverter 35 | * 36 | * @author biezhi 37 | * @date 2018-12-13 38 | */ 39 | @Slf4j 40 | public class ReaderConverter { 41 | 42 | Map fieldIndexes; 43 | 44 | Map> fieldConverters; 45 | 46 | void initFieldConverter(Field[] fields) throws Exception { 47 | this.fieldConverters = new HashMap<>(); 48 | this.fieldIndexes = new HashMap<>(fields.length); 49 | 50 | for (Field field : fields) { 51 | ExcelColumn column = field.getAnnotation(ExcelColumn.class); 52 | if (null == column) { 53 | continue; 54 | } 55 | field.setAccessible(true); 56 | fieldIndexes.put(column.index(), field); 57 | 58 | Converter converter; 59 | if (NullConverter.class.equals(column.converter())) { 60 | converter = ConverterCache.computeConvert(field); 61 | } else { 62 | converter = column.converter().newInstance(); 63 | } 64 | if (null != converter) { 65 | fieldConverters.put(field, converter); 66 | } 67 | } 68 | } 69 | 70 | void writeFiledValue(Row row, Object instance, Field field) { 71 | ExcelColumn column = field.getAnnotation(ExcelColumn.class); 72 | Cell cell = row.getCell(column.index()); 73 | if (null == cell) { 74 | return; 75 | } 76 | try { 77 | Object cellValue = getCellValue(field, cell); 78 | field.set(instance, cellValue); 79 | } catch (Exception e) { 80 | log.error("write value {} to field {} failed", cell.getStringCellValue(), field.getName(), e); 81 | } 82 | } 83 | 84 | public Object getCellValue(Field field, Cell cell) throws ConverterException { 85 | return cell.getStringCellValue(); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/reader/ReaderFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.reader; 17 | 18 | import io.github.biezhi.excel.plus.Reader; 19 | import io.github.biezhi.excel.plus.exception.ReaderException; 20 | import io.github.biezhi.excel.plus.util.ExcelUtil; 21 | import lombok.experimental.UtilityClass; 22 | import lombok.extern.slf4j.Slf4j; 23 | 24 | import java.io.ByteArrayInputStream; 25 | import java.io.FileInputStream; 26 | import java.io.FileNotFoundException; 27 | import java.io.IOException; 28 | import java.util.stream.Stream; 29 | 30 | /** 31 | * Excel Reader Factory 32 | * 33 | * @author biezhi 34 | * @date 2018-12-13 35 | */ 36 | @Slf4j 37 | @UtilityClass 38 | public class ReaderFactory { 39 | 40 | public static Stream readByFile(Reader reader) { 41 | if (ExcelUtil.isXLSX(reader.fromFile())) { 42 | return new ReaderWith2007(null).readExcel(reader); 43 | } else { 44 | if (ExcelUtil.isCSV(reader.fromFile())) { 45 | try { 46 | return new ReaderWithCSV(new FileInputStream(reader.fromFile())).readExcel(reader); 47 | } catch (FileNotFoundException e) { 48 | throw new ReaderException(reader.fromFile().getName() + " not found", e); 49 | } 50 | } else if (ExcelUtil.isXLS(reader.fromFile())) { 51 | return new ReaderWith2003(ExcelUtil.create(reader.fromFile())).readExcel(reader); 52 | } else { 53 | throw new ReaderException(reader.fromFile().getName() + " is the wrong format"); 54 | } 55 | } 56 | } 57 | 58 | public static Stream readByStream(Reader reader) throws ReaderException { 59 | byte[] bytes; 60 | try { 61 | bytes = ExcelUtil.streamAsBytes(reader.fromStream()); 62 | } catch (IOException e) { 63 | throw new ReaderException(e); 64 | } 65 | 66 | if (ExcelUtil.isXLSX(new ByteArrayInputStream(bytes))) { 67 | reader.from(new ByteArrayInputStream(bytes)); 68 | return new ReaderWith2007(null).readExcel(reader); 69 | } else { 70 | if (ExcelUtil.isXLS(new ByteArrayInputStream(bytes))) { 71 | return new ReaderWith2003(ExcelUtil.create(new ByteArrayInputStream(bytes))).readExcel(reader); 72 | } else { 73 | return new ReaderWithCSV(new ByteArrayInputStream(bytes)).readExcel(reader); 74 | } 75 | } 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/reader/ReaderWith2003.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.reader; 17 | 18 | import io.github.biezhi.excel.plus.Reader; 19 | import io.github.biezhi.excel.plus.conveter.Converter; 20 | import io.github.biezhi.excel.plus.exception.ConverterException; 21 | import io.github.biezhi.excel.plus.exception.ReaderException; 22 | import io.github.biezhi.excel.plus.util.StringUtil; 23 | import lombok.extern.slf4j.Slf4j; 24 | import org.apache.poi.ss.usermodel.*; 25 | 26 | import java.lang.reflect.Field; 27 | import java.time.LocalDate; 28 | import java.time.LocalDateTime; 29 | import java.time.ZoneId; 30 | import java.util.Date; 31 | import java.util.stream.Stream; 32 | 33 | /** 34 | * Reader 2003 Excel 35 | * 36 | * @author biezhi 37 | * @date 2018-12-11 38 | */ 39 | @Slf4j 40 | public class ReaderWith2003 extends ReaderConverter implements ExcelReader { 41 | 42 | private Workbook workbook; 43 | 44 | public ReaderWith2003(Workbook workbook) { 45 | this.workbook = workbook; 46 | } 47 | 48 | @Override 49 | public Stream readExcel(Reader reader) throws ReaderException { 50 | Class type = reader.modelType(); 51 | Stream.Builder builder = Stream.builder(); 52 | try { 53 | this.initFieldConverter(type.getDeclaredFields()); 54 | Sheet sheet = getSheet(reader); 55 | 56 | int startRow = reader.startRow(); 57 | int totalRow = sheet.getPhysicalNumberOfRows(); 58 | 59 | for (int i = 0; i < totalRow; i++) { 60 | if (i < startRow) { 61 | continue; 62 | } 63 | Row row = sheet.getRow(i); 64 | if (null == row) { 65 | continue; 66 | } 67 | 68 | Object instance = type.newInstance(); 69 | for (Field field : fieldIndexes.values()) { 70 | this.writeFiledValue(row, instance, field); 71 | } 72 | builder.add((T) instance); 73 | } 74 | return builder.build(); 75 | } catch (Exception e) { 76 | throw new ReaderException(e); 77 | } 78 | } 79 | 80 | public Sheet getSheet(Reader reader) { 81 | return StringUtil.isNotEmpty(reader.sheetName()) ? 82 | workbook.getSheet(reader.sheetName()) : workbook.getSheetAt(reader.sheetIndex()); 83 | } 84 | 85 | public Object getCellValue(Field field, Cell cell) throws ConverterException { 86 | Converter converter = fieldConverters.get(field); 87 | 88 | if (null == converter) { 89 | return cell.getStringCellValue(); 90 | } 91 | if (cell.getCellType() != CellType.NUMERIC) { 92 | return converter.stringToR(cell.getStringCellValue()); 93 | } 94 | if (isDateType(field.getType())) { 95 | Date javaDate = DateUtil.getJavaDate(cell.getNumericCellValue()); 96 | if (field.getType().equals(Date.class)) { 97 | return javaDate; 98 | } else if (field.getType().equals(LocalDate.class)) { 99 | return javaDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); 100 | } else if (field.getType().equals(LocalDateTime.class)) { 101 | return javaDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); 102 | } 103 | return null; 104 | } else { 105 | return converter.stringToR(cell.getNumericCellValue() + ""); 106 | } 107 | } 108 | 109 | private boolean isDateType(Class type) { 110 | return Date.class.equals(type) || LocalDate.class.equals(type) || LocalDateTime.class.equals(type); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/reader/ReaderWith2007.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.reader; 17 | 18 | import io.github.biezhi.excel.plus.Reader; 19 | import io.github.biezhi.excel.plus.exception.ReaderException; 20 | import io.github.biezhi.excel.plus.util.StringUtil; 21 | import org.apache.poi.ooxml.util.SAXHelper; 22 | import org.apache.poi.openxml4j.exceptions.OpenXML4JException; 23 | import org.apache.poi.openxml4j.opc.OPCPackage; 24 | import org.apache.poi.openxml4j.opc.PackageAccess; 25 | import org.apache.poi.ss.usermodel.DataFormatter; 26 | import org.apache.poi.ss.usermodel.Workbook; 27 | import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable; 28 | import org.apache.poi.xssf.eventusermodel.XSSFReader; 29 | import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler; 30 | import org.apache.poi.xssf.model.SharedStrings; 31 | import org.apache.poi.xssf.model.Styles; 32 | import org.apache.poi.xssf.model.StylesTable; 33 | import org.xml.sax.ContentHandler; 34 | import org.xml.sax.InputSource; 35 | import org.xml.sax.SAXException; 36 | import org.xml.sax.XMLReader; 37 | 38 | import javax.xml.parsers.ParserConfigurationException; 39 | import java.io.IOException; 40 | import java.io.InputStream; 41 | import java.util.stream.Stream; 42 | 43 | /** 44 | * Read 2007 Excel 45 | * 46 | * @author biezhi 47 | * @date 2018-12-11 48 | */ 49 | public class ReaderWith2007 implements ExcelReader { 50 | 51 | public ReaderWith2007(Workbook workbook) { 52 | // ignore 53 | } 54 | 55 | public Stream readExcel(Reader reader) throws ReaderException { 56 | Class type = reader.modelType(); 57 | try { 58 | // The package open is instantaneous, as it should be. 59 | try (OPCPackage p = getPackage(reader)) { 60 | 61 | SheetToCSV sheetToCSV = new SheetToCSV<>(p, reader.startRow(), type); 62 | 63 | this.process(reader, sheetToCSV); 64 | 65 | Stream.Builder stream = sheetToCSV.getRowsStream(); 66 | return stream.build(); 67 | } 68 | } catch (Exception e) { 69 | throw new ReaderException(e); 70 | } 71 | } 72 | 73 | private OPCPackage getPackage(Reader reader) throws Exception { 74 | if (reader.fromFile() != null) { 75 | return OPCPackage.open(reader.fromFile(), PackageAccess.READ); 76 | } else { 77 | return OPCPackage.open(reader.fromStream()); 78 | } 79 | } 80 | 81 | /** 82 | * Initiates the processing of the XLS workbook file to CSV. 83 | * 84 | * @throws IOException If reading the data from the package fails. 85 | * @throws SAXException if parsing the XML data fails. 86 | */ 87 | public void process(Reader reader, SheetToCSV sheetToCSV) throws IOException, OpenXML4JException, SAXException { 88 | ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(sheetToCSV.getOpcPackage()); 89 | XSSFReader xssfReader = new XSSFReader(sheetToCSV.getOpcPackage()); 90 | StylesTable styles = xssfReader.getStylesTable(); 91 | XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData(); 92 | int index = 0; 93 | 94 | boolean bySheetName = StringUtil.isNotEmpty(reader.sheetName()); 95 | 96 | while (iter.hasNext()) { 97 | try (InputStream stream = iter.next()) { 98 | String sheetName = iter.getSheetName(); 99 | if (bySheetName && reader.sheetName().equals(sheetName)) { 100 | processSheet(styles, strings, sheetToCSV, stream); 101 | break; 102 | } 103 | if (!bySheetName && reader.sheetIndex() == index) { 104 | processSheet(styles, strings, sheetToCSV, stream); 105 | break; 106 | } 107 | } 108 | ++index; 109 | } 110 | } 111 | 112 | /** 113 | * Parses and shows the content of one sheet 114 | * using the specified styles and shared-strings tables. 115 | * 116 | * @param styles The table of styles that may be referenced by cells in the sheet 117 | * @param strings The table of strings that may be referenced by cells in the sheet 118 | * @param sheetInputStream The stream to read the sheet-data from. 119 | * @throws java.io.IOException An IO exception from the parser, 120 | * possibly from a byte stream or character stream 121 | * supplied by the application. 122 | * @throws SAXException if parsing the XML data fails. 123 | */ 124 | public void processSheet( 125 | Styles styles, 126 | SharedStrings strings, 127 | XSSFSheetXMLHandler.SheetContentsHandler sheetHandler, 128 | InputStream sheetInputStream) throws IOException, SAXException { 129 | 130 | DataFormatter formatter = new XLSXDataFormatter(); 131 | InputSource sheetSource = new InputSource(sheetInputStream); 132 | 133 | try { 134 | XMLReader sheetParser = SAXHelper.newXMLReader(); 135 | ContentHandler handler = new XSSFSheetXMLHandler( 136 | styles, null, strings, sheetHandler, formatter, false); 137 | sheetParser.setContentHandler(handler); 138 | sheetParser.parse(sheetSource); 139 | } catch (ParserConfigurationException e) { 140 | throw new RuntimeException("SAX parser appears to be broken - " + e.getMessage()); 141 | } 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/reader/ReaderWithCSV.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.reader; 17 | 18 | import io.github.biezhi.excel.plus.Reader; 19 | import io.github.biezhi.excel.plus.annotation.ExcelColumn; 20 | import io.github.biezhi.excel.plus.conveter.Converter; 21 | import io.github.biezhi.excel.plus.exception.ReaderException; 22 | import lombok.extern.slf4j.Slf4j; 23 | 24 | import java.io.BufferedReader; 25 | import java.io.InputStream; 26 | import java.io.InputStreamReader; 27 | import java.lang.reflect.Field; 28 | import java.util.stream.Stream; 29 | 30 | /** 31 | * CSV Reader 32 | * 33 | * @author biezhi 34 | * @date 2018-12-13 35 | */ 36 | @Slf4j 37 | public class ReaderWithCSV extends ReaderConverter implements ExcelReader { 38 | 39 | private InputStream inputStream; 40 | 41 | public ReaderWithCSV(InputStream inputStream) { 42 | this.inputStream = inputStream; 43 | } 44 | 45 | @Override 46 | public Stream readExcel(Reader reader) throws ReaderException { 47 | Class type = reader.modelType(); 48 | 49 | try { 50 | this.initFieldConverter(type.getDeclaredFields()); 51 | } catch (Exception e) { 52 | throw new ReaderException(e); 53 | } 54 | 55 | Stream.Builder builder = Stream.builder(); 56 | 57 | try (BufferedReader br = new BufferedReader( 58 | new InputStreamReader(inputStream, reader.charset()))) { 59 | 60 | int startRow = reader.startRow(); 61 | 62 | int pos = 0; 63 | String line = ""; 64 | while ((line = br.readLine()) != null) { 65 | if (pos++ < startRow) { 66 | continue; 67 | } 68 | Object instance = type.newInstance(); 69 | String[] csvLine = line.split(","); 70 | this.csvLineToInstance(instance, csvLine); 71 | builder.add((T) instance); 72 | } 73 | return builder.build(); 74 | } catch (Exception e) { 75 | throw new ReaderException(e); 76 | } 77 | } 78 | 79 | private void csvLineToInstance(Object instance, String[] csvLine) { 80 | for (Field field : fieldIndexes.values()) { 81 | ExcelColumn column = field.getAnnotation(ExcelColumn.class); 82 | try { 83 | if (csvLine.length < (column.index() + 1)) { 84 | continue; 85 | } 86 | Object cellValue = csvLine[column.index()]; 87 | Converter converter = fieldConverters.get(field); 88 | if (null != converter) { 89 | cellValue = converter.stringToR(csvLine[column.index()]); 90 | } 91 | field.set(instance, cellValue); 92 | } catch (Exception e) { 93 | log.error("write value {} to field {} failed", csvLine[column.index()], field.getName(), e); 94 | } 95 | } 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/reader/SheetToCSV.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.reader; 17 | 18 | import io.github.biezhi.excel.plus.conveter.Converter; 19 | import io.github.biezhi.excel.plus.util.ExcelUtil; 20 | import lombok.extern.slf4j.Slf4j; 21 | import org.apache.poi.openxml4j.opc.OPCPackage; 22 | import org.apache.poi.ss.util.CellAddress; 23 | import org.apache.poi.ss.util.CellReference; 24 | import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler; 25 | import org.apache.poi.xssf.usermodel.XSSFComment; 26 | 27 | import java.lang.reflect.Field; 28 | import java.util.stream.Stream; 29 | 30 | /** 31 | * Uses the XSSF Event SAX helpers to do most of the work 32 | * of parsing the Sheet XML, and outputs the contents 33 | * as a (basic) CSV. 34 | */ 35 | @Slf4j 36 | public class SheetToCSV extends ReaderConverter implements XSSFSheetXMLHandler.SheetContentsHandler { 37 | 38 | private boolean firstCellOfRow; 39 | private int currentRow = -1; 40 | private int currentCol = -1; 41 | 42 | private final OPCPackage opcPackage; 43 | private final Stream.Builder rowsStream; 44 | private final Class type; 45 | private final int startRow; 46 | 47 | private T row; 48 | 49 | public SheetToCSV(OPCPackage opcPackage, int startRow, Class type) { 50 | this.opcPackage = opcPackage; 51 | this.rowsStream = Stream.builder(); 52 | this.startRow = startRow; 53 | 54 | this.type = type; 55 | 56 | try { 57 | this.initFieldConverter(type.getDeclaredFields()); 58 | } catch (Exception e) { 59 | log.error("init field converter fail", e); 60 | } 61 | } 62 | 63 | @Override 64 | public void startRow(int rowNum) { 65 | row = null; 66 | // Prepare for this row 67 | firstCellOfRow = true; 68 | currentRow = rowNum; 69 | currentCol = -1; 70 | if (currentRow < startRow) { 71 | return; 72 | } 73 | } 74 | 75 | @Override 76 | public void endRow(int rowNum) { 77 | if (currentRow < startRow) { 78 | return; 79 | } 80 | if(null == row){ 81 | return; 82 | } 83 | rowsStream.add(row); 84 | } 85 | 86 | @Override 87 | public void cell(String cellReference, String formattedValue, 88 | XSSFComment comment) { 89 | 90 | if (currentRow < startRow) { 91 | return; 92 | } 93 | 94 | if (firstCellOfRow) { 95 | firstCellOfRow = false; 96 | } 97 | 98 | // gracefully handle missing CellRef here in a similar way as XSSFCell does 99 | if (cellReference == null) { 100 | cellReference = new CellAddress(currentRow, currentCol).formatAsString(); 101 | } 102 | 103 | currentCol = (new CellReference(cellReference)).getCol(); 104 | 105 | Field field = fieldIndexes.get(currentCol); 106 | if (null != field) { 107 | 108 | if(row == null){ 109 | row = ExcelUtil.newInstance(type); 110 | } 111 | 112 | try { 113 | Object cellValue = formattedValue; 114 | Converter converter = fieldConverters.get(field); 115 | if (null != converter) { 116 | cellValue = converter.stringToR(formattedValue); 117 | } 118 | field.set(row, cellValue); 119 | } catch (Exception e) { 120 | log.error("write field {} value fail", field.getName(), e); 121 | } 122 | } 123 | } 124 | 125 | public OPCPackage getOpcPackage() { 126 | return opcPackage; 127 | } 128 | 129 | public Stream.Builder getRowsStream() { 130 | return rowsStream; 131 | } 132 | 133 | } -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/reader/XLSXDataFormatter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.reader; 17 | 18 | import org.apache.poi.ss.usermodel.DataFormatter; 19 | 20 | /** 21 | * @author biezhi 22 | * @date 2018-12-13 23 | */ 24 | public class XLSXDataFormatter extends DataFormatter { 25 | 26 | @Override 27 | public String formatRawCellContents(double value, int formatIndex, String formatString, boolean use1904Windowing) { 28 | if ("m/d/yy".equals(formatString)) { 29 | formatString = "m/d/yyyy"; 30 | } 31 | if ("m/d/yy h:mm".equals(formatString)) { 32 | formatString = "m/d/yyyy HH:mm"; 33 | } 34 | String contents = super.formatRawCellContents(value, formatIndex, formatString, use1904Windowing); 35 | return contents; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/types/Result.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, biezhi 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.types; 17 | 18 | import java.util.*; 19 | import java.util.concurrent.atomic.AtomicInteger; 20 | 21 | /** 22 | * Excel Result 23 | * 24 | * @author biezhi 25 | * @date 2019-03-14 26 | */ 27 | public class Result { 28 | 29 | private AtomicInteger atomicSuccess = new AtomicInteger(0); 30 | private AtomicInteger atomicError = new AtomicInteger(0); 31 | 32 | private Map errorMap = new TreeMap<>(); 33 | 34 | private List rows; 35 | 36 | private List successRows; 37 | private List errorRows; 38 | 39 | public Result(List rows) { 40 | this.rows = rows; 41 | this.successRows = new ArrayList<>(rows.size()); 42 | this.errorRows = new ArrayList<>(); 43 | } 44 | 45 | public Result valid(RowPredicate rowPredicate) { 46 | for (int i = 0, size = rows.size(); i < size; i++) { 47 | Valid valid = rowPredicate.test(i + 1, rows.get(i)); 48 | if (null == valid) { 49 | continue; 50 | } 51 | if (valid.isSuccess()) { 52 | successRows.add(rows.get(i)); 53 | atomicSuccess.incrementAndGet(); 54 | } else { 55 | atomicError.incrementAndGet(); 56 | errorRows.add(rows.get(i)); 57 | errorMap.put(i + 1, valid.msg()); 58 | } 59 | } 60 | return this; 61 | } 62 | 63 | public boolean isValid() { 64 | return Integer.valueOf(rows.size()).equals(atomicSuccess.get()); 65 | } 66 | 67 | public int count() { 68 | return rows.size(); 69 | } 70 | 71 | public int successCount() { 72 | return atomicSuccess.get(); 73 | } 74 | 75 | public int errorCount() { 76 | return atomicError.get(); 77 | } 78 | 79 | public List rows() { 80 | return rows; 81 | } 82 | 83 | public List successRows() { 84 | return successRows; 85 | } 86 | 87 | public List errorRows() { 88 | return errorRows; 89 | } 90 | 91 | public List errorMessages() { 92 | return new ArrayList<>(errorMap.values()); 93 | } 94 | 95 | public Map errorMap() { 96 | return errorMap; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/types/RowPredicate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, biezhi 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.types; 17 | 18 | /** 19 | * Excel Row Predicate 20 | * 21 | * @author biezhi 22 | * @date 2019-03-14 23 | */ 24 | @FunctionalInterface 25 | public interface RowPredicate { 26 | 27 | Valid test(R r, T t); 28 | 29 | } -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/types/StyleConsumer.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.types; 2 | 3 | @FunctionalInterface 4 | public interface StyleConsumer { 5 | 6 | /** 7 | * Performs this operation on the given arguments. 8 | * 9 | * @param t the first input argument 10 | * @param u the second input argument 11 | */ 12 | U accept(T t, U u); 13 | 14 | } -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/types/Valid.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, biezhi 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.types; 17 | 18 | /** 19 | * Valid 20 | *

21 | * Used to verify compliance with rules when reading excel lines 22 | * 23 | * @author biezhi 24 | * @date 2019-03-14 25 | */ 26 | public class Valid { 27 | 28 | /** 29 | * Current row verification success identifier 30 | */ 31 | private boolean success; 32 | 33 | /** 34 | * Prompt message when verification fails 35 | */ 36 | private String msg; 37 | 38 | private Valid() { 39 | } 40 | 41 | public boolean isSuccess() { 42 | return success; 43 | } 44 | 45 | public String msg() { 46 | return msg; 47 | } 48 | 49 | public static Valid ok() { 50 | Valid valid = new Valid(); 51 | valid.success = true; 52 | return valid; 53 | } 54 | 55 | public static Valid error(String msg) { 56 | Valid valid = new Valid(); 57 | valid.success = false; 58 | valid.msg = msg; 59 | return valid; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/util/ExcelUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.util; 17 | 18 | import io.github.biezhi.excel.plus.exception.ReaderException; 19 | import lombok.experimental.UtilityClass; 20 | import org.apache.poi.hssf.usermodel.HSSFWorkbook; 21 | import org.apache.poi.ss.usermodel.Workbook; 22 | import org.apache.poi.ss.usermodel.WorkbookFactory; 23 | import org.apache.poi.xssf.usermodel.XSSFWorkbook; 24 | 25 | import java.io.*; 26 | 27 | /** 28 | * Excel Utils 29 | * 30 | * @author biezhi 31 | * @date 2018-12-11 32 | */ 33 | @UtilityClass 34 | public class ExcelUtil { 35 | 36 | public static T newInstance(Class type) { 37 | try { 38 | return type.newInstance(); 39 | } catch (Exception e) { 40 | return null; 41 | } 42 | } 43 | 44 | public static Workbook create(File file) throws ReaderException { 45 | try { 46 | return WorkbookFactory.create(file); 47 | } catch (IOException e) { 48 | throw new ReaderException(e); 49 | } 50 | } 51 | 52 | public static Workbook create(InputStream inputStream) throws ReaderException { 53 | try { 54 | return WorkbookFactory.create(inputStream); 55 | } catch (IOException e) { 56 | throw new ReaderException(e); 57 | } 58 | } 59 | 60 | public static String getFileExtension(String fileName) { 61 | int lastIndexOf = fileName.lastIndexOf("."); 62 | if (lastIndexOf == -1) { 63 | return ""; // empty extension 64 | } 65 | return fileName.substring(lastIndexOf + 1); 66 | } 67 | 68 | public static boolean isXLSX(File file) { 69 | if (null == file || !file.exists()) { 70 | return false; 71 | } 72 | String ext = getFileExtension(file.getName()); 73 | return ext.toUpperCase().equals("XLSX"); 74 | } 75 | 76 | public static boolean isXLS(File file) { 77 | if (null == file || !file.exists()) { 78 | return false; 79 | } 80 | String ext = getFileExtension(file.getName()); 81 | return ext.toUpperCase().equals("XLS"); 82 | } 83 | 84 | public static boolean isCSV(File file) { 85 | if (null == file || !file.exists()) { 86 | return false; 87 | } 88 | String ext = getFileExtension(file.getName()); 89 | return ext.toUpperCase().equals("CSV"); 90 | } 91 | 92 | public static byte[] streamAsBytes(InputStream inputStream) throws IOException { 93 | if (null == inputStream) { 94 | return null; 95 | } 96 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 97 | // Fake code simulating the copy 98 | // You can generally do better with nio if you need... 99 | // And please, unlike me, do something about the Exceptions :D 100 | byte[] buffer = new byte[1024]; 101 | int len; 102 | while ((len = inputStream.read(buffer)) > -1) { 103 | baos.write(buffer, 0, len); 104 | } 105 | baos.flush(); 106 | return baos.toByteArray(); 107 | } 108 | 109 | public static boolean isXLSX(InputStream inputStream) { 110 | try { 111 | new XSSFWorkbook(inputStream); 112 | } catch (Exception e) { 113 | return false; 114 | } 115 | return true; 116 | } 117 | 118 | public static boolean isXLS(InputStream inputStream) { 119 | try { 120 | new HSSFWorkbook(inputStream); 121 | } catch (Exception e) { 122 | return false; 123 | } 124 | return true; 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.util; 17 | 18 | import lombok.experimental.UtilityClass; 19 | 20 | /** 21 | * StringUtil 22 | * 23 | * @author biezhi 24 | * @date 2018-12-12 25 | */ 26 | @UtilityClass 27 | public class StringUtil { 28 | 29 | public static boolean isNotEmpty(String value) { 30 | return null != value && !value.isEmpty(); 31 | } 32 | 33 | public static boolean isEmpty(String value) { 34 | return null == value || value.isEmpty(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/writer/ExcelWriter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.writer; 17 | 18 | import io.github.biezhi.excel.plus.Constant; 19 | import io.github.biezhi.excel.plus.Writer; 20 | import io.github.biezhi.excel.plus.annotation.ExcelColumn; 21 | import io.github.biezhi.excel.plus.conveter.*; 22 | import io.github.biezhi.excel.plus.exception.WriterException; 23 | import io.github.biezhi.excel.plus.util.StringUtil; 24 | import lombok.extern.slf4j.Slf4j; 25 | import org.apache.poi.ss.usermodel.*; 26 | import org.apache.poi.ss.util.CellRangeAddress; 27 | import org.apache.poi.xssf.streaming.SXSSFWorkbook; 28 | 29 | import java.io.OutputStream; 30 | import java.lang.reflect.Field; 31 | import java.time.LocalDate; 32 | import java.time.LocalDateTime; 33 | import java.util.*; 34 | 35 | import static java.util.Comparator.comparingInt; 36 | 37 | /** 38 | * ExcelWriter 39 | * 40 | * @author biezhi 41 | * @date 2018-12-11 42 | */ 43 | @Slf4j 44 | public abstract class ExcelWriter { 45 | 46 | private int rowNum; 47 | private Sheet sheet; 48 | private Map fieldIndexes; 49 | private List columns; 50 | 51 | Workbook workbook; 52 | OutputStream outputStream; 53 | 54 | ExcelWriter(OutputStream outputStream) { 55 | this.outputStream = outputStream; 56 | } 57 | 58 | ExcelWriter() { 59 | } 60 | 61 | /** 62 | * Write data to Excel Sheet 63 | *

64 | * 1. create sheet 65 | * 2. write title(optional) 66 | * 3. write column header 67 | * 4. write row 68 | * 5. write to OutputStream 69 | * 70 | * @param writer excel-plus writer 71 | * @throws WriterException 72 | */ 73 | void writeSheet(Writer writer) throws WriterException { 74 | // create sheet 75 | this.sheet = workbook.createSheet(writer.sheetName()); 76 | 77 | // setting styles 78 | CellStyle headerStyle = null; 79 | CellStyle columnStyle = null; 80 | CellStyle titleStyle = null; 81 | if (null != writer.headerStyle()) { 82 | headerStyle = writer.headerStyle().accept(workbook, workbook.createCellStyle()); 83 | } 84 | if (null != writer.cellStyle()) { 85 | columnStyle = writer.cellStyle().accept(workbook, workbook.createCellStyle()); 86 | } 87 | if (null != writer.titleStyle()) { 88 | titleStyle = writer.titleStyle().accept(workbook, workbook.createCellStyle()); 89 | } 90 | 91 | if (writer.isRaw()) { 92 | writer.sheetConsumer().accept(sheet); 93 | } else { 94 | // compute the Filed to be written 95 | Collection rows = writer.rows(); 96 | Field[] fields = rows.iterator().next().getClass().getDeclaredFields(); 97 | 98 | this.fieldIndexes = new HashMap<>(fields.length); 99 | this.columns = new ArrayList<>(); 100 | 101 | for (Field field : fields) { 102 | ExcelColumn column = field.getAnnotation(ExcelColumn.class); 103 | if (null != column) { 104 | field.setAccessible(true); 105 | fieldIndexes.put(column.index(), field); 106 | columns.add(column); 107 | } 108 | } 109 | 110 | int colRowIndex = 0; 111 | // write title 112 | String title = writer.headerTitle(); 113 | if (StringUtil.isNotEmpty(title)) { 114 | Integer maxColIndex = columns.stream() 115 | .map(ExcelColumn::index) 116 | .max(comparingInt(Integer::intValue)) 117 | .get(); 118 | 119 | this.writeHeader(titleStyle, sheet, title, maxColIndex); 120 | colRowIndex = 1; 121 | } 122 | 123 | this.rowNum = writer.startRow(); 124 | if (this.rowNum == 0) { 125 | this.rowNum = colRowIndex + 1; 126 | } 127 | 128 | try { 129 | // write column header 130 | this.writeColumnNames(colRowIndex, headerStyle); 131 | 132 | // write rows 133 | for (Object row : rows) { 134 | this.writeRow(row, columnStyle); 135 | } 136 | } catch (Exception e) { 137 | log.error("write row fail", e); 138 | } 139 | } 140 | 141 | // write to OutputStream 142 | try (OutputStream os = outputStream) { 143 | workbook.write(os); 144 | if (workbook instanceof SXSSFWorkbook) { 145 | ((SXSSFWorkbook) workbook).dispose(); 146 | } 147 | } catch (Exception e) { 148 | throw new WriterException("workbook write to OutputStream error", e); 149 | } 150 | } 151 | 152 | private void writeHeader(CellStyle cellStyle, Sheet sheet, String title, int maxColIndex) { 153 | Row titleRow = sheet.createRow(0); 154 | titleRow.setHeightInPoints(50); 155 | 156 | for (int i = 0; i <= maxColIndex; i++) { 157 | Cell cell = titleRow.createCell(i); 158 | if (i == 0) { 159 | cell.setCellValue(title); 160 | } 161 | if (null != cellStyle) { 162 | cell.setCellStyle(cellStyle); 163 | } 164 | } 165 | sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, maxColIndex)); 166 | } 167 | 168 | private void writeColumnNames(int rowIndex, CellStyle headerStyle) { 169 | Row rowHead = sheet.createRow(rowIndex); 170 | for (ExcelColumn column : columns) { 171 | Cell cell = rowHead.createCell(column.index()); 172 | if (null != headerStyle) { 173 | cell.setCellStyle(headerStyle); 174 | } 175 | cell.setCellValue(column.title()); 176 | if (column.width() > 0) { 177 | sheet.setColumnWidth(column.index(), column.width()); 178 | } else { 179 | sheet.setColumnWidth(column.index(), Constant.DEFAULT_COLUMN_WIDTH); 180 | } 181 | } 182 | } 183 | 184 | private void writeRow(Object instance, CellStyle columnStyle) throws Exception { 185 | Row row = sheet.createRow(rowNum++); 186 | for (Integer index : fieldIndexes.keySet()) { 187 | Field field = fieldIndexes.get(index); 188 | if (null == field) { 189 | continue; 190 | } 191 | 192 | Object value = field.get(instance); 193 | if (value == null) { 194 | continue; 195 | } 196 | 197 | Cell cell = row.createCell(index); 198 | if (null != columnStyle) { 199 | cell.setCellStyle(columnStyle); 200 | } 201 | 202 | String fieldValue = computeColumnContent(value, field); 203 | cell.setCellValue(fieldValue); 204 | } 205 | } 206 | 207 | String computeColumnContent(Object value, Field field) throws Exception { 208 | if (field.getType().equals(String.class)) { 209 | return value.toString(); 210 | } 211 | ExcelColumn column = field.getAnnotation(ExcelColumn.class); 212 | if (!NullConverter.class.equals(column.converter())) { 213 | Converter convert = column.converter().newInstance(); 214 | ConverterCache.addConvert(convert); 215 | return convert.toString(value); 216 | } else { 217 | if (StringUtil.isNotEmpty(column.datePattern())) { 218 | String content = ""; 219 | if (Date.class.equals(field.getType())) { 220 | content = new DateConverter(column.datePattern()).toString((Date) value); 221 | } else if (LocalDate.class.equals(field.getType())) { 222 | content = new LocalDateConverter(column.datePattern()).toString((LocalDate) value); 223 | } 224 | if (LocalDateTime.class.equals(field.getType())) { 225 | content = new LocalDateTimeConverter(column.datePattern()).toString((LocalDateTime) value); 226 | } 227 | return content; 228 | } else { 229 | Converter converter = ConverterCache.computeConvert(field); 230 | if (null != converter) { 231 | return converter.toString(value); 232 | } else { 233 | return value.toString(); 234 | } 235 | } 236 | } 237 | } 238 | 239 | } 240 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/writer/ResponseWrapper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.writer; 17 | 18 | import io.github.biezhi.excel.plus.exception.WriterException; 19 | import io.github.biezhi.excel.plus.util.StringUtil; 20 | import lombok.experimental.UtilityClass; 21 | 22 | import javax.servlet.http.HttpServletResponse; 23 | import java.io.OutputStream; 24 | import java.nio.charset.StandardCharsets; 25 | 26 | import static io.github.biezhi.excel.plus.Constant.XLSX_CONTENT_TYPE; 27 | import static io.github.biezhi.excel.plus.Constant.XLS_CONTENT_TYPE; 28 | 29 | /** 30 | * Used to wrap the HttpServletResponse and download file name 31 | * 32 | * @author biezhi 33 | * @date 2018/12/12 34 | */ 35 | @UtilityClass 36 | public class ResponseWrapper { 37 | 38 | public static OutputStream createXLSX(HttpServletResponse servletResponse, String fileName) throws WriterException { 39 | servletResponse.setContentType(XLSX_CONTENT_TYPE); 40 | return create(servletResponse, fileName); 41 | } 42 | 43 | public static OutputStream createXLS(HttpServletResponse servletResponse, String fileName) throws WriterException { 44 | servletResponse.setContentType(XLS_CONTENT_TYPE); 45 | return create(servletResponse, fileName); 46 | } 47 | 48 | public static OutputStream create(HttpServletResponse servletResponse, String fileName) throws WriterException { 49 | try { 50 | if (null == servletResponse) { 51 | throw new WriterException("response instance not null"); 52 | } 53 | if (StringUtil.isEmpty(fileName)) { 54 | throw new WriterException("response file name not empty"); 55 | } 56 | fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), "ISO8859-1"); 57 | servletResponse.setHeader("Content-Disposition", "attachment; filename=" + fileName); 58 | return servletResponse.getOutputStream(); 59 | } catch (Exception e) { 60 | throw new WriterException(e); 61 | } 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/writer/WriterWith2003.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.writer; 17 | 18 | import io.github.biezhi.excel.plus.Writer; 19 | import io.github.biezhi.excel.plus.exception.WriterException; 20 | import org.apache.poi.hssf.usermodel.HSSFWorkbook; 21 | import org.apache.poi.ss.usermodel.WorkbookFactory; 22 | 23 | import java.io.IOException; 24 | import java.io.OutputStream; 25 | 26 | /** 27 | * Excel Writer by 2003 28 | * 29 | * @author biezhi 30 | * @date 2018-12-11 31 | */ 32 | public class WriterWith2003 extends ExcelWriter { 33 | 34 | public WriterWith2003(OutputStream outputStream) { 35 | super(outputStream); 36 | } 37 | 38 | @Override 39 | public void writeSheet(Writer writer) throws WriterException { 40 | if (writer.template() != null) { 41 | try { 42 | this.workbook = WorkbookFactory.create(writer.template()); 43 | super.writeSheet(writer); 44 | } catch (IOException e) { 45 | throw new WriterException(e); 46 | } 47 | } else { 48 | this.workbook = new HSSFWorkbook(); 49 | super.writeSheet(writer); 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/writer/WriterWith2007.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.writer; 17 | 18 | import io.github.biezhi.excel.plus.Writer; 19 | import io.github.biezhi.excel.plus.exception.WriterException; 20 | import org.apache.poi.ss.usermodel.WorkbookFactory; 21 | import org.apache.poi.xssf.streaming.SXSSFWorkbook; 22 | 23 | import java.io.IOException; 24 | import java.io.OutputStream; 25 | 26 | /** 27 | * Excel Writer by 2007 28 | * 29 | * @author biezhi 30 | * @date 2018-12-11 31 | */ 32 | public class WriterWith2007 extends ExcelWriter { 33 | 34 | public WriterWith2007(OutputStream outputStream) { 35 | super(outputStream); 36 | } 37 | 38 | @Override 39 | public void writeSheet(Writer writer) throws WriterException { 40 | if (writer.template() != null) { 41 | try { 42 | this.workbook = WorkbookFactory.create(writer.template()); 43 | super.writeSheet(writer); 44 | } catch (IOException e) { 45 | throw new WriterException(e); 46 | } 47 | } else { 48 | this.workbook = new SXSSFWorkbook(writer.bufferSize()); 49 | super.writeSheet(writer); 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/io/github/biezhi/excel/plus/writer/WriterWithCSV.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018, biezhi (biezhi.me@gmail.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.github.biezhi.excel.plus.writer; 17 | 18 | import io.github.biezhi.excel.plus.Writer; 19 | import io.github.biezhi.excel.plus.annotation.ExcelColumn; 20 | import io.github.biezhi.excel.plus.exception.WriterException; 21 | 22 | import java.io.IOException; 23 | import java.io.OutputStream; 24 | import java.io.OutputStreamWriter; 25 | import java.lang.reflect.Field; 26 | import java.nio.charset.StandardCharsets; 27 | import java.util.*; 28 | 29 | import static java.util.stream.Collectors.toList; 30 | 31 | /** 32 | * CSV Writer 33 | * 34 | * @author biezhi 35 | * @date 2018-12-11 36 | */ 37 | public class WriterWithCSV extends ExcelWriter { 38 | 39 | private OutputStream outputStream; 40 | private List csvLines; 41 | 42 | public WriterWithCSV(OutputStream outputStream) { 43 | this.outputStream = outputStream; 44 | } 45 | 46 | @Override 47 | public void writeSheet(Writer writer) throws WriterException { 48 | Collection rows = writer.rows(); 49 | this.parseCSVLines(rows); 50 | 51 | try (OutputStreamWriter osWriter = 52 | new OutputStreamWriter(outputStream, writer.charset())) { 53 | 54 | 55 | osWriter.write('\ufeff'); 56 | 57 | for (String[] csvLine : csvLines) { 58 | writeLine(osWriter, csvLine); 59 | } 60 | } catch (Exception e) { 61 | throw new WriterException(e); 62 | } 63 | } 64 | 65 | private void writeLine(OutputStreamWriter osWriter, String[] csvLine) throws IOException { 66 | for (int i = 0; i < csvLine.length; i++) { 67 | String col = csvLine[i]; 68 | col = null == col ? "" : col; 69 | osWriter.write(col); 70 | if (i < csvLine.length - 1) { 71 | osWriter.write(","); 72 | } 73 | } 74 | osWriter.write("\n"); 75 | } 76 | 77 | private void parseCSVLines(Collection rows) { 78 | csvLines = new ArrayList<>(rows.size()); 79 | 80 | Class type = rows.iterator().next().getClass(); 81 | Field[] fields = type.getDeclaredFields(); 82 | Map fieldIndexes = new HashMap<>(fields.length); 83 | 84 | for (Field field : fields) { 85 | ExcelColumn column = field.getAnnotation(ExcelColumn.class); 86 | if (null != column) { 87 | field.setAccessible(true); 88 | fieldIndexes.put(column.index(), field); 89 | } 90 | } 91 | 92 | List sortedFields = fieldIndexes.keySet().stream() 93 | .sorted().map(fieldIndexes::get) 94 | .collect(toList()); 95 | 96 | for (Object item : rows) { 97 | try { 98 | String[] row = parseRow(sortedFields, item); 99 | csvLines.add(row); 100 | } catch (Exception e) { 101 | e.printStackTrace(); 102 | } 103 | } 104 | } 105 | 106 | private String[] parseRow(List sortedFields, Object item) throws Exception { 107 | String[] row = new String[sortedFields.size()]; 108 | int size = sortedFields.size(); 109 | for (int i = 0; i < size; i++) { 110 | Object value = sortedFields.get(i).get(item); 111 | if (null == value) { 112 | row[i] = ""; 113 | } else { 114 | row[i] = this.computeColumnContent(value, sortedFields.get(i)); 115 | } 116 | } 117 | return row; 118 | } 119 | 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/BaseTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus; 2 | 3 | import io.github.biezhi.excel.plus.exception.WriterException; 4 | import io.github.biezhi.excel.plus.model.PerformanceTestModel; 5 | import io.github.biezhi.excel.plus.model.Sample; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | import java.math.BigDecimal; 11 | import java.nio.file.Files; 12 | import java.nio.file.Paths; 13 | import java.time.LocalDate; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.Random; 17 | import java.util.UUID; 18 | 19 | /** 20 | * Base Test 21 | * 22 | * @author biezhi 23 | * @date 2018-12-13 24 | */ 25 | @Slf4j 26 | public class BaseTest { 27 | 28 | protected final int testCount = 1_0000; 29 | // protected final int testCount = 100_0000; 30 | 31 | protected final String testFileName = "test_write_100w_rows.xlsx"; 32 | 33 | protected List buildData() { 34 | List samples = new ArrayList<>(); 35 | samples.add(new Sample(LocalDate.now(), "hello01", 101)); 36 | samples.add(new Sample(LocalDate.now(), "数据项02", 102)); 37 | samples.add(new Sample(LocalDate.now(), "数据项03", 103)); 38 | samples.add(new Sample(LocalDate.now(), "数据项04", 104)); 39 | samples.add(new Sample(LocalDate.now(), "hello05", 105)); 40 | return samples; 41 | } 42 | 43 | protected List readyData() { 44 | 45 | List data = new ArrayList<>(testCount); 46 | 47 | LocalDate now = LocalDate.now(); 48 | Random random = new Random(); 49 | 50 | for (int i = 1; i <= testCount; i++) { 51 | data.add(new PerformanceTestModel(i, UUID.randomUUID().toString(), now, 52 | new BigDecimal(String.valueOf(random.nextDouble() * 1000)).setScale(2, 0).doubleValue(), 53 | new BigDecimal(String.valueOf(random.nextDouble() * 10000)).setScale(3, 0), 54 | "15800001112", (byte) (i % 3)) 55 | ); 56 | } 57 | return data; 58 | } 59 | 60 | protected void writeTestExcel(List rows) throws WriterException { 61 | log.info("data ready !!!"); 62 | log.info("start write !!!"); 63 | 64 | Writer.create() 65 | .withRows(rows) 66 | .headerTitle("Test Write Model Excel") 67 | .to(new File(testFileName)); 68 | } 69 | 70 | protected String classPath() { 71 | return BaseTest.class.getResource("/").getPath(); 72 | } 73 | 74 | protected void deleteTempFile(String fileName) { 75 | try { 76 | Files.delete(Paths.get(fileName)); 77 | } catch (IOException e) { 78 | log.warn("delete file {} fail", fileName, e); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/ReaderTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus; 2 | 3 | import io.github.biezhi.excel.plus.exception.ReaderException; 4 | import io.github.biezhi.excel.plus.model.Sample; 5 | import org.junit.Test; 6 | 7 | import java.io.File; 8 | import java.io.FileInputStream; 9 | import java.io.FileNotFoundException; 10 | import java.util.List; 11 | import java.util.stream.Stream; 12 | 13 | import static org.junit.Assert.*; 14 | 15 | /** 16 | * {@link Reader} Test 17 | * 18 | * @author biezhi 19 | * @date 2018-12-13 20 | */ 21 | public class ReaderTest extends BaseTest { 22 | 23 | @Test 24 | public void testCreate() { 25 | Reader reader = Reader.create(null); 26 | 27 | assertNotNull(reader); 28 | 29 | assertNull(reader.modelType()); 30 | assertNull(reader.fromFile()); 31 | assertNull(reader.fromStream()); 32 | assertNull(reader.sheetName()); 33 | 34 | assertEquals(2, reader.startRow()); 35 | assertEquals(0, reader.sheetIndex()); 36 | 37 | } 38 | 39 | @Test 40 | public void testCreateByFile() throws ReaderException { 41 | Reader reader = Reader.create(Sample.class, new File(classPath() + "/SampleData.xlsx")); 42 | 43 | assertNotNull(reader); 44 | assertNotNull(reader.fromFile()); 45 | 46 | Stream stream = reader.asStream(); 47 | assertNotNull(stream); 48 | } 49 | 50 | @Test 51 | public void testCreateByStream() throws FileNotFoundException { 52 | Reader reader = Reader.create(Sample.class, new FileInputStream(new File(classPath() + "/SampleData.xlsx"))); 53 | 54 | assertNotNull(reader); 55 | assertNotNull(reader.fromStream()); 56 | 57 | Stream stream = reader.asStream(); 58 | assertNotNull(stream); 59 | } 60 | 61 | @Test(expected = IllegalArgumentException.class) 62 | public void testCreateByFileNotExist() { 63 | Reader.create(Sample.class, new File("abcd123566.xlsx")); 64 | } 65 | 66 | @Test(expected = IllegalArgumentException.class) 67 | public void testReaderFileAndStreamIsNull() throws ReaderException { 68 | Reader.create(Sample.class).asStream(); 69 | } 70 | 71 | @Test 72 | public void testReaderArgs() { 73 | Reader reader = Reader.create(Sample.class); 74 | 75 | reader.from(new File(classPath() + "/SampleData.xlsx")) 76 | .sheet(1) 77 | .start(1) 78 | .sheet("SalesOrders"); 79 | 80 | assertNotNull(reader.fromFile()); 81 | 82 | assertEquals(1, reader.startRow()); 83 | assertEquals(1, reader.sheetIndex()); 84 | assertEquals("SalesOrders", reader.sheetName()); 85 | } 86 | 87 | @Test(expected = IllegalArgumentException.class) 88 | public void testStartRowError() { 89 | Reader.create(null).start(-1); 90 | } 91 | 92 | @Test(expected = IllegalArgumentException.class) 93 | public void testSheetIndexError() { 94 | Reader.create(null).sheet(-1); 95 | } 96 | 97 | @Test(expected = IllegalArgumentException.class) 98 | public void testSheetNameError() { 99 | Reader.create(null).sheet(null); 100 | } 101 | 102 | @Test(expected = IllegalArgumentException.class) 103 | public void testModelTypeError() throws ReaderException { 104 | Reader.create(null).asList(); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/WriterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus; 2 | 3 | import io.github.biezhi.excel.plus.enums.ExcelType; 4 | import io.github.biezhi.excel.plus.exception.WriterException; 5 | import org.junit.Test; 6 | 7 | import java.io.File; 8 | import java.util.stream.Stream; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | 13 | /** 14 | * {@link Writer} Test 15 | * 16 | * @author biezhi 17 | * @date 2018-12-13 18 | */ 19 | public class WriterTest extends BaseTest { 20 | 21 | @Test 22 | public void testCreate() { 23 | Writer writer = Writer.create(); 24 | 25 | assertNotNull(writer); 26 | 27 | assertNull(writer.rows()); 28 | assertNull(writer.titleStyle()); 29 | assertNull(writer.headerStyle()); 30 | assertNull(writer.cellStyle()); 31 | assertNull(writer.sheetConsumer()); 32 | assertNull(writer.headerTitle()); 33 | 34 | 35 | assertEquals(0, writer.startRow()); 36 | assertEquals(100, writer.bufferSize()); 37 | assertEquals("Sheet0", writer.sheetName()); 38 | 39 | assertFalse(writer.isRaw()); 40 | } 41 | 42 | 43 | @Test(expected = WriterException.class) 44 | public void testRowsIsNull() throws WriterException { 45 | String fileName = "test_temp_012.xlsx"; 46 | Writer.create().to(new File(fileName)); 47 | deleteTempFile(fileName); 48 | } 49 | 50 | @Test 51 | public void testChangeStartRow() { 52 | Writer writer = Writer.create().start(10); 53 | assertNotNull(writer); 54 | assertEquals(10, writer.startRow()); 55 | } 56 | 57 | @Test 58 | public void testWithTemplate() { 59 | Writer writer = Writer.create().withTemplate(classPath() + "/template.xlsx"); 60 | 61 | assertNotNull(writer); 62 | assertNotNull(writer.template()); 63 | assertTrue(writer.template().exists()); 64 | 65 | writer = Writer.create().withTemplate(new File(classPath() + "/template.xlsx")); 66 | 67 | assertNotNull(writer); 68 | assertNotNull(writer.template()); 69 | assertTrue(writer.template().exists()); 70 | } 71 | 72 | @Test(expected = IllegalArgumentException.class) 73 | public void testNullTemplate(){ 74 | Writer.create().withTemplate((File) null); 75 | } 76 | 77 | @Test(expected = IllegalArgumentException.class) 78 | public void testNotExistTemplate(){ 79 | Writer.create().withTemplate(new File("abcd.12346")); 80 | } 81 | 82 | @Test 83 | public void testChangeBufferSize(){ 84 | Writer writer = Writer.create().bufferSize(200); 85 | 86 | assertNotNull(writer); 87 | assertEquals(200, writer.bufferSize()); 88 | } 89 | 90 | @Test 91 | public void testCreateWithArgs() throws WriterException { 92 | String fileName = "test_create_args.xlsx"; 93 | 94 | Writer writer = Writer.create(); 95 | 96 | writer.withRows(buildData()) 97 | .headerTitle("Test Title") 98 | .to(new File(fileName)); 99 | 100 | assertNotNull(writer); 101 | 102 | assertNotNull(writer.rows()); 103 | assertNotNull(writer.cellStyle()); 104 | assertNotNull(writer.headerTitle()); 105 | 106 | deleteTempFile(fileName); 107 | } 108 | 109 | @Test 110 | public void testCustomTitleStyle(){ 111 | Writer writer = Writer.create(); 112 | 113 | assertNotNull(writer); 114 | assertNotNull(writer.titleStyle()); 115 | } 116 | 117 | @Test 118 | public void testCustomHeaderStyle(){ 119 | Writer writer = Writer.create(); 120 | 121 | assertNotNull(writer); 122 | assertNotNull(writer.headerStyle()); 123 | } 124 | 125 | @Test 126 | public void testWithRaw(){ 127 | Writer writer = Writer.create().withRaw(); 128 | 129 | assertNotNull(writer); 130 | assertTrue(writer.isRaw()); 131 | } 132 | 133 | @Test 134 | public void testChangeSheetName() { 135 | String sheetName = "MySheet"; 136 | 137 | Writer writer = Writer.create(); 138 | writer.sheet(sheetName); 139 | 140 | assertEquals(sheetName, writer.sheetName()); 141 | } 142 | 143 | @Test(expected = IllegalArgumentException.class) 144 | public void testStartRowError() { 145 | Writer.create().start(-1); 146 | } 147 | 148 | @Test(expected = IllegalArgumentException.class) 149 | public void testSheetNameError() { 150 | Writer.create().sheet(null); 151 | } 152 | 153 | @Test(expected = WriterException.class) 154 | public void testToNotExistFile() throws WriterException { 155 | Writer.create().withRows(buildData()).to(new File("/a/b/c")); 156 | } 157 | 158 | @Test 159 | public void testWriteCSV() throws WriterException { 160 | String fileName = "write_csv_test.csv"; 161 | Writer.create().withRows(buildData()).to(new File(fileName)); 162 | deleteTempFile(fileName); 163 | } 164 | 165 | @Test 166 | public void testAppendWriteCSV() throws WriterException { 167 | String fileName = "append_write_csv_test.csv"; 168 | Writer.create(ExcelType.CSV).withRows(buildData()).isAppend(true).to(new File(fileName)); 169 | } 170 | 171 | } 172 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/BigIntConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.BigIntConverter; 4 | import io.github.biezhi.excel.plus.conveter.Converter; 5 | import io.github.biezhi.excel.plus.exception.ConverterException; 6 | import org.junit.Test; 7 | 8 | import java.math.BigInteger; 9 | 10 | import static org.junit.Assert.assertEquals; 11 | import static org.junit.Assert.assertNull; 12 | 13 | /** 14 | * @author biezhi 15 | * @date 2018-12-14 16 | */ 17 | public class BigIntConverterTest { 18 | 19 | private Converter converter = new BigIntConverter(); 20 | 21 | @Test 22 | public void testStringToR() throws ConverterException { 23 | BigInteger num1 = converter.stringToR("123"); 24 | assertEquals(new BigInteger("123"), num1); 25 | 26 | BigInteger num2 = converter.stringToR(Integer.MAX_VALUE + ""); 27 | assertEquals(new BigInteger(Integer.MAX_VALUE + ""), num2); 28 | 29 | assertNull(converter.stringToR(null)); 30 | } 31 | 32 | @Test(expected = ConverterException.class) 33 | public void testStringToRError() throws ConverterException { 34 | converter.stringToR("abc"); 35 | } 36 | 37 | @Test 38 | public void testToString() throws ConverterException { 39 | String value = converter.toString(new BigInteger("123")); 40 | assertEquals("123", value); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/BooleanConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.BooleanConverter; 4 | import io.github.biezhi.excel.plus.conveter.Converter; 5 | import io.github.biezhi.excel.plus.exception.ConverterException; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | /** 11 | * @author biezhi 12 | * @date 2018-12-13 13 | */ 14 | public class BooleanConverterTest { 15 | 16 | private Converter converter = new BooleanConverter(); 17 | 18 | @Test 19 | public void testStringToR() throws ConverterException { 20 | assertTrue(converter.stringToR("true")); 21 | assertFalse(converter.stringToR("false")); 22 | assertFalse(converter.stringToR("qqac")); 23 | 24 | assertTrue(converter.stringToR("TRUE")); 25 | assertFalse(converter.stringToR("FALSE")); 26 | } 27 | 28 | @Test 29 | public void testToString() throws ConverterException { 30 | assertEquals("true", converter.toString(true)); 31 | assertEquals("false", converter.toString(false)); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/ByteConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.ByteConverter; 4 | import io.github.biezhi.excel.plus.conveter.Converter; 5 | import io.github.biezhi.excel.plus.exception.ConverterException; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | 10 | /** 11 | * @author biezhi 12 | * @date 2018-12-13 13 | */ 14 | public class ByteConverterTest { 15 | 16 | private Converter converter = new ByteConverter(); 17 | 18 | @Test 19 | public void testStringToR() throws ConverterException { 20 | assertEquals(java.util.Optional.of((byte) 123).get(), converter.stringToR("123")); 21 | } 22 | 23 | @Test(expected = ConverterException.class) 24 | public void testStringToRError() throws ConverterException { 25 | converter.stringToR(Integer.MAX_VALUE + ""); 26 | converter.stringToR("abc"); 27 | } 28 | 29 | @Test 30 | public void testToString() throws ConverterException { 31 | assertEquals("123", converter.toString((byte) 123)); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/ConverterCacheTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.annotation.ExcelColumn; 4 | import io.github.biezhi.excel.plus.conveter.*; 5 | import io.github.biezhi.excel.plus.model.Sample; 6 | import org.junit.Test; 7 | 8 | import java.math.BigInteger; 9 | import java.time.LocalDateTime; 10 | import java.util.Date; 11 | 12 | import static org.junit.Assert.*; 13 | 14 | /** 15 | * @author biezhi 16 | * @date 2018-12-15 17 | */ 18 | public class ConverterCacheTest { 19 | 20 | static class NomalModel { 21 | long l1; 22 | float f1; 23 | short s1; 24 | byte b1; 25 | 26 | @ExcelColumn(datePattern = "yyyy-MM-dd") 27 | Date d1; 28 | 29 | BigInteger bi1; 30 | 31 | @ExcelColumn(datePattern = "yyyy-MM-dd HH:mm:ss") 32 | LocalDateTime ldt1; 33 | 34 | @ExcelColumn(converter = TestStatusConv.class) 35 | Integer status; 36 | 37 | @ExcelColumn 38 | String normalConvert; 39 | } 40 | 41 | @Test 42 | public void testAddConvert() { 43 | Converter converter = ConverterCache.getConvert(TestStatusConv.class); 44 | assertNull(converter); 45 | 46 | ConverterCache.addConvert(new TestStatusConv()); 47 | converter = ConverterCache.getConvert(TestStatusConv.class); 48 | assertNotNull(converter); 49 | } 50 | 51 | @Test 52 | public void testComputeConverter() throws Exception { 53 | Converter converter = ConverterCache.computeConvert(Sample.class.getDeclaredField("date")); 54 | assertNotNull(converter); 55 | assertEquals(LocalDateConverter.class, converter.getClass()); 56 | 57 | converter = ConverterCache.computeConvert(Sample.class.getDeclaredField("location")); 58 | assertNotNull(converter); 59 | assertEquals(StringConverter.class, converter.getClass()); 60 | 61 | converter = ConverterCache.computeConvert(Sample.class.getDeclaredField("proportion")); 62 | assertNotNull(converter); 63 | assertEquals(IntConverter.class, converter.getClass()); 64 | 65 | converter = ConverterCache.computeConvert(Sample.class.getDeclaredField("ss")); 66 | assertNotNull(converter); 67 | assertEquals(DoubleConverter.class, converter.getClass()); 68 | 69 | converter = ConverterCache.computeConvert(Sample.class.getDeclaredField("amount")); 70 | assertNotNull(converter); 71 | assertEquals(DecimalConverter.class, converter.getClass()); 72 | 73 | converter = ConverterCache.computeConvert(NomalModel.class.getDeclaredField("l1")); 74 | assertNotNull(converter); 75 | assertEquals(LongConverter.class, converter.getClass()); 76 | 77 | converter = ConverterCache.computeConvert(NomalModel.class.getDeclaredField("f1")); 78 | assertNotNull(converter); 79 | assertEquals(FloatConverter.class, converter.getClass()); 80 | 81 | converter = ConverterCache.computeConvert(NomalModel.class.getDeclaredField("s1")); 82 | assertNotNull(converter); 83 | assertEquals(ShortConverter.class, converter.getClass()); 84 | 85 | converter = ConverterCache.computeConvert(NomalModel.class.getDeclaredField("b1")); 86 | assertNotNull(converter); 87 | assertEquals(ByteConverter.class, converter.getClass()); 88 | 89 | converter = ConverterCache.computeConvert(NomalModel.class.getDeclaredField("d1")); 90 | assertNotNull(converter); 91 | assertEquals(DateConverter.class, converter.getClass()); 92 | 93 | converter = ConverterCache.computeConvert(NomalModel.class.getDeclaredField("bi1")); 94 | assertNotNull(converter); 95 | assertEquals(BigIntConverter.class, converter.getClass()); 96 | 97 | converter = ConverterCache.computeConvert(NomalModel.class.getDeclaredField("ldt1")); 98 | assertNotNull(converter); 99 | assertEquals(LocalDateTimeConverter.class, converter.getClass()); 100 | 101 | converter = ConverterCache.computeConvert(NomalModel.class.getDeclaredField("status")); 102 | assertNotNull(converter); 103 | assertEquals(TestStatusConv.class, converter.getClass()); 104 | 105 | assertNull(ConverterCache.computeConvert(null)); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/DateConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.Converter; 4 | import io.github.biezhi.excel.plus.conveter.DateConverter; 5 | import io.github.biezhi.excel.plus.exception.ConverterException; 6 | import org.junit.Test; 7 | 8 | import java.text.SimpleDateFormat; 9 | import java.util.Calendar; 10 | import java.util.Date; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | import static org.junit.Assert.assertNull; 14 | 15 | /** 16 | * @author biezhi 17 | * @date 2018-12-14 18 | */ 19 | public class DateConverterTest { 20 | 21 | @Test 22 | public void testStringToR() throws ConverterException { 23 | Converter converter = new DateConverter("yyyy/MM/dd"); 24 | 25 | Date date = converter.stringToR("2018/12/12"); 26 | 27 | Calendar cal = Calendar.getInstance(); 28 | cal.setTime(date); 29 | 30 | assertEquals(2018, cal.get(Calendar.YEAR)); 31 | assertEquals(12, cal.get(Calendar.MONTH) + 1); 32 | assertEquals(12, cal.get(Calendar.DAY_OF_MONTH)); 33 | 34 | assertNull(converter.stringToR(null)); 35 | } 36 | 37 | @Test(expected = ConverterException.class) 38 | public void testStringToRError() throws ConverterException { 39 | Converter converter = new DateConverter("yyyy/MM/dd"); 40 | converter.stringToR("2018-12-12"); 41 | } 42 | 43 | @Test 44 | public void testToString() throws ConverterException { 45 | Converter converter = new DateConverter("yyyy/MM/dd"); 46 | 47 | String value = converter.toString(new Date()); 48 | assertEquals(new SimpleDateFormat("yyyy/MM/dd").format(new Date()), value); 49 | 50 | assertNull(converter.toString(null)); 51 | } 52 | 53 | @Test(expected = ConverterException.class) 54 | public void testToStringError() throws ConverterException { 55 | Converter converter = new DateConverter("abcd"); 56 | converter.toString(new Date()); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/DecimalConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.Converter; 4 | import io.github.biezhi.excel.plus.conveter.DecimalConverter; 5 | import io.github.biezhi.excel.plus.exception.ConverterException; 6 | import org.junit.Test; 7 | 8 | import java.math.BigDecimal; 9 | 10 | import static org.junit.Assert.assertEquals; 11 | import static org.junit.Assert.assertNull; 12 | 13 | /** 14 | * @author biezhi 15 | * @date 2018-12-14 16 | */ 17 | public class DecimalConverterTest { 18 | 19 | private Converter converter = new DecimalConverter(); 20 | 21 | @Test 22 | public void testStringToR() throws ConverterException { 23 | assertEquals(new BigDecimal("123"), converter.stringToR("123")); 24 | assertNull(converter.stringToR(null)); 25 | } 26 | 27 | @Test(expected = ConverterException.class) 28 | public void testStringToRError() throws ConverterException { 29 | converter.stringToR("abc"); 30 | } 31 | 32 | @Test 33 | public void testToString() throws ConverterException { 34 | String value = converter.toString(new BigDecimal("123")); 35 | assertEquals("123", value); 36 | assertNull(converter.toString(null)); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/DoubleConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.Converter; 4 | import io.github.biezhi.excel.plus.conveter.DecimalConverter; 5 | import io.github.biezhi.excel.plus.conveter.DoubleConverter; 6 | import io.github.biezhi.excel.plus.exception.ConverterException; 7 | import org.junit.Test; 8 | 9 | import java.math.BigDecimal; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | import static org.junit.Assert.assertNull; 13 | 14 | /** 15 | * @author biezhi 16 | * @date 2018-12-14 17 | */ 18 | public class DoubleConverterTest { 19 | 20 | private Converter converter = new DoubleConverter(); 21 | 22 | @Test 23 | public void testStringToR() throws ConverterException { 24 | assertEquals(new Double("123"), converter.stringToR("123")); 25 | assertNull(converter.stringToR(null)); 26 | } 27 | 28 | @Test(expected = ConverterException.class) 29 | public void testStringToRError() throws ConverterException { 30 | converter.stringToR("abc"); 31 | } 32 | 33 | @Test 34 | public void testToString() throws ConverterException { 35 | assertEquals("123.0", converter.toString(new Double("123"))); 36 | assertEquals("123.0", converter.toString(123D)); 37 | assertNull(converter.toString(null)); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/FloatConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.Converter; 4 | import io.github.biezhi.excel.plus.conveter.DoubleConverter; 5 | import io.github.biezhi.excel.plus.conveter.FloatConverter; 6 | import io.github.biezhi.excel.plus.exception.ConverterException; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | import static org.junit.Assert.assertNull; 11 | 12 | /** 13 | * @author biezhi 14 | * @date 2018-12-14 15 | */ 16 | public class FloatConverterTest { 17 | 18 | private Converter converter = new FloatConverter(); 19 | 20 | @Test 21 | public void testStringToR() throws ConverterException { 22 | assertEquals(new Float("123"), converter.stringToR("123")); 23 | assertNull(converter.stringToR(null)); 24 | } 25 | 26 | @Test(expected = ConverterException.class) 27 | public void testStringToRError() throws ConverterException { 28 | converter.stringToR("abc"); 29 | } 30 | 31 | @Test 32 | public void testToString() throws ConverterException { 33 | assertEquals("123.0", converter.toString(new Float("123"))); 34 | assertEquals("123.0", converter.toString(123F)); 35 | assertNull(converter.toString(null)); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/IntConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.Converter; 4 | import io.github.biezhi.excel.plus.conveter.IntConverter; 5 | import io.github.biezhi.excel.plus.exception.ConverterException; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | import static org.junit.Assert.assertNull; 10 | 11 | /** 12 | * @author biezhi 13 | * @date 2018-12-13 14 | */ 15 | public class IntConverterTest { 16 | 17 | private Converter converter = new IntConverter(); 18 | 19 | @Test 20 | public void testStringToR() throws ConverterException { 21 | int num1 = converter.stringToR("123"); 22 | assertEquals(123, num1); 23 | 24 | int num2 = converter.stringToR(Integer.MAX_VALUE + ""); 25 | assertEquals(Integer.MAX_VALUE, num2); 26 | 27 | assertNull(converter.stringToR(null)); 28 | } 29 | 30 | @Test(expected = ConverterException.class) 31 | public void testStringToRError() throws ConverterException { 32 | converter.stringToR("abc"); 33 | converter.stringToR(Long.MAX_VALUE + ""); 34 | } 35 | 36 | @Test 37 | public void testToString() throws ConverterException { 38 | String value = converter.toString(123); 39 | assertEquals("123", value); 40 | assertNull(converter.toString(null)); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/LocalDateConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.Converter; 4 | import io.github.biezhi.excel.plus.conveter.LocalDateConverter; 5 | import io.github.biezhi.excel.plus.exception.ConverterException; 6 | import org.junit.Test; 7 | 8 | import java.time.LocalDate; 9 | import java.time.format.DateTimeFormatter; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | import static org.junit.Assert.assertNull; 13 | 14 | /** 15 | * @author biezhi 16 | * @date 2018-12-14 17 | */ 18 | public class LocalDateConverterTest { 19 | 20 | @Test 21 | public void testStringToR() throws ConverterException { 22 | Converter converter = new LocalDateConverter("yyyy/MM/dd"); 23 | 24 | LocalDate date = converter.stringToR("2018/12/12"); 25 | 26 | assertEquals(2018, date.getYear()); 27 | assertEquals(12, date.getMonthValue()); 28 | assertEquals(12, date.getDayOfMonth()); 29 | 30 | assertNull(converter.stringToR(null)); 31 | } 32 | 33 | @Test(expected = ConverterException.class) 34 | public void testStringToRError() throws ConverterException { 35 | Converter converter = new LocalDateConverter("yyyy/MM/dd"); 36 | converter.stringToR("2018-12-12"); 37 | } 38 | 39 | @Test 40 | public void testToString() throws ConverterException { 41 | Converter converter = new LocalDateConverter("yyyy/MM/dd"); 42 | 43 | String value = converter.toString(LocalDate.now()); 44 | assertEquals(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")), value); 45 | 46 | assertNull(converter.toString(null)); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/LocalDateTimeConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.Converter; 4 | import io.github.biezhi.excel.plus.conveter.LocalDateTimeConverter; 5 | import io.github.biezhi.excel.plus.exception.ConverterException; 6 | import org.junit.Test; 7 | 8 | import java.time.LocalDateTime; 9 | import java.time.format.DateTimeFormatter; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | import static org.junit.Assert.assertNull; 13 | 14 | /** 15 | * @author biezhi 16 | * @date 2018-12-14 17 | */ 18 | public class LocalDateTimeConverterTest { 19 | 20 | private final String pattern = "yyyy/MM/dd HH:mm:ss"; 21 | 22 | @Test 23 | public void testStringToR() throws ConverterException { 24 | Converter converter = new LocalDateTimeConverter(pattern); 25 | 26 | LocalDateTime date = converter.stringToR("2018/12/12 12:32:11"); 27 | 28 | assertEquals(2018, date.getYear()); 29 | assertEquals(12, date.getMonthValue()); 30 | assertEquals(12, date.getDayOfMonth()); 31 | 32 | assertNull(converter.stringToR(null)); 33 | } 34 | 35 | @Test(expected = ConverterException.class) 36 | public void testStringToRError() throws ConverterException { 37 | Converter converter = new LocalDateTimeConverter(pattern); 38 | converter.stringToR("2018-12-12"); 39 | } 40 | 41 | @Test 42 | public void testToString() throws ConverterException { 43 | Converter converter = new LocalDateTimeConverter(pattern); 44 | 45 | String value = converter.toString(LocalDateTime.now()); 46 | assertEquals(LocalDateTime.now().format(DateTimeFormatter.ofPattern(pattern)), value); 47 | 48 | assertNull(converter.toString(null)); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/LongConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.Converter; 4 | import io.github.biezhi.excel.plus.conveter.LongConverter; 5 | import io.github.biezhi.excel.plus.exception.ConverterException; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | import static org.junit.Assert.assertNull; 10 | 11 | /** 12 | * @author biezhi 13 | * @date 2018-12-13 14 | */ 15 | public class LongConverterTest { 16 | 17 | private Converter converter = new LongConverter(); 18 | 19 | @Test 20 | public void testStringToR() throws ConverterException { 21 | assertEquals(new Long("123"), converter.stringToR("123")); 22 | assertNull(converter.stringToR(null)); 23 | } 24 | 25 | @Test(expected = ConverterException.class) 26 | public void testStringToRError() throws ConverterException { 27 | converter.stringToR("abc"); 28 | converter.stringToR((Long.MAX_VALUE + 1) + ""); 29 | } 30 | 31 | @Test 32 | public void testToString() throws ConverterException { 33 | String value = converter.toString(123L); 34 | assertEquals("123", value); 35 | assertNull(converter.toString(null)); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/NullConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.NullConverter; 4 | import org.junit.Test; 5 | 6 | /** 7 | * @author biezhi 8 | * @date 2018-12-15 9 | */ 10 | public class NullConverterTest { 11 | 12 | @Test(expected = RuntimeException.class) 13 | public void testStringToR(){ 14 | new NullConverter().stringToR("hello"); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/ShortConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.Converter; 4 | import io.github.biezhi.excel.plus.conveter.DoubleConverter; 5 | import io.github.biezhi.excel.plus.conveter.ShortConverter; 6 | import io.github.biezhi.excel.plus.exception.ConverterException; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | import static org.junit.Assert.assertNull; 11 | 12 | /** 13 | * @author biezhi 14 | * @date 2018-12-14 15 | */ 16 | public class ShortConverterTest { 17 | 18 | private Converter converter = new ShortConverter(); 19 | 20 | @Test 21 | public void testStringToR() throws ConverterException { 22 | assertEquals(new Short("123"), converter.stringToR("123")); 23 | assertNull(converter.stringToR(null)); 24 | } 25 | 26 | @Test(expected = ConverterException.class) 27 | public void testStringToRError() throws ConverterException { 28 | converter.stringToR("abc"); 29 | } 30 | 31 | @Test 32 | public void testToString() throws ConverterException { 33 | assertEquals("123", converter.toString(new Short("123"))); 34 | assertEquals("123", converter.toString((short) 123)); 35 | assertNull(converter.toString(null)); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/StringConverterTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.Converter; 4 | import io.github.biezhi.excel.plus.conveter.StringConverter; 5 | import io.github.biezhi.excel.plus.exception.ConverterException; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | import static org.junit.Assert.assertNull; 10 | 11 | /** 12 | * @author biezhi 13 | * @date 2018-12-14 14 | */ 15 | public class StringConverterTest { 16 | 17 | private Converter converter = new StringConverter(); 18 | 19 | @Test 20 | public void testStringToR() throws ConverterException { 21 | assertEquals("abc", converter.stringToR("abc")); 22 | assertNull(converter.stringToR(null)); 23 | } 24 | 25 | @Test 26 | public void testToString() throws ConverterException { 27 | assertEquals("123", converter.toString("123")); 28 | assertNull(converter.toString(null)); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/converter/TestStatusConv.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.converter; 2 | 3 | import io.github.biezhi.excel.plus.conveter.Converter; 4 | 5 | public class TestStatusConv implements Converter { 6 | @Override 7 | public Integer stringToR(String value) { 8 | if ("enable".equals(value)) { 9 | return 1; 10 | } 11 | return 0; 12 | } 13 | 14 | @Override 15 | public String toString(Integer value) { 16 | if (null == value) { 17 | return null; 18 | } else if (value == 1) { 19 | return "enable"; 20 | } 21 | return "disable"; 22 | } 23 | } -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/examples/Excel2003Test.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.examples; 2 | 3 | import io.github.biezhi.excel.plus.BaseTest; 4 | import io.github.biezhi.excel.plus.Reader; 5 | import io.github.biezhi.excel.plus.Writer; 6 | import io.github.biezhi.excel.plus.enums.ExcelType; 7 | import io.github.biezhi.excel.plus.exception.ReaderException; 8 | import io.github.biezhi.excel.plus.exception.WriterException; 9 | import io.github.biezhi.excel.plus.model.Sample; 10 | import org.junit.Test; 11 | 12 | import java.io.File; 13 | import java.time.LocalDate; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | import static org.junit.Assert.assertEquals; 18 | 19 | /** 20 | * XLS Test 21 | * 22 | * @author biezhi 23 | * @date 2018-12-13 24 | */ 25 | public class Excel2003Test extends BaseTest { 26 | 27 | @Test 28 | public void testWrite2003() throws WriterException { 29 | String fileName = "sample_test.xls"; 30 | 31 | List samples = new ArrayList<>(); 32 | samples.add(new Sample(LocalDate.now(), "hello01", 101)); 33 | samples.add(new Sample(LocalDate.now(), "hello02", 102)); 34 | samples.add(new Sample(LocalDate.now(), "hello03", 103)); 35 | samples.add(new Sample(LocalDate.now(), "hello04", 104)); 36 | samples.add(new Sample(LocalDate.now(), "hello05", 105)); 37 | 38 | Writer.create(ExcelType.XLS) 39 | .headerTitle("一份简单的Excel表格") 40 | .withRows(samples) 41 | .to(new File(fileName)); 42 | 43 | // deleteTempFile(fileName); 44 | } 45 | 46 | @Test 47 | public void testRead2003() throws WriterException, ReaderException { 48 | testWrite2003(); 49 | 50 | List samples = Reader.create(Sample.class) 51 | .from(new File("sample_test.xls")) 52 | .asList(); 53 | 54 | assertEquals(5, samples.size()); 55 | assertEquals("hello01", samples.get(0).getLocation()); 56 | assertEquals("hello05", samples.get(samples.size() - 1).getLocation()); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/examples/ReaderExample.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.examples; 2 | 3 | import io.github.biezhi.excel.plus.BaseTest; 4 | import io.github.biezhi.excel.plus.Reader; 5 | import io.github.biezhi.excel.plus.types.Result; 6 | import io.github.biezhi.excel.plus.exception.ReaderException; 7 | import io.github.biezhi.excel.plus.model.Book; 8 | import io.github.biezhi.excel.plus.model.Financial; 9 | import io.github.biezhi.excel.plus.model.PerformanceTestModel; 10 | import io.github.biezhi.excel.plus.model.Sample; 11 | import io.github.biezhi.excel.plus.types.Valid; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.junit.Test; 14 | 15 | import java.io.File; 16 | import java.math.BigDecimal; 17 | import java.nio.file.Files; 18 | import java.nio.file.Paths; 19 | import java.util.List; 20 | 21 | import static java.util.stream.Collectors.toList; 22 | import static org.junit.Assert.assertEquals; 23 | 24 | /** 25 | * @author biezhi 26 | * @date 2018-12-11 27 | */ 28 | @Slf4j 29 | public class ReaderExample extends BaseTest { 30 | 31 | @Test 32 | public void testReadBasic() throws ReaderException { 33 | List financials = Reader.create(Financial.class) 34 | .from(new File(classPath() + "/FinancialSample.xlsx")) 35 | .asList(); 36 | 37 | log.info("financials size: {}", financials.size()); 38 | } 39 | 40 | @Test 41 | public void testRead100wRows() throws Exception { 42 | List rows = readyData(); 43 | writeTestExcel(rows); 44 | log.info("write done !!!"); 45 | 46 | long start = System.currentTimeMillis(); 47 | 48 | List list = Reader.create(PerformanceTestModel.class) 49 | .from(new File(testFileName)) 50 | .asList(); 51 | 52 | long end = System.currentTimeMillis(); 53 | log.info("Read " + list.size() + " rows, time consuming: " + (end - start) + "ms"); 54 | // If you want to open the file view, please comment this line 55 | Files.delete(Paths.get(testFileName)); 56 | } 57 | 58 | @Test 59 | public void testReadBySheetIndex() throws ReaderException { 60 | System.out.println(classPath()); 61 | List samples = Reader.create(Sample.class) 62 | .from(new File(classPath() + "/SampleData.xlsx")) 63 | .sheet(1) 64 | .start(1) 65 | .asList(); 66 | 67 | assertEquals(43, samples.size()); 68 | assertEquals(new BigDecimal("189.05"), samples.get(0).getAmount()); 69 | assertEquals(new BigDecimal("139.72"), samples.get(samples.size() - 1).getAmount()); 70 | } 71 | 72 | @Test 73 | public void testReadBySheetName() throws ReaderException { 74 | List samples = Reader.create(Sample.class) 75 | .from(new File(classPath() + "/SampleData.xlsx")) 76 | .sheet("SalesOrders") 77 | .start(1) 78 | .asList(); 79 | 80 | assertEquals(43, samples.size()); 81 | assertEquals(new BigDecimal("189.05"), samples.get(0).getAmount()); 82 | assertEquals(new BigDecimal("139.72"), samples.get(samples.size() - 1).getAmount()); 83 | } 84 | 85 | @Test 86 | public void testReadAndFilter() throws ReaderException { 87 | List samples = Reader.create(Sample.class) 88 | .from(new File(classPath() + "/SampleData.xlsx")) 89 | .sheet("SalesOrders") 90 | .start(1) 91 | .asStream() 92 | .filter(sample -> sample.getAmount().intValue() > 1000) 93 | .collect(toList()); 94 | 95 | assertEquals(6, samples.size()); 96 | assertEquals(new BigDecimal("1619.19"), samples.get(0).getAmount()); 97 | assertEquals(new BigDecimal("1879.06"), samples.get(samples.size() - 1).getAmount()); 98 | } 99 | 100 | @Test 101 | public void testReadAndValid() throws ReaderException { 102 | Result result = Reader.create(Sample.class) 103 | .from(new File(classPath() + "/SampleData.xlsx")) 104 | .sheet("SalesOrders") 105 | .start(1) 106 | .asResult() 107 | .valid((rowNum, item) -> { 108 | if (item.getAmount().intValue() > 1000) { 109 | return Valid.error(String.format("第 %d 行金额超过 1000", rowNum)); 110 | } 111 | return Valid.ok(); 112 | }); 113 | 114 | log.info("rows size: {}", result.count()); 115 | log.info("success rows size: {}", result.successCount()); 116 | log.info("errorMessages: {}", result.errorMessages()); 117 | 118 | assertEquals(6, result.errorCount()); 119 | assertEquals(37, result.successCount()); 120 | 121 | assertEquals(new BigDecimal("189.05"), result.successRows().get(0).getAmount()); 122 | assertEquals(new BigDecimal("1619.19"), result.errorRows().get(0).getAmount()); 123 | } 124 | 125 | @Test 126 | public void testReadCSV() { 127 | List books = Reader.create(Book.class) 128 | .from(new File(classPath() + "/book.csv")) 129 | .start(0) 130 | .asList(); 131 | 132 | log.info("{}", books); 133 | assertEquals(5, books.size()); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/examples/WriterExample.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.examples; 2 | 3 | import io.github.biezhi.excel.plus.BaseTest; 4 | import io.github.biezhi.excel.plus.Writer; 5 | import io.github.biezhi.excel.plus.enums.ExcelType; 6 | import io.github.biezhi.excel.plus.exception.WriterException; 7 | import io.github.biezhi.excel.plus.model.Book; 8 | import io.github.biezhi.excel.plus.model.PerformanceTestModel; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.apache.poi.hssf.util.HSSFColor; 11 | import org.apache.poi.ss.usermodel.Cell; 12 | import org.apache.poi.ss.usermodel.Font; 13 | import org.apache.poi.ss.usermodel.Row; 14 | import org.junit.Ignore; 15 | import org.junit.Test; 16 | 17 | import java.io.File; 18 | import java.io.FileNotFoundException; 19 | import java.io.FileOutputStream; 20 | import java.time.LocalDate; 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | /** 25 | * @author biezhi 26 | * @date 2018-12-11 27 | */ 28 | @Slf4j 29 | public class WriterExample extends BaseTest { 30 | 31 | @Test 32 | public void testWrite100wRows() throws WriterException { 33 | 34 | List rows = readyData(); 35 | 36 | long start = System.currentTimeMillis(); 37 | writeTestExcel(rows); 38 | long end = System.currentTimeMillis(); 39 | 40 | log.info("Write " + testCount + " rows, time consuming: " + (end - start) + "ms"); 41 | 42 | // If you want to open the file view, please comment this line 43 | deleteTempFile(testFileName); 44 | } 45 | 46 | @Test 47 | public void testWriteSample() throws WriterException { 48 | String fileName = "sample_test.xlsx"; 49 | 50 | Writer.create() 51 | .headerTitle("一份简单的Excel表格") 52 | .withRows(buildData()) 53 | .to(new File("sample_test.xlsx")); 54 | 55 | deleteTempFile(fileName); 56 | } 57 | 58 | @Test 59 | public void testWriteCustomStyle() throws WriterException { 60 | String fileName = "sample_custom_style_test.xlsx"; 61 | 62 | Writer.create() 63 | .headerTitle("一份自定义样式的Excel表格") 64 | .withRows(buildData()) 65 | .titleStyle((wb, style) -> { 66 | Font font = wb.createFont(); 67 | font.setFontHeightInPoints((short) 40); 68 | font.setColor(HSSFColor.HSSFColorPredefined.RED.getIndex()); 69 | style.setFont(font); 70 | return style; 71 | }) 72 | .headerStyle((wb, style) -> { 73 | Font font = wb.createFont(); 74 | font.setFontHeightInPoints((short) 20); 75 | font.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex()); 76 | style.setFont(font); 77 | return style; 78 | }) 79 | .cellStyle((wb, style) -> { 80 | Font font = wb.createFont(); 81 | font.setFontHeightInPoints((short) 20); 82 | font.setColor(HSSFColor.HSSFColorPredefined.BLUE.getIndex()); 83 | style.setFont(font); 84 | return style; 85 | }) 86 | .to(new File(fileName)); 87 | 88 | deleteTempFile(fileName); 89 | } 90 | 91 | @Test 92 | public void testWriteCustom() throws WriterException { 93 | String fileName = "sample_custom_with_raw.xlsx"; 94 | 95 | Writer.create() 96 | .withRaw() 97 | .createRow(sheet -> { 98 | sheet.setDefaultColumnWidth(30); 99 | 100 | for (int r = 0; r < 3; r++) { 101 | Row row = sheet.createRow(r); 102 | for (int c = 0; c < 5; c++) { 103 | Cell cell = row.createCell(c); 104 | cell.setCellValue("row:" + r + ", cell:" + c); 105 | } 106 | } 107 | }) 108 | .to(new File(fileName)); 109 | 110 | deleteTempFile(fileName); 111 | } 112 | 113 | @Ignore 114 | public void testWriteByTemplate() throws WriterException { 115 | String fileName = "sample_custom_with_template.xlsx"; 116 | 117 | Writer.create() 118 | .withTemplate(classPath() + "/template.xls") 119 | .withRows(buildData()) 120 | .to(new File(fileName)); 121 | 122 | deleteTempFile(fileName); 123 | } 124 | 125 | @Test 126 | public void testWriteToOutputStream() throws FileNotFoundException, WriterException { 127 | String fileName = "sample_test_to_stream.xlsx"; 128 | 129 | Writer.create() 130 | .headerTitle("一份简单的Excel表格") 131 | .withRows(buildData()) 132 | .to(new FileOutputStream(new File(fileName))); 133 | 134 | deleteTempFile(fileName); 135 | } 136 | 137 | @Test 138 | public void testWriteByCSV() throws WriterException { 139 | String fileName = "write_as_csv.csv"; 140 | 141 | Writer.create(ExcelType.CSV) 142 | .withRows(buildData()) 143 | .to(new File(fileName)); 144 | 145 | deleteTempFile(fileName); 146 | } 147 | 148 | @Test 149 | public void testWriteBookXLSX() throws WriterException { 150 | List books = new ArrayList<>(); 151 | books.add(new Book("新名字的故事", "埃莱娜·费兰特", 59.0D, LocalDate.of(2017, 4, 1))); 152 | books.add(new Book("鱼王", "Царь-рыба", 78.0D, LocalDate.of(2017, 4, 1))); 153 | books.add(new Book("不可思议的朋友", "[日] 田岛征彦", 45.0D, LocalDate.of(2017, 7, 1))); 154 | books.add(new Book("杀死一只知更鸟", "[美] 哈珀·李", 48.0D, LocalDate.of(2017, 2, 1))); 155 | books.add(new Book("现代艺术150年", " [英] 威尔·贡培兹", 65.0D, LocalDate.of(2017, 3, 1))); 156 | 157 | Writer.create() 158 | .withRows(books) 159 | .headerTitle("书籍列表 V1") 160 | .to(new File("book.xlsx")); 161 | 162 | deleteTempFile("book.xlsx"); 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/model/Book.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.model; 2 | 3 | import io.github.biezhi.excel.plus.annotation.ExcelColumn; 4 | import lombok.Data; 5 | 6 | import java.time.LocalDate; 7 | 8 | @Data 9 | public class Book { 10 | 11 | @ExcelColumn(title = "书名", index = 0) 12 | private String title; 13 | 14 | @ExcelColumn(title = "作者", index = 1) 15 | private String author; 16 | 17 | @ExcelColumn(title = "售价", index = 2) 18 | private Double price; 19 | 20 | @ExcelColumn(title = "出版日期", index = 3, datePattern = "yyyy年M月") 21 | private LocalDate publishDate; 22 | 23 | public Book() { 24 | } 25 | 26 | public Book(String title, String author, Double price, LocalDate publishDate) { 27 | this.title = title; 28 | this.author = author; 29 | this.price = price; 30 | this.publishDate = publishDate; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/model/Financial.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.model; 2 | 3 | import io.github.biezhi.excel.plus.annotation.ExcelColumn; 4 | import lombok.Data; 5 | 6 | import java.util.Date; 7 | 8 | /** 9 | * FinancialSample.xlsx Test Model 10 | * 11 | * @author biezhi 12 | * @date 2018-12-12 13 | */ 14 | @Data 15 | public class Financial { 16 | 17 | @ExcelColumn(index = 0) 18 | private String segment; 19 | 20 | @ExcelColumn(index = 1) 21 | private String country; 22 | 23 | @ExcelColumn(index = 4) 24 | private Double unitsSold; 25 | 26 | @ExcelColumn(index = 6) 27 | private String salePrice; 28 | 29 | // @ExcelColumn(index = 12, datePattern = "yyyy/M/d") 30 | @ExcelColumn(index = 12, datePattern = "M/d/yyyy") 31 | private Date date; 32 | 33 | @ExcelColumn(index = 14) 34 | private String month; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/model/Member.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.model; 2 | 3 | import io.github.biezhi.excel.plus.annotation.ExcelColumn; 4 | import lombok.Data; 5 | 6 | import java.math.BigDecimal; 7 | import java.util.Date; 8 | 9 | /** 10 | * @author biezhi 11 | * @date 2018-12-12 12 | */ 13 | @Data 14 | public class Member { 15 | 16 | @ExcelColumn(title = "卡号", index = 0) 17 | private Long cardNo; 18 | 19 | @ExcelColumn(title = "卡类型", index = 1) 20 | private String cardType; 21 | 22 | @ExcelColumn(title = "领用状态", index = 2) 23 | private String requisitionStatus; 24 | 25 | @ExcelColumn(title = "状态", index = 3) 26 | private String status; 27 | 28 | @ExcelColumn(title = "余额(元)", index = 6) 29 | private BigDecimal amount; 30 | 31 | @ExcelColumn(title = "会员", index = 7) 32 | private String nickname; 33 | 34 | @ExcelColumn(title = "性别", index = 9) 35 | private String gender; 36 | 37 | @ExcelColumn(title = "手机", index = 10) 38 | private String mobile; 39 | 40 | @ExcelColumn(title = "发卡日期", index = 14, datePattern = "M/d/yyyy HH:mm") 41 | private Date sendCardTime; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/model/PerformanceTestModel.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.model; 2 | 3 | import io.github.biezhi.excel.plus.annotation.ExcelColumn; 4 | import lombok.Data; 5 | 6 | import java.math.BigDecimal; 7 | import java.time.LocalDate; 8 | 9 | /** 10 | * 性能测试实体 11 | * 12 | * @author biezhi 13 | * @date 2018-12-13 14 | */ 15 | @Data 16 | public class PerformanceTestModel { 17 | 18 | @ExcelColumn(title = "序号", index = 0) 19 | private Integer id; 20 | 21 | @ExcelColumn(title = "UUID", index = 1, width = 50 * 256) 22 | private String uuid; 23 | 24 | @ExcelColumn(title = "日期", index = 2, datePattern = "yyyy年MM月dd日") 25 | private LocalDate date; 26 | 27 | @ExcelColumn(title = "余额", index = 3) 28 | private double amount; 29 | 30 | @ExcelColumn(title = "本金", index = 4) 31 | private BigDecimal principal; 32 | 33 | @ExcelColumn(title = "手机号", index = 5) 34 | private String mobile; 35 | 36 | @ExcelColumn(title = "状态", index = 6, converter = StatusConverter.class) 37 | private Byte status; 38 | 39 | public PerformanceTestModel() { 40 | } 41 | 42 | public PerformanceTestModel(Integer id, String uuid, LocalDate date, double amount, BigDecimal principal, String mobile, Byte status) { 43 | this.id = id; 44 | this.uuid = uuid; 45 | this.date = date; 46 | this.amount = amount; 47 | this.principal = principal; 48 | this.mobile = mobile; 49 | this.status = status; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/model/Sample.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.model; 2 | 3 | import io.github.biezhi.excel.plus.annotation.ExcelColumn; 4 | import lombok.Data; 5 | 6 | import java.math.BigDecimal; 7 | import java.time.LocalDate; 8 | 9 | /** 10 | * SampleData.xlsx Test Model 11 | * 12 | * @author biezhi 13 | * @date 2018-12-12 14 | */ 15 | @Data 16 | public class Sample { 17 | 18 | @ExcelColumn(title = "日期", index = 0, datePattern = "M/d/yy") 19 | private LocalDate date; 20 | 21 | @ExcelColumn(title = "地区", index = 1) 22 | private String location; 23 | 24 | @ExcelColumn(title = "proportion", index = 4) 25 | private int proportion; 26 | 27 | @ExcelColumn(title = "ss", index = 5) 28 | private double ss; 29 | 30 | @ExcelColumn(title = "余额", index = 6) 31 | private BigDecimal amount; 32 | 33 | public Sample() { 34 | } 35 | 36 | public Sample(LocalDate date, String location, int proportion) { 37 | this.date = date; 38 | this.location = location; 39 | this.proportion = proportion; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/model/StatusConverter.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.model; 2 | 3 | import io.github.biezhi.excel.plus.conveter.Converter; 4 | 5 | public class StatusConverter implements Converter { 6 | 7 | @Override 8 | public Byte stringToR(String value) { 9 | if ("正常".equals(value)) { 10 | return 1; 11 | } else if ("拉黑".equals(value)) { 12 | return 2; 13 | } 14 | return -1; 15 | } 16 | 17 | @Override 18 | public String toString(Byte value) { 19 | if (null == value) { 20 | return ""; 21 | } 22 | if (value == 1) { 23 | return "正常"; 24 | } else if (value == 2) { 25 | return "拉黑"; 26 | } else { 27 | return "等待"; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/reader/ReaderFactoryTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.reader; 2 | 3 | import io.github.biezhi.excel.plus.BaseTest; 4 | import io.github.biezhi.excel.plus.Reader; 5 | import io.github.biezhi.excel.plus.exception.ReaderException; 6 | import io.github.biezhi.excel.plus.model.Book; 7 | import io.github.biezhi.excel.plus.model.Sample; 8 | import org.junit.Test; 9 | 10 | import java.io.File; 11 | import java.io.FileInputStream; 12 | import java.io.FileNotFoundException; 13 | import java.util.List; 14 | import java.util.stream.Collectors; 15 | import java.util.stream.Stream; 16 | 17 | import static org.junit.Assert.assertEquals; 18 | import static org.junit.Assert.assertNotNull; 19 | 20 | /** 21 | * ReaderFactoryTest 22 | * 23 | * @author biezhi 24 | * @date 2018-12-14 25 | */ 26 | public class ReaderFactoryTest extends BaseTest { 27 | 28 | @Test 29 | public void testReadByFileXLSX() throws ReaderException { 30 | Reader reader = Reader.create(Sample.class); 31 | reader.from(new File(classPath() + "/SampleData.xlsx")).sheet(1).start(1); 32 | 33 | Stream stream = ReaderFactory.readByFile(reader); 34 | List samples = stream.collect(Collectors.toList()); 35 | 36 | assertNotNull(stream); 37 | assertNotNull(samples); 38 | assertEquals(43, samples.size()); 39 | } 40 | 41 | @Test 42 | public void testReadByFileXLS() throws ReaderException { 43 | Reader reader = Reader.create(Sample.class); 44 | reader.from(new File(classPath() + "/SampleData.xls")).sheet(1).start(1); 45 | 46 | Stream stream = ReaderFactory.readByFile(reader); 47 | List samples = stream.collect(Collectors.toList()); 48 | 49 | assertNotNull(stream); 50 | assertNotNull(samples); 51 | assertEquals(43, samples.size()); 52 | } 53 | 54 | @Test 55 | public void testReadByFileCSV() throws ReaderException { 56 | Reader reader = Reader.create(Book.class); 57 | reader.from(new File(classPath() + "/book.csv")).start(0); 58 | 59 | Stream stream = ReaderFactory.readByFile(reader); 60 | List samples = stream.collect(Collectors.toList()); 61 | 62 | assertNotNull(stream); 63 | assertNotNull(samples); 64 | assertEquals(5, samples.size()); 65 | } 66 | 67 | @Test 68 | public void testReadByStreamXLSX() throws FileNotFoundException, ReaderException { 69 | Reader reader = Reader.create(Sample.class); 70 | reader.from(new FileInputStream(new File(classPath() + "/SampleData.xlsx"))).sheet(1).start(1); 71 | 72 | Stream stream = ReaderFactory.readByStream(reader); 73 | List samples = stream.collect(Collectors.toList()); 74 | 75 | assertNotNull(stream); 76 | assertNotNull(samples); 77 | assertEquals(43, samples.size()); 78 | } 79 | 80 | @Test 81 | public void testReadByStreamXLS() throws FileNotFoundException, ReaderException { 82 | Reader reader = Reader.create(Sample.class); 83 | reader.from(new FileInputStream(new File(classPath() + "/SampleData.xls"))).sheet(1).start(1); 84 | 85 | Stream stream = ReaderFactory.readByStream(reader); 86 | List samples = stream.collect(Collectors.toList()); 87 | 88 | assertNotNull(stream); 89 | assertNotNull(samples); 90 | assertEquals(43, samples.size()); 91 | } 92 | 93 | @Test 94 | public void testReadByStreamCSV() throws FileNotFoundException, ReaderException { 95 | Reader reader = Reader.create(Book.class); 96 | reader.from(new FileInputStream(new File(classPath() + "/book.csv"))).start(0); 97 | 98 | Stream stream = ReaderFactory.readByStream(reader); 99 | List samples = stream.collect(Collectors.toList()); 100 | 101 | assertNotNull(stream); 102 | assertNotNull(samples); 103 | assertEquals(5, samples.size()); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/util/ExcelUtilTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.util; 2 | 3 | import io.github.biezhi.excel.plus.BaseTest; 4 | import io.github.biezhi.excel.plus.Reader; 5 | import io.github.biezhi.excel.plus.exception.ReaderException; 6 | import io.github.biezhi.excel.plus.reader.XLSXDataFormatter; 7 | import org.apache.poi.ss.usermodel.Workbook; 8 | import org.junit.Test; 9 | 10 | import java.io.*; 11 | 12 | import static org.junit.Assert.*; 13 | 14 | 15 | /** 16 | * @author biezhi 17 | * @date 2018-12-14 18 | */ 19 | public class ExcelUtilTest extends BaseTest { 20 | 21 | @Test 22 | public void testNewInstance() { 23 | String s = ExcelUtil.newInstance(String.class); 24 | assertNotNull(s); 25 | 26 | XLSXDataFormatter formatter = ExcelUtil.newInstance(XLSXDataFormatter.class); 27 | assertNotNull(formatter); 28 | 29 | Reader reader = ExcelUtil.newInstance(Reader.class); 30 | assertNull(reader); 31 | } 32 | 33 | @Test(expected = ReaderException.class) 34 | public void testCreateByFile() throws ReaderException { 35 | Workbook workbook = ExcelUtil.create(new File(classPath() + "/SampleData.xlsx")); 36 | 37 | assertNotNull(workbook); 38 | 39 | ExcelUtil.create(new File(classPath() + "/abc.xlsx")); 40 | } 41 | 42 | @Test(expected = FileNotFoundException.class) 43 | public void testCreateByInputStream() throws FileNotFoundException, ReaderException { 44 | Workbook workbook = ExcelUtil.create(new FileInputStream(new File(classPath() + "/SampleData.xlsx"))); 45 | 46 | assertNotNull(workbook); 47 | 48 | ExcelUtil.create(new FileInputStream(new File(classPath() + "/abc.xlsx"))); 49 | } 50 | 51 | @Test 52 | public void testGetFileExtension() { 53 | assertEquals("txt", ExcelUtil.getFileExtension("abc.txt")); 54 | assertEquals("CSV", ExcelUtil.getFileExtension("abc.CSV")); 55 | assertEquals("xls", ExcelUtil.getFileExtension("abc.xls")); 56 | assertEquals("xlsx", ExcelUtil.getFileExtension("abc.xlsx")); 57 | assertEquals("", ExcelUtil.getFileExtension("abcd")); 58 | } 59 | 60 | @Test(expected = FileNotFoundException.class) 61 | public void testIsXLSX() throws FileNotFoundException { 62 | assertTrue(ExcelUtil.isXLSX(new File(classPath() + "/SampleData.xlsx"))); 63 | assertFalse(ExcelUtil.isXLSX(new File(classPath() + "/hello.xls"))); 64 | assertFalse(ExcelUtil.isXLSX(new File(classPath() + "/SampleData.xls"))); 65 | assertFalse(ExcelUtil.isXLSX((File) null)); 66 | 67 | assertTrue(ExcelUtil.isXLSX(new FileInputStream(new File(classPath() + "/SampleData.xlsx")))); 68 | assertFalse(ExcelUtil.isXLSX(new FileInputStream(new File(classPath() + "/SampleData.xls")))); 69 | assertFalse(ExcelUtil.isXLSX((InputStream) null)); 70 | 71 | ExcelUtil.isXLSX(new FileInputStream(new File(classPath() + "/hello.xls"))); 72 | } 73 | 74 | @Test(expected = FileNotFoundException.class) 75 | public void testIsXLS() throws FileNotFoundException { 76 | assertFalse(ExcelUtil.isXLS(new File(classPath() + "/SampleData.xlsx"))); 77 | assertFalse(ExcelUtil.isXLS(new File(classPath() + "/hello.xls"))); 78 | assertFalse(ExcelUtil.isXLS((File) null)); 79 | assertTrue(ExcelUtil.isXLS(new File(classPath() + "/SampleData.xls"))); 80 | 81 | assertTrue(ExcelUtil.isXLS(new FileInputStream(new File(classPath() + "/SampleData.xls")))); 82 | assertFalse(ExcelUtil.isXLS(new FileInputStream(new File(classPath() + "/SampleData.xlsx")))); 83 | assertFalse(ExcelUtil.isXLS((InputStream) null)); 84 | 85 | ExcelUtil.isXLS(new FileInputStream(new File(classPath() + "/hello.xlsx"))); 86 | } 87 | 88 | @Test 89 | public void testIsCSV() { 90 | assertTrue(ExcelUtil.isCSV(new File(classPath() + "/book.csv"))); 91 | 92 | assertFalse(ExcelUtil.isCSV(new File(classPath() + "/book.abc"))); 93 | assertFalse(ExcelUtil.isCSV(new File(classPath() + "/hello.csv"))); 94 | assertFalse(ExcelUtil.isCSV(null)); 95 | } 96 | 97 | @Test 98 | public void testStreamAsBytes() throws IOException { 99 | assertNull(ExcelUtil.streamAsBytes(null)); 100 | 101 | InputStream inputStream = new FileInputStream(new File(classPath() + "/book.csv")); 102 | 103 | byte[] bytes = ExcelUtil.streamAsBytes(inputStream); 104 | 105 | assertNotNull(bytes); 106 | assertEquals(275, bytes.length); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/util/StringUtilTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.util; 2 | 3 | import org.junit.Test; 4 | 5 | import static junit.framework.TestCase.assertTrue; 6 | import static org.junit.Assert.assertFalse; 7 | 8 | /** 9 | * @author biezhi 10 | * @date 2018-12-14 11 | */ 12 | public class StringUtilTest { 13 | 14 | private String a = null; 15 | private String b = ""; 16 | private String c = "hello"; 17 | 18 | @Test 19 | public void testEmpty(){ 20 | assertTrue(StringUtil.isEmpty(a)); 21 | assertTrue(StringUtil.isEmpty(b)); 22 | assertFalse(StringUtil.isEmpty(c)); 23 | } 24 | 25 | @Test 26 | public void testNotEmpty(){ 27 | assertFalse(StringUtil.isNotEmpty(a)); 28 | assertFalse(StringUtil.isNotEmpty(b)); 29 | assertTrue(StringUtil.isNotEmpty(c)); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/io/github/biezhi/excel/plus/writer/ResponseWrapperTest.java: -------------------------------------------------------------------------------- 1 | package io.github.biezhi.excel.plus.writer; 2 | 3 | import io.github.biezhi.excel.plus.exception.WriterException; 4 | import org.junit.Test; 5 | 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | /** 9 | * @author biezhi 10 | * @date 2018-12-15 11 | */ 12 | public class ResponseWrapperTest { 13 | 14 | @Test(expected = WriterException.class) 15 | public void testCreate() throws WriterException { 16 | HttpServletResponse response = null; 17 | ResponseWrapper.create(response, "abc.xlsx"); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/test/resources/FinancialSample.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellokaton/excel-plus/96630e6d2fa9700890ba15c37e63aee98898bbc8/src/test/resources/FinancialSample.xlsx -------------------------------------------------------------------------------- /src/test/resources/SampleData.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellokaton/excel-plus/96630e6d2fa9700890ba15c37e63aee98898bbc8/src/test/resources/SampleData.xls -------------------------------------------------------------------------------- /src/test/resources/SampleData.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellokaton/excel-plus/96630e6d2fa9700890ba15c37e63aee98898bbc8/src/test/resources/SampleData.xlsx -------------------------------------------------------------------------------- /src/test/resources/book.csv: -------------------------------------------------------------------------------- 1 | 新名字的故事,埃莱娜·费兰特,59.0,2017年4月 2 | 鱼王,Царь-рыба,78.0,2017年4月 3 | 不可思议的朋友,[日] 田岛征彦,45.0,2017年7月 4 | 杀死一只知更鸟,[美] 哈珀·李,48.0,2017年2月 5 | 现代艺术150年, [英] 威尔·贡培兹,65.0,2017年3月 6 | -------------------------------------------------------------------------------- /src/test/resources/template.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hellokaton/excel-plus/96630e6d2fa9700890ba15c37e63aee98898bbc8/src/test/resources/template.xlsx --------------------------------------------------------------------------------