diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..17b8aab --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*.{groovy, java, kt, xml}] +#缩进风格:空格 +indent_style = space +#缩进大小 +indent_size = 4 +#换行符lf +end_of_line = lf +#字符集utf-8 +charset = utf-8 +#是否删除行尾的空格 +trim_trailing_whitespace = true +#是否在文件的最后插入一个空行 +insert_final_newline = true \ No newline at end of file diff --git a/.mvn/jvm.config b/.mvn/jvm.config new file mode 100644 index 0000000..f432c96 --- /dev/null +++ b/.mvn/jvm.config @@ -0,0 +1 @@ +-Xmx1536m \ No newline at end of file diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000..e89f07c Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..bdc03cb --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..8191cf3 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: java +jdk: openjdk8 +cache: + directories: + - $HOME/.m2 +before_install: + - chmod +x mvnw +install: + - ./mvnw install -Dgpg.skip -B -V -Dmaven.test.skip=true + - ./mvnw javadoc:javadoc \ No newline at end of file diff --git a/README.md b/README.md index f5414de..93ee305 100644 --- a/README.md +++ b/README.md @@ -1,150 +1,89 @@ +easyexcel +====================== +[![Build Status](https://travis-ci.org/alibaba/easyexcel.svg?branch=master)](https://travis-ci.org/alibaba/easyexcel) +[![Maven central](https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel) +[![License](http://img.shields.io/:license-apache-brightgreen.svg)](http://www.apache.org/licenses/LICENSE-2.0.html) + +[QQ群:662022184](//shang.qq.com/wpa/qunwpa?idkey=53d9d821b0833e3c14670f007488a61e300f00ff4f1b81fd950590d90dd80f80) + # JAVA解析Excel工具easyexcel -Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到KB级别,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便 +Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便 ## 相关文档 -* [关于软件](/abouteasyexcel.md) * [快速使用](/quickstart.md) +* [关于软件](/abouteasyexcel.md) * [常见问题](/problem.md) * [更新记事](/update.md) * [English-README](/easyexcel_en.md) -## 二方包 - - com.alibaba - easyexcel - {latestVersion} - - -## 最新版本:1.1.2-beta4 ## 维护者 姬朋飞(玉霄) ## 快速开始 ### 读Excel -测试代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/ReadTest.java](/src/test/java/com/alibaba/easyexcel/test/ReadTest.java) +DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/demo/read/ReadTest.java](/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java) -读07版小于1000行数据返回List> -``` -List data = EasyExcelFactory.read(inputStream, new Sheet(1, 0)); -``` -读07版小于1000行数据返回List -``` -List data = EasyExcelFactory.read(inputStream, new Sheet(2, 1,JavaModel.class)); -``` -读07版大于1000行数据返回List> -``` -ExcelListener excelListener = new ExcelListener(); -EasyExcelFactory.readBySax(inputStream, new Sheet(1, 1), excelListener); +```java + /** + * 最简单的读 + *

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

2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} + *

3. 直接读即可 + */ + @Test + public void simpleRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭 + EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead(); + } ``` -读07版大于1000行数据返回List -``` -ExcelListener excelListener = new ExcelListener(); -EasyExcelFactory.readBySax(inputStream, new Sheet(2, 1,JavaModel.class), excelListener); -``` -读03版方法同上 ### 写Excel -测试代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/WriteTest.java](/src/test/java/com/alibaba/easyexcel/test/WriteTest.java) -没有模板 -```OutputStream out = new FileOutputStream("/Users/jipengfei/2007.xlsx"); -ExcelWriter writer = EasyExcelFactory.getWriter(out); - -//写第一个sheet, sheet1 数据全是List 无模型映射关系 -Sheet sheet1 = new Sheet(1, 3); -sheet1.setSheetName("第一个sheet"); -//设置列宽 设置每列的宽度 -Map columnWidth = new HashMap(); -columnWidth.put(0,10000);columnWidth.put(1,40000);columnWidth.put(2,10000);columnWidth.put(3,10000); -sheet1.setColumnWidthMap(columnWidth); -sheet1.setHead(createTestListStringHead()); -//or 设置自适应宽度 -//sheet1.setAutoWidth(Boolean.TRUE); -writer.write1(createTestListObject(), sheet1); - -//写第二个sheet sheet2 模型上打有表头的注解,合并单元格 -Sheet sheet2 = new Sheet(2, 3, JavaModel1.class, "第二个sheet", null); -sheet2.setTableStyle(createTableStyle()); -writer.write(createTestListJavaMode(), sheet2); - -//写第三个sheet包含多个table情况 -Sheet sheet3 = new Sheet(3, 0); -sheet3.setSheetName("第三个sheet"); -Table table1 = new Table(1); -table1.setHead(createTestListStringHead()); -writer.write1(createTestListObject(), sheet3, table1); - -//写sheet2 模型上打有表头的注解 -Table table2 = new Table(2); -table2.setTableStyle(createTableStyle()); -table2.setClazz(JavaModel1.class); -writer.write(createTestListJavaMode(), sheet3, table2); - -//关闭资源 -writer.finish(); -out.close(); -``` -有模板 -```InputStream inputStream = new BufferedInputStream(new FileInputStream("/Users/jipengfei/temp.xlsx")); -OutputStream out = new FileOutputStream("/Users/jipengfei/2007.xlsx"); -ExcelWriter writer = EasyExcelFactory.getWriterWithTemp(inputStream,out,ExcelTypeEnum.XLSX,true); - -//写第一个sheet, sheet1 数据全是List 无模型映射关系 -Sheet sheet1 = new Sheet(1, 3); -sheet1.setSheetName("第一个sheet"); -//设置列宽 设置每列的宽度 -Map columnWidth = new HashMap(); -columnWidth.put(0,10000);columnWidth.put(1,40000);columnWidth.put(2,10000);columnWidth.put(3,10000); -sheet1.setColumnWidthMap(columnWidth); -sheet1.setHead(createTestListStringHead()); -//or 设置自适应宽度 -//sheet1.setAutoWidth(Boolean.TRUE); -writer.write1(createTestListObject(), sheet1); - -//写第二个sheet sheet2 模型上打有表头的注解,合并单元格 -Sheet sheet2 = new Sheet(2, 3, JavaModel1.class, "第二个sheet", null); -sheet2.setTableStyle(createTableStyle()); -writer.write(createTestListJavaMode(), sheet2); - -//写第三个sheet包含多个table情况 -Sheet sheet3 = new Sheet(3, 0); -sheet3.setSheetName("第三个sheet"); -Table table1 = new Table(1); -table1.setHead(createTestListStringHead()); -writer.write1(createTestListObject(), sheet3, table1); - -//写sheet2 模型上打有表头的注解 -Table table2 = new Table(2); -table2.setTableStyle(createTableStyle()); -table2.setClazz(JavaModel1.class); -writer.write(createTestListJavaMode(), sheet3, table2); - -//关闭资源 -writer.finish(); -out.close(); +DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java](/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java) +```java + /** + * 最简单的写 + *

1. 创建excel对应的实体对象 参照{@link com.alibaba.easyexcel.test.demo.write.DemoData} + *

2. 直接写即可 + */ + @Test + public void simpleWrite() { + String fileName = TestFileUtil.getPath() + "write" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 如果这里想使用03 则 传入excelType参数即可 + EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data()); + } ``` -### web下载实例写法 -``` -public class Down { - @GetMapping("/a.htm") - public void cooperation(HttpServletRequest request, HttpServletResponse response) { - ServletOutputStream out = response.getOutputStream(); - response.setContentType("multipart/form-data"); +### web上传、下载 +DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java](/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java) +```java + /** + * 文件下载 + *

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

2. 设置返回的 参数 + *

3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大 + */ + @GetMapping("download") + public void download(HttpServletResponse response) throws IOException { + response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); - response.setHeader("Content-disposition", "attachment;filename="+fileName+".xlsx"); - ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX, true); - String fileName = new String(("UserInfo " + new SimpleDateFormat("yyyy-MM-dd").format(new Date())) - .getBytes(), "UTF-8"); - Sheet sheet1 = new Sheet(1, 0); - sheet1.setSheetName("第一个sheet"); - writer.write0(getListString(), sheet1); - writer.finish(); - - out.flush(); - } + response.setHeader("Content-disposition", "attachment;filename=demo.xlsx"); + EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data()); + } + + /** + * 文件上传 + *

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

2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener} + *

3. 直接读即可 + */ + @PostMapping("upload") + @ResponseBody + public String upload(MultipartFile file) throws IOException { + EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener()).sheet().doRead(); + return "success"; } -} ``` ### 联系我们 有问题阿里同事可以通过钉钉找到我,阿里外同学可以通过git留言。其他技术非技术相关的也欢迎一起探讨。 ### 招聘&交流 -阿里巴巴新零售事业部--诚招JAVA资深开发、技术专家。有意向可以微信联系,简历可以发我邮箱jipengfei.jpf@alibaba-inc.com -或者加QQ群: 662022184 +阿里巴巴新零售事业部--诚招JAVA资深开发、技术专家。有意向可以微信联系,简历可以发我邮箱jipengfei.jpf@alibaba-inc.com \ No newline at end of file diff --git a/img/WechatIMG8.png b/img/WechatIMG8.png deleted file mode 100644 index a87e52e..0000000 Binary files a/img/WechatIMG8.png and /dev/null differ diff --git a/img/readme/quickstart/read/demo.png b/img/readme/quickstart/read/demo.png new file mode 100644 index 0000000..8bd1413 Binary files /dev/null and b/img/readme/quickstart/read/demo.png differ diff --git a/img/readme/quickstart/write/complexHeadWrite.png b/img/readme/quickstart/write/complexHeadWrite.png new file mode 100644 index 0000000..995ffc3 Binary files /dev/null and b/img/readme/quickstart/write/complexHeadWrite.png differ diff --git a/img/readme/quickstart/write/converterWrite.png b/img/readme/quickstart/write/converterWrite.png new file mode 100644 index 0000000..5c9f289 Binary files /dev/null and b/img/readme/quickstart/write/converterWrite.png differ diff --git a/img/readme/quickstart/write/customHandlerWrite.png b/img/readme/quickstart/write/customHandlerWrite.png new file mode 100644 index 0000000..41916c3 Binary files /dev/null and b/img/readme/quickstart/write/customHandlerWrite.png differ diff --git a/img/readme/quickstart/write/dynamicHeadWrite.png b/img/readme/quickstart/write/dynamicHeadWrite.png new file mode 100644 index 0000000..3b25ad7 Binary files /dev/null and b/img/readme/quickstart/write/dynamicHeadWrite.png differ diff --git a/img/readme/quickstart/write/imageWrite.png b/img/readme/quickstart/write/imageWrite.png new file mode 100644 index 0000000..c6a0c67 Binary files /dev/null and b/img/readme/quickstart/write/imageWrite.png differ diff --git a/img/readme/quickstart/write/indexWrite.png b/img/readme/quickstart/write/indexWrite.png new file mode 100644 index 0000000..8dbec17 Binary files /dev/null and b/img/readme/quickstart/write/indexWrite.png differ diff --git a/img/readme/quickstart/write/longestMatchColumnWidthWrite.png b/img/readme/quickstart/write/longestMatchColumnWidthWrite.png new file mode 100644 index 0000000..c8a0604 Binary files /dev/null and b/img/readme/quickstart/write/longestMatchColumnWidthWrite.png differ diff --git a/img/readme/quickstart/write/mergeWrite.png b/img/readme/quickstart/write/mergeWrite.png new file mode 100644 index 0000000..b631e59 Binary files /dev/null and b/img/readme/quickstart/write/mergeWrite.png differ diff --git a/img/readme/quickstart/write/repeatedWrite.png b/img/readme/quickstart/write/repeatedWrite.png new file mode 100644 index 0000000..fb204a4 Binary files /dev/null and b/img/readme/quickstart/write/repeatedWrite.png differ diff --git a/img/readme/quickstart/write/simpleWrite.png b/img/readme/quickstart/write/simpleWrite.png new file mode 100644 index 0000000..e5924b1 Binary files /dev/null and b/img/readme/quickstart/write/simpleWrite.png differ diff --git a/img/readme/quickstart/write/styleWrite.png b/img/readme/quickstart/write/styleWrite.png new file mode 100644 index 0000000..356c3a7 Binary files /dev/null and b/img/readme/quickstart/write/styleWrite.png differ diff --git a/img/readme/quickstart/write/tableWrite.png b/img/readme/quickstart/write/tableWrite.png new file mode 100644 index 0000000..0006a9e Binary files /dev/null and b/img/readme/quickstart/write/tableWrite.png differ diff --git a/img/readme/quickstart/write/templateWrite.png b/img/readme/quickstart/write/templateWrite.png new file mode 100644 index 0000000..75f7cb1 Binary files /dev/null and b/img/readme/quickstart/write/templateWrite.png differ diff --git a/img/readme/quickstart/write/widthAndHeightWrite.png b/img/readme/quickstart/write/widthAndHeightWrite.png new file mode 100644 index 0000000..d59d897 Binary files /dev/null and b/img/readme/quickstart/write/widthAndHeightWrite.png differ diff --git a/img/readme/wechat.png b/img/readme/wechat.png new file mode 100644 index 0000000..b805760 Binary files /dev/null and b/img/readme/wechat.png differ diff --git a/img/style/eclipse/step.jpg b/img/style/eclipse/step.jpg new file mode 100644 index 0000000..fcbb857 Binary files /dev/null and b/img/style/eclipse/step.jpg differ diff --git a/img/style/idea/step1.png b/img/style/idea/step1.png new file mode 100644 index 0000000..d4a39f5 Binary files /dev/null and b/img/style/idea/step1.png differ diff --git a/img/style/idea/step2.png b/img/style/idea/step2.png new file mode 100644 index 0000000..2dd0414 Binary files /dev/null and b/img/style/idea/step2.png differ diff --git a/img/style/idea/step3.png b/img/style/idea/step3.png new file mode 100644 index 0000000..2fbde4a Binary files /dev/null and b/img/style/idea/step3.png differ diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..d560832 --- /dev/null +++ b/mvnw @@ -0,0 +1,305 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..d06ac67 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,172 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + echo Found %WRAPPER_JAR% +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.3/maven-wrapper-0.5.3.jar" + ) + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml index f0270b6..f85fd40 100644 --- a/pom.xml +++ b/pom.xml @@ -1,10 +1,10 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.alibaba easyexcel - 1.1.2-beta5 + 2.0.0-beta1 jar easyexcel @@ -26,11 +26,11 @@ - - - - - + + + + + @@ -59,25 +59,65 @@ org.apache.poi poi - 3.17 + 4.0.1 org.apache.poi poi-ooxml - 3.17 + 4.0.1 cglib cglib 3.1 + + org.slf4j + slf4j-api + 1.7.26 + + + org.ehcache + ehcache + 3.7.1 + + + + ch.qos.logback + logback-classic + 1.2.3 + test + + + com.alibaba + fastjson + 1.2.58 + test + + + org.projectlombok + lombok + 1.18.8 + test + + + org.springframework.boot + spring-boot + 1.5.21.RELEASE + test + + + org.springframework.boot + spring-boot-starter-web + 1.5.21.RELEASE + test + junit junit 4.12 test - @@ -92,6 +132,48 @@ + + + org.apache.maven.plugins + maven-pmd-plugin + 3.12.0 + + true + true + + rulesets/java/ali-comment.xml + rulesets/java/ali-concurrent.xml + rulesets/java/ali-constant.xml + rulesets/java/ali-exception.xml + rulesets/java/ali-flowcontrol.xml + rulesets/java/ali-naming.xml + rulesets/java/ali-oop.xml + rulesets/java/ali-orm.xml + rulesets/java/ali-other.xml + rulesets/java/ali-set.xml + + + com/alibaba/excel/event/AnalysisEventListener.java + + + + + + pmd-check-verify + validate + + check + + + + + + com.alibaba.p3c + p3c-pmd + 2.0.0 + + + org.apache.maven.plugins maven-compiler-plugin @@ -132,7 +214,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.9.1 + 3.1.0 attach-javadocs @@ -144,4 +226,4 @@ - \ No newline at end of file + diff --git a/quickstart.md b/quickstart.md index afba795..6312800 100644 --- a/quickstart.md +++ b/quickstart.md @@ -1,365 +1,902 @@ # easyexcel核心功能 +## 目录 +### 读 +DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/demo/read/ReadTest.java](/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java) +* [最简单的读](#simpleRead) +* [指定列的下标或者列名](#indexOrNameRead) +* [读多个sheet](#repeatedRead) +* [日期、数字或者自定义格式转换](#converterRead) +* [多行头](#complexHeaderRead) +* [同步的返回](#synchronousRead) +* [web中的读](#webRead) +### 写 +DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java](/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java) +* [最简单的写](#simpleWrite) +* [指定写入的列](#indexWrite) +* [复杂头写入](#complexHeadWrite) +* [重复多次写入](#repeatedWrite) +* [日期、数字或者自定义格式转换](#converterWrite) +* [图片导出](#imageWrite) +* [根据模板写入](#templateWrite) +* [列宽、行高](#widthAndHeightWrite) +* [自定义样式](#styleWrite) +* [合并单元格](#mergeWrite) +* [使用table去写入](#tableWrite) +* [动态头,实时生成头写入](#dynamicHeadWrite) +* [自动列宽(不太精确)](#longestMatchColumnWidthWrite) +* [自定义拦截器(下拉,超链接等上面几点都不符合但是要对单元格进行操作的参照这个)](#customHandlerWrite) +* [web中的写](#webWrite) + +## 读excel样例 +### 最简单的读 +##### excel示例 +![img](img/readme/quickstart/read/demo.png) +##### 对象 +```java +@Data +public class DemoData { + private String string; + private Date date; + private Double doubleData; +} +``` +##### 监听器 +```java +public class DemoDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static final int BATCH_COUNT = 5; + List list = new ArrayList(); + + @Override + public void invoke(DemoData data, AnalysisContext context) { + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + list.add(data); + if (list.size() >= BATCH_COUNT) { + saveData(); + list.clear(); + } + } -## *读任意大小的03、07版Excel不会OO]
-## *读Excel自动通过注解,把结果映射为java模型
-## *读Excel支持多sheet
-## *读Excel时候是否对Excel内容做trim()增加容错
-## *写小量数据的03版Excel(不要超过2000行)
-## *写任意大07版Excel不会OOM
-## *写Excel通过注解将表头自动写入Excel
-## *写Excel可以自定义Excel样式 如:字体,加粗,表头颜色,数据内容颜色
-## *写Excel到多个不同sheet
-## *写Excel时一个sheet可以写多个Table
-## *写Excel时候自定义是否需要写表头
- -## 二方包依赖 - -使用前最好咨询下最新版,或者到mvn仓库搜索先easyexcel的最新版 + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + saveData(); + LOGGER.info("所有数据解析完成!"); + } + /** + * 加上存储数据库 + */ + private void saveData() { + LOGGER.info("{}条数据,开始存储数据库!", list.size()); + LOGGER.info("存储数据库成功!"); + } +} ``` - - com.alibaba - easyexcel - 1.0.0-RELEASE - +##### 代码 +```java + /** + * 最简单的读 + *

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

2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} + *

3. 直接读即可 + */ + @Test + public void simpleRead() { + // 写法1: + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭 + EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead(); + + // 写法2: + fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build(); + ReadSheet readSheet = EasyExcel.readSheet(0).build(); + excelReader.read(readSheet); + // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的 + excelReader.finish(); + } ``` -## 读Excel -使用easyexcel解析03、07版本的Excel只是ExcelTypeEnum不同,其他使用完全相同,使用者无需知道底层解析的差异。 - -### 无java模型直接把excel解析的每行结果以List<String>返回 在ExcelListener获取解析结果 - -读excel代码示例如下: +### 指定列的下标或者列名 +##### excel示例 +参照:[excel示例](#simpleReadExcel) +##### 对象 +```java +@Data +public class IndexOrNameData { + /** + * 强制读取第三个 这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配 + */ + @ExcelProperty(index = 2) + private Double doubleData; + /** + * 用名字去匹配,这里需要注意,如果名字重复,会导致只有一个字段读取到数据 + */ + @ExcelProperty("字符串标题") + private String string; + @ExcelProperty("日期标题") + private Date date; +} ``` +##### 监听器 +参照:[监听器](#simpleReadListener) 只是泛型变了而已 +##### 代码 +```java + /** + * 指定列的下标或者列名 + * + *

1. 创建excel对应的实体对象,并使用{@link ExcelProperty}注解. 参照{@link IndexOrNameData} + *

2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link IndexOrNameDataListener} + *

3. 直接读即可 + */ @Test - public void testExcel2003NoModel() { - InputStream inputStream = getInputStream("loan1.xls"); - try { - // 解析每行结果在listener中处理 - ExcelListener listener = new ExcelListener(); - - ExcelReader excelReader = new ExcelReader(inputStream, ExcelTypeEnum.XLS, null, listener); - excelReader.read(); - } catch (Exception e) { - - } finally { - try { - inputStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } + public void indexOrNameRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + // 这里默认读取第一个sheet + EasyExcel.read(fileName, IndexOrNameData.class, new IndexOrNameDataListener()).sheet().doRead(); } ``` -ExcelListener示例代码如下: -``` - /* 解析监听器, - * 每解析一行会回调invoke()方法。 - * 整个excel解析结束会执行doAfterAllAnalysed()方法 - * - * 下面只是我写的一个样例而已,可以根据自己的逻辑修改该类。 - * @author jipengfei - * @date 2017/03/14 - */ -public class ExcelListener extends AnalysisEventListener { - //自定义用于暂时存储data。 - //可以通过实例获取该值 - private List datas = new ArrayList(); - public void invoke(Object object, AnalysisContext context) { - System.out.println("当前行:"+context.getCurrentRowNum()); - System.out.println(object); - datas.add(object);//数据存储到list,供批量处理,或后续自己业务逻辑处理。 - doSomething(object);//根据自己业务做处理 - } - private void doSomething(Object object) { - //1、入库调用接口 - } - public void doAfterAllAnalysed(AnalysisContext context) { - // datas.clear();//解析结束销毁不用的资源 - } - public List getDatas() { - return datas; - } - public void setDatas(List datas) { - this.datas = datas; +### 读多个sheet +##### excel示例 +参照:[excel示例](#simpleReadExcel) +##### 对象 +参照:[对象](#simpleReadObject) +##### 监听器 +参照:[监听器](#simpleReadListener) +##### 代码 +```java + /** + * 读多个sheet,这里注意一个sheet不能读取多次,多次读取需要重新读取文件 + *

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

2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} + *

3. 直接读即可 + */ + @Test + public void repeatedRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build(); + ReadSheet readSheet1 = EasyExcel.readSheet(0).build(); + ReadSheet readSheet2 = EasyExcel.readSheet(1).build(); + excelReader.read(readSheet1); + excelReader.read(readSheet2); + // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的 + excelReader.finish(); } -} ``` -### 有java模型映射 -java模型写法如下: -``` -public class LoanInfo extends BaseRowModel { - @ExcelProperty(index = 0) - private String bankLoanId; - - @ExcelProperty(index = 1) - private Long customerId; - - @ExcelProperty(index = 2,format = "yyyy/MM/dd") - private Date loanDate; - - @ExcelProperty(index = 3) - private BigDecimal quota; - - @ExcelProperty(index = 4) - private String bankInterestRate; - - @ExcelProperty(index = 5) - private Integer loanTerm; - - @ExcelProperty(index = 6,format = "yyyy/MM/dd") - private Date loanEndDate; - - @ExcelProperty(index = 7) - private BigDecimal interestPerMonth; - - @ExcelProperty(value = {"一级表头","二级表头"}) - private BigDecimal sax; + +### 日期、数字或者自定义格式转换 +##### excel示例 +参照:[excel示例](#simpleReadExcel) +##### 对象 +```java +@Data +public class ConverterData { + /** + * 我自定义 转换器,不管数据库传过来什么 。我给他加上“自定义:” + */ + @ExcelProperty(converter = CustomStringStringConverter.class) + private String string; + /** + * 这里用string 去接日期才能格式化。我想接收年月日格式 + */ + @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒") + private String date; + /** + * 我想接收百分比的数字 + */ + @NumberFormat("#.##%") + private String doubleData; } ``` -@ExcelProperty(index = 3)数字代表该字段与excel对应列号做映射,也可以采用 @ExcelProperty(value = {"一级表头","二级表头"})用于解决不确切知道excel第几列和该字段映射,位置不固定,但表头的内容知道的情况。 -``` - @Test - public void testExcel2003WithReflectModel() { - InputStream inputStream = getInputStream("loan1.xls"); - try { - // 解析每行结果在listener中处理 - AnalysisEventListener listener = new ExcelListener(); +##### 监听器 +参照:[监听器](#simpleReadListener) 只是泛型变了 +##### 自定义转换器 +````java +public class CustomStringStringConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return String.class; + } - ExcelReader excelReader = new ExcelReader(inputStream, ExcelTypeEnum.XLS, null, listener); + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } - excelReader.read(new Sheet(1, 2, LoanInfo.class)); - } catch (Exception e) { + /** + * 这里读的时候会调用 + * + * @param cellData + * NotNull + * @param contentProperty + * Nullable + * @param globalConfiguration + * NotNull + * @return + */ + @Override + public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return "自定义:" + cellData.getStringValue(); + } - } finally { - try { - inputStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } + /** + * 这里是写的时候会调用 不用管 + * + * @param value + * NotNull + * @param contentProperty + * Nullable + * @param globalConfiguration + * NotNull + * @return + */ + @Override + public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(value); + } +} +```` +##### 代码 +```java + /** + * 日期、数字或者自定义格式转换 + *

+ * 默认读的转换器{@link DefaultConverterLoader#loadDefaultReadConverter()} + *

1. 创建excel对应的实体对象 参照{@link ConverterData}.里面可以使用注解{@link DateTimeFormat}、{@link NumberFormat}或者自定义注解 + *

2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link ConverterDataListener} + *

3. 直接读即可 + */ + @Test + public void converterRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + // 这里 需要指定读用哪个class去读,然后读取第一个sheet 然后千万别忘记 finish + EasyExcel.read(fileName, ConverterData.class, new ConverterDataListener()) + // 这里注意 我们也可以registerConverter来指定自定义转换器, 但是这个转换变成全局了, 所有java为string,excel为string的都会用这个转换器。 + // 如果就想单个字段使用请使用@ExcelProperty 指定converter + // .registerConverter(new CustomStringStringConverter()) + // 读取sheet + .sheet().doRead(); } ``` -带模型解析与不带模型解析主要在构造new Sheet(1, 2, LoanInfo.class)时候包含class。Class需要继承BaseRowModel暂时BaseRowModel没有任何内容,后面升级可能会增加一些默认的数据。 -## 写Excel +### 多行头 +##### excel示例 +参照:[excel示例](#simpleReadExcel) +##### 对象 +参照:[对象](#simpleReadObject) +##### 监听器 +参照:[监听器](#simpleReadListener) +##### 代码 +```java + /** + * 多行头 + * + *

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

2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} + *

3. 设置headRowNumber参数,然后读。 这里要注意headRowNumber如果不指定, 会根据你传入的class的{@link ExcelProperty#value()}里面的表头的数量来决定行数, + * 如果不传入class则默认为1.当然你指定了headRowNumber不管是否传入class都是以你传入的为准。 + */ + @Test + public void complexHeaderRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + // 这里 需要指定读用哪个class去读,然后读取第一个sheet 然后千万别忘记 finish + EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet() + // 这里可以设置1,因为头就是一行。如果多行头,可以设置其他值。不传入也可以,因为默认会根据DemoData 来解析,他没有指定头,也就是默认1行 + .headRowNumber(1).doRead(); + } +``` -### 每行数据是List<String>无表头 +### 同步的返回 +##### excel示例 +参照:[excel示例](#simpleReadExcel) +##### 对象 +参照:[对象](#simpleReadObject) +##### 代码 +```java + /** + * 同步的返回,不推荐使用,如果数据量大会把数据放到内存里面 + */ + @Test + public void synchronousRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + // 这里 需要指定读用哪个class去读,然后读取第一个sheet 同步读取会自动finish + List list = EasyExcel.read(fileName).head(DemoData.class).sheet().doReadSync(); + for (Object obj : list) { + DemoData data = (DemoData)obj; + LOGGER.info("读取到数据:{}", JSON.toJSONString(data)); + } -``` - OutputStream out = new FileOutputStream("/Users/jipengfei/77.xlsx"); - try { - ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX,false); - //写第一个sheet, sheet1 数据全是List 无模型映射关系 - Sheet sheet1 = new Sheet(1, 0); - sheet1.setSheetName("第一个sheet"); - writer.write(getListString(), sheet1); - writer.finish(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - out.close(); - } catch (IOException e) { - e.printStackTrace(); - } + // 这里 也可以不指定class,返回一个list,然后读取第一个sheet 同步读取会自动finish + list = EasyExcel.read(fileName).sheet().doReadSync(); + for (Object obj : list) { + // 返回每条数据的键值对 表示所在的列 和所在列的值 + Map data = (Map)obj; + LOGGER.info("读取到数据:{}", JSON.toJSONString(data)); } + } ``` -### 每行数据是一个java模型有表头----表头层级为一 - -生成Excel格式如下图 -![屏幕快照 2017-06-02 上午9.49.39.png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/dfcb44d05380e2e26bce93f850d9fc99.png) - -模型写法如下: +### web中的读 +##### 示例代码 +DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java](/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java) +##### excel示例 +参照:[excel示例](#simpleReadExcel) +##### 对象 +参照:[对象](#simpleReadObject) 只是名字变了 +##### 监听器 +参照:[监听器](#simpleReadListener) 只是泛型变了 +##### 代码 +```java + /** + * 文件上传 + *

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

2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener} + *

3. 直接读即可 + */ + @PostMapping("upload") + @ResponseBody + public String upload(MultipartFile file) throws IOException { + EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener()).sheet().doRead(); + return "success"; + } ``` -public class ExcelPropertyIndexModel extends BaseRowModel { - - @ExcelProperty(value = "姓名" ,index = 0) - private String name; - @ExcelProperty(value = "年龄",index = 1) - private String age; - - @ExcelProperty(value = "邮箱",index = 2) - private String email; +## 写excel样例 +### 通用数据生成 后面不会重复写 +```java + private List data() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + DemoData data = new DemoData(); + data.setString("字符串" + i); + data.setDate(new Date()); + data.setDoubleData(0.56); + list.add(data); + } + return list; + } +``` +### 最简单的写 +##### excel示例 +![img](img/readme/quickstart/write/simpleWrite.png) +##### 对象 +```java +@Data +public class DemoData { + @ExcelProperty("字符串标题") + private String string; + @ExcelProperty("日期标题") + private Date date; + @ExcelProperty("数字标题") + private Double doubleData; +} +``` +##### 代码 +```java + /** + * 最简单的写 + *

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

2. 直接写即可 + */ + @Test + public void simpleWrite() { + // 写法1 + String fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 如果这里想使用03 则 传入excelType参数即可 + EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data()); + + // 写法2 + fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读 + ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); + WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); + excelWriter.write(data(), writeSheet); + /// 千万别忘记finish 会帮忙关闭流 + excelWriter.finish(); + } +``` - @ExcelProperty(value = "地址",index = 3) - private String address; +### 指定写入的列 +##### excel示例 +![img](img/readme/quickstart/write/indexWrite.png) +##### 对象 +```java +@Data +public class IndexData { + @ExcelProperty(value = "字符串标题", index = 0) + private String string; + @ExcelProperty(value = "日期标题", index = 1) + private Date date; + /** + * 这里设置3 会导致第二列空的 + */ + @ExcelProperty(value = "数字标题", index = 3) + private Double doubleData; +} +``` +##### 代码 +```java + /** + * 指定写入的列 + *

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

2. 使用{@link ExcelProperty}注解指定写入的列 + *

3. 直接写即可 + */ + @Test + public void indexWrite() { + String fileName = TestFileUtil.getPath() + "indexWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, IndexData.class).sheet("模板").doWrite(data()); + } +``` - @ExcelProperty(value = "性别",index = 4) - private String sax; +### 复杂头写入 +##### excel示例 +![img](img/readme/quickstart/write/complexHeadWrite.png) +##### 对象 +```java +@Data +public class ComplexHeadData { + @ExcelProperty({"主标题", "字符串标题"}) + private String string; + @ExcelProperty({"主标题", "日期标题"}) + private Date date; + @ExcelProperty({"主标题", "数字标题"}) + private Double doubleData; +} +``` +##### 代码 +```java + /** + * 复杂头写入 + *

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

2. 使用{@link ExcelProperty}注解指定复杂的头 + *

3. 直接写即可 + */ + @Test + public void complexHeadWrite() { + String fileName = TestFileUtil.getPath() + "complexHeadWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, ComplexHeadData.class).sheet("模板").doWrite(data()); + } +``` - @ExcelProperty(value = "高度",index = 5) - private String heigh; +### 重复多次写入 +##### excel示例 +![img](img/readme/quickstart/write/repeatedWrite.png) +##### 对象 +参照:[对象](#simpleWriteObject) +##### 代码 +```java + /** + * 重复多次写入 + *

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

2. 使用{@link ExcelProperty}注解指定复杂的头 + *

3. 直接调用二次写入即可 + */ + @Test + public void repeatedWrite() { + String fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读 + ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); + WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); + // 第一次写入会创建头 + excelWriter.write(data(), writeSheet); + // 第二次写入会在上一次写入的最后一行后面写入 + excelWriter.write(data(), writeSheet); + /// 千万别忘记finish 会帮忙关闭流 + excelWriter.finish(); + } +``` - @ExcelProperty(value = "备注",index = 6) - private String last; +### 日期、数字或者自定义格式转换 +##### excel示例 +![img](img/readme/quickstart/write/converterWrite.png) +##### 对象 +```java +@Data +public class ConverterData { + /** + * 我想所有的 字符串起前面加上"自定义:"三个字 + */ + @ExcelProperty(value = "字符串标题", converter = CustomStringStringConverter.class) + private String string; + /** + * 我想写到excel 用年月日的格式 + */ + @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒") + @ExcelProperty("日期标题") + private Date date; + /** + * 我想写到excel 用百分比表示 + */ + @NumberFormat("#.##%") + @ExcelProperty(value = "数字标题") + private Double doubleData; } ``` - @ExcelProperty(value = "姓名",index = 0) value是表头数据,默认会写在excel的表头位置,index代表第几列。 +##### 代码 +```java + /** + * 日期、数字或者自定义格式转换 + *

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

2. 使用{@link ExcelProperty}配合使用注解{@link DateTimeFormat}、{@link NumberFormat}或者自定义注解 + *

3. 直接写即可 + */ + @Test + public void converterWrite() { + String fileName = TestFileUtil.getPath() + "converterWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, ConverterData.class).sheet("模板").doWrite(data()); + } +``` + +### 图片导出 +##### excel示例 +![img](img/readme/quickstart/write/imageWrite.png) +##### 对象 +```java +@Data +@ContentRowHeight(100) +@ColumnWidth(100 / 8) +public class ImageData { + private File file; + private InputStream inputStream; + /** + * 如果string类型 必须指定转换器,string默认转换成string + */ + @ExcelProperty(converter = StringImageConverter.class) + private String string; + private byte[] byteArray; +} ``` - @Test - public void test1() throws FileNotFoundException { - OutputStream out = new FileOutputStream("/Users/jipengfei/78.xlsx"); +##### 代码 +```java + /** + * 图片导出 + *

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

2. 直接写即可 + */ + @Test + public void imageWrite() throws Exception { + String fileName = TestFileUtil.getPath() + "imageWrite" + System.currentTimeMillis() + ".xlsx"; + // 如果使用流 记得关闭 + InputStream inputStream = null; try { - ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX); - //写第一个sheet, sheet1 数据全是List 无模型映射关系 - Sheet sheet1 = new Sheet(1, 0,ExcelPropertyIndexModel.class); - writer.write(getData(), sheet1); - writer.finish(); - } catch (Exception e) { - e.printStackTrace(); + List list = new ArrayList(); + ImageData imageData = new ImageData(); + list.add(imageData); + String imagePath = TestFileUtil.getPath() + "converter" + File.separator + "img.jpg"; + // 放入四种类型的图片 实际使用只要选一种即可 + imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath))); + imageData.setFile(new File(imagePath)); + imageData.setString(imagePath); + inputStream = FileUtils.openInputStream(new File(imagePath)); + imageData.setInputStream(inputStream); + EasyExcel.write(fileName, ImageData.class).sheet().doWrite(list); } finally { - try { - out.close(); - } catch (IOException e) { - e.printStackTrace(); + if (inputStream != null) { + inputStream.close(); } } } ``` -### 每行数据是一个java模型有表头----表头层级为多层级 -生成Excel格式如下图: -![屏幕快照 2017-06-02 上午9.53.07.png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/0cdb1673665e7940cd670871afb4b3d7.png) -java模型写法如下: +### 根据模板写入 +##### 模板excel示例 +参照:[模板excel示例](#simpleReadExcel) +##### excel示例 +![img](img/readme/quickstart/write/templateWrite.png) +##### 对象 +参照:[对象](#simpleWriteObject) +##### 代码 +```java + /** + * 根据模板写入 + *

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

2. 使用{@link ExcelProperty}注解指定写入的列 + *

3. 使用withTemplate 读取模板 + *

4. 直接写即可 + */ + @Test + public void templateWrite() { + String templateFileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + String fileName = TestFileUtil.getPath() + "templateWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, DemoData.class).withTemplate(templateFileName).sheet().doWrite(data()); + } ``` -public class MultiLineHeadExcelModel extends BaseRowModel { - - @ExcelProperty(value = {"表头1","表头1","表头31"},index = 0) - private String p1; - - @ExcelProperty(value = {"表头1","表头1","表头32"},index = 1) - private String p2; - @ExcelProperty(value = {"表头3","表头3","表头3"},index = 2) - private int p3; - - @ExcelProperty(value = {"表头4","表头4","表头4"},index = 3) - private long p4; - - @ExcelProperty(value = {"表头5","表头51","表头52"},index = 4) - private String p5; - - @ExcelProperty(value = {"表头6","表头61","表头611"},index = 5) - private String p6; +### 列宽、行高 +##### excel示例 +![img](img/readme/quickstart/write/widthAndHeightWrite.png) +##### 对象 +````java +@Data +@ContentRowHeight(10) +@HeadRowHeight(20) +@ColumnWidth(25) +public class WidthAndHeightData { + @ExcelProperty("字符串标题") + private String string; + @ExcelProperty("日期标题") + private Date date; + /** + * 宽度为50 + */ + @ColumnWidth(50) + @ExcelProperty("数字标题") + private Double doubleData; +} +```` +##### 代码 +```java + /** + * 列宽、行高 + *

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

2. 使用注解{@link ColumnWidth}、{@link HeadRowHeight}、{@link ContentRowHeight}指定宽度或高度 + *

3. 直接写即可 + */ + @Test + public void widthAndHeightWrite() { + String fileName = TestFileUtil.getPath() + "widthAndHeightWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, WidthAndHeightData.class).sheet("模板").doWrite(data()); + } +``` - @ExcelProperty(value = {"表头6","表头61","表头612"},index = 6) - private String p7; +### 自定义样式 +##### excel示例 +![img](img/readme/quickstart/write/styleWrite.png) +##### 对象 +参照:[对象](#simpleWriteObject) +##### 代码 +```java + /** + * 自定义样式 + *

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

2. 创建一个style策略 并注册 + *

3. 直接写即可 + */ + @Test + public void styleWrite() { + String fileName = TestFileUtil.getPath() + "styleWrite" + System.currentTimeMillis() + ".xlsx"; + // 头的策略 + WriteCellStyle headWriteCellStyle = new WriteCellStyle(); + // 背景设置为红色 + headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex()); + WriteFont headWriteFont = new WriteFont(); + headWriteFont.setFontHeightInPoints((short)20); + headWriteCellStyle.setWriteFont(headWriteFont); + // 内容的策略 + WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); + // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定 + contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); + // 背景绿色 + contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex()); + WriteFont contentWriteFont = new WriteFont(); + // 字体大小 + contentWriteFont.setFontHeightInPoints((short)20); + contentWriteCellStyle.setWriteFont(contentWriteFont); + // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现 + HorizontalCellStyleStrategy horizontalCellStyleStrategy = + new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle); + + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, DemoData.class).registerWriteHandler(horizontalCellStyleStrategy).sheet("模板") + .doWrite(data()); + } +``` - @ExcelProperty(value = {"表头6","表头62","表头621"},index = 7) - private String p8; +### 合并单元格 +##### excel示例 +![img](img/readme/quickstart/write/mergeWrite.png) +##### 对象 +参照:[对象](#simpleWriteObject) +##### 代码 +```java + /** + * 合并单元格 + *

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

2. 创建一个merge策略 并注册 + *

3. 直接写即可 + */ + @Test + public void mergeWrite() { + String fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx"; + // 每隔2行会合并 把eachColumn 设置成 3 也就是我们数据的长度,所以就第一列会合并。当然其他合并策略也可以自己写 + LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0); + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, DemoData.class).registerWriteHandler(loopMergeStrategy).sheet("模板") + .doWrite(data()); + } +``` - @ExcelProperty(value = {"表头6","表头62","表头622"},index = 8) - private String p9; -} +### 使用table去写入 +##### excel示例 +![img](img/readme/quickstart/write/tableWrite.png) +##### 对象 +参照:[对象](#simpleWriteObject) +##### 代码 +```java + /** + * 使用table去写入 + *

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

2. 然后写入table即可 + */ + @Test + public void tableWrite() { + String fileName = TestFileUtil.getPath() + "tableWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里直接写多个table的案例了,如果只有一个 也可以直一行代码搞定,参照其他案例 + // 这里 需要指定写用哪个class去读 + ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); + // 把sheet设置为不需要头 不然会输出sheet的头 这样看起来第一个table 就有2个头了 + WriteSheet writeSheet = EasyExcel.writerSheet("模板").needHead(Boolean.FALSE).build(); + // 这里必须指定需要头,table 会继承sheet的配置,sheet配置了不需要,table 默认也是不需要 + WriteTable writeTable0 = EasyExcel.writerTable(0).needHead(Boolean.TRUE).build(); + WriteTable writeTable1 = EasyExcel.writerTable(1).needHead(Boolean.TRUE).build(); + // 第一次写入会创建头 + excelWriter.write(data(), writeSheet, writeTable0); + // 第二次写如也会创建头,然后在第一次的后面写入数据 + excelWriter.write(data(), writeSheet, writeTable1); + /// 千万别忘记finish 会帮忙关闭流 + excelWriter.finish(); + } ``` -写Excel写法同上,只需将ExcelPropertyIndexModel.class改为MultiLineHeadExcelModel.class +### 动态头,实时生成头写入 +##### excel示例 +![img](img/readme/quickstart/write/dynamicHeadWrite.png) +##### 对象 +参照:[对象](#simpleWriteObject) +##### 代码 +```java + /** + * 动态头,实时生成头写入 + *

+ * 思路是这样子的,先创建List头格式的sheet仅仅写入头,然后通过table 不写入头的方式 去写入数据 + * + *

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

2. 然后写入table即可 + */ + @Test + public void dynamicHeadWrite() { + String fileName = TestFileUtil.getPath() + "dynamicHeadWrite" + System.currentTimeMillis() + ".xlsx"; + // write的时候 不传入 class 在table的时候传入 + EasyExcel.write(fileName) + // 这里放入动态头 + .head(head()).sheet("模板") + // table的时候 传入class 并且设置needHead =false + .table().head(DemoData.class).needHead(Boolean.FALSE).doWrite(data()); + } -### 一个Excel多个sheet写法 + private List> head() { + List> list = new ArrayList>(); + List head0 = new ArrayList(); + head0.add("字符串" + System.currentTimeMillis()); + List head1 = new ArrayList(); + head1.add("数字" + System.currentTimeMillis()); + List head2 = new ArrayList(); + head2.add("日期" + System.currentTimeMillis()); + list.add(head0); + list.add(head1); + list.add(head2); + return list; + } +``` +### 自动列宽(不太精确) +##### excel示例 +![img](img/readme/quickstart/write/longestMatchColumnWidthWrite.png) +##### 对象 +```java +@Data +public class LongestMatchColumnWidthData { + @ExcelProperty("字符串标题") + private String string; + @ExcelProperty("日期标题很长日期标题很长日期标题很长很长") + private Date date; + @ExcelProperty("数字") + private Double doubleData; +} ``` - @Test - public void test1() throws FileNotFoundException { +##### 代码 +```java + /** + * 自动列宽(不太精确) + *

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

+ * poi 自带{@link SXSSFSheet#autoSizeColumn(int)} 对中文支持也不太好。目前没找到很好的算法。 有的话可以推荐下。 + * + *

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

+ * 2. 注册策略{@link LongestMatchColumnWidthStyleStrategy} + *

+ * 3. 直接写即可 + */ + @Test + public void longestMatchColumnWidthWrite() { + String fileName = + TestFileUtil.getPath() + "longestMatchColumnWidthWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, LongestMatchColumnWidthData.class) + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("模板").doWrite(dataLong()); + } - OutputStream out = new FileOutputStream("/Users/jipengfei/77.xlsx"); - try { - ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX,false); - //写第一个sheet, sheet1 数据全是List 无模型映射关系 - Sheet sheet1 = new Sheet(1, 0); - sheet1.setSheetName("第一个sheet"); - writer.write(getListString(), sheet1); - - //写第二个sheet sheet2 模型上打有表头的注解,合并单元格 - Sheet sheet2 = new Sheet(2, 3, MultiLineHeadExcelModel.class, "第二个sheet", null); - sheet2.setTableStyle(getTableStyle1()); - writer.write(getModeldatas(), sheet2); - - //写sheet3 模型上没有注解,表头数据动态传入 - List> head = new ArrayList>(); - List headCoulumn1 = new ArrayList(); - List headCoulumn2 = new ArrayList(); - List headCoulumn3 = new ArrayList(); - headCoulumn1.add("第一列"); - headCoulumn2.add("第二列"); - headCoulumn3.add("第三列"); - head.add(headCoulumn1); - head.add(headCoulumn2); - head.add(headCoulumn3); - Sheet sheet3 = new Sheet(3, 1, NoAnnModel.class, "第三个sheet", head); - writer.write(getNoAnnModels(), sheet3); - writer.finish(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - out.close(); - } catch (IOException e) { - e.printStackTrace(); - } + private List dataLong() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + LongestMatchColumnWidthData data = new LongestMatchColumnWidthData(); + data.setString("测试很长的字符串测试很长的字符串测试很长的字符串" + i); + data.setDate(new Date()); + data.setDoubleData(1000000000000.0); + list.add(data); } + return list; } ``` -### 一个sheet中有多个表格 - +### 自定义拦截器(上面几点都不符合但是要对单元格进行操作的参照这个) +##### excel示例 +![img](img/readme/quickstart/write/customHandlerWrite.png) +##### 对象 +参照:[对象](#simpleWriteObject) +##### 代码 +```java + /** + * 下拉,超链接等自定义拦截器(上面几点都不符合但是要对单元格进行操作的参照这个) + *

+ * demo这里实现2点。1. 对第一行第一列的头超链接到:https://github.com/alibaba/easyexcel 2. 对第一列第一行和第二行的数据新增下拉框,显示 测试1 测试2 + *

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

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

+ * 2. 直接写即可 + */ + @Test + public void customHandlerWrite() { + String fileName = TestFileUtil.getPath() + "customHandlerWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, DemoData.class).registerWriteHandler(new CustomSheetWriteHandler()) + .registerWriteHandler(new CustomCellWriteHandler()).sheet("模板").doWrite(data()); + } ``` -@Test - public void test2() throws FileNotFoundException { - OutputStream out = new FileOutputStream("/Users/jipengfei/77.xlsx"); - try { - ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX,false); - - //写sheet1 数据全是List 无模型映射关系 - Sheet sheet1 = new Sheet(1, 0); - sheet1.setSheetName("第一个sheet"); - Table table1 = new Table(1); - writer.write(getListString(), sheet1, table1); - writer.write(getListString(), sheet1, table1); - - //写sheet2 模型上打有表头的注解 - Table table2 = new Table(2); - table2.setTableStyle(getTableStyle1()); - table2.setClazz(MultiLineHeadExcelModel.class); - writer.write(getModeldatas(), sheet1, table2); - - //写sheet3 模型上没有注解,表头数据动态传入,此情况下模型field顺序与excel现实顺序一致 - List> head = new ArrayList>(); - List headCoulumn1 = new ArrayList(); - List headCoulumn2 = new ArrayList(); - List headCoulumn3 = new ArrayList(); - headCoulumn1.add("第一列"); - headCoulumn2.add("第二列"); - headCoulumn3.add("第三列"); - head.add(headCoulumn1); - head.add(headCoulumn2); - head.add(headCoulumn3); - Table table3 = new Table(3); - table3.setHead(head); - table3.setClazz(NoAnnModel.class); - table3.setTableStyle(getTableStyle2()); - writer.write(getNoAnnModels(), sheet1, table3); - writer.write(getNoAnnModels(), sheet1, table3); - - writer.finish(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - out.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } + +### web中的写 +##### 示例代码 +DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java](/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java) +##### 对象 +参照:[对象](#simpleWriteObject) 就是名称变了下 +##### 代码 +```java + /** + * 文件下载 + *

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

2. 设置返回的 参数 + *

3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大 + */ + @GetMapping("download") + public void download(HttpServletResponse response) throws IOException { + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + response.setHeader("Content-disposition", "attachment;filename=demo.xlsx"); + EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data()); } ``` ## 测试数据分析 - ![POI usermodel PK easyexcel(Excel 2003).png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/02c4bfbbab99a649788523d04f84a42f.png) ![POI usermodel PK easyexcel(Excel 2007).png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/f6a8a19ec959f0eb564e652de523fc9e.png) ![POI usermodel PK easyexcel(Excel 2003) (1).png](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/26888f7ea1cb8dc56db494926544edf7.png) diff --git a/src/main/java/com/alibaba/excel/EasyExcel.java b/src/main/java/com/alibaba/excel/EasyExcel.java new file mode 100644 index 0000000..432c513 --- /dev/null +++ b/src/main/java/com/alibaba/excel/EasyExcel.java @@ -0,0 +1,8 @@ +package com.alibaba.excel; + +/** + * This is actually {@link EasyExcelFactory}, and short names look better. + * + * @author jipengfei + */ +public class EasyExcel extends EasyExcelFactory {} diff --git a/src/main/java/com/alibaba/excel/EasyExcelFactory.java b/src/main/java/com/alibaba/excel/EasyExcelFactory.java index 5327dc9..39fe031 100644 --- a/src/main/java/com/alibaba/excel/EasyExcelFactory.java +++ b/src/main/java/com/alibaba/excel/EasyExcelFactory.java @@ -1,19 +1,40 @@ package com.alibaba.excel; +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.event.WriteHandler; import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.read.builder.ExcelReaderBuilder; +import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder; +import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.support.ExcelTypeEnum; - -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; +import com.alibaba.excel.write.builder.ExcelWriterBuilder; +import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder; +import com.alibaba.excel.write.builder.ExcelWriterTableBuilder; /** * Reader and writer factory class * + *

Quick start

+ *

Read

+ *

Sample1

+ * + *

Sample2

+ * + *

Write

+ * + *

Sample1

+ * + *

Sample2

+ * + * + * * @author jipengfei */ public class EasyExcelFactory { @@ -21,21 +42,24 @@ public class EasyExcelFactory { /** * Quickly read small files,no more than 10,000 lines. * - * @param in the POI filesystem that contains the Workbook stream. - * @param sheet read sheet. + * @param in + * the POI filesystem that contains the Workbook stream. + * @param sheet + * read sheet. * @return analysis result. + * @deprecated please use 'EasyExcel.read(in).sheet(sheetNo).doReadSync();' */ + @Deprecated public static List read(InputStream in, Sheet sheet) { final List rows = new ArrayList(); - new ExcelReader(in, null, new AnalysisEventListener() { + new ExcelReader(in, null, new AnalysisEventListener() { @Override public void invoke(Object object, AnalysisContext context) { rows.add(object); } @Override - public void doAfterAllAnalysed(AnalysisContext context) { - } + public void doAfterAllAnalysed(AnalysisContext context) {} }, false).read(sheet); return rows; } @@ -43,10 +67,15 @@ public class EasyExcelFactory { /** * Parsing large file * - * @param in the POI filesystem that contains the Workbook stream. - * @param sheet read sheet. - * @param listener Callback method after each row is parsed. + * @param in + * the POI filesystem that contains the Workbook stream. + * @param sheet + * read sheet. + * @param listener + * Callback method after each row is parsed. + * @deprecated please use 'EasyExcel.read(in,head,listener).sheet(sheetNo).doRead().finish();' */ + @Deprecated public static void readBySax(InputStream in, Sheet sheet, AnalysisEventListener listener) { new ExcelReader(in, null, listener).read(sheet); } @@ -54,10 +83,14 @@ public class EasyExcelFactory { /** * Get ExcelReader. * - * @param in the POI filesystem that contains the Workbook stream. - * @param listener Callback method after each row is parsed. + * @param in + * the POI filesystem that contains the Workbook stream. + * @param listener + * Callback method after each row is parsed. * @return ExcelReader. + * @deprecated please use {@link EasyExcel#read()} build 'ExcelReader' */ + @Deprecated public static ExcelReader getReader(InputStream in, AnalysisEventListener listener) { return new ExcelReader(in, null, listener); } @@ -65,56 +98,449 @@ public class EasyExcelFactory { /** * Get ExcelWriter * - * @param outputStream the java OutputStream you wish to write the data to. + * @param outputStream + * the java OutputStream you wish to write the value to. * @return new ExcelWriter. + * @deprecated please use {@link EasyExcel#write()} */ + @Deprecated public static ExcelWriter getWriter(OutputStream outputStream) { - return new ExcelWriter(outputStream, ExcelTypeEnum.XLSX, true); + return write().file(outputStream).autoCloseStream(Boolean.FALSE).convertAllFiled(Boolean.FALSE).build(); } /** * Get ExcelWriter * - * @param outputStream the java OutputStream you wish to write the data to. - * @param typeEnum 03 or 07 - * @param needHead Do you need to write the header to the file? - * @return new ExcelWriter + * @param outputStream + * the java OutputStream you wish to write the value to. + * @param typeEnum + * 03 or 07 + * @param needHead + * Do you need to write the header to the file? + * @return new ExcelWriter + * @deprecated please use {@link EasyExcel#write()} */ + @Deprecated public static ExcelWriter getWriter(OutputStream outputStream, ExcelTypeEnum typeEnum, boolean needHead) { - return new ExcelWriter(outputStream, typeEnum, needHead); + return write().file(outputStream).excelType(typeEnum).needHead(needHead).autoCloseStream(Boolean.FALSE) + .convertAllFiled(Boolean.FALSE).build(); } /** * Get ExcelWriter with a template file * - * @param temp Append data after a POI file , Can be null(the template POI filesystem that contains the - * Workbook stream) - * @param outputStream the java OutputStream you wish to write the data to - * @param typeEnum 03 or 07 - * @return new ExcelWriter + * @param temp + * Append value after a POI file , Can be null(the template POI filesystem that contains the Workbook + * stream) + * @param outputStream + * the java OutputStream you wish to write the value to + * @param typeEnum + * 03 or 07 + * @param needHead + * Whether a write header is required + * @return new ExcelWriter + * @deprecated please use {@link EasyExcel#write()} */ + @Deprecated public static ExcelWriter getWriterWithTemp(InputStream temp, OutputStream outputStream, ExcelTypeEnum typeEnum, - boolean needHead) { - return new ExcelWriter(temp, outputStream, typeEnum, needHead); + boolean needHead) { + return write().withTemplate(temp).file(outputStream).excelType(typeEnum).needHead(needHead) + .autoCloseStream(Boolean.FALSE).convertAllFiled(Boolean.FALSE).build(); } /** * Get ExcelWriter with a template file * - * @param temp Append data after a POI file , Can be null(the template POI filesystem that contains the - * Workbook stream) - * @param outputStream the java OutputStream you wish to write the data to - * @param typeEnum 03 or 07 + * @param temp + * Append value after a POI file , Can be null(the template POI filesystem that contains the Workbook + * stream) + * @param outputStream + * the java OutputStream you wish to write the value to + * @param typeEnum + * 03 or 07 * @param needHead - * @param handler User-defined callback - * @return new ExcelWriter + * Whether a write header is required + * @param handler + * User-defined callback + * @return new ExcelWriter + * @deprecated please use {@link EasyExcel#write()} + */ + @Deprecated + public static ExcelWriter getWriterWithTempAndHandler(InputStream temp, OutputStream outputStream, + ExcelTypeEnum typeEnum, boolean needHead, WriteHandler handler) { + return write().withTemplate(temp).file(outputStream).excelType(typeEnum).needHead(needHead) + .registerWriteHandler(handler).autoCloseStream(Boolean.FALSE).convertAllFiled(Boolean.FALSE).build(); + } + + /** + * Build excel the write + * + * @return + */ + public static ExcelWriterBuilder write() { + return new ExcelWriterBuilder(); + } + + /** + * Build excel the write + * + * @param file + * File to write + * @return Excel writer builder + */ + public static ExcelWriterBuilder write(File file) { + return write(file, null); + } + + /** + * Build excel the write + * + * @param file + * File to write + * @param head + * Annotate the class for configuration information + * @return Excel writer builder + */ + public static ExcelWriterBuilder write(File file, Class head) { + ExcelWriterBuilder excelWriterBuilder = new ExcelWriterBuilder(); + excelWriterBuilder.file(file); + if (head != null) { + excelWriterBuilder.head(head); + } + return excelWriterBuilder; + } + + /** + * Build excel the write + * + * @param pathName + * File path to write + * @return Excel writer builder + */ + public static ExcelWriterBuilder write(String pathName) { + return write(pathName, null); + } + + /** + * Build excel the write + * + * @param pathName + * File path to write + * @param head + * Annotate the class for configuration information + * @return Excel writer builder + */ + public static ExcelWriterBuilder write(String pathName, Class head) { + ExcelWriterBuilder excelWriterBuilder = new ExcelWriterBuilder(); + excelWriterBuilder.file(pathName); + if (head != null) { + excelWriterBuilder.head(head); + } + return excelWriterBuilder; + } + + /** + * Build excel the write + * + * @param outputStream + * Output stream to write + * @return Excel writer builder + */ + public static ExcelWriterBuilder write(OutputStream outputStream) { + return write(outputStream, null); + } + + /** + * Build excel the write + * + * @param outputStream + * Output stream to write + * @param head + * Annotate the class for configuration information. + * @return Excel writer builder + */ + public static ExcelWriterBuilder write(OutputStream outputStream, Class head) { + ExcelWriterBuilder excelWriterBuilder = new ExcelWriterBuilder(); + excelWriterBuilder.file(outputStream); + if (head != null) { + excelWriterBuilder.head(head); + } + return excelWriterBuilder; + } + + /** + * Build excel the writerSheet + * + * @return Excel sheet writer builder + */ + public static ExcelWriterSheetBuilder writerSheet() { + return writerSheet(null, null); + } + + /** + * Build excel the writerSheet + * + * @param sheetNo + * Index of sheet,0 base. + * @return Excel sheet writer builder. + */ + public static ExcelWriterSheetBuilder writerSheet(Integer sheetNo) { + return writerSheet(sheetNo, null); + } + + /** + * Build excel the 'writerSheet' + * + * @param sheetName + * The name of sheet. + * @return Excel sheet writer builder. + */ + public static ExcelWriterSheetBuilder writerSheet(String sheetName) { + return writerSheet(null, sheetName); + } + + /** + * Build excel the 'writerSheet' + * + * @param sheetNo + * Index of sheet,0 base. + * @param sheetName + * The name of sheet. + * @return Excel sheet writer builder. + */ + public static ExcelWriterSheetBuilder writerSheet(Integer sheetNo, String sheetName) { + ExcelWriterSheetBuilder excelWriterSheetBuilder = new ExcelWriterSheetBuilder(); + if (sheetNo != null) { + excelWriterSheetBuilder.sheetNo(sheetNo); + } + if (sheetName != null) { + excelWriterSheetBuilder.sheetName(sheetName); + } + return excelWriterSheetBuilder; + } + + /** + * Build excel the writerTable + * + * @return Excel table writer builder. + */ + public static ExcelWriterTableBuilder writerTable() { + return writerTable(null); + } + + /** + * Build excel the 'writerTable' + * + * @param tableNo + * Index of table,0 base. + * @return Excel table writer builder. + */ + public static ExcelWriterTableBuilder writerTable(Integer tableNo) { + ExcelWriterTableBuilder excelWriterTableBuilder = new ExcelWriterTableBuilder(); + if (tableNo != null) { + excelWriterTableBuilder.tableNo(tableNo); + } + return excelWriterTableBuilder; + } + + /** + * Build excel the read + * + * @return Excel reader builder. + */ + public static ExcelReaderBuilder read() { + return new ExcelReaderBuilder(); + } + + /** + * Build excel the read + * + * @param file + * File to read. + * @return Excel reader builder. */ - public static ExcelWriter getWriterWithTempAndHandler(InputStream temp, - OutputStream outputStream, - ExcelTypeEnum typeEnum, - boolean needHead, - WriteHandler handler) { - return new ExcelWriter(temp, outputStream, typeEnum, needHead, handler); + public static ExcelReaderBuilder read(File file) { + return read(file, null, null); } + /** + * Build excel the read + * + * @param file + * File to read. + * @param readListener + * Read listener. + * @return Excel reader builder. + */ + public static ExcelReaderBuilder read(File file, ReadListener readListener) { + return read(file, null, readListener); + } + + /** + * Build excel the read + * + * @param file + * File to read. + * @param head + * Annotate the class for configuration information. + * @param readListener + * Read listener. + * @return Excel reader builder. + */ + public static ExcelReaderBuilder read(File file, Class head, ReadListener readListener) { + ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder(); + excelReaderBuilder.file(file); + if (head != null) { + excelReaderBuilder.head(head); + } + if (readListener != null) { + excelReaderBuilder.registerReadListener(readListener); + } + return excelReaderBuilder; + } + + /** + * Build excel the read + * + * @param pathName + * File path to read. + * @return Excel reader builder. + */ + public static ExcelReaderBuilder read(String pathName) { + return read(pathName, null, null); + } + + /** + * Build excel the read + * + * @param pathName + * File path to read. + * @param readListener + * Read listener. + * @return Excel reader builder. + */ + public static ExcelReaderBuilder read(String pathName, ReadListener readListener) { + return read(pathName, null, readListener); + } + + /** + * Build excel the read + * + * @param pathName + * File path to read. + * @param head + * Annotate the class for configuration information. + * @param readListener + * Read listener. + * @return Excel reader builder. + */ + public static ExcelReaderBuilder read(String pathName, Class head, ReadListener readListener) { + ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder(); + excelReaderBuilder.file(pathName); + if (head != null) { + excelReaderBuilder.head(head); + } + if (readListener != null) { + excelReaderBuilder.registerReadListener(readListener); + } + return excelReaderBuilder; + } + + /** + * Build excel the read + * + * @param inputStream + * Input stream to read. + * @return Excel reader builder. + */ + public static ExcelReaderBuilder read(InputStream inputStream) { + return read(inputStream, null, null); + } + + /** + * Build excel the read + * + * @param inputStream + * Input stream to read. + * @param readListener + * Read listener. + * @return Excel reader builder. + */ + public static ExcelReaderBuilder read(InputStream inputStream, ReadListener readListener) { + return read(inputStream, null, readListener); + } + + /** + * Build excel the read + * + * @param inputStream + * Input stream to read. + * @param head + * Annotate the class for configuration information. + * @param readListener + * Read listener. + * @return Excel reader builder. + */ + public static ExcelReaderBuilder read(InputStream inputStream, Class head, ReadListener readListener) { + ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder(); + excelReaderBuilder.file(inputStream); + if (head != null) { + excelReaderBuilder.head(head); + } + if (readListener != null) { + excelReaderBuilder.registerReadListener(readListener); + } + return excelReaderBuilder; + } + + /** + * Build excel the 'readSheet' + * + * @return Excel sheet reader builder. + */ + public static ExcelReaderSheetBuilder readSheet() { + return readSheet(null, null); + } + + /** + * Build excel the 'readSheet' + * + * @param sheetNo + * Index of sheet,0 base. + * @return Excel sheet reader builder. + */ + public static ExcelReaderSheetBuilder readSheet(Integer sheetNo) { + return readSheet(sheetNo, null); + } + + /** + * Build excel the 'readSheet' + * + * @param sheetName + * The name of sheet. + * @return Excel sheet reader builder. + */ + public static ExcelReaderSheetBuilder readSheet(String sheetName) { + return readSheet(null, sheetName); + } + + /** + * Build excel the 'readSheet' + * + * @param sheetNo + * Index of sheet,0 base. + * @param sheetName + * The name of sheet. + * @return Excel sheet reader builder. + */ + public static ExcelReaderSheetBuilder readSheet(Integer sheetNo, String sheetName) { + ExcelReaderSheetBuilder excelReaderSheetBuilder = new ExcelReaderSheetBuilder(); + if (sheetNo != null) { + excelReaderSheetBuilder.sheetNo(sheetNo); + } + if (sheetName != null) { + excelReaderSheetBuilder.sheetName(sheetName); + } + return excelReaderSheetBuilder; + } } diff --git a/src/main/java/com/alibaba/excel/ExcelReader.java b/src/main/java/com/alibaba/excel/ExcelReader.java index 9ed5892..3cb6b01 100644 --- a/src/main/java/com/alibaba/excel/ExcelReader.java +++ b/src/main/java/com/alibaba/excel/ExcelReader.java @@ -1,60 +1,84 @@ package com.alibaba.excel; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.alibaba.excel.analysis.ExcelAnalyser; import com.alibaba.excel.analysis.ExcelAnalyserImpl; +import com.alibaba.excel.analysis.ExcelExecutor; +import com.alibaba.excel.cache.MapCache; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; -import com.alibaba.excel.metadata.BaseRowModel; +import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.parameter.AnalysisParam; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.support.ExcelTypeEnum; -import java.io.InputStream; -import java.util.List; - /** * Excel readers are all read in event mode. * * @author jipengfei */ public class ExcelReader { + private static final Logger LOGGER = LoggerFactory.getLogger(ExcelReader.class); /** * Analyser */ - private ExcelAnalyser analyser ; + private ExcelAnalyser excelAnalyser; + + private boolean finished = false; /** * Create new reader * - * @param in the POI filesystem that contains the Workbook stream - * @param excelTypeEnum 03 or 07 - * @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext - * @param eventListener Callback method after each row is parsed. + * @param in + * the POI filesystem that contains the Workbook stream + * @param excelTypeEnum + * 03 or 07 + * @param customContent + * {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext + * @param eventListener + * Callback method after each row is parsed. + * @deprecated please use {@link EasyExcelFactory#read()} build 'ExcelReader' */ @Deprecated public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent, - AnalysisEventListener eventListener) { + AnalysisEventListener eventListener) { this(in, excelTypeEnum, customContent, eventListener, true); } /** * Create new reader * - * @param in the POI filesystem that contains the Workbook stream - * @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext - * @param eventListener Callback method after each row is parsed + * @param in + * the POI filesystem that contains the Workbook stream + * @param customContent + * {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext + * @param eventListener + * Callback method after each row is parsed + * @deprecated please use {@link EasyExcelFactory#read()} build 'ExcelReader' */ - public ExcelReader(InputStream in, Object customContent, - AnalysisEventListener eventListener) { + @Deprecated + public ExcelReader(InputStream in, Object customContent, AnalysisEventListener eventListener) { this(in, customContent, eventListener, true); } /** * Create new reader * - * @param param old param Deprecated - * @param eventListener Callback method after each row is parsed. + * @param param + * old param Deprecated + * @param eventListener + * Callback method after each row is parsed. + * @deprecated please use {@link EasyExcelFactory#read()} build 'ExcelReader' */ @Deprecated public ExcelReader(AnalysisParam param, AnalysisEventListener eventListener) { @@ -64,86 +88,210 @@ public class ExcelReader { /** * Create new reader * - * @param in the POI filesystem that contains the Workbook stream - * @param excelTypeEnum 03 or 07 - * @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext - * @param eventListener Callback method after each row is parsed. - * @param trim The content of the form is empty and needs to be empty. The purpose is to be fault-tolerant, - * because there are often table contents with spaces that can not be converted into custom - * types. For example: '1234 ' contain a space cannot be converted to int. + * @param in + * @param customContent + * {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext + * @param eventListener + * @param trim + * The content of the form is empty and needs to be empty. The purpose is to be fault-tolerant, because + * there are often table contents with spaces that can not be converted into custom types. For example: + * '1234 ' contain a space cannot be converted to int. + * @deprecated please use {@link EasyExcelFactory#read()} build 'ExcelReader' */ @Deprecated - public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent, - AnalysisEventListener eventListener, boolean trim) { - validateParam(in, eventListener); - analyser = new ExcelAnalyserImpl(in, excelTypeEnum, customContent, eventListener, trim); + public ExcelReader(InputStream in, Object customContent, AnalysisEventListener eventListener, boolean trim) { + this(in, null, customContent, eventListener, trim); } /** * Create new reader * * @param in - * @param customContent {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext + * the POI filesystem that contains the Workbook stream + * @param excelTypeEnum + * 03 or 07 + * @param customContent + * {@link AnalysisEventListener#invoke(Object, AnalysisContext) }AnalysisContext * @param eventListener - * @param trim The content of the form is empty and needs to be empty. The purpose is to be fault-tolerant, - * because there are often table contents with spaces that can not be converted into custom - * types. For example: '1234 ' contain a space cannot be converted to int. + * Callback method after each row is parsed. + * @param trim + * The content of the form is empty and needs to be empty. The purpose is to be fault-tolerant, because + * there are often table contents with spaces that can not be converted into custom types. For example: + * '1234 ' contain a space cannot be converted to int. + * @deprecated please use {@link EasyExcelFactory#read()} build 'ExcelReader' */ - public ExcelReader(InputStream in, Object customContent, - AnalysisEventListener eventListener, boolean trim) { - ExcelTypeEnum excelTypeEnum = ExcelTypeEnum.valueOf(in); - validateParam(in, eventListener); - analyser =new ExcelAnalyserImpl(in, excelTypeEnum, customContent, eventListener, trim); + @Deprecated + public ExcelReader(InputStream in, ExcelTypeEnum excelTypeEnum, Object customContent, + AnalysisEventListener eventListener, boolean trim) { + ReadWorkbook readWorkbook = new ReadWorkbook(); + readWorkbook.setInputStream(in); + readWorkbook.setExcelType(excelTypeEnum); + readWorkbook.setCustomObject(customContent); + if (eventListener != null) { + List customReadListenerList = new ArrayList(); + customReadListenerList.add(eventListener); + readWorkbook.setCustomReadListenerList(customReadListenerList); + } + readWorkbook.setAutoTrim(trim); + readWorkbook.setAutoCloseStream(Boolean.FALSE); + readWorkbook.setMandatoryUseInputStream(Boolean.TRUE); + readWorkbook.setReadCache(new MapCache()); + readWorkbook.setConvertAllFiled(Boolean.FALSE); + readWorkbook.setDefaultReturnMap(Boolean.FALSE); + excelAnalyser = new ExcelAnalyserImpl(readWorkbook); + } + + public ExcelReader(ReadWorkbook readWorkbook) { + excelAnalyser = new ExcelAnalyserImpl(readWorkbook); } /** * Parse all sheet content by default */ public void read() { - analyser.analysis(); + ExcelExecutor excelExecutor = excelAnalyser.excelExecutor(); + if (excelExecutor.sheetList().isEmpty()) { + LOGGER.warn("Excel doesn't have any sheets."); + return; + } + for (ReadSheet readSheet : excelExecutor.sheetList()) { + read(readSheet); + } + } + + /** + * Parse the specified sheet,SheetNo start from 1 + * + * @param readSheet + * Read sheet + */ + public ExcelReader read(ReadSheet readSheet) { + checkFinished(); + excelAnalyser.analysis(readSheet); + return this; } /** * Parse the specified sheet,SheetNo start from 1 * - * @param sheet Read sheet + * @param sheet + * Read sheet + * @deprecated please us {@link #read(ReadSheet)} */ + @Deprecated public void read(Sheet sheet) { - analyser.analysis(sheet); + ReadSheet readSheet = null; + if (sheet != null) { + readSheet = new ReadSheet(); + readSheet.setSheetNo(sheet.getSheetNo() - 1); + readSheet.setSheetName(sheet.getSheetName()); + readSheet.setClazz(sheet.getClazz()); + readSheet.setHead(sheet.getHead()); + readSheet.setHeadRowNumber(sheet.getHeadLineMun()); + } + read(readSheet); } /** * Parse the specified sheet * - * @param sheet Read sheet - * @param clazz object parsed into each row of data + * @param sheet + * Read sheet + * @param clazz + * object parsed into each row of value + * + * @deprecated Set the class in the sheet before read */ @Deprecated - public void read(Sheet sheet, Class clazz) { - sheet.setClazz(clazz); - analyser.analysis(sheet); + public void read(Sheet sheet, Class clazz) { + if (sheet != null) { + sheet.setClazz(clazz); + } + read(sheet); + } + + /** + * Context for the entire execution process + * + * @return + */ + public AnalysisContext analysisContext() { + checkFinished(); + return excelAnalyser.analysisContext(); + } + + /** + * Current executor + * + * @return + */ + public ExcelExecutor excelExecutor() { + checkFinished(); + return excelAnalyser.excelExecutor(); } /** * Parse the workBook get all sheets * * @return workBook all sheets + * + * @deprecated please use {@link #excelExecutor()} */ + @Deprecated public List getSheets() { - return analyser.getSheets(); + List sheetList = excelExecutor().sheetList(); + List sheets = new ArrayList(); + if (sheetList == null || sheetList.isEmpty()) { + return sheets; + } + for (ReadSheet readSheet : sheetList) { + Sheet sheet = new Sheet(readSheet.getSheetNo() + 1); + sheet.setSheetName(readSheet.getSheetName()); + sheets.add(sheet); + } + return sheets; } /** - * validate param * - * @param in - * @param eventListener + * @return + * @deprecated please use {@link #analysisContext()} + */ + @Deprecated + public AnalysisContext getAnalysisContext() { + return analysisContext(); + } + + /** + * Complete the entire read file.Release the cache and close stream. + */ + public void finish() { + if (finished) { + return; + } + finished = true; + excelAnalyser.finish(); + } + + /** + * Prevents calls to {@link #finish} from freeing the cache + * */ - private void validateParam(InputStream in, AnalysisEventListener eventListener) { - if (eventListener == null) { - throw new IllegalArgumentException("AnalysisEventListener can not null"); - } else if (in == null) { - throw new IllegalArgumentException("InputStream can not null"); + @Override + protected void finalize() { + if (finished) { + return; + } + try { + excelAnalyser.finish(); + } catch (Throwable e) { + LOGGER.warn("Destroy object failed", e); + } + } + + private void checkFinished() { + if (finished) { + throw new ExcelAnalysisException("Can not use a finished reader."); } } } diff --git a/src/main/java/com/alibaba/excel/ExcelWriter.java b/src/main/java/com/alibaba/excel/ExcelWriter.java index e3c5e0e..c99787d 100644 --- a/src/main/java/com/alibaba/excel/ExcelWriter.java +++ b/src/main/java/com/alibaba/excel/ExcelWriter.java @@ -1,182 +1,292 @@ package com.alibaba.excel; -import com.alibaba.excel.event.WriteHandler; -import com.alibaba.excel.metadata.BaseRowModel; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.metadata.Table; import com.alibaba.excel.parameter.GenerateParam; import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.write.ExcelBuilder; import com.alibaba.excel.write.ExcelBuilderImpl; - -import java.io.InputStream; -import java.io.OutputStream; -import java.util.List; +import com.alibaba.excel.write.handler.WriteHandler; +import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.WriteTable; +import com.alibaba.excel.write.metadata.WriteWorkbook; /** - * Excel Writer This tool is used to write data out to Excel via POI. - * This object can perform the following two functions. + * Excel Writer This tool is used to write value out to Excel via POI. This object can perform the following two + * functions. + * *
- *    1. Create a new empty Excel workbook, write the data to the stream after the data is filled.
+ *    1. Create a new empty Excel workbook, write the value to the stream after the value is filled.
  *    2. Edit existing Excel, write the original Excel file, or write it to other places.}
  * 
+ * * @author jipengfei */ public class ExcelWriter { - private ExcelBuilder excelBuilder; /** * Create new writer - * @param outputStream the java OutputStream you wish to write the data to - * @param typeEnum 03 or 07 + * + * @param writeWorkbook */ - public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum) { - this(outputStream, typeEnum, true); + public ExcelWriter(WriteWorkbook writeWorkbook) { + excelBuilder = new ExcelBuilderImpl(writeWorkbook); } - @Deprecated - private Class objectClass; - /** - * @param generateParam + * Create new writer + * + * @param outputStream + * the java OutputStream you wish to write the value to + * @param typeEnum + * 03 or 07 + * @deprecated please use {@link com.alibaba.excel.write.builder.ExcelWriterBuilder} build ExcelWriter */ @Deprecated - public ExcelWriter(GenerateParam generateParam) { - this(generateParam.getOutputStream(), generateParam.getType(), true); - this.objectClass = generateParam.getClazz(); + public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum) { + this(outputStream, typeEnum, true); } /** * * Create new writer - * @param outputStream the java OutputStream you wish to write the data to - * @param typeEnum 03 or 07 - * @param needHead Do you need to write the header to the file? + * + * @param outputStream + * the java OutputStream you wish to write the value to + * @param typeEnum + * 03 or 07 + * @param needHead + * Do you need to write the header to the file? + * @deprecated please use {@link com.alibaba.excel.write.builder.ExcelWriterBuilder} build ExcelWriter */ + @Deprecated public ExcelWriter(OutputStream outputStream, ExcelTypeEnum typeEnum, boolean needHead) { - excelBuilder = new ExcelBuilderImpl(null, outputStream, typeEnum, needHead, null); + this(null, outputStream, typeEnum, needHead, null); } /** - * Create new writer - * @param templateInputStream Append data after a POI file ,Can be null(the template POI filesystem that contains the Workbook stream) - * @param outputStream the java OutputStream you wish to write the data to - * @param typeEnum 03 or 07 + * Create new writer + * + * @param templateInputStream + * Append value after a POI file ,Can be null(the template POI filesystem that contains the Workbook + * stream) + * @param outputStream + * the java OutputStream you wish to write the value to + * @param typeEnum + * 03 or 07 + * @deprecated please use {@link com.alibaba.excel.write.builder.ExcelWriterBuilder} build ExcelWriter */ - public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum,Boolean needHead) { - excelBuilder = new ExcelBuilderImpl(templateInputStream,outputStream, typeEnum, needHead, null); + @Deprecated + public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum, + Boolean needHead) { + this(templateInputStream, outputStream, typeEnum, needHead, null); } + /** + * Create new writer + * + * @param templateInputStream + * Append value after a POI file ,Can be null(the template POI filesystem that contains the Workbook + * stream) + * @param outputStream + * the java OutputStream you wish to write the value to + * @param typeEnum + * 03 or 07 + * @param writeHandler + * User-defined callback + * @deprecated please use {@link com.alibaba.excel.write.builder.ExcelWriterBuilder} build ExcelWriter + */ + @Deprecated + public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum, + Boolean needHead, WriteHandler writeHandler) { + List customWriteHandlerList = new ArrayList(); + customWriteHandlerList.add(writeHandler); + WriteWorkbook writeWorkbook = new WriteWorkbook(); + writeWorkbook.setTemplateInputStream(templateInputStream); + writeWorkbook.setOutputStream(outputStream); + writeWorkbook.setExcelType(typeEnum); + writeWorkbook.setNeedHead(needHead); + writeWorkbook.setCustomWriteHandlerList(customWriteHandlerList); + excelBuilder = new ExcelBuilderImpl(writeWorkbook); + } /** - * Create new writer - * @param templateInputStream Append data after a POI file ,Can be null(the template POI filesystem that contains the Workbook stream) - * @param outputStream the java OutputStream you wish to write the data to - * @param typeEnum 03 or 07 - * @param writeHandler User-defined callback + * @param generateParam + * @deprecated please use {@link com.alibaba.excel.write.builder.ExcelWriterBuilder} build ExcelWriter */ - public ExcelWriter(InputStream templateInputStream, OutputStream outputStream, ExcelTypeEnum typeEnum, Boolean needHead, - WriteHandler writeHandler) { - excelBuilder = new ExcelBuilderImpl(templateInputStream,outputStream, typeEnum, needHead,writeHandler); + @Deprecated + public ExcelWriter(GenerateParam generateParam) { + this(generateParam.getOutputStream(), generateParam.getType(), true); } /** * Write data to a sheet - * @param data Data to be written - * @param sheet Write to this sheet + * + * @param data + * Data to be written + * @param writeSheet + * Write to this sheet * @return this current writer */ - public ExcelWriter write(List data, Sheet sheet) { - excelBuilder.addContent(data, sheet); - return this; + public ExcelWriter write(List data, WriteSheet writeSheet) { + return write(data, writeSheet, null); } + /** + * Write value to a sheet + * + * @param data + * Data to be written + * @param writeSheet + * Write to this sheet + * @param writeTable + * Write to this table + * @return this + */ + public ExcelWriter write(List data, WriteSheet writeSheet, WriteTable writeTable) { + excelBuilder.addContent(data, writeSheet, writeTable); + return this; + } /** * Write data to a sheet - * @param data Data to be written + * + * @param data + * Data to be written + * @param sheet + * Write to this sheet * @return this current writer + * @deprecated please use {@link ExcelWriter#write(List, WriteSheet)} */ @Deprecated - public ExcelWriter write(List data) { - if (objectClass != null) { - return this.write(data,new Sheet(1,0,objectClass)); - }else { - return this.write0(data,new Sheet(1,0,objectClass)); - - } + public ExcelWriter write(List data, Sheet sheet) { + return write(data, sheet, null); } /** + * Write value to a sheet * - * Write data to a sheet - * @param data Data to be written - * @param sheet Write to this sheet + * @param data + * Data to be written + * @param sheet + * Write to this sheet + * @param table + * Write to this table * @return this + * @deprecated * @deprecated please use {@link ExcelWriter#write(List, WriteSheet,WriteTable)} */ - public ExcelWriter write1(List> data, Sheet sheet) { - excelBuilder.addContent(data, sheet); - return this; + @Deprecated + public ExcelWriter write(List data, Sheet sheet, Table table) { + WriteSheet writeSheet = null; + if (sheet != null) { + writeSheet = new WriteSheet(); + writeSheet.setSheetNo(sheet.getSheetNo() - 1); + writeSheet.setSheetName(sheet.getSheetName()); + writeSheet.setClazz(sheet.getClazz()); + writeSheet.setHead(sheet.getHead()); + writeSheet.setTableStyle(sheet.getTableStyle()); + writeSheet.setRelativeHeadRowIndex(sheet.getStartRow()); + writeSheet.setColumnWidthMap(sheet.getColumnWidthMap()); + } + + WriteTable writeTable = null; + if (table != null) { + writeTable = new WriteTable(); + writeTable.setTableNo(table.getTableNo()); + writeTable.setClazz(table.getClazz()); + writeTable.setHead(table.getHead()); + writeTable.setTableStyle(table.getTableStyle()); + } + return write(data, writeSheet, writeTable); } /** * Write data to a sheet - * @param data Data to be written - * @param sheet Write to this sheet - * @return this + * + * @param data + * Data to be written + * @param sheet + * Write to this sheet + * @return this current writer + * @deprecated please use {@link ExcelWriter#write(List, WriteSheet)} */ - public ExcelWriter write0(List> data, Sheet sheet) { - excelBuilder.addContent(data, sheet); - return this; + @Deprecated + public ExcelWriter write0(List data, Sheet sheet) { + return write(data, sheet, null); } /** - * Write data to a sheet - * @param data Data to be written - * @param sheet Write to this sheet - * @param table Write to this table + * Write value to a sheet + * + * @param data + * Data to be written + * @param sheet + * Write to this sheet + * @param table + * Write to this table * @return this + * @deprecated * @deprecated please use {@link ExcelWriter#write(List, WriteSheet,WriteTable)} */ - public ExcelWriter write(List data, Sheet sheet, Table table) { - excelBuilder.addContent(data, sheet, table); - return this; + @Deprecated + public ExcelWriter write0(List data, Sheet sheet, Table table) { + return write(data, sheet, table); } /** * Write data to a sheet - * @param data Data to be written - * @param sheet Write to this sheet - * @param table Write to this table - * @return this + * + * @param data + * Data to be written + * @param sheet + * Write to this sheet + * @return this current writer + * @deprecated please use {@link ExcelWriter#write(List, WriteSheet)} */ - public ExcelWriter write0(List> data, Sheet sheet, Table table) { - excelBuilder.addContent(data, sheet, table); - return this; + @Deprecated + public ExcelWriter write1(List data, Sheet sheet) { + return write(data, sheet, null); } /** - * Merge Cells,Indexes are zero-based. + * Write value to a sheet * - * @param firstRow Index of first row - * @param lastRow Index of last row (inclusive), must be equal to or larger than {@code firstRow} - * @param firstCol Index of first column - * @param lastCol Index of last column (inclusive), must be equal to or larger than {@code firstCol} + * @param data + * Data to be written + * @param sheet + * Write to this sheet + * @param table + * Write to this table + * @return this + * @deprecated * @deprecated please use {@link ExcelWriter#write(List, WriteSheet,WriteTable)} */ - public ExcelWriter merge(int firstRow, int lastRow, int firstCol, int lastCol){ - excelBuilder.merge(firstRow,lastRow,firstCol,lastCol); - return this; + @Deprecated + public ExcelWriter write1(List data, Sheet sheet, Table table) { + return write(data, sheet, table); } /** - * Write data to a sheet - * @param data Data to be written - * @param sheet Write to this sheet - * @param table Write to this table - * @return + * Merge Cells,Indexes are zero-based. + * + * @param firstRow + * Index of first row + * @param lastRow + * Index of last row (inclusive), must be equal to or larger than {@code firstRow} + * @param firstCol + * Index of first column + * @param lastCol + * Index of last column (inclusive), must be equal to or larger than {@code firstCol} + * @deprecated please use{@link OnceAbsoluteMergeStrategy} */ - public ExcelWriter write1(List> data, Sheet sheet, Table table) { - excelBuilder.addContent(data, sheet, table); + @Deprecated + public ExcelWriter merge(int firstRow, int lastRow, int firstCol, int lastCol) { + excelBuilder.merge(firstRow, lastRow, firstCol, lastCol); return this; } @@ -186,4 +296,5 @@ public class ExcelWriter { public void finish() { excelBuilder.finish(); } + } diff --git a/src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java deleted file mode 100644 index 45c0d9b..0000000 --- a/src/main/java/com/alibaba/excel/analysis/BaseSaxAnalyser.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.alibaba.excel.analysis; - -import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.event.AnalysisEventListener; -import com.alibaba.excel.event.AnalysisEventRegisterCenter; -import com.alibaba.excel.event.OneRowAnalysisFinishEvent; -import com.alibaba.excel.metadata.Sheet; -import com.alibaba.excel.util.TypeUtil; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -/** - * @author jipengfei - */ -public abstract class BaseSaxAnalyser implements AnalysisEventRegisterCenter, ExcelAnalyser { - - protected AnalysisContext analysisContext; - - private LinkedHashMap listeners = new LinkedHashMap(); - - /** - * execute method - */ - protected abstract void execute(); - - - @Override - public void appendLister(String name, AnalysisEventListener listener) { - if (!listeners.containsKey(name)) { - listeners.put(name, listener); - } - } - - @Override - public void analysis(Sheet sheetParam) { - execute(); - } - - @Override - public void analysis() { - execute(); - } - - /** - */ - @Override - public void cleanAllListeners() { - listeners = new LinkedHashMap(); - } - - @Override - public void notifyListeners(OneRowAnalysisFinishEvent event) { - analysisContext.setCurrentRowAnalysisResult(event.getData()); - /** Parsing header content **/ - if (analysisContext.getCurrentRowNum() < analysisContext.getCurrentSheet().getHeadLineMun()) { - if (analysisContext.getCurrentRowNum() <= analysisContext.getCurrentSheet().getHeadLineMun() - 1) { - analysisContext.buildExcelHeadProperty(null, - (List)analysisContext.getCurrentRowAnalysisResult()); - } - } else { - List content = converter((List)event.getData()); - /** Parsing Analyze the body content **/ - analysisContext.setCurrentRowAnalysisResult(content); - if (listeners.size() == 1) { - analysisContext.setCurrentRowAnalysisResult(content); - } - /** notify all event listeners **/ - for (Map.Entry entry : listeners.entrySet()) { - entry.getValue().invoke(analysisContext.getCurrentRowAnalysisResult(), analysisContext); - } - } - } - - private List converter(List data) { - List list = new ArrayList(); - if (data != null) { - for (String str : data) { - list.add(TypeUtil.formatFloat(str)); - } - } - return list; - } - -} diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java index b5aef4d..8d987ea 100644 --- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyser.java @@ -1,8 +1,7 @@ package com.alibaba.excel.analysis; -import com.alibaba.excel.metadata.Sheet; - -import java.util.List; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.metadata.ReadSheet; /** * Excel file analyser @@ -10,24 +9,31 @@ import java.util.List; * @author jipengfei */ public interface ExcelAnalyser { - /** * parse one sheet * - * @param sheetParam + * @param readSheet + * sheet to read + */ + void analysis(ReadSheet readSheet); + + /** + * Complete the entire read file.Release the cache and close stream */ - void analysis(Sheet sheetParam); + void finish(); /** - * parse all sheets + * Acquisition excel executor + * + * @return Excel file Executor */ - void analysis(); + ExcelExecutor excelExecutor(); /** - * get all sheet of workbook + * get the analysis context. * - * @return all sheets + * @return analysis context */ - List getSheets(); + AnalysisContext analysisContext(); } diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java index b8dd376..dcf1d84 100644 --- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java @@ -1,95 +1,145 @@ package com.alibaba.excel.analysis; +import java.io.InputStream; + +import org.apache.poi.poifs.crypt.Decryptor; +import org.apache.poi.poifs.filesystem.DocumentFactoryHelper; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.util.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.alibaba.excel.analysis.v03.XlsSaxAnalyser; import com.alibaba.excel.analysis.v07.XlsxSaxAnalyser; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContextImpl; -import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.exception.ExcelAnalysisException; -import com.alibaba.excel.metadata.Sheet; -import com.alibaba.excel.modelbuild.ModelBuildEventListener; +import com.alibaba.excel.exception.ExcelAnalysisStopException; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.read.metadata.ReadWorkbook; +import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; import com.alibaba.excel.support.ExcelTypeEnum; - -import java.io.InputStream; -import java.util.List; +import com.alibaba.excel.util.FileUtils; /** * @author jipengfei */ public class ExcelAnalyserImpl implements ExcelAnalyser { + private static final Logger LOGGER = LoggerFactory.getLogger(ExcelAnalyserImpl.class); private AnalysisContext analysisContext; - private BaseSaxAnalyser saxAnalyser; + private ExcelExecutor excelExecutor; - public ExcelAnalyserImpl(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom, - AnalysisEventListener eventListener, boolean trim) { - analysisContext = new AnalysisContextImpl(inputStream, excelTypeEnum, custom, - eventListener, trim); + public ExcelAnalyserImpl(ReadWorkbook readWorkbook) { + try { + analysisContext = new AnalysisContextImpl(readWorkbook); + choiceExcelExecutor(); + } catch (RuntimeException e) { + finish(); + throw e; + } catch (Throwable e) { + finish(); + throw new ExcelAnalysisException(e); + } } - private BaseSaxAnalyser getSaxAnalyser() { - if (saxAnalyser != null) { - return this.saxAnalyser; + private void choiceExcelExecutor() throws Exception { + ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder(); + ExcelTypeEnum excelType = readWorkbookHolder.getExcelType(); + if (excelType == null) { + excelExecutor = new XlsxSaxAnalyser(analysisContext, null); + return; } - try { - if (analysisContext.getExcelType() != null) { - switch (analysisContext.getExcelType()) { - case XLS: - this.saxAnalyser = new XlsSaxAnalyser(analysisContext); - break; - case XLSX: - this.saxAnalyser = new XlsxSaxAnalyser(analysisContext); - break; + switch (excelType) { + case XLS: + POIFSFileSystem poifsFileSystem = null; + if (readWorkbookHolder.getFile() != null) { + poifsFileSystem = new POIFSFileSystem(readWorkbookHolder.getFile()); + } else { + poifsFileSystem = new POIFSFileSystem(readWorkbookHolder.getInputStream()); } - } else { - try { - this.saxAnalyser = new XlsxSaxAnalyser(analysisContext); - } catch (Exception e) { - if (!analysisContext.getInputStream().markSupported()) { - throw new ExcelAnalysisException( - "Xls must be available markSupported,you can do like this new " - + "BufferedInputStream(new FileInputStream(\"/xxxx\")) "); + // So in encrypted excel, it looks like XLS but it's actually XLSX + if (poifsFileSystem.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) { + InputStream decryptedStream = null; + try { + decryptedStream = DocumentFactoryHelper.getDecryptedStream(poifsFileSystem.getRoot(), null); + excelExecutor = new XlsxSaxAnalyser(analysisContext, decryptedStream); + return; + } finally { + IOUtils.closeQuietly(decryptedStream); + // as we processed the full stream already, we can close the filesystem here + // otherwise file handles are leaked + poifsFileSystem.close(); } - this.saxAnalyser = new XlsSaxAnalyser(analysisContext); } - } - } catch (Exception e) { - throw new ExcelAnalysisException("File type error,io must be available markSupported,you can do like " - + "this new BufferedInputStream(new FileInputStream(\\\"/xxxx\\\")) \"", e); + excelExecutor = new XlsSaxAnalyser(analysisContext, poifsFileSystem); + break; + case XLSX: + excelExecutor = new XlsxSaxAnalyser(analysisContext, null); + break; + default: } - return this.saxAnalyser; } @Override - public void analysis(Sheet sheetParam) { - analysisContext.setCurrentSheet(sheetParam); - analysis(); + public void analysis(ReadSheet readSheet) { + try { + analysisContext.currentSheet(excelExecutor, readSheet); + try { + excelExecutor.execute(); + } catch (ExcelAnalysisStopException e) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Custom stop!"); + } + } + analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext); + } catch (RuntimeException e) { + finish(); + throw e; + } catch (Throwable e) { + finish(); + throw new ExcelAnalysisException(e); + } } @Override - public void analysis() { - BaseSaxAnalyser saxAnalyser = getSaxAnalyser(); - appendListeners(saxAnalyser); - saxAnalyser.execute(); - analysisContext.getEventListener().doAfterAllAnalysed(analysisContext); + public void finish() { + if (analysisContext == null || analysisContext.readWorkbookHolder() == null) { + return; + } + ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder(); + try { + if (readWorkbookHolder.getReadCache() != null) { + readWorkbookHolder.getReadCache().destroy(); + } + } catch (Throwable e) { + throw new ExcelAnalysisException("Can not close IO", e); + } + try { + if (analysisContext.readWorkbookHolder().getAutoCloseStream() + && readWorkbookHolder.getInputStream() != null) { + readWorkbookHolder.getInputStream().close(); + } + } catch (Throwable e) { + throw new ExcelAnalysisException("Can not close IO", e); + } + try { + if (readWorkbookHolder.getTempFile() != null) { + FileUtils.delete(readWorkbookHolder.getTempFile()); + } + } catch (Throwable e) { + throw new ExcelAnalysisException("Can not close IO", e); + } } @Override - public List getSheets() { - BaseSaxAnalyser saxAnalyser = getSaxAnalyser(); - saxAnalyser.cleanAllListeners(); - return saxAnalyser.getSheets(); + public com.alibaba.excel.analysis.ExcelExecutor excelExecutor() { + return excelExecutor; } - private void appendListeners(BaseSaxAnalyser saxAnalyser) { - saxAnalyser.cleanAllListeners(); - if (analysisContext.getCurrentSheet() != null && analysisContext.getCurrentSheet().getClazz() != null) { - saxAnalyser.appendLister("model_build_listener", new ModelBuildEventListener()); - } - if (analysisContext.getEventListener() != null) { - saxAnalyser.appendLister("user_define_listener", analysisContext.getEventListener()); - } + @Override + public AnalysisContext analysisContext() { + return analysisContext; } - } diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelExecutor.java b/src/main/java/com/alibaba/excel/analysis/ExcelExecutor.java new file mode 100644 index 0000000..8868d2e --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/ExcelExecutor.java @@ -0,0 +1,26 @@ +package com.alibaba.excel.analysis; + +import java.util.List; + +import com.alibaba.excel.read.metadata.ReadSheet; + +/** + * Excel file Executor + * + * @author Jiaju Zhuang + */ +public interface ExcelExecutor { + + /** + * Returns the actual sheet in excel + * + * @return Actual sheet in excel + */ + List sheetList(); + + /** + * Read sheet + */ + void execute(); + +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java new file mode 100644 index 0000000..6128708 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java @@ -0,0 +1,33 @@ +package com.alibaba.excel.analysis.v03; + +import com.alibaba.excel.metadata.CellData; + +/** + * + * @author Dan Zheng + */ +public abstract class AbstractXlsRecordHandler implements XlsRecordHandler { + protected int row = -1; + protected int column = -1; + protected CellData cellData; + + @Override + public int getRow() { + return row; + } + + @Override + public int getColumn() { + return column; + } + + @Override + public CellData getCellData() { + return cellData; + } + + @Override + public int compareTo(XlsRecordHandler o) { + return this.getOrder() - o.getOrder(); + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java new file mode 100644 index 0000000..b786bcb --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java @@ -0,0 +1,61 @@ +package com.alibaba.excel.analysis.v03; + +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.metadata.CellData; + +/** + * Intercepts handle xls reads. + * + * @author Dan Zheng + */ +public interface XlsRecordHandler extends Comparable { + /** + * Which tags are supported + * + * @param record + * Excel analysis record + * @return Which tags are supported + */ + boolean support(Record record); + + /** + * Initialize + */ + void init(); + + /** + * Processing record + * + * @param record + */ + void processRecord(Record record); + + /** + * Get row + * + * @return Row index + */ + int getRow(); + + /** + * Get column + * + * @return Column index + */ + int getColumn(); + + /** + * Get value + * + * @return Excel internal cell data + */ + CellData getCellData(); + + /** + * Get order + * + * @return Order + */ + int getOrder(); +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java index 0154625..996e33a 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java @@ -1,292 +1,154 @@ package com.alibaba.excel.analysis.v03; -import com.alibaba.excel.analysis.BaseSaxAnalyser; -import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.event.OneRowAnalysisFinishEvent; -import com.alibaba.excel.exception.ExcelAnalysisException; -import com.alibaba.excel.metadata.Sheet; -import org.apache.poi.hssf.eventusermodel.*; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder; +import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; +import org.apache.poi.hssf.eventusermodel.HSSFEventFactory; +import org.apache.poi.hssf.eventusermodel.HSSFListener; +import org.apache.poi.hssf.eventusermodel.HSSFRequest; +import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener; import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; -import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; -import org.apache.poi.hssf.model.HSSFFormulaParser; -import org.apache.poi.hssf.record.*; +import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.POIFSFileSystem; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; +import com.alibaba.excel.analysis.ExcelExecutor; +import com.alibaba.excel.analysis.v03.handlers.BlankOrErrorRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.BofRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.FormulaRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.LabelRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.MissingCellDummyRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.NoteRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.NumberRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.RkRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.SstRecordHandler; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.read.listener.event.EachRowAnalysisFinishEvent; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.read.metadata.holder.ReadRowHolder; +import com.alibaba.excel.util.CollectionUtils; /** - * /** * A text extractor for Excel files. *

* Returns the textual content of the file, suitable for * indexing by - * something like Lucene, but not really * intended for display to the user. *

*

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

* * @see - * XLS2CSVmra + * /** * A text extractor for Excel files. * + *

+ * * Returns the textual content of the file, suitable for * indexing by something like Lucene, but not really * + * intended for display to the user. * + *

+ * * + *

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

+ * * * @see XLS2CSVmra * * @author jipengfei */ -public class XlsSaxAnalyser extends BaseSaxAnalyser implements HSSFListener { - - private boolean analyAllSheet = false; +public class XlsSaxAnalyser implements HSSFListener, ExcelExecutor { + private boolean outputFormulaValues = true; + private POIFSFileSystem poifsFileSystem; + private int lastRowNumber; + private int lastColumnNumber; + private boolean notAllEmpty = false; + /** + * For parsing Formulas + */ + private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener; + private FormatTrackingHSSFListener formatListener; + private Map records; + private List sheets = new ArrayList(); + private HSSFWorkbook stubWorkbook; + private List recordHandlers = new ArrayList(); + private AnalysisContext analysisContext; - public XlsSaxAnalyser(AnalysisContext context) throws IOException { + public XlsSaxAnalyser(AnalysisContext context, POIFSFileSystem poifsFileSystem) throws IOException { this.analysisContext = context; - this.records = new ArrayList(); - if (analysisContext.getCurrentSheet() == null) { - this.analyAllSheet = true; - } - context.setCurrentRowNum(0); - this.fs = new POIFSFileSystem(analysisContext.getInputStream()); - + this.records = new TreeMap(); + this.poifsFileSystem = poifsFileSystem; } @Override - public List getSheets() { - execute(); + public List sheetList() { return sheets; } @Override public void execute() { - init(); MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this); formatListener = new FormatTrackingHSSFListener(listener); + workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener); + if (workbookBuildingListener != null && stubWorkbook == null) { + stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook(); + } + + init(); HSSFEventFactory factory = new HSSFEventFactory(); HSSFRequest request = new HSSFRequest(); - if (outputFormulaValues) { request.addListenerForAllRecords(formatListener); } else { - workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener); request.addListenerForAllRecords(workbookBuildingListener); } try { - factory.processWorkbookEvents(request, fs); + factory.processWorkbookEvents(request, poifsFileSystem); } catch (IOException e) { throw new ExcelAnalysisException(e); } + // Sometimes tables lack the end record of the last column + if (!records.isEmpty()) { + endRow(); + } } private void init() { lastRowNumber = 0; lastColumnNumber = 0; - nextRow = 0; - - nextColumn = 0; - - sheetIndex = 0; - - records = new ArrayList(); - - notAllEmpty = false; - - orderedBSRs = null; - - boundSheetRecords = new ArrayList(); - - sheets = new ArrayList(); - if (analysisContext.getCurrentSheet() == null) { - this.analyAllSheet = true; - } else { - this.analyAllSheet = false; - } + records = new TreeMap(); + sheets = new ArrayList(); + buildXlsRecordHandlers(); } - private POIFSFileSystem fs; - - private int lastRowNumber; - private int lastColumnNumber; - - /** - * Should we output the formula, or the value it has? - */ - private boolean outputFormulaValues = true; - - /** - * For parsing Formulas - */ - private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener; - private HSSFWorkbook stubWorkbook; - private SSTRecord sstRecord; - private FormatTrackingHSSFListener formatListener; - - /** - * So we known which sheet we're on - */ - - private int nextRow; - private int nextColumn; - private boolean outputNextStringRecord; - - /** - * Main HSSFListener method, processes events, and outputs the CSV as the file is processed. - */ - - private int sheetIndex; - - private List records; - - private boolean notAllEmpty = false; - - private BoundSheetRecord[] orderedBSRs; - - private List boundSheetRecords = new ArrayList(); - - private List sheets = new ArrayList(); - + @Override public void processRecord(Record record) { int thisRow = -1; int thisColumn = -1; - String thisStr = null; - - switch (record.getSid()) { - case BoundSheetRecord.sid: - boundSheetRecords.add((BoundSheetRecord)record); - break; - case BOFRecord.sid: - BOFRecord br = (BOFRecord)record; - if (br.getType() == BOFRecord.TYPE_WORKSHEET) { - // Create sub workbook if required - if (workbookBuildingListener != null && stubWorkbook == null) { - stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook(); - } - - if (orderedBSRs == null) { - orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords); - } - sheetIndex++; - - Sheet sheet = new Sheet(sheetIndex, 0); - sheet.setSheetName(orderedBSRs[sheetIndex - 1].getSheetname()); - sheets.add(sheet); - if (this.analyAllSheet) { - analysisContext.setCurrentSheet(sheet); - } - } - break; - - case SSTRecord.sid: - sstRecord = (SSTRecord)record; - break; - - case BlankRecord.sid: - BlankRecord brec = (BlankRecord)record; - - thisRow = brec.getRow(); - thisColumn = brec.getColumn(); - thisStr = ""; - break; - case BoolErrRecord.sid: - BoolErrRecord berec = (BoolErrRecord)record; - - thisRow = berec.getRow(); - thisColumn = berec.getColumn(); - thisStr = ""; - break; - - case FormulaRecord.sid: - FormulaRecord frec = (FormulaRecord)record; - - thisRow = frec.getRow(); - thisColumn = frec.getColumn(); - - if (outputFormulaValues) { - if (Double.isNaN(frec.getValue())) { - // Formula result is a string - // This is stored in the next record - outputNextStringRecord = true; - nextRow = frec.getRow(); - nextColumn = frec.getColumn(); - } else { - thisStr = formatListener.formatNumberDateCell(frec); - } - } else { - thisStr = HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()); - } - break; - case StringRecord.sid: - if (outputNextStringRecord) { - // String for formula - StringRecord srec = (StringRecord)record; - thisStr = srec.getString(); - thisRow = nextRow; - thisColumn = nextColumn; - outputNextStringRecord = false; - } - break; - - case LabelRecord.sid: - LabelRecord lrec = (LabelRecord)record; - - thisRow = lrec.getRow(); - thisColumn = lrec.getColumn(); - thisStr = lrec.getValue(); - break; - case LabelSSTRecord.sid: - LabelSSTRecord lsrec = (LabelSSTRecord)record; - - thisRow = lsrec.getRow(); - thisColumn = lsrec.getColumn(); - if (sstRecord == null) { - thisStr = ""; - } else { - thisStr = sstRecord.getString(lsrec.getSSTIndex()).toString(); + CellData cellData = null; + for (XlsRecordHandler handler : this.recordHandlers) { + if (handler.support(record)) { + handler.processRecord(record); + thisRow = handler.getRow(); + thisColumn = handler.getColumn(); + cellData = handler.getCellData(); + if (cellData != null) { + records.put(thisColumn, cellData); } break; - case NoteRecord.sid: - NoteRecord nrec = (NoteRecord)record; - - thisRow = nrec.getRow(); - thisColumn = nrec.getColumn(); - // TODO: Find object to match nrec.getShapeId() - thisStr = "(TODO)"; - break; - case NumberRecord.sid: - NumberRecord numrec = (NumberRecord)record; - - thisRow = numrec.getRow(); - thisColumn = numrec.getColumn(); - - // Format - thisStr = formatListener.formatNumberDateCell(numrec); - break; - case RKRecord.sid: - RKRecord rkrec = (RKRecord)record; - - thisRow = rkrec.getRow(); - thisColumn = rkrec.getColumn(); - thisStr = ""; - break; - default: - break; - } - - // Handle new row - if (thisRow != -1 && thisRow != lastRowNumber) { - lastColumnNumber = -1; - } - - // Handle missing column - if (record instanceof MissingCellDummyRecord) { - MissingCellDummyRecord mc = (MissingCellDummyRecord)record; - thisRow = mc.getRow(); - thisColumn = mc.getColumn(); - thisStr = ""; + } } - // If we got something to print out, do so - if (thisStr != null) { - - if (analysisContext.trim()) { - thisStr = thisStr.trim(); + if (cellData != null) { + if (analysisContext.currentReadHolder().globalConfiguration().getAutoTrim() + && CellDataTypeEnum.STRING == cellData.getType()) { + cellData.setStringValue(cellData.getStringValue().trim()); } - if (!"".equals(thisStr)) { + if (CellDataTypeEnum.EMPTY != cellData.getType()) { notAllEmpty = true; } - // } - records.add(thisStr); + } + + // Handle new row + if (thisRow != -1 && thisRow != lastRowNumber) { + lastColumnNumber = -1; } // Update column and row count @@ -297,22 +159,45 @@ public class XlsSaxAnalyser extends BaseSaxAnalyser implements HSSFListener { lastColumnNumber = thisColumn; } + processLastCellOfRow(record); + } + + private void processLastCellOfRow(Record record) { // Handle end of row if (record instanceof LastCellOfRowDummyRecord) { - thisRow = ((LastCellOfRowDummyRecord)record).getRow(); + endRow(); + } + } - if (lastColumnNumber == -1) { - lastColumnNumber = 0; - } - analysisContext.setCurrentRowNum(thisRow); - Sheet sheet = analysisContext.getCurrentSheet(); + private void endRow() { + if (lastColumnNumber == -1) { + lastColumnNumber = 0; + } + if (notAllEmpty) { + analysisContext.readRowHolder( + new ReadRowHolder(lastRowNumber, analysisContext.readSheetHolder().getGlobalConfiguration())); + analysisContext.readSheetHolder().notifyEndOneRow(new EachRowAnalysisFinishEvent(records), analysisContext); + } + records.clear(); + lastColumnNumber = -1; + } - if ((sheet == null || sheet.getSheetNo() == sheetIndex) && notAllEmpty) { - notifyListeners(new OneRowAnalysisFinishEvent(records)); - } - records.clear(); - lastColumnNumber = -1; - notAllEmpty = false; + private void buildXlsRecordHandlers() { + if (CollectionUtils.isEmpty(recordHandlers)) { + recordHandlers.add(new BlankOrErrorRecordHandler()); + recordHandlers.add(new BofRecordHandler(workbookBuildingListener, analysisContext, sheets)); + recordHandlers.add(new FormulaRecordHandler(stubWorkbook, formatListener)); + recordHandlers.add(new LabelRecordHandler()); + recordHandlers.add(new NoteRecordHandler()); + recordHandlers.add(new NumberRecordHandler(formatListener)); + recordHandlers.add(new RkRecordHandler()); + recordHandlers.add(new SstRecordHandler()); + recordHandlers.add(new MissingCellDummyRecordHandler()); + Collections.sort(recordHandlers); + } + + for (XlsRecordHandler x : recordHandlers) { + x.init(); } } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java new file mode 100644 index 0000000..f64d437 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java @@ -0,0 +1,47 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.BlankRecord; +import org.apache.poi.hssf.record.BoolErrRecord; +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class BlankOrErrorRecordHandler extends AbstractXlsRecordHandler { + + @Override + public boolean support(Record record) { + return BlankRecord.sid == record.getSid() || BoolErrRecord.sid == record.getSid(); + } + + @Override + public void processRecord(Record record) { + if (record.getSid() == BlankRecord.sid) { + BlankRecord br = (BlankRecord)record; + this.row = br.getRow(); + this.column = br.getColumn(); + this.cellData = new CellData(CellDataTypeEnum.EMPTY); + } else if (record.getSid() == BoolErrRecord.sid) { + BoolErrRecord ber = (BoolErrRecord)record; + this.row = ber.getRow(); + this.column = ber.getColumn(); + this.cellData = new CellData(ber.getBooleanValue()); + } + } + + @Override + public void init() { + + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java new file mode 100644 index 0000000..da5967d --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java @@ -0,0 +1,76 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder; +import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.BoundSheetRecord; +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.metadata.ReadSheet; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class BofRecordHandler extends AbstractXlsRecordHandler { + private List boundSheetRecords = new ArrayList(); + private BoundSheetRecord[] orderedBsrs; + private int sheetIndex; + private List sheets; + private AnalysisContext context; + private boolean analyAllSheet; + private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener; + + public BofRecordHandler(EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener, + AnalysisContext context, List sheets) { + this.context = context; + this.workbookBuildingListener = workbookBuildingListener; + this.sheets = sheets; + } + + @Override + public boolean support(Record record) { + return BoundSheetRecord.sid == record.getSid() || BOFRecord.sid == record.getSid(); + } + + @Override + public void processRecord(Record record) { + if (record.getSid() == BoundSheetRecord.sid) { + boundSheetRecords.add((BoundSheetRecord)record); + } else if (record.getSid() == BOFRecord.sid) { + BOFRecord br = (BOFRecord)record; + if (br.getType() == BOFRecord.TYPE_WORKSHEET) { + if (orderedBsrs == null) { + orderedBsrs = BoundSheetRecord.orderByBofPosition(boundSheetRecords); + } + sheetIndex++; + ReadSheet readSheet = new ReadSheet(sheetIndex, orderedBsrs[sheetIndex - 1].getSheetname()); + sheets.add(readSheet); + if (this.analyAllSheet) { + context.currentSheet(null, readSheet); + } + } + } + } + + @Override + public void init() { + if (context.readSheetHolder() == null) { + this.analyAllSheet = true; + } + sheetIndex = 0; + orderedBsrs = null; + boundSheetRecords.clear(); + sheets.clear(); + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java new file mode 100644 index 0000000..f8899c0 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java @@ -0,0 +1,114 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; +import org.apache.poi.hssf.model.HSSFFormulaParser; +import org.apache.poi.hssf.record.FormulaRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.StringRecord; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.CellType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class FormulaRecordHandler extends AbstractXlsRecordHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(FormulaRecordHandler.class); + + private static final String ERROR = "#VALUE!"; + private int nextRow; + private int nextColumn; + private boolean outputNextStringRecord; + private CellData tempCellData; + private FormatTrackingHSSFListener formatListener; + private HSSFWorkbook stubWorkbook; + + public FormulaRecordHandler(HSSFWorkbook stubWorkbook, FormatTrackingHSSFListener formatListener) { + this.stubWorkbook = stubWorkbook; + this.formatListener = formatListener; + } + + @Override + public boolean support(Record record) { + return FormulaRecord.sid == record.getSid() || StringRecord.sid == record.getSid(); + } + + @Override + public void processRecord(Record record) { + if (record.getSid() == FormulaRecord.sid) { + FormulaRecord frec = (FormulaRecord)record; + + this.row = frec.getRow(); + this.column = frec.getColumn(); + CellType cellType = CellType.forInt(frec.getCachedResultType()); + String formulaValue = null; + try { + formulaValue = HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()); + } catch (Exception e) { + LOGGER.warn("Get formula value error.{}", e.getMessage()); + } + switch (cellType) { + case STRING: + // Formula result is a string + // This is stored in the next record + outputNextStringRecord = true; + nextRow = frec.getRow(); + nextColumn = frec.getColumn(); + tempCellData = new CellData(CellDataTypeEnum.STRING); + tempCellData.setFormula(Boolean.TRUE); + tempCellData.setFormulaValue(formulaValue); + break; + case NUMERIC: + this.cellData = new CellData(frec.getValue()); + this.cellData.setFormula(Boolean.TRUE); + this.cellData.setFormulaValue(formulaValue); + break; + case ERROR: + this.cellData = new CellData(CellDataTypeEnum.ERROR); + this.cellData.setStringValue(ERROR); + this.cellData.setFormula(Boolean.TRUE); + this.cellData.setFormulaValue(formulaValue); + break; + case BOOLEAN: + this.cellData = new CellData(frec.getCachedBooleanValue()); + this.cellData.setFormula(Boolean.TRUE); + this.cellData.setFormulaValue(formulaValue); + break; + default: + this.cellData = new CellData(CellDataTypeEnum.EMPTY); + this.cellData.setFormula(Boolean.TRUE); + this.cellData.setFormulaValue(formulaValue); + break; + } + } else if (record.getSid() == StringRecord.sid) { + if (outputNextStringRecord) { + // String for formula + StringRecord srec = (StringRecord)record; + this.cellData = tempCellData; + this.cellData.setStringValue(srec.getString()); + this.row = nextRow; + this.column = nextColumn; + outputNextStringRecord = false; + tempCellData = null; + } + } + } + + @Override + public void init() { + this.nextRow = 0; + this.nextColumn = 0; + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java new file mode 100644 index 0000000..35732c1 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java @@ -0,0 +1,37 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.LabelRecord; +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.metadata.CellData; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class LabelRecordHandler extends AbstractXlsRecordHandler { + @Override + public boolean support(Record record) { + return LabelRecord.sid == record.getSid(); + } + + @Override + public void processRecord(Record record) { + LabelRecord lrec = (LabelRecord)record; + this.row = lrec.getRow(); + this.column = lrec.getColumn(); + this.cellData = new CellData(lrec.getValue()); + } + + @Override + public void init() { + + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java new file mode 100644 index 0000000..c879504 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java @@ -0,0 +1,38 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class MissingCellDummyRecordHandler extends AbstractXlsRecordHandler { + @Override + public boolean support(Record record) { + return record instanceof MissingCellDummyRecord; + } + + @Override + public void init() { + + } + + @Override + public void processRecord(Record record) { + MissingCellDummyRecord mcdr = (MissingCellDummyRecord)record; + this.row = mcdr.getRow(); + this.column = mcdr.getColumn(); + this.cellData = new CellData(CellDataTypeEnum.EMPTY); + } + + @Override + public int getOrder() { + return 1; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java new file mode 100644 index 0000000..9ab800c --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java @@ -0,0 +1,38 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.NoteRecord; +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class NoteRecordHandler extends AbstractXlsRecordHandler { + @Override + public boolean support(Record record) { + return NoteRecord.sid == record.getSid(); + } + + @Override + public void processRecord(Record record) { + NoteRecord nrec = (NoteRecord)record; + this.row = nrec.getRow(); + this.column = nrec.getColumn(); + this.cellData = new CellData(CellDataTypeEnum.EMPTY); + } + + @Override + public void init() { + + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java new file mode 100644 index 0000000..23aff5a --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java @@ -0,0 +1,46 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; +import org.apache.poi.hssf.record.NumberRecord; +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.metadata.CellData; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class NumberRecordHandler extends AbstractXlsRecordHandler { + private FormatTrackingHSSFListener formatListener; + + public NumberRecordHandler(FormatTrackingHSSFListener formatListener) { + this.formatListener = formatListener; + } + + @Override + public boolean support(Record record) { + return NumberRecord.sid == record.getSid(); + } + + @Override + public void processRecord(Record record) { + NumberRecord numrec = (NumberRecord)record; + this.row = numrec.getRow(); + this.column = numrec.getColumn(); + this.cellData = new CellData(numrec.getValue()); + this.cellData.setDataFormat(formatListener.getFormatIndex(numrec)); + this.cellData.setDataFormatString(formatListener.getFormatString(numrec)); + } + + @Override + public void init() { + + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java new file mode 100644 index 0000000..140fb72 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java @@ -0,0 +1,39 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.RKRecord; +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class RkRecordHandler extends AbstractXlsRecordHandler { + @Override + public boolean support(Record record) { + return RKRecord.sid == record.getSid(); + } + + @Override + public void processRecord(Record record) { + RKRecord rkrec = (RKRecord)record; + + this.row = rkrec.getRow(); + this.row = rkrec.getColumn(); + this.cellData = new CellData(CellDataTypeEnum.EMPTY); + } + + @Override + public void init() { + + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java new file mode 100644 index 0000000..5c1c8ae --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java @@ -0,0 +1,49 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.LabelSSTRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.SSTRecord; + +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class SstRecordHandler extends AbstractXlsRecordHandler { + private SSTRecord sstRecord; + + @Override + public boolean support(Record record) { + return SSTRecord.sid == record.getSid() || LabelSSTRecord.sid == record.getSid(); + } + + @Override + public void processRecord(Record record) { + if (record.getSid() == SSTRecord.sid) { + sstRecord = (SSTRecord)record; + } else if (record.getSid() == LabelSSTRecord.sid) { + LabelSSTRecord lsrec = (LabelSSTRecord)record; + this.row = lsrec.getRow(); + this.column = lsrec.getColumn(); + if (sstRecord == null) { + this.cellData = new CellData(CellDataTypeEnum.EMPTY); + } else { + this.cellData = new CellData(sstRecord.getString(lsrec.getSSTIndex()).toString()); + } + } + } + + @Override + public void init() { + + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java new file mode 100644 index 0000000..9d228d2 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java @@ -0,0 +1,51 @@ +package com.alibaba.excel.analysis.v07; + +import org.xml.sax.Attributes; +import org.xml.sax.helpers.DefaultHandler; + +import com.alibaba.excel.cache.ReadCache; + +/** + * Sax read sharedStringsTable.xml + * + * @author Jiaju Zhuang + */ +public class SharedStringsTableHandler extends DefaultHandler { + private static final String T_TAG = "t"; + private static final String SI_TAG = "si"; + /** + * The final piece of data + */ + private String currentData; + /** + * Current element data + */ + private String currentElementData; + + private ReadCache readCache; + + public SharedStringsTableHandler(ReadCache readCache) { + this.readCache = readCache; + } + + @Override + public void startElement(String uri, String localName, String name, Attributes attributes) { + if (SI_TAG.equals(name)) { + currentData = ""; + } + } + + @Override + public void endElement(String uri, String localName, String name) { + if (T_TAG.equals(name)) { + currentData += currentElementData; + } else if (SI_TAG.equals(name)) { + readCache.put(currentData); + } + } + + @Override + public void characters(char[] ch, int start, int length) { + currentElementData = new String(ch, start, length); + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java new file mode 100644 index 0000000..a4db7f4 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java @@ -0,0 +1,37 @@ +package com.alibaba.excel.analysis.v07; + +import org.xml.sax.Attributes; + +/** + * Cell handler + * + * @author Dan Zheng + */ +public interface XlsxCellHandler { + /** + * Which tags are supported + * + * @param name + * Tag name + * @return Support parsing or not + */ + boolean support(String name); + + /** + * Start handle + * + * @param name + * Tag name + * @param attributes + * Tag attributes + */ + void startHandle(String name, Attributes attributes); + + /** + * End handle + * + * @param name + * Tag name + */ + void endHandle(String name); +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java new file mode 100644 index 0000000..82f7d2c --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java @@ -0,0 +1,27 @@ +package com.alibaba.excel.analysis.v07; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.poi.xssf.model.StylesTable; + +import com.alibaba.excel.analysis.v07.handlers.CountRowCellHandler; +import com.alibaba.excel.analysis.v07.handlers.DefaultCellHandler; +import com.alibaba.excel.analysis.v07.handlers.ProcessResultCellHandler; +import com.alibaba.excel.context.AnalysisContext; + +/** + * Build handler + * + * @author Dan Zheng + */ +public class XlsxHandlerFactory { + public static List buildCellHandlers(AnalysisContext analysisContext, StylesTable stylesTable) { + List result = new ArrayList(); + result.add(new CountRowCellHandler(analysisContext)); + DefaultCellHandler defaultCellHandler = new DefaultCellHandler(analysisContext, stylesTable); + result.add(defaultCellHandler); + result.add(new ProcessResultCellHandler(analysisContext, defaultCellHandler)); + return result; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java index 2431e9a..8306fc1 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java @@ -1,20 +1,13 @@ package com.alibaba.excel.analysis.v07; -import com.alibaba.excel.annotation.FieldType; -import com.alibaba.excel.constant.ExcelXmlConstants; -import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.event.AnalysisEventRegisterCenter; -import com.alibaba.excel.event.OneRowAnalysisFinishEvent; -import com.alibaba.excel.util.PositionUtils; -import org.apache.poi.xssf.model.SharedStringsTable; -import org.apache.poi.xssf.usermodel.XSSFRichTextString; +import java.util.List; + +import org.apache.poi.xssf.model.StylesTable; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; -import java.util.Arrays; - -import static com.alibaba.excel.constant.ExcelXmlConstants.*; +import com.alibaba.excel.context.AnalysisContext; /** * @@ -22,117 +15,41 @@ import static com.alibaba.excel.constant.ExcelXmlConstants.*; */ public class XlsxRowHandler extends DefaultHandler { - private String currentCellIndex; - - private FieldType currentCellType; - - private int curRow; - - private int curCol; - - private String[] curRowContent = new String[20]; - - private String currentCellValue; - - private SharedStringsTable sst; - - private AnalysisContext analysisContext; + private List cellHandlers; + private XlsxRowResultHolder rowResultHolder; - private AnalysisEventRegisterCenter registerCenter; - - public XlsxRowHandler(AnalysisEventRegisterCenter registerCenter, SharedStringsTable sst, - AnalysisContext analysisContext) { - this.registerCenter = registerCenter; - this.analysisContext = analysisContext; - this.sst = sst; - - } - - @Override - public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { - - setTotalRowCount(name, attributes); - - startCell(name, attributes); - - startCellValue(name); - - } - - private void startCellValue(String name) { - if (name.equals(CELL_VALUE_TAG) || name.equals(CELL_VALUE_TAG_1)) { - // initialize current cell value - currentCellValue = ""; - } - } - - private void startCell(String name, Attributes attributes) { - if (ExcelXmlConstants.CELL_TAG.equals(name)) { - currentCellIndex = attributes.getValue(ExcelXmlConstants.POSITION); - int nextRow = PositionUtils.getRow(currentCellIndex); - if (nextRow > curRow) { - curRow = nextRow; - // endRow(ROW_TAG); - } - analysisContext.setCurrentRowNum(curRow); - curCol = PositionUtils.getCol(currentCellIndex); - - String cellType = attributes.getValue("t"); - currentCellType = FieldType.EMPTY; - if (cellType != null && cellType.equals("s")) { - currentCellType = FieldType.STRING; + public XlsxRowHandler(AnalysisContext analysisContext, StylesTable stylesTable) { + this.cellHandlers = XlsxHandlerFactory.buildCellHandlers(analysisContext, stylesTable); + for (XlsxCellHandler cellHandler : cellHandlers) { + if (cellHandler instanceof XlsxRowResultHolder) { + this.rowResultHolder = (XlsxRowResultHolder)cellHandler; + break; } } } - private void endCellValue(String name) throws SAXException { - // ensure size - if (curCol >= curRowContent.length) { - curRowContent = Arrays.copyOf(curRowContent, (int)(curCol * 1.5)); - } - if (CELL_VALUE_TAG.equals(name)) { - - switch (currentCellType) { - case STRING: - int idx = Integer.parseInt(currentCellValue); - currentCellValue = new XSSFRichTextString(sst.getEntryAt(idx)).toString(); - currentCellType = FieldType.EMPTY; - break; + @Override + public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { + for (XlsxCellHandler cellHandler : cellHandlers) { + if (cellHandler.support(name)) { + cellHandler.startHandle(name, attributes); } - curRowContent[curCol] = currentCellValue; - } else if (CELL_VALUE_TAG_1.equals(name)) { - curRowContent[curCol] = currentCellValue; } } @Override public void endElement(String uri, String localName, String name) throws SAXException { - endRow(name); - endCellValue(name); + for (XlsxCellHandler cellHandler : cellHandlers) { + if (cellHandler.support(name)) { + cellHandler.endHandle(name); + } + } } @Override public void characters(char[] ch, int start, int length) throws SAXException { - currentCellValue += new String(ch, start, length); - } - - - private void setTotalRowCount(String name, Attributes attributes) { - if (DIMENSION.equals(name)) { - String d = attributes.getValue(DIMENSION_REF); - String totalStr = d.substring(d.indexOf(":") + 1, d.length()); - String c = totalStr.toUpperCase().replaceAll("[A-Z]", ""); - analysisContext.setTotalCount(Integer.parseInt(c)); - } - - } - - private void endRow(String name) { - if (name.equals(ROW_TAG)) { - registerCenter.notifyListeners(new OneRowAnalysisFinishEvent(curRowContent,curCol)); - curRowContent = new String[20]; + if (rowResultHolder != null) { + rowResultHolder.appendCurrentCellValue(new String(ch, start, length)); } } - } - diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java new file mode 100644 index 0000000..953d45e --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java @@ -0,0 +1,31 @@ +package com.alibaba.excel.analysis.v07; + +import java.util.Map; + +import com.alibaba.excel.metadata.CellData; + +/** + * Result holder + * + * @author jipengfei + */ +public interface XlsxRowResultHolder { + /** + * Clear Result + */ + void clearResult(); + + /** + * Append current 'cellValue' + * + * @param currentCellValue + */ + void appendCurrentCellValue(String currentCellValue); + + /** + * Get row content + * + * @return + */ + Map getCurRowContent(); +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java index 34f2480..748306a 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java @@ -1,90 +1,169 @@ package com.alibaba.excel.analysis.v07; -import com.alibaba.excel.analysis.BaseSaxAnalyser; -import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.exception.ExcelAnalysisException; -import com.alibaba.excel.metadata.Sheet; -import org.apache.poi.openxml4j.exceptions.OpenXML4JException; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.xssf.eventusermodel.XSSFReader; -import org.apache.poi.xssf.model.SharedStringsTable; -import org.apache.xmlbeans.XmlException; +import org.apache.poi.xssf.model.StylesTable; +import org.apache.poi.xssf.usermodel.XSSFRelation; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr; import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; +import com.alibaba.excel.analysis.ExcelExecutor; +import com.alibaba.excel.cache.Ehcache; +import com.alibaba.excel.cache.MapCache; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; +import com.alibaba.excel.util.FileUtils; /** * * @author jipengfei */ -public class XlsxSaxAnalyser extends BaseSaxAnalyser { +public class XlsxSaxAnalyser implements ExcelExecutor { + private static final Logger LOGGER = LoggerFactory.getLogger(XlsxSaxAnalyser.class); + /** + * If it's less than 5M, use map cache, or use ehcache. + */ + private static final long USE_MAP_CACHE_SIZE = 5 * 1000 * 1000L; + private AnalysisContext analysisContext; + private List sheetList; + private Map sheetMap; + /** + * Current style information + */ + private StylesTable stylesTable; + + public XlsxSaxAnalyser(AnalysisContext analysisContext, InputStream decryptedStream) throws Exception { + this.analysisContext = analysisContext; + // Initialize cache + ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder(); - private XSSFReader xssfReader; + OPCPackage pkg = readOpcPackage(readWorkbookHolder, decryptedStream); + PackagePart sharedStringsTablePackagePart = + pkg.getPartsByContentType(XSSFRelation.SHARED_STRINGS.getContentType()).get(0); - private SharedStringsTable sharedStringsTable; + // Specify default cache + defaultReadCache(readWorkbookHolder, sharedStringsTablePackagePart); - private List sheetSourceList = new ArrayList(); + // Analysis sharedStringsTable.xml + analysisSharedStringsTable(sharedStringsTablePackagePart.getInputStream(), readWorkbookHolder); - private boolean use1904WindowDate = false; + XSSFReader xssfReader = new XSSFReader(pkg); + analysisUse1904WindowDate(xssfReader, readWorkbookHolder); - public XlsxSaxAnalyser(AnalysisContext analysisContext) throws IOException, OpenXML4JException, XmlException { - this.analysisContext = analysisContext; + stylesTable = xssfReader.getStylesTable(); + sheetList = new ArrayList(); + sheetMap = new HashMap(); + XSSFReader.SheetIterator ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData(); + int index = 0; + if (!ite.hasNext()) { + throw new ExcelAnalysisException("Can not find any sheet!"); + } + while (ite.hasNext()) { + InputStream inputStream = ite.next(); + sheetList.add(new ReadSheet(index, ite.getSheetName())); + sheetMap.put(index, inputStream); + index++; + } + } - analysisContext.setCurrentRowNum(0); - this.xssfReader = new XSSFReader(OPCPackage.open(analysisContext.getInputStream())); - this.sharedStringsTable = this.xssfReader.getSharedStringsTable(); + private void defaultReadCache(ReadWorkbookHolder readWorkbookHolder, PackagePart sharedStringsTablePackagePart) + throws IOException { + if (readWorkbookHolder.getReadCache() != null) { + readWorkbookHolder.getReadCache().init(analysisContext); + return; + } + long size = sharedStringsTablePackagePart.getSize(); + if (size < 0) { + size = sharedStringsTablePackagePart.getInputStream().available(); + } + if (size < USE_MAP_CACHE_SIZE) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Use map cache.size:{}", size); + } + readWorkbookHolder.setReadCache(new MapCache()); + } else { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Use ehcache.size:{}", size); + } + readWorkbookHolder.setReadCache(new Ehcache()); + } + readWorkbookHolder.getReadCache().init(analysisContext); + } + private void analysisUse1904WindowDate(XSSFReader xssfReader, ReadWorkbookHolder readWorkbookHolder) + throws Exception { + if (readWorkbookHolder.globalConfiguration().getUse1904windowing() != null) { + return; + } InputStream workbookXml = xssfReader.getWorkbookData(); WorkbookDocument ctWorkbook = WorkbookDocument.Factory.parse(workbookXml); CTWorkbook wb = ctWorkbook.getWorkbook(); CTWorkbookPr prefix = wb.getWorkbookPr(); - if (prefix != null) { - this.use1904WindowDate = prefix.getDate1904(); + if (prefix != null && prefix.getDate1904()) { + readWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.TRUE); + } else { + readWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.FALSE); } - this.analysisContext.setUse1904WindowDate(use1904WindowDate); + } + private void analysisSharedStringsTable(InputStream sharedStringsTableInputStream, + ReadWorkbookHolder readWorkbookHolder) throws Exception { + ContentHandler handler = new SharedStringsTableHandler(readWorkbookHolder.getReadCache()); + parseXmlSource(sharedStringsTableInputStream, handler); + readWorkbookHolder.getReadCache().putFinished(); + } - XSSFReader.SheetIterator ite; - sheetSourceList = new ArrayList(); - ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData(); - while (ite.hasNext()) { - InputStream inputStream = ite.next(); - String sheetName = ite.getSheetName(); - SheetSource sheetSource = new SheetSource(sheetName, inputStream); - sheetSourceList.add(sheetSource); + private OPCPackage readOpcPackage(ReadWorkbookHolder readWorkbookHolder, InputStream decryptedStream) + throws Exception { + if (decryptedStream == null && readWorkbookHolder.getFile() != null) { + return OPCPackage.open(readWorkbookHolder.getFile()); } - + if (readWorkbookHolder.getMandatoryUseInputStream()) { + if (decryptedStream != null) { + return OPCPackage.open(decryptedStream); + } else { + return OPCPackage.open(readWorkbookHolder.getInputStream()); + } + } + File readTempFile = FileUtils.createCacheTmpFile(); + readWorkbookHolder.setTempFile(readTempFile); + File tempFile = new File(readTempFile.getPath(), UUID.randomUUID().toString() + ".xlsx"); + if (decryptedStream != null) { + FileUtils.writeToFile(tempFile, decryptedStream); + } else { + FileUtils.writeToFile(tempFile, readWorkbookHolder.getInputStream()); + } + return OPCPackage.open(tempFile); } @Override - protected void execute() { - Sheet sheetParam = analysisContext.getCurrentSheet(); - if (sheetParam != null && sheetParam.getSheetNo() > 0 && sheetSourceList.size() >= sheetParam.getSheetNo()) { - InputStream sheetInputStream = sheetSourceList.get(sheetParam.getSheetNo() - 1).getInputStream(); - parseXmlSource(sheetInputStream); - - } else { - int i = 0; - for (SheetSource sheetSource : sheetSourceList) { - i++; - analysisContext.setCurrentSheet(new Sheet(i)); - parseXmlSource(sheetSource.getInputStream()); - } - } + public List sheetList() { + return sheetList; } - private void parseXmlSource(InputStream inputStream) { - InputSource sheetSource = new InputSource(inputStream); + private void parseXmlSource(InputStream inputStream, ContentHandler handler) { + InputSource inputSource = new InputSource(inputStream); try { SAXParserFactory saxFactory = SAXParserFactory.newInstance(); saxFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); @@ -92,55 +171,28 @@ public class XlsxSaxAnalyser extends BaseSaxAnalyser { saxFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); SAXParser saxParser = saxFactory.newSAXParser(); XMLReader xmlReader = saxParser.getXMLReader(); - ContentHandler handler = new XlsxRowHandler(this, sharedStringsTable, analysisContext); xmlReader.setContentHandler(handler); - xmlReader.parse(sheetSource); + xmlReader.parse(inputSource); inputStream.close(); + } catch (ExcelAnalysisException e) { + throw e; } catch (Exception e) { - e.printStackTrace(); throw new ExcelAnalysisException(e); + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + throw new ExcelAnalysisException("Can not close 'inputStream'!"); + } + } } } @Override - public List getSheets() { - List sheets = new ArrayList(); - int i = 1; - for (SheetSource sheetSource : sheetSourceList) { - Sheet sheet = new Sheet(i, 0); - sheet.setSheetName(sheetSource.getSheetName()); - i++; - sheets.add(sheet); - } - - return sheets; + public void execute() { + parseXmlSource(sheetMap.get(analysisContext.readSheetHolder().getSheetNo()), + new XlsxRowHandler(analysisContext, stylesTable)); } - class SheetSource { - - private String sheetName; - - private InputStream inputStream; - - public SheetSource(String sheetName, InputStream inputStream) { - this.sheetName = sheetName; - this.inputStream = inputStream; - } - - public String getSheetName() { - return sheetName; - } - - public void setSheetName(String sheetName) { - this.sheetName = sheetName; - } - - public InputStream getInputStream() { - return inputStream; - } - - public void setInputStream(InputStream inputStream) { - this.inputStream = inputStream; - } - } } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java new file mode 100644 index 0000000..ea63409 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java @@ -0,0 +1,42 @@ +package com.alibaba.excel.analysis.v07.handlers; + +import static com.alibaba.excel.constant.ExcelXmlConstants.DIMENSION; +import static com.alibaba.excel.constant.ExcelXmlConstants.DIMENSION_REF; + +import org.xml.sax.Attributes; + +import com.alibaba.excel.analysis.v07.XlsxCellHandler; +import com.alibaba.excel.context.AnalysisContext; + +/** + * Cell Handler + * + * @author jipengfei + */ +public class CountRowCellHandler implements XlsxCellHandler { + + private final AnalysisContext analysisContext; + + public CountRowCellHandler(AnalysisContext analysisContext) { + this.analysisContext = analysisContext; + } + + @Override + public boolean support(String name) { + return DIMENSION.equals(name); + } + + @Override + public void startHandle(String name, Attributes attributes) { + String d = attributes.getValue(DIMENSION_REF); + String totalStr = d.substring(d.indexOf(":") + 1, d.length()); + String c = totalStr.toUpperCase().replaceAll("[A-Z]", ""); + analysisContext.readSheetHolder().setTotal(Integer.parseInt(c)); + } + + @Override + public void endHandle(String name) { + + } + +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java new file mode 100644 index 0000000..671693b --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java @@ -0,0 +1,182 @@ +package com.alibaba.excel.analysis.v07.handlers; + +import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_DATA_FORMAT_TAG; +import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_FORMULA_TAG; +import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_INLINE_STRING_VALUE_TAG; +import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_TAG; +import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_VALUE_TAG; +import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_VALUE_TYPE_TAG; + +import java.util.Map; +import java.util.TreeMap; + +import org.apache.poi.ss.usermodel.BuiltinFormats; +import org.apache.poi.xssf.model.StylesTable; +import org.apache.poi.xssf.usermodel.XSSFCellStyle; +import org.apache.poi.xssf.usermodel.XSSFRichTextString; +import org.xml.sax.Attributes; + +import com.alibaba.excel.analysis.v07.XlsxCellHandler; +import com.alibaba.excel.analysis.v07.XlsxRowResultHolder; +import com.alibaba.excel.constant.ExcelXmlConstants; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.read.metadata.holder.ReadRowHolder; +import com.alibaba.excel.util.BooleanUtils; +import com.alibaba.excel.util.PositionUtils; +import com.alibaba.excel.util.StringUtils; + +/** + * Cell Handler + * + * @author jipengfei + */ +public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder { + private final AnalysisContext analysisContext; + private String currentTag; + private String currentCellIndex; + private int curRow; + private int curCol; + private Map curRowContent = new TreeMap(); + private CellData currentCellData; + /** + * Current style information + */ + private StylesTable stylesTable; + + public DefaultCellHandler(AnalysisContext analysisContext, StylesTable stylesTable) { + this.analysisContext = analysisContext; + this.stylesTable = stylesTable; + } + + @Override + public void clearResult() { + curRowContent = new TreeMap(); + } + + @Override + public boolean support(String name) { + return CELL_VALUE_TAG.equals(name) || CELL_FORMULA_TAG.equals(name) || CELL_INLINE_STRING_VALUE_TAG.equals(name) + || CELL_TAG.equals(name); + } + + @Override + public void startHandle(String name, Attributes attributes) { + currentTag = name; + // start a cell + if (CELL_TAG.equals(name)) { + currentCellIndex = attributes.getValue(ExcelXmlConstants.POSITION); + int nextRow = PositionUtils.getRow(currentCellIndex); + if (nextRow > curRow) { + curRow = nextRow; + } + analysisContext + .readRowHolder(new ReadRowHolder(curRow, analysisContext.readSheetHolder().getGlobalConfiguration())); + curCol = PositionUtils.getCol(currentCellIndex); + + // t="s" ,it's means String + // t="str" ,it's means String,but does not need to be read in the 'sharedStrings.xml' + // t="inlineStr" ,it's means String + // t="b" ,it's means Boolean + // t="e" ,it's means Error + // t="n" ,it's means Number + // t is null ,it's means Empty or Number + CellDataTypeEnum type = CellDataTypeEnum.buildFromCellType(attributes.getValue(CELL_VALUE_TYPE_TAG)); + currentCellData = new CellData(type); + + // Put in data transformation information + String dateFormatIndex = attributes.getValue(CELL_DATA_FORMAT_TAG); + if (dateFormatIndex != null) { + int dateFormatIndexInteger = Integer.parseInt(dateFormatIndex); + XSSFCellStyle xssfCellStyle = stylesTable.getStyleAt(dateFormatIndexInteger); + int dataFormat = xssfCellStyle.getDataFormat(); + String dataFormatString = xssfCellStyle.getDataFormatString(); + currentCellData.setDataFormat(dataFormat); + if (dataFormatString == null) { + currentCellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat)); + } else { + currentCellData.setDataFormatString(dataFormatString); + } + } + } + // cell is formula + if (CELL_FORMULA_TAG.equals(name)) { + currentCellData.setFormula(Boolean.TRUE); + } + } + + @Override + public void endHandle(String name) { + if (CELL_VALUE_TAG.equals(name)) { + // Have to go "sharedStrings.xml" and get it + if (currentCellData.getType() == CellDataTypeEnum.STRING) { + String stringValue = analysisContext.readWorkbookHolder().getReadCache() + .get(Integer.valueOf(currentCellData.getStringValue())); + if (stringValue != null && analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()) { + stringValue = stringValue.trim(); + } + currentCellData.setStringValue(stringValue); + } else if (currentCellData.getType() == CellDataTypeEnum.DIRECT_STRING) { + currentCellData.setType(CellDataTypeEnum.STRING); + } + curRowContent.put(curCol, currentCellData); + } + // This is a special form of string + if (CELL_INLINE_STRING_VALUE_TAG.equals(name)) { + XSSFRichTextString richTextString = new XSSFRichTextString(currentCellData.getStringValue()); + String stringValue = richTextString.toString(); + if (stringValue != null && analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()) { + stringValue = stringValue.trim(); + } + currentCellData.setStringValue(stringValue); + curRowContent.put(curCol, currentCellData); + } + } + + @Override + public void appendCurrentCellValue(String currentCellValue) { + if (StringUtils.isEmpty(currentCellValue)) { + return; + } + if (currentTag == null) { + return; + } + if (CELL_FORMULA_TAG.equals(currentTag)) { + currentCellData.setFormulaValue(currentCellValue); + return; + } + CellDataTypeEnum oldType = currentCellData.getType(); + switch (oldType) { + case DIRECT_STRING: + case STRING: + case ERROR: + if (currentCellData.getStringValue() == null) { + currentCellData.setStringValue(currentCellValue); + } else { + currentCellData.setStringValue(currentCellData.getStringValue() + currentCellValue); + } + break; + case BOOLEAN: + if (currentCellData.getBooleanValue() == null) { + currentCellData.setBooleanValue(BooleanUtils.valueOf(currentCellValue)); + } + break; + case NUMBER: + case EMPTY: + currentCellData.setType(CellDataTypeEnum.NUMBER); + if (currentCellData.getDoubleValue() == null) { + currentCellData.setDoubleValue(Double.valueOf(currentCellValue)); + } + break; + default: + throw new IllegalStateException("Cannot set values now"); + } + } + + @Override + public Map getCurRowContent() { + return curRowContent; + } + +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java new file mode 100644 index 0000000..193cb78 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java @@ -0,0 +1,41 @@ +package com.alibaba.excel.analysis.v07.handlers; + +import static com.alibaba.excel.constant.ExcelXmlConstants.ROW_TAG; + +import org.xml.sax.Attributes; + +import com.alibaba.excel.analysis.v07.XlsxCellHandler; +import com.alibaba.excel.analysis.v07.XlsxRowResultHolder; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.event.EachRowAnalysisFinishEvent; + +/** + * Cell Handler + * + * @author jipengfei + */ +public class ProcessResultCellHandler implements XlsxCellHandler { + private AnalysisContext analysisContext; + private XlsxRowResultHolder rowResultHandler; + + public ProcessResultCellHandler(AnalysisContext analysisContext, XlsxRowResultHolder rowResultHandler) { + this.analysisContext = analysisContext; + this.rowResultHandler = rowResultHandler; + } + + @Override + public boolean support(String name) { + return ROW_TAG.equals(name); + } + + @Override + public void startHandle(String name, Attributes attributes) {} + + @Override + public void endHandle(String name) { + analysisContext.readSheetHolder() + .notifyEndOneRow(new EachRowAnalysisFinishEvent(rowResultHandler.getCurRowContent()), analysisContext); + rowResultHandler.clearResult(); + } + +} diff --git a/src/main/java/com/alibaba/excel/annotation/ExcelColumnNum.java b/src/main/java/com/alibaba/excel/annotation/ExcelColumnNum.java deleted file mode 100644 index eb56fe3..0000000 --- a/src/main/java/com/alibaba/excel/annotation/ExcelColumnNum.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.alibaba.excel.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Created by jipengfei on 17/3/19. - * Field column num at excel head - * - * @author jipengfei - */ -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -public @interface ExcelColumnNum { - - /** - * col num - * @return - */ - int value(); - - /** - * - * Default @see com.alibaba.excel.util.TypeUtil - * if default is not meet you can set format - * - * @return - */ - String format() default ""; -} diff --git a/src/main/java/com/alibaba/excel/annotation/ExcelIgnore.java b/src/main/java/com/alibaba/excel/annotation/ExcelIgnore.java new file mode 100644 index 0000000..3d3ce63 --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/ExcelIgnore.java @@ -0,0 +1,17 @@ +package com.alibaba.excel.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Ignore convert excel + * + * @author Jiaju Zhuang + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelIgnore {} diff --git a/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java b/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java index a063a32..b107d32 100644 --- a/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java +++ b/src/main/java/com/alibaba/excel/annotation/ExcelProperty.java @@ -6,6 +6,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import com.alibaba.excel.converters.AutoConverter; +import com.alibaba.excel.converters.Converter; + /** * @author jipengfei */ @@ -14,23 +17,41 @@ import java.lang.annotation.Target; @Inherited public @interface ExcelProperty { - /** - * @return - */ - String[] value() default {""}; + /** + * The name of the sheet header. + * + *

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

+ * read: When you have multiple heads, take the first one + * + * @return The name of the sheet header + */ + String[] value() default {""}; + /** + * Index of column + * + * Read or write it on the index of column,If it's equal to -1, it's sorted by Java class + * + * @return Index of column + */ + int index() default -1; - /** - * @return - */ - int index() default 99999; + /** + * Force the current field to use this converter. + * + * @return Converter + */ + Class converter() default AutoConverter.class; - /** - * - * default @see com.alibaba.excel.util.TypeUtil - * if default is not meet you can set format - * - * @return - */ - String format() default ""; + /** + * + * default @see com.alibaba.excel.util.TypeUtil if default is not meet you can set format + * + * @return Format string + * @deprecated please use {@link com.alibaba.excel.annotation.format.DateTimeFormat} + */ + @Deprecated + String format() default ""; } diff --git a/src/main/java/com/alibaba/excel/annotation/FieldType.java b/src/main/java/com/alibaba/excel/annotation/FieldType.java deleted file mode 100644 index 7372995..0000000 --- a/src/main/java/com/alibaba/excel/annotation/FieldType.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.alibaba.excel.annotation; - -/** - * - * @author jipengfei - */ -public enum FieldType { - - STRING, INT, LONG, DATE, BOOLEAN, DOUBLE,EMPTY; - -} diff --git a/src/main/java/com/alibaba/excel/annotation/format/DateTimeFormat.java b/src/main/java/com/alibaba/excel/annotation/format/DateTimeFormat.java new file mode 100644 index 0000000..96aff22 --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/format/DateTimeFormat.java @@ -0,0 +1,38 @@ +package com.alibaba.excel.annotation.format; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Convert date format. + * + *

+ * write: It can be used on classes {@link java.util.Date} + *

+ * read: It can be used on classes {@link String} + * + * @author Jiaju Zhuang + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface DateTimeFormat { + + /** + * + * Specific format reference {@link java.text.SimpleDateFormat} + * + * @return Format pattern + */ + String value() default ""; + + /** + * True if date uses 1904 windowing, or false if using 1900 date windowing. + * + * @return True if date uses 1904 windowing, or false if using 1900 date windowing. + */ + boolean use1904windowing() default false; +} diff --git a/src/main/java/com/alibaba/excel/annotation/format/NumberFormat.java b/src/main/java/com/alibaba/excel/annotation/format/NumberFormat.java new file mode 100644 index 0000000..8951681 --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/format/NumberFormat.java @@ -0,0 +1,39 @@ +package com.alibaba.excel.annotation.format; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.math.RoundingMode; + +/** + * Convert number format. + * + *

+ * write: It can be used on classes that inherit {@link Number} + *

+ * read: It can be used on classes {@link String} + * + * @author Jiaju Zhuang + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface NumberFormat { + + /** + * + * Specific format reference {@link org.apache.commons.math3.fraction.BigFractionFormat} + * + * @return Format pattern + */ + String value() default ""; + + /** + * Rounded by default + * + * @return RoundingMode + */ + RoundingMode roundingMode() default RoundingMode.HALF_UP; +} diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/ColumnWidth.java b/src/main/java/com/alibaba/excel/annotation/write/style/ColumnWidth.java new file mode 100644 index 0000000..00306cc --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/write/style/ColumnWidth.java @@ -0,0 +1,27 @@ +package com.alibaba.excel.annotation.write.style; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Set the width of the table + * + * @author Jiaju Zhuang + */ +@Target({ElementType.FIELD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ColumnWidth { + + /** + * Column width + *

+ * -1 means the default column width is used + * + * @return Column width + */ + int value() default -1; +} diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/ContentRowHeight.java b/src/main/java/com/alibaba/excel/annotation/write/style/ContentRowHeight.java new file mode 100644 index 0000000..8f338e8 --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/write/style/ContentRowHeight.java @@ -0,0 +1,27 @@ +package com.alibaba.excel.annotation.write.style; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Set the height of each table + * + * @author Jiaju Zhuang + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ContentRowHeight { + + /** + * Set the content height + *

+ * -1 mean the auto set height + * + * @return Content height + */ + short value() default -1; +} diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/HeadRowHeight.java b/src/main/java/com/alibaba/excel/annotation/write/style/HeadRowHeight.java new file mode 100644 index 0000000..828d2c0 --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/write/style/HeadRowHeight.java @@ -0,0 +1,26 @@ +package com.alibaba.excel.annotation.write.style; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Set the height of each table + * + * @author Jiaju Zhuang + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface HeadRowHeight { + /** + * Set the header height + *

+ * -1 mean the auto set height + * + * @return Header height + */ + short value() default -1; +} diff --git a/src/main/java/com/alibaba/excel/cache/Ehcache.java b/src/main/java/com/alibaba/excel/cache/Ehcache.java new file mode 100644 index 0000000..abf0169 --- /dev/null +++ b/src/main/java/com/alibaba/excel/cache/Ehcache.java @@ -0,0 +1,213 @@ +package com.alibaba.excel.cache; + +import java.io.File; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.ehcache.CacheManager; +import org.ehcache.PersistentCacheManager; +import org.ehcache.config.builders.CacheConfigurationBuilder; +import org.ehcache.config.builders.CacheManagerBuilder; +import org.ehcache.config.builders.ResourcePoolsBuilder; +import org.ehcache.config.units.MemoryUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.util.FileUtils; +import com.alibaba.excel.util.StringUtils; + +/** + * Default cache + * + * @author Jiaju Zhuang + */ +public class Ehcache implements ReadCache { + + private static final Logger LOGGER = LoggerFactory.getLogger(Ehcache.class); + + private static final int BATCH_COUNT = 1000; + private static final int CHECK_INTERVAL = 500; + private static final int MAX_CACHE_ACTIVATE = 10; + + private static final String CACHE = "cache"; + private static final String DATA_SEPARATOR = "@"; + private static final String KEY_VALUE_SEPARATOR = "!"; + private static final String SPECIAL_SEPARATOR = "&"; + private static final String ESCAPED_DATA_SEPARATOR = "&d;"; + private static final String ESCAPED_KEY_VALUE_SEPARATOR = "&kv;"; + private static final String ESCAPED_SPECIAL_SEPARATOR = "&s;"; + + private static final int DEBUG_WRITE_SIZE = 100 * 10000; + private static final int DEBUG_CACHE_MISS_SIZE = 1000; + + /** + * Key index + */ + private int index = 0; + private StringBuilder data = new StringBuilder(); + private CacheManager cacheManager; + /** + * Bulk storage data + */ + private org.ehcache.Cache cache; + /** + * Currently active cache + */ + private Map> cacheMap = new HashMap>(); + /** + * Count how many times get + */ + private int getCount = 0; + /** + * Count active cache + * + */ + private LinkedList countList = new LinkedList(); + + /** + * Count the last {@link #CHECK_INTERVAL} used + */ + private Set lastCheckIntervalUsedSet = new HashSet(); + + /** + * Count the number of cache misses + */ + private int cacheMiss = 0; + + @Override + public void init(AnalysisContext analysisContext) { + File readTempFile = analysisContext.readWorkbookHolder().getTempFile(); + if (readTempFile == null) { + readTempFile = FileUtils.createCacheTmpFile(); + analysisContext.readWorkbookHolder().setTempFile(readTempFile); + } + File cacheFile = new File(readTempFile.getPath(), UUID.randomUUID().toString()); + PersistentCacheManager persistentCacheManager = + CacheManagerBuilder.newCacheManagerBuilder().with(CacheManagerBuilder.persistence(cacheFile)) + .withCache(CACHE, CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class, String.class, + ResourcePoolsBuilder.newResourcePoolsBuilder().disk(10, MemoryUnit.GB))) + .build(true); + cacheManager = persistentCacheManager; + cache = persistentCacheManager.getCache(CACHE, Integer.class, String.class); + } + + @Override + public void put(String value) { + data.append(index).append(KEY_VALUE_SEPARATOR).append(escape(value)).append(DATA_SEPARATOR); + if ((index + 1) % BATCH_COUNT == 0) { + cache.put(index / BATCH_COUNT, data.toString()); + data = new StringBuilder(); + } + index++; + if (LOGGER.isDebugEnabled()) { + if (index % DEBUG_WRITE_SIZE == 0) { + LOGGER.debug("Already put :{}", index); + } + } + } + + private String escape(String str) { + if (StringUtils.isEmpty(str)) { + return str; + } + str = str.replaceAll(SPECIAL_SEPARATOR, ESCAPED_SPECIAL_SEPARATOR); + str = str.replaceAll(DATA_SEPARATOR, ESCAPED_DATA_SEPARATOR); + str = str.replaceAll(KEY_VALUE_SEPARATOR, ESCAPED_KEY_VALUE_SEPARATOR); + return str; + } + + private String unescape(String str) { + if (StringUtils.isEmpty(str)) { + return str; + } + str = str.replaceAll(ESCAPED_KEY_VALUE_SEPARATOR, KEY_VALUE_SEPARATOR); + str = str.replaceAll(ESCAPED_DATA_SEPARATOR, DATA_SEPARATOR); + str = str.replaceAll(ESCAPED_SPECIAL_SEPARATOR, SPECIAL_SEPARATOR); + return str; + } + + @Override + public String get(Integer key) { + if (key == null || key < 0) { + return null; + } + getCount++; + int route = key / BATCH_COUNT; + if (cacheMap.containsKey(route)) { + lastCheckIntervalUsedSet.add(route); + String value = cacheMap.get(route).get(key); + checkClear(); + return value; + } + Map tempCacheMap = new HashMap(BATCH_COUNT / 3 * 4 + 1); + String batchData = cache.get(route); + String[] dataStrings = batchData.split(DATA_SEPARATOR); + for (String dataString : dataStrings) { + String[] keyValue = dataString.split(KEY_VALUE_SEPARATOR); + tempCacheMap.put(Integer.valueOf(keyValue[0]), unescape(keyValue[1])); + } + countList.add(route); + cacheMap.put(route, tempCacheMap); + if (LOGGER.isDebugEnabled()) { + if (cacheMiss++ % DEBUG_CACHE_MISS_SIZE == 0) { + LOGGER.debug("Cache misses count:{}", cacheMiss); + } + } + lastCheckIntervalUsedSet.add(route); + String value = tempCacheMap.get(key); + checkClear(); + return value; + } + + private void checkClear() { + if (countList.size() > MAX_CACHE_ACTIVATE) { + Integer route = countList.getFirst(); + countList.removeFirst(); + cacheMap.remove(route); + } + if (getCount++ % CHECK_INTERVAL != 0) { + return; + } + Iterator>> iterator = cacheMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry> entry = iterator.next(); + if (lastCheckIntervalUsedSet.contains(entry.getKey())) { + continue; + } + // Last 'CHECK_INTERVAL' not use + iterator.remove(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Cache remove because {} times unused.", CHECK_INTERVAL); + } + Iterator countIterator = countList.iterator(); + while (countIterator.hasNext()) { + Integer route = countIterator.next(); + if (route.equals(entry.getKey())) { + countIterator.remove(); + break; + } + } + } + lastCheckIntervalUsedSet.clear(); + } + + @Override + public void putFinished() { + if (StringUtils.isEmpty(data.toString())) { + return; + } + cache.put(index / BATCH_COUNT, data.toString()); + } + + @Override + public void destroy() { + cacheManager.close(); + } + +} diff --git a/src/main/java/com/alibaba/excel/cache/MapCache.java b/src/main/java/com/alibaba/excel/cache/MapCache.java new file mode 100644 index 0000000..ae948fb --- /dev/null +++ b/src/main/java/com/alibaba/excel/cache/MapCache.java @@ -0,0 +1,40 @@ +package com.alibaba.excel.cache; + +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.excel.context.AnalysisContext; + +/** + * + * Putting temporary data directly into a map is a little more efficient but very memory intensive + * + * @author Jiaju Zhuang + */ +public class MapCache implements ReadCache { + private Map cache = new HashMap(); + private int index = 0; + + @Override + public void init(AnalysisContext analysisContext) {} + + @Override + public void put(String value) { + cache.put(index++, value); + } + + @Override + public String get(Integer key) { + if (key == null || key < 0) { + return null; + } + return cache.get(key); + } + + @Override + public void putFinished() {} + + @Override + public void destroy() {} + +} diff --git a/src/main/java/com/alibaba/excel/cache/ReadCache.java b/src/main/java/com/alibaba/excel/cache/ReadCache.java new file mode 100644 index 0000000..48072fa --- /dev/null +++ b/src/main/java/com/alibaba/excel/cache/ReadCache.java @@ -0,0 +1,47 @@ +package com.alibaba.excel.cache; + +import com.alibaba.excel.context.AnalysisContext; + +/** + * Read cache + * + * @author Jiaju Zhuang + */ +public interface ReadCache { + + /** + * Initialize cache + * + * @param analysisContext + * A context is the main anchorage point of a excel reader. + */ + void init(AnalysisContext analysisContext); + + /** + * Automatically generate the key and put it in the cache.Key start from 0 + * + * @param value + * Cache value + */ + void put(String value); + + /** + * Get value + * + * @param key + * Index + * @return Value + */ + String get(Integer key); + + /** + * It's called when all the values are put in + */ + void putFinished(); + + /** + * Called when the excel read is complete + */ + void destroy(); + +} diff --git a/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java b/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java index dcd2d5a..f01a33b 100644 --- a/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java +++ b/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java @@ -10,8 +10,16 @@ public class ExcelXmlConstants { public static final String ROW_TAG = "row"; public static final String CELL_TAG = "c"; + public static final String CELL_VALUE_TYPE_TAG = "t"; + /** + * Number formatted label + */ + public static final String CELL_DATA_FORMAT_TAG = "s"; + public static final String CELL_FORMULA_TAG = "f"; public static final String CELL_VALUE_TAG = "v"; - - public static final String CELL_VALUE_TAG_1 = "t"; + /** + * When the data is "inlineStr" his tag is "t" + */ + public static final String CELL_INLINE_STRING_VALUE_TAG = "t"; } diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContext.java b/src/main/java/com/alibaba/excel/context/AnalysisContext.java index 23c846f..7b8ba86 100644 --- a/src/main/java/com/alibaba/excel/context/AnalysisContext.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContext.java @@ -1,132 +1,137 @@ package com.alibaba.excel.context; +import java.io.InputStream; + +import com.alibaba.excel.analysis.ExcelExecutor; import com.alibaba.excel.event.AnalysisEventListener; -import com.alibaba.excel.metadata.BaseRowModel; -import com.alibaba.excel.metadata.ExcelHeadProperty; import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.read.metadata.holder.ReadHolder; +import com.alibaba.excel.read.metadata.holder.ReadRowHolder; +import com.alibaba.excel.read.metadata.holder.ReadSheetHolder; +import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; import com.alibaba.excel.support.ExcelTypeEnum; -import java.io.InputStream; -import java.util.List; - /** * * A context is the main anchorage point of a excel reader. + * * @author jipengfei */ public interface AnalysisContext { - /** - * Custom attribute + * Select the current table + * + * @param excelExecutor + * Excel file Executor + * @param readSheet + * sheet to read */ - Object getCustom(); + void currentSheet(ExcelExecutor excelExecutor, ReadSheet readSheet); /** - * get current sheet + * All information about the workbook you are currently working on * - * @return current analysis sheet + * @return Current workbook holder */ - Sheet getCurrentSheet(); + ReadWorkbookHolder readWorkbookHolder(); /** - * set current sheet - * @param sheet + * All information about the sheet you are currently working on + * + * @return Current sheet holder */ - void setCurrentSheet(Sheet sheet); + ReadSheetHolder readSheetHolder(); /** + * Set row of currently operated cell * - * get excel type - * @return excel type + * @param readRowHolder + * Current row holder */ - ExcelTypeEnum getExcelType(); + void readRowHolder(ReadRowHolder readRowHolder); /** - * get in io - * @return file io + * Row of currently operated cell + * + * @return Current row holder */ - InputStream getInputStream(); + ReadRowHolder readRowHolder(); /** + * The current read operation corresponds to the readSheetHolder or readWorkbookHolder * - * custom listener - * @return listener + * @return Current holder */ - AnalysisEventListener getEventListener(); + ReadHolder currentReadHolder(); /** - * get current row + * Custom attribute + * * @return */ - Integer getCurrentRowNum(); - - /** - * set current row num - * @param row - */ - void setCurrentRowNum(Integer row); + Object getCustom(); /** - * get total row ,Data may be inaccurate - * @return + * get current sheet + * + * @return current analysis sheet + * @deprecated please use {@link #readSheetHolder()} */ @Deprecated - Integer getTotalCount(); + Sheet getCurrentSheet(); /** - * get total row ,Data may be inaccurate * - * @param totalCount - */ - void setTotalCount(Integer totalCount); - - /** - * get excel head - * @return + * get excel type + * + * @return excel type + * @deprecated please use {@link #readWorkbookHolder()} */ - ExcelHeadProperty getExcelHeadProperty(); + @Deprecated + ExcelTypeEnum getExcelType(); /** + * get in io * - * @param clazz - * @param headOneRow + * @return file io + * @deprecated please use {@link #readWorkbookHolder()} */ - void buildExcelHeadProperty(Class clazz, List headOneRow); + @Deprecated + InputStream getInputStream(); /** + * get current row * - *if need to short match the content * @return + * @deprecated please use {@link #readRowHolder()} */ - boolean trim(); + @Deprecated + Integer getCurrentRowNum(); /** - * set current result - * @param result + * get total row ,Data may be inaccurate + * + * @return + * @deprecated please use {@link #readRowHolder()} */ - void setCurrentRowAnalysisResult(Object result); - + @Deprecated + Integer getTotalCount(); /** * get current result - * @return get current result + * + * @return get current result + * @deprecated please use {@link #readRowHolder()} */ + @Deprecated Object getCurrentRowAnalysisResult(); /** * Interrupt execution + * + * @deprecated please use {@link AnalysisEventListener#hasNext(AnalysisContext)} */ + @Deprecated void interrupt(); - - /** - * date use1904WindowDate - * @return - */ - boolean use1904WindowDate(); - - /** - * date use1904WindowDate - * @param use1904WindowDate - */ - void setUse1904WindowDate(boolean use1904WindowDate); } diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java index fff5055..d9d7ded 100644 --- a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java @@ -1,172 +1,189 @@ package com.alibaba.excel.context; -import com.alibaba.excel.event.AnalysisEventListener; +import java.io.InputStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.analysis.ExcelExecutor; +import com.alibaba.excel.analysis.v07.XlsxSaxAnalyser; import com.alibaba.excel.exception.ExcelAnalysisException; -import com.alibaba.excel.metadata.BaseRowModel; -import com.alibaba.excel.metadata.ExcelHeadProperty; import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.read.metadata.ReadWorkbook; +import com.alibaba.excel.read.metadata.holder.ReadHolder; +import com.alibaba.excel.read.metadata.holder.ReadRowHolder; +import com.alibaba.excel.read.metadata.holder.ReadSheetHolder; +import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; import com.alibaba.excel.support.ExcelTypeEnum; - -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; +import com.alibaba.excel.util.StringUtils; /** * * @author jipengfei */ public class AnalysisContextImpl implements AnalysisContext { - - private Object custom; - - private Sheet currentSheet; - - private ExcelTypeEnum excelType; - - private InputStream inputStream; - - private AnalysisEventListener eventListener; - - private Integer currentRowNum; - - private Integer totalCount; - - private ExcelHeadProperty excelHeadProperty; - - private boolean trim; - - private boolean use1904WindowDate = false; - - @Override - public void setUse1904WindowDate(boolean use1904WindowDate) { - this.use1904WindowDate = use1904WindowDate; + private static final Logger LOGGER = LoggerFactory.getLogger(AnalysisContextImpl.class); + /** + * The Workbook currently written + */ + private ReadWorkbookHolder readWorkbookHolder; + /** + * Current sheet holder + */ + private ReadSheetHolder readSheetHolder; + /** + * Current row holder + */ + private ReadRowHolder readRowHolder; + /** + * Configuration of currently operated cell + */ + private ReadHolder currentReadHolder; + + public AnalysisContextImpl(ReadWorkbook readWorkbook) { + if (readWorkbook == null) { + throw new IllegalArgumentException("Workbook argument cannot be null"); + } + readWorkbookHolder = new ReadWorkbookHolder(readWorkbook); + currentReadHolder = readWorkbookHolder; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Initialization 'AnalysisContextImpl' complete"); + } } @Override - public Object getCurrentRowAnalysisResult() { - return currentRowAnalysisResult; + public void currentSheet(ExcelExecutor excelExecutor, ReadSheet readSheet) { + if (readSheet == null) { + throw new IllegalArgumentException("Sheet argument cannot be null."); + } + readSheetHolder = new ReadSheetHolder(readSheet, readWorkbookHolder); + currentReadHolder = readSheetHolder; + selectSheet(excelExecutor); + if (readWorkbookHolder.getHasReadSheet().contains(readSheetHolder.getSheetNo())) { + throw new ExcelAnalysisException("Cannot read sheet repeatedly."); + } + readWorkbookHolder.getHasReadSheet().add(readSheetHolder.getSheetNo()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Began to read:{}", readSheetHolder); + } } - @Override - public void interrupt() { - throw new ExcelAnalysisException("interrupt error"); + private void selectSheet(ExcelExecutor excelExecutor) { + if (excelExecutor instanceof XlsxSaxAnalyser) { + selectSheet07(excelExecutor); + } else { + selectSheet03(); + } } - @Override - public boolean use1904WindowDate() { - return use1904WindowDate; + private void selectSheet03() { + if (readSheetHolder.getSheetNo() != null && readSheetHolder.getSheetNo() >= 0) { + return; + } + if (!StringUtils.isEmpty(readSheetHolder.getSheetName())) { + LOGGER.warn("Excel 2003 does not support matching sheets by name, defaults to the first one."); + } + readSheetHolder.setSheetNo(0); + } + + private void selectSheet07(ExcelExecutor excelExecutor) { + if (readSheetHolder.getSheetNo() != null && readSheetHolder.getSheetNo() >= 0) { + for (ReadSheet readSheetExcel : excelExecutor.sheetList()) { + if (readSheetExcel.getSheetNo().equals(readSheetHolder.getSheetNo())) { + readSheetHolder.setSheetName(readSheetExcel.getSheetName()); + return; + } + } + throw new ExcelAnalysisException("Can not find sheet:" + readSheetHolder.getSheetNo()); + } + if (!StringUtils.isEmpty(readSheetHolder.getSheetName())) { + for (ReadSheet readSheetExcel : excelExecutor.sheetList()) { + String sheetName = readSheetExcel.getSheetName(); + if (sheetName == null) { + continue; + } + if (readSheetHolder.globalConfiguration().getAutoTrim()) { + sheetName = sheetName.trim(); + } + if (sheetName.equals(readSheetHolder.getSheetName())) { + readSheetHolder.setSheetNo(readSheetExcel.getSheetNo()); + return; + } + } + } + ReadSheet readSheetExcel = excelExecutor.sheetList().get(0); + readSheetHolder.setSheetNo(readSheetExcel.getSheetNo()); + readSheetHolder.setSheetName(readSheetExcel.getSheetName()); } @Override - public void setCurrentRowAnalysisResult(Object currentRowAnalysisResult) { - this.currentRowAnalysisResult = currentRowAnalysisResult; - } - - private Object currentRowAnalysisResult; - - public AnalysisContextImpl(InputStream inputStream, ExcelTypeEnum excelTypeEnum, Object custom, - AnalysisEventListener listener, boolean trim) { - this.custom = custom; - this.eventListener = listener; - this.inputStream = inputStream; - this.excelType = excelTypeEnum; - this.trim = trim; + public ReadWorkbookHolder readWorkbookHolder() { + return readWorkbookHolder; } @Override - public void setCurrentSheet(Sheet currentSheet) { - cleanCurrentSheet(); - this.currentSheet = currentSheet; - if (currentSheet.getClazz() != null) { - buildExcelHeadProperty(currentSheet.getClazz(), null); - } + public ReadSheetHolder readSheetHolder() { + return readSheetHolder; } - private void cleanCurrentSheet() { - this.currentSheet = null; - this.excelHeadProperty = null; - this.totalCount = 0; - this.currentRowAnalysisResult = null; - this.currentRowNum =0; + @Override + public ReadRowHolder readRowHolder() { + return readRowHolder; } @Override - public ExcelTypeEnum getExcelType() { - return excelType; + public void readRowHolder(ReadRowHolder readRowHolder) { + this.readRowHolder = readRowHolder; } - public void setExcelType(ExcelTypeEnum excelType) { - this.excelType = excelType; + @Override + public ReadHolder currentReadHolder() { + return currentReadHolder; } + @Override public Object getCustom() { - return custom; - } - - public void setCustom(Object custom) { - this.custom = custom; + return readWorkbookHolder.getCustomObject(); } @Override public Sheet getCurrentSheet() { - return currentSheet; + Sheet sheet = new Sheet(readSheetHolder.getSheetNo() + 1); + sheet.setSheetName(readSheetHolder.getSheetName()); + sheet.setHead(readSheetHolder.getHead()); + sheet.setClazz(readSheetHolder.getClazz()); + sheet.setHeadLineMun(readSheetHolder.getHeadRowNumber()); + return sheet; } @Override - public InputStream getInputStream() { - return inputStream; - } - - public void setInputStream(InputStream inputStream) { - this.inputStream = inputStream; + public ExcelTypeEnum getExcelType() { + return readWorkbookHolder.getExcelType(); } @Override - public AnalysisEventListener getEventListener() { - return eventListener; - } - - public void setEventListener(AnalysisEventListener eventListener) { - this.eventListener = eventListener; + public InputStream getInputStream() { + return readWorkbookHolder.getInputStream(); } @Override public Integer getCurrentRowNum() { - return this.currentRowNum; - } - - @Override - public void setCurrentRowNum(Integer row) { - this.currentRowNum = row; + return readRowHolder.getRowIndex(); } @Override public Integer getTotalCount() { - return totalCount; + return readSheetHolder.getTotal(); } @Override - public void setTotalCount(Integer totalCount) { - this.totalCount = totalCount; - } - - @Override - public ExcelHeadProperty getExcelHeadProperty() { - return this.excelHeadProperty; - } - - @Override - public void buildExcelHeadProperty(Class clazz, List headOneRow) { - if (this.excelHeadProperty == null && (clazz != null || headOneRow != null)) { - this.excelHeadProperty = new ExcelHeadProperty(clazz, new ArrayList>()); - } - if (this.excelHeadProperty.getHead() == null && headOneRow != null) { - this.excelHeadProperty.appendOneRow(headOneRow); - } + public Object getCurrentRowAnalysisResult() { + return readRowHolder.getCurrentRowAnalysisResult(); } @Override - public boolean trim() { - return this.trim; + public void interrupt() { + throw new ExcelAnalysisException("interrupt error"); } } diff --git a/src/main/java/com/alibaba/excel/context/WriteContext.java b/src/main/java/com/alibaba/excel/context/WriteContext.java index b1aee59..17db4ca 100644 --- a/src/main/java/com/alibaba/excel/context/WriteContext.java +++ b/src/main/java/com/alibaba/excel/context/WriteContext.java @@ -1,293 +1,105 @@ package com.alibaba.excel.context; -import com.alibaba.excel.event.WriteHandler; -import com.alibaba.excel.metadata.BaseRowModel; -import com.alibaba.excel.metadata.ExcelHeadProperty; -import com.alibaba.excel.metadata.Table; -import com.alibaba.excel.support.ExcelTypeEnum; -import com.alibaba.excel.util.CollectionUtils; -import com.alibaba.excel.util.StyleUtil; -import com.alibaba.excel.util.WorkBookUtil; -import org.apache.poi.ss.usermodel.*; -import org.apache.poi.ss.util.CellRangeAddress; - -import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import static com.alibaba.excel.util.StyleUtil.buildSheetStyle; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; + +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.WriteTable; +import com.alibaba.excel.write.metadata.holder.WriteHolder; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; /** - * A context is the main anchorage point of a excel writer. + * Write context * * @author jipengfei */ -public class WriteContext { - - /*** - * The sheet currently written - */ - private Sheet currentSheet; - - /** - * current param - */ - private com.alibaba.excel.metadata.Sheet currentSheetParam; - +public interface WriteContext { /** - * The sheet currently written's name + * If the current sheet already exists, select it; if not, create it + * + * @param writeSheet Current sheet */ - private String currentSheetName; + void currentSheet(WriteSheet writeSheet); /** + * If the current table already exists, select it; if not, create it * + * @param writeTable */ - private Table currentTable; + void currentTable(WriteTable writeTable); /** - * Excel type + * All information about the workbook you are currently working on + * + * @return */ - private ExcelTypeEnum excelType; + WriteWorkbookHolder writeWorkbookHolder(); /** - * POI Workbook + * All information about the sheet you are currently working on + * + * @return */ - private Workbook workbook; + WriteSheetHolder writeSheetHolder(); /** - * Final output stream + * All information about the table you are currently working on + * + * @return */ - private OutputStream outputStream; + WriteTableHolder writeTableHolder(); /** - * Written form collection + * Configuration of currently operated cell. May be 'writeSheetHolder' or 'writeTableHolder' or + * 'writeWorkbookHolder' + * + * @return */ - private Map tableMap = new ConcurrentHashMap(); + WriteHolder currentWriteHolder(); /** - * Cell default style + * close */ - private CellStyle defaultCellStyle; + void finish(); /** - * Current table head style + * Current sheet + * + * @return + * @deprecated please us e{@link #writeSheetHolder()} */ - private CellStyle currentHeadCellStyle; + @Deprecated + Sheet getCurrentSheet(); /** - * Current table content style + * Need head + * + * @return + * @deprecated please us e{@link #writeSheetHolder()} */ - private CellStyle currentContentCellStyle; + @Deprecated + boolean needHead(); /** - * the header attribute of excel + * Get outputStream + * + * @return + * @deprecated please us e{@link #writeWorkbookHolder()} ()} */ - private ExcelHeadProperty excelHeadProperty; - - private boolean needHead = Boolean.TRUE; - - private WriteHandler afterWriteHandler; - - public WriteHandler getAfterWriteHandler() { - return afterWriteHandler; - } - - public WriteContext(InputStream templateInputStream, OutputStream out, ExcelTypeEnum excelType, - boolean needHead, WriteHandler afterWriteHandler) throws IOException { - this.needHead = needHead; - this.outputStream = out; - this.afterWriteHandler = afterWriteHandler; - this.workbook = WorkBookUtil.createWorkBook(templateInputStream, excelType); - this.defaultCellStyle = StyleUtil.buildDefaultCellStyle(this.workbook); - - } + @Deprecated + OutputStream getOutputStream(); /** - * @param sheet - */ - public void currentSheet(com.alibaba.excel.metadata.Sheet sheet) { - if (null == currentSheetParam || currentSheetParam.getSheetNo() != sheet.getSheetNo()) { - cleanCurrentSheet(); - currentSheetParam = sheet; - try { - this.currentSheet = workbook.getSheetAt(sheet.getSheetNo() - 1); - } catch (Exception e) { - this.currentSheet = WorkBookUtil.createSheet(workbook, sheet); - if (null != afterWriteHandler) { - this.afterWriteHandler.sheet(sheet.getSheetNo(), currentSheet); - } - } - buildSheetStyle(currentSheet, sheet.getColumnWidthMap()); - /** **/ - this.initCurrentSheet(sheet); - } - - } - - private void initCurrentSheet(com.alibaba.excel.metadata.Sheet sheet) { - - /** **/ - initExcelHeadProperty(sheet.getHead(), sheet.getClazz()); - - initTableStyle(sheet.getTableStyle()); - - initTableHead(); - - } - - private void cleanCurrentSheet() { - this.currentSheet = null; - this.currentSheetParam = null; - this.excelHeadProperty = null; - this.currentHeadCellStyle = null; - this.currentContentCellStyle = null; - this.currentTable = null; - - } - - /** - * init excel header + * Get workbook * - * @param head - * @param clazz + * @return + * @deprecated please us e{@link #writeWorkbookHolder()} ()} */ - private void initExcelHeadProperty(List> head, Class clazz) { - if (head != null || clazz != null) { this.excelHeadProperty = new ExcelHeadProperty(clazz, head); } - } - - public void initTableHead() { - if (needHead && null != excelHeadProperty && !CollectionUtils.isEmpty(excelHeadProperty.getHead())) { - int startRow = currentSheet.getLastRowNum(); - if (startRow > 0) { - startRow += 4; - } else { - startRow = currentSheetParam.getStartRow(); - } - addMergedRegionToCurrentSheet(startRow); - int i = startRow; - for (; i < this.excelHeadProperty.getRowNum() + startRow; i++) { - Row row = WorkBookUtil.createRow(currentSheet, i); - if (null != afterWriteHandler) { - this.afterWriteHandler.row(i, row); - } - addOneRowOfHeadDataToExcel(row, this.excelHeadProperty.getHeadByRowNum(i - startRow)); - } - } - } - - private void addMergedRegionToCurrentSheet(int startRow) { - for (com.alibaba.excel.metadata.CellRange cellRangeModel : excelHeadProperty.getCellRangeModels()) { - currentSheet.addMergedRegion(new CellRangeAddress(cellRangeModel.getFirstRow() + startRow, - cellRangeModel.getLastRow() + startRow, - cellRangeModel.getFirstCol(), cellRangeModel.getLastCol())); - } - } - - private void addOneRowOfHeadDataToExcel(Row row, List headByRowNum) { - if (headByRowNum != null && headByRowNum.size() > 0) { - for (int i = 0; i < headByRowNum.size(); i++) { - Cell cell = WorkBookUtil.createCell(row, i, getCurrentHeadCellStyle(), headByRowNum.get(i)); - if (null != afterWriteHandler) { - this.afterWriteHandler.cell(i, cell); - } - } - } - } - - private void initTableStyle(com.alibaba.excel.metadata.TableStyle tableStyle) { - if (tableStyle != null) { - this.currentHeadCellStyle = StyleUtil.buildCellStyle(this.workbook, tableStyle.getTableHeadFont(), - tableStyle.getTableHeadBackGroundColor()); - this.currentContentCellStyle = StyleUtil.buildCellStyle(this.workbook, tableStyle.getTableContentFont(), - tableStyle.getTableContentBackGroundColor()); - } - } - - private void cleanCurrentTable() { - this.excelHeadProperty = null; - this.currentHeadCellStyle = null; - this.currentContentCellStyle = null; - this.currentTable = null; - - } - - public void currentTable(Table table) { - if (null == currentTable || currentTable.getTableNo() != table.getTableNo()) { - cleanCurrentTable(); - this.currentTable = table; - this.initExcelHeadProperty(table.getHead(), table.getClazz()); - this.initTableStyle(table.getTableStyle()); - this.initTableHead(); - } - - } - - public ExcelHeadProperty getExcelHeadProperty() { - return this.excelHeadProperty; - } - - public boolean needHead() { - return this.needHead; - } - - public Sheet getCurrentSheet() { - return currentSheet; - } + @Deprecated + Workbook getWorkbook(); - public void setCurrentSheet(Sheet currentSheet) { - this.currentSheet = currentSheet; - } - - public String getCurrentSheetName() { - return currentSheetName; - } - - public void setCurrentSheetName(String currentSheetName) { - this.currentSheetName = currentSheetName; - } - - public ExcelTypeEnum getExcelType() { - return excelType; - } - - public void setExcelType(ExcelTypeEnum excelType) { - this.excelType = excelType; - } - - public OutputStream getOutputStream() { - return outputStream; - } - - public CellStyle getCurrentHeadCellStyle() { - return this.currentHeadCellStyle == null ? defaultCellStyle : this.currentHeadCellStyle; - } - - public CellStyle getCurrentContentStyle() { - return this.currentContentCellStyle; - } - - public Workbook getWorkbook() { - return workbook; - } - - public com.alibaba.excel.metadata.Sheet getCurrentSheetParam() { - return currentSheetParam; - } - - public void setCurrentSheetParam(com.alibaba.excel.metadata.Sheet currentSheetParam) { - this.currentSheetParam = currentSheetParam; - } - - public Table getCurrentTable() { - return currentTable; - } - - public void setCurrentTable(Table currentTable) { - this.currentTable = currentTable; - } } - - diff --git a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java new file mode 100644 index 0000000..ebe0d26 --- /dev/null +++ b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java @@ -0,0 +1,398 @@ +package com.alibaba.excel.context; + +import java.io.OutputStream; +import java.util.List; +import java.util.Map; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellRangeAddress; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.exception.ExcelGenerateException; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.util.WorkBookUtil; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.RowWriteHandler; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.handler.WorkbookWriteHandler; +import com.alibaba.excel.write.handler.WriteHandler; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.WriteTable; +import com.alibaba.excel.write.metadata.WriteWorkbook; +import com.alibaba.excel.write.metadata.holder.WriteHolder; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; +import com.alibaba.excel.write.property.ExcelWriteHeadProperty; + +/** + * A context is the main anchorage point of a excel writer. + * + * @author jipengfei + */ +public class WriteContextImpl implements WriteContext { + + private static final Logger LOGGER = LoggerFactory.getLogger(WriteContextImpl.class); + + /** + * The Workbook currently written + */ + private WriteWorkbookHolder writeWorkbookHolder; + /** + * Current sheet holder + */ + private WriteSheetHolder writeSheetHolder; + /** + * The table currently written + */ + private WriteTableHolder writeTableHolder; + /** + * Configuration of currently operated cell + */ + private WriteHolder currentWriteHolder; + + public WriteContextImpl(WriteWorkbook writeWorkbook) { + if (writeWorkbook == null) { + throw new IllegalArgumentException("Workbook argument cannot be null"); + } + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Begin to Initialization 'WriteContextImpl'"); + } + initCurrentWorkbookHolder(writeWorkbook); + beforeWorkbookCreate(); + try { + writeWorkbookHolder.setWorkbook(WorkBookUtil.createWorkBook(writeWorkbookHolder)); + } catch (Exception e) { + throw new ExcelGenerateException("Create workbook failure", e); + } + afterWorkbookCreate(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Initialization 'WriteContextImpl' complete"); + } + } + + private void beforeWorkbookCreate() { + List handlerList = currentWriteHolder.writeHandlerMap().get(WorkbookWriteHandler.class); + if (handlerList == null || handlerList.isEmpty()) { + return; + } + for (WriteHandler writeHandler : handlerList) { + if (writeHandler instanceof WorkbookWriteHandler) { + ((WorkbookWriteHandler)writeHandler).beforeWorkbookCreate(); + } + } + } + + private void afterWorkbookCreate() { + List handlerList = currentWriteHolder.writeHandlerMap().get(WorkbookWriteHandler.class); + if (handlerList == null || handlerList.isEmpty()) { + return; + } + for (WriteHandler writeHandler : handlerList) { + if (writeHandler instanceof WorkbookWriteHandler) { + ((WorkbookWriteHandler)writeHandler).afterWorkbookCreate(writeWorkbookHolder); + } + } + } + + private void initCurrentWorkbookHolder(WriteWorkbook writeWorkbook) { + writeWorkbookHolder = new WriteWorkbookHolder(writeWorkbook); + currentWriteHolder = writeWorkbookHolder; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("CurrentConfiguration is writeWorkbookHolder"); + } + } + + /** + * @param writeSheet + */ + @Override + public void currentSheet(WriteSheet writeSheet) { + if (writeSheet == null) { + throw new IllegalArgumentException("Sheet argument cannot be null"); + } + if (writeSheet.getSheetNo() == null || writeSheet.getSheetNo() <= 0) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Sheet number is null"); + } + writeSheet.setSheetNo(0); + } + if (writeWorkbookHolder.getHasBeenInitializedSheet().containsKey(writeSheet.getSheetNo())) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Sheet:{} is already existed", writeSheet.getSheetNo()); + } + writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheet().get(writeSheet.getSheetNo()); + writeSheetHolder.setNewInitialization(Boolean.FALSE); + writeTableHolder = null; + currentWriteHolder = writeSheetHolder; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("CurrentConfiguration is writeSheetHolder"); + } + return; + } + initCurrentSheetHolder(writeSheet); + beforeSheetCreate(); + // Initialization current sheet + initSheet(); + afterSheetCreate(); + } + + private void beforeSheetCreate() { + List handlerList = currentWriteHolder.writeHandlerMap().get(SheetWriteHandler.class); + if (handlerList == null || handlerList.isEmpty()) { + return; + } + for (WriteHandler writeHandler : handlerList) { + if (writeHandler instanceof SheetWriteHandler) { + ((SheetWriteHandler)writeHandler).beforeSheetCreate(writeWorkbookHolder, writeSheetHolder); + } + } + } + + private void afterSheetCreate() { + List handlerList = currentWriteHolder.writeHandlerMap().get(SheetWriteHandler.class); + if (handlerList == null || handlerList.isEmpty()) { + return; + } + for (WriteHandler writeHandler : handlerList) { + if (writeHandler instanceof SheetWriteHandler) { + ((SheetWriteHandler)writeHandler).afterSheetCreate(writeWorkbookHolder, writeSheetHolder); + } + } + if (null != writeWorkbookHolder.getWriteWorkbook().getWriteHandler()) { + writeWorkbookHolder.getWriteWorkbook().getWriteHandler().sheet(writeSheetHolder.getSheetNo(), + writeSheetHolder.getSheet()); + } + } + + private void initCurrentSheetHolder(WriteSheet writeSheet) { + writeSheetHolder = new WriteSheetHolder(writeSheet, writeWorkbookHolder); + writeWorkbookHolder.getHasBeenInitializedSheet().put(writeSheet.getSheetNo(), writeSheetHolder); + writeTableHolder = null; + currentWriteHolder = writeSheetHolder; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("CurrentConfiguration is writeSheetHolder"); + } + } + + private void initSheet() { + Sheet currentSheet; + try { + currentSheet = writeWorkbookHolder.getWorkbook().getSheetAt(writeSheetHolder.getSheetNo()); + } catch (Exception e) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Can not find sheet:{} ,now create it", writeSheetHolder.getSheetNo()); + } + currentSheet = WorkBookUtil.createSheet(writeWorkbookHolder.getWorkbook(), writeSheetHolder.getSheetName()); + } + writeSheetHolder.setSheet(currentSheet); + // Initialization head + initHead(writeSheetHolder.excelWriteHeadProperty()); + } + + public void initHead(ExcelWriteHeadProperty excelWriteHeadProperty) { + if (!currentWriteHolder.needHead() || !currentWriteHolder.excelWriteHeadProperty().hasHead()) { + return; + } + int newRowIndex = writeSheetHolder.getNewRowIndexAndStartDoWrite(); + newRowIndex += currentWriteHolder.relativeHeadRowIndex(); + // Combined head + addMergedRegionToCurrentSheet(excelWriteHeadProperty, newRowIndex); + for (int relativeRowIndex = 0, i = newRowIndex; i < excelWriteHeadProperty.getHeadRowNumber() + newRowIndex; + i++, relativeRowIndex++) { + beforeRowCreate(newRowIndex, relativeRowIndex); + Row row = WorkBookUtil.createRow(writeSheetHolder.getSheet(), i); + afterRowCreate(row, relativeRowIndex); + addOneRowOfHeadDataToExcel(row, excelWriteHeadProperty.getHeadMap(), relativeRowIndex); + } + } + + private void beforeRowCreate(int rowIndex, int relativeRowIndex) { + List handlerList = currentWriteHolder.writeHandlerMap().get(RowWriteHandler.class); + if (handlerList == null || handlerList.isEmpty()) { + return; + } + for (WriteHandler writeHandler : handlerList) { + if (writeHandler instanceof RowWriteHandler) { + ((RowWriteHandler)writeHandler).beforeRowCreate(writeSheetHolder, writeTableHolder, rowIndex, + relativeRowIndex, true); + } + } + } + + private void afterRowCreate(Row row, int relativeRowIndex) { + List handlerList = currentWriteHolder.writeHandlerMap().get(RowWriteHandler.class); + if (handlerList == null || handlerList.isEmpty()) { + return; + } + for (WriteHandler writeHandler : handlerList) { + if (writeHandler instanceof RowWriteHandler) { + ((RowWriteHandler)writeHandler).afterRowCreate(writeSheetHolder, writeTableHolder, row, + relativeRowIndex, true); + } + } + if (null != writeWorkbookHolder.getWriteWorkbook().getWriteHandler()) { + writeWorkbookHolder.getWriteWorkbook().getWriteHandler().row(row.getRowNum(), row); + } + } + + private void addMergedRegionToCurrentSheet(ExcelWriteHeadProperty excelWriteHeadProperty, int rowIndex) { + for (com.alibaba.excel.metadata.CellRange cellRangeModel : excelWriteHeadProperty.headCellRangeList()) { + writeSheetHolder.getSheet().addMergedRegion(new CellRangeAddress(cellRangeModel.getFirstRow() + rowIndex, + cellRangeModel.getLastRow() + rowIndex, cellRangeModel.getFirstCol(), cellRangeModel.getLastCol())); + } + } + + private void addOneRowOfHeadDataToExcel(Row row, Map headMap, int relativeRowIndex) { + for (Map.Entry entry : headMap.entrySet()) { + Head head = entry.getValue(); + beforeCellCreate(row, head, relativeRowIndex); + Cell cell = WorkBookUtil.createCell(row, entry.getKey(), head.getHeadNameList().get(relativeRowIndex)); + afterCellCreate(head, cell, relativeRowIndex); + } + } + + private void beforeCellCreate(Row row, Head head, int relativeRowIndex) { + List handlerList = currentWriteHolder.writeHandlerMap().get(CellWriteHandler.class); + if (handlerList == null || handlerList.isEmpty()) { + return; + } + for (WriteHandler writeHandler : handlerList) { + if (writeHandler instanceof CellWriteHandler) { + ((CellWriteHandler)writeHandler).beforeCellCreate(writeSheetHolder, writeTableHolder, row, head, + relativeRowIndex, true); + } + } + } + + private void afterCellCreate(Head head, Cell cell, int relativeRowIndex) { + List handlerList = currentWriteHolder.writeHandlerMap().get(CellWriteHandler.class); + if (handlerList == null || handlerList.isEmpty()) { + return; + } + for (WriteHandler writeHandler : handlerList) { + if (writeHandler instanceof CellWriteHandler) { + ((CellWriteHandler)writeHandler).afterCellCreate(writeSheetHolder, writeTableHolder, null, cell, head, + relativeRowIndex, true); + } + } + if (null != writeWorkbookHolder.getWriteWorkbook().getWriteHandler()) { + writeWorkbookHolder.getWriteWorkbook().getWriteHandler().cell(cell.getRowIndex(), cell); + } + } + + @Override + public void currentTable(WriteTable writeTable) { + if (writeTable == null) { + return; + } + if (writeTable.getTableNo() == null || writeTable.getTableNo() <= 0) { + writeTable.setTableNo(0); + } + if (writeSheetHolder.getHasBeenInitializedTable().containsKey(writeTable.getTableNo())) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Table:{} is already existed", writeTable.getTableNo()); + } + writeTableHolder = writeSheetHolder.getHasBeenInitializedTable().get(writeTable.getTableNo()); + writeTableHolder.setNewInitialization(Boolean.FALSE); + currentWriteHolder = writeTableHolder; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("CurrentConfiguration is writeTableHolder"); + } + return; + } + initCurrentTableHolder(writeTable); + initHead(writeTableHolder.excelWriteHeadProperty()); + } + + private void initCurrentTableHolder(WriteTable writeTable) { + writeTableHolder = new WriteTableHolder(writeTable, writeSheetHolder, writeWorkbookHolder); + writeSheetHolder.getHasBeenInitializedTable().put(writeTable.getTableNo(), writeTableHolder); + currentWriteHolder = writeTableHolder; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("CurrentConfiguration is writeTableHolder"); + } + } + + @Override + public WriteWorkbookHolder writeWorkbookHolder() { + return writeWorkbookHolder; + } + + @Override + public WriteSheetHolder writeSheetHolder() { + return writeSheetHolder; + } + + @Override + public WriteTableHolder writeTableHolder() { + return writeTableHolder; + } + + @Override + public WriteHolder currentWriteHolder() { + return currentWriteHolder; + } + + @Override + public void finish() { + if (writeWorkbookHolder == null) { + return; + } + try { + writeWorkbookHolder.getWorkbook().write(writeWorkbookHolder.getOutputStream()); + writeWorkbookHolder.getWorkbook().close(); + } catch (Throwable e) { + throw new ExcelGenerateException("Can not close IO", e); + } + try { + if (writeWorkbookHolder.getAutoCloseStream() && writeWorkbookHolder.getOutputStream() != null) { + writeWorkbookHolder.getOutputStream().close(); + } + } catch (Throwable e) { + throw new ExcelGenerateException("Can not close IO", e); + } + try { + if (writeWorkbookHolder.getAutoCloseStream() && writeWorkbookHolder.getTemplateInputStream() != null) { + writeWorkbookHolder.getTemplateInputStream().close(); + } + } catch (Throwable e) { + throw new ExcelGenerateException("Can not close IO", e); + } + try { + if (!writeWorkbookHolder.getAutoCloseStream() && writeWorkbookHolder.getFile() != null + && writeWorkbookHolder.getOutputStream() != null) { + writeWorkbookHolder.getOutputStream().close(); + } + } catch (Throwable e) { + throw new ExcelGenerateException("Can not close IO", e); + } + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Finished write."); + } + } + + @Override + public Sheet getCurrentSheet() { + return writeSheetHolder.getSheet(); + } + + @Override + public boolean needHead() { + return writeSheetHolder.needHead(); + } + + @Override + public OutputStream getOutputStream() { + return writeWorkbookHolder.getOutputStream(); + } + + @Override + public Workbook getWorkbook() { + return writeWorkbookHolder.getWorkbook(); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/AutoConverter.java b/src/main/java/com/alibaba/excel/converters/AutoConverter.java new file mode 100644 index 0000000..800d2d8 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/AutoConverter.java @@ -0,0 +1,36 @@ +package com.alibaba.excel.converters; + +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * An empty converter.It's automatically converted by type. + * + * @author Jiaju Zhuang + */ +public class AutoConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return null; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } + + @Override + public Object convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return null; + } + + @Override + public CellData convertToExcelData(Object value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return null; + } +} diff --git a/src/main/java/com/alibaba/excel/converters/Converter.java b/src/main/java/com/alibaba/excel/converters/Converter.java new file mode 100644 index 0000000..8700d12 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/Converter.java @@ -0,0 +1,61 @@ +package com.alibaba.excel.converters; + +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Convert between Java objects and excel objects + * + * @author Dan Zheng + * @param + */ +public interface Converter { + + /** + * Back to object types in Java + * + * @return Support for Java class + */ + Class supportJavaTypeKey(); + + /** + * Back to object enum in excel + * + * @return Support for {@link CellDataTypeEnum} + */ + CellDataTypeEnum supportExcelTypeKey(); + + /** + * Convert excel objects to Java objects + * + * @param cellData + * Excel cell data.NotNull. + * @param contentProperty + * Content property.Nullable. + * @param globalConfiguration + * Global configuration.NotNull. + * @return Data to put into a Java object + * @throws Exception + * Exception. + */ + T convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws Exception; + + /** + * Convert Java objects to excel objects + * + * @param value + * Java Data.NotNull. + * @param contentProperty + * Content property.Nullable. + * @param globalConfiguration + * Global configuration.NotNull. + * @return Data to put into a Excel + * @throws Exception + * Exception. + */ + CellData convertToExcelData(T value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) + throws Exception; +} diff --git a/src/main/java/com/alibaba/excel/converters/ConverterKeyBuild.java b/src/main/java/com/alibaba/excel/converters/ConverterKeyBuild.java new file mode 100644 index 0000000..0bd5499 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/ConverterKeyBuild.java @@ -0,0 +1,40 @@ +package com.alibaba.excel.converters; + +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.excel.enums.CellDataTypeEnum; + +/** + * Converter unique key.Consider that you can just use class as the key. + * + * @author Jiaju Zhuang + */ +public class ConverterKeyBuild { + + private static final Map BOXING_MAP = new HashMap(16); + + static { + BOXING_MAP.put(int.class.getName(), Integer.class.getName()); + BOXING_MAP.put(byte.class.getName(), Byte.class.getName()); + BOXING_MAP.put(long.class.getName(), Long.class.getName()); + BOXING_MAP.put(double.class.getName(), Double.class.getName()); + BOXING_MAP.put(float.class.getName(), Float.class.getName()); + BOXING_MAP.put(char.class.getName(), Character.class.getName()); + BOXING_MAP.put(short.class.getName(), Short.class.getName()); + BOXING_MAP.put(boolean.class.getName(), Boolean.class.getName()); + } + + public static String buildKey(Class clazz) { + String className = clazz.getName(); + String boxingClassName = BOXING_MAP.get(clazz.getName()); + if (boxingClassName == null) { + return className; + } + return boxingClassName; + } + + public static String buildKey(Class clazz, CellDataTypeEnum cellDataTypeEnum) { + return buildKey(clazz) + "-" + cellDataTypeEnum.toString(); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java b/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java new file mode 100644 index 0000000..e53c1f8 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java @@ -0,0 +1,146 @@ +package com.alibaba.excel.converters; + +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.excel.converters.bigdecimal.BigDecimalBooleanConverter; +import com.alibaba.excel.converters.bigdecimal.BigDecimalNumberConverter; +import com.alibaba.excel.converters.bigdecimal.BigDecimalStringConverter; +import com.alibaba.excel.converters.booleanconverter.BooleanBooleanConverter; +import com.alibaba.excel.converters.booleanconverter.BooleanNumberConverter; +import com.alibaba.excel.converters.booleanconverter.BooleanStringConverter; +import com.alibaba.excel.converters.bytearray.BoxingByteArrayImageConverter; +import com.alibaba.excel.converters.bytearray.ByteArrayImageConverter; +import com.alibaba.excel.converters.byteconverter.ByteBooleanConverter; +import com.alibaba.excel.converters.byteconverter.ByteNumberConverter; +import com.alibaba.excel.converters.byteconverter.ByteStringConverter; +import com.alibaba.excel.converters.date.DateNumberConverter; +import com.alibaba.excel.converters.date.DateStringConverter; +import com.alibaba.excel.converters.doubleconverter.DoubleBooleanConverter; +import com.alibaba.excel.converters.doubleconverter.DoubleNumberConverter; +import com.alibaba.excel.converters.doubleconverter.DoubleStringConverter; +import com.alibaba.excel.converters.file.FileImageConverter; +import com.alibaba.excel.converters.floatconverter.FloatBooleanConverter; +import com.alibaba.excel.converters.floatconverter.FloatNumberConverter; +import com.alibaba.excel.converters.floatconverter.FloatStringConverter; +import com.alibaba.excel.converters.inputstream.InputStreamImageConverter; +import com.alibaba.excel.converters.integer.IntegerBooleanConverter; +import com.alibaba.excel.converters.integer.IntegerNumberConverter; +import com.alibaba.excel.converters.integer.IntegerStringConverter; +import com.alibaba.excel.converters.longconverter.LongBooleanConverter; +import com.alibaba.excel.converters.longconverter.LongNumberConverter; +import com.alibaba.excel.converters.longconverter.LongStringConverter; +import com.alibaba.excel.converters.shortconverter.ShortBooleanConverter; +import com.alibaba.excel.converters.shortconverter.ShortNumberConverter; +import com.alibaba.excel.converters.shortconverter.ShortStringConverter; +import com.alibaba.excel.converters.string.StringBooleanConverter; +import com.alibaba.excel.converters.string.StringErrorConverter; +import com.alibaba.excel.converters.string.StringNumberConverter; +import com.alibaba.excel.converters.string.StringStringConverter; + +/** + * Load default handler + * + * @author Jiaju Zhuang + */ +public class DefaultConverterLoader { + private static Map defaultWriteConverter; + private static Map allConverter; + + /** + * Load default write converter + * + * @return + */ + public static Map loadDefaultWriteConverter() { + if (defaultWriteConverter != null) { + return defaultWriteConverter; + } + defaultWriteConverter = new HashMap(32); + putWriteConverter(new BigDecimalNumberConverter()); + putWriteConverter(new BooleanBooleanConverter()); + putWriteConverter(new ByteNumberConverter()); + putWriteConverter(new DateStringConverter()); + putWriteConverter(new DoubleNumberConverter()); + putWriteConverter(new FloatNumberConverter()); + putWriteConverter(new IntegerNumberConverter()); + putWriteConverter(new LongNumberConverter()); + putWriteConverter(new ShortNumberConverter()); + putWriteConverter(new StringStringConverter()); + putWriteConverter(new FileImageConverter()); + putWriteConverter(new InputStreamImageConverter()); + putWriteConverter(new ByteArrayImageConverter()); + putWriteConverter(new BoxingByteArrayImageConverter()); + return defaultWriteConverter; + } + + private static void putWriteConverter(Converter converter) { + defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter); + } + + /** + * Load default read converter + * + * @return + */ + public static Map loadDefaultReadConverter() { + return loadAllConverter(); + } + + /** + * Load all converter + * + * @return + */ + public static Map loadAllConverter() { + if (allConverter != null) { + return allConverter; + } + allConverter = new HashMap(64); + putAllConverter(new BigDecimalBooleanConverter()); + putAllConverter(new BigDecimalNumberConverter()); + putAllConverter(new BigDecimalStringConverter()); + + putAllConverter(new BooleanBooleanConverter()); + putAllConverter(new BooleanNumberConverter()); + putAllConverter(new BooleanStringConverter()); + + putAllConverter(new ByteBooleanConverter()); + putAllConverter(new ByteNumberConverter()); + putAllConverter(new ByteStringConverter()); + + putAllConverter(new DateNumberConverter()); + putAllConverter(new DateStringConverter()); + + putAllConverter(new DoubleBooleanConverter()); + putAllConverter(new DoubleNumberConverter()); + putAllConverter(new DoubleStringConverter()); + + putAllConverter(new FloatBooleanConverter()); + putAllConverter(new FloatNumberConverter()); + putAllConverter(new FloatStringConverter()); + + putAllConverter(new IntegerBooleanConverter()); + putAllConverter(new IntegerNumberConverter()); + putAllConverter(new IntegerStringConverter()); + + putAllConverter(new LongBooleanConverter()); + putAllConverter(new LongNumberConverter()); + putAllConverter(new LongStringConverter()); + + putAllConverter(new ShortBooleanConverter()); + putAllConverter(new ShortNumberConverter()); + putAllConverter(new ShortStringConverter()); + + putAllConverter(new StringBooleanConverter()); + putAllConverter(new StringNumberConverter()); + putAllConverter(new StringStringConverter()); + putAllConverter(new StringErrorConverter()); + return allConverter; + } + + private static void putAllConverter(Converter converter) { + allConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), + converter); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalBooleanConverter.java new file mode 100644 index 0000000..8dcac0c --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalBooleanConverter.java @@ -0,0 +1,46 @@ +package com.alibaba.excel.converters.bigdecimal; + +import java.math.BigDecimal; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * BigDecimal and boolean converter + * + * @author Jiaju Zhuang + */ +public class BigDecimalBooleanConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return BigDecimal.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.BOOLEAN; + } + + @Override + public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (cellData.getBooleanValue()) { + return BigDecimal.ONE; + } + return BigDecimal.ZERO; + } + + @Override + public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (BigDecimal.ONE.equals(value)) { + return new CellData(Boolean.TRUE); + } + return new CellData(Boolean.FALSE); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalNumberConverter.java b/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalNumberConverter.java new file mode 100644 index 0000000..f7f1405 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalNumberConverter.java @@ -0,0 +1,39 @@ +package com.alibaba.excel.converters.bigdecimal; + +import java.math.BigDecimal; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * BigDecimal and number converter + * + * @author Jiaju Zhuang + */ +public class BigDecimalNumberConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return BigDecimal.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.NUMBER; + } + + @Override + public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return BigDecimal.valueOf(cellData.getDoubleValue()); + } + + @Override + public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(value.doubleValue()); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalStringConverter.java b/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalStringConverter.java new file mode 100644 index 0000000..8c5f0f4 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/bigdecimal/BigDecimalStringConverter.java @@ -0,0 +1,41 @@ +package com.alibaba.excel.converters.bigdecimal; + +import java.math.BigDecimal; +import java.text.ParseException; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.NumberUtils; + +/** + * BigDecimal and string converter + * + * @author Jiaju Zhuang + */ +public class BigDecimalStringConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return BigDecimal.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws ParseException { + return NumberUtils.parseBigDecimal(cellData.getStringValue(), contentProperty); + } + + @Override + public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return NumberUtils.formatToCellData(value, contentProperty); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanBooleanConverter.java new file mode 100644 index 0000000..08b83fe --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanBooleanConverter.java @@ -0,0 +1,38 @@ +package com.alibaba.excel.converters.booleanconverter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Boolean and boolean converter + * + * @author Jiaju Zhuang + */ +public class BooleanBooleanConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Boolean.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.BOOLEAN; + } + + @Override + public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return cellData.getBooleanValue(); + } + + @Override + public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(value); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanNumberConverter.java b/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanNumberConverter.java new file mode 100644 index 0000000..44cbdb9 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanNumberConverter.java @@ -0,0 +1,47 @@ +package com.alibaba.excel.converters.booleanconverter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Boolean and number converter + * + * @author Jiaju Zhuang + */ +public class BooleanNumberConverter implements Converter { + + private static final Double ONE = 1.0; + private static final Double ZERO = 0.0; + + @Override + public Class supportJavaTypeKey() { + return Boolean.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.NUMBER; + } + + @Override + public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (ONE.equals(cellData.getDoubleValue())) { + return Boolean.TRUE; + } + return Boolean.FALSE; + } + + @Override + public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (value) { + return new CellData(ONE); + } + return new CellData(ZERO); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanStringConverter.java b/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanStringConverter.java new file mode 100644 index 0000000..e86c6ad --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/booleanconverter/BooleanStringConverter.java @@ -0,0 +1,38 @@ +package com.alibaba.excel.converters.booleanconverter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Boolean and string converter + * + * @author Jiaju Zhuang + */ +public class BooleanStringConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Boolean.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Boolean convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return Boolean.valueOf(cellData.getStringValue()); + } + + @Override + public CellData convertToExcelData(Boolean value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(value.toString()); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java b/src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java new file mode 100644 index 0000000..c083601 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/bytearray/BoxingByteArrayImageConverter.java @@ -0,0 +1,41 @@ +package com.alibaba.excel.converters.bytearray; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Boxing Byte array and image converter + * + * @author Jiaju Zhuang + */ +public class BoxingByteArrayImageConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return Byte[].class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.IMAGE; + } + + @Override + public Byte[] convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + throw new UnsupportedOperationException("Cannot convert images to byte arrays"); + } + + @Override + public CellData convertToExcelData(Byte[] value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + byte[] byteValue = new byte[value.length]; + for (int i = 0; i < value.length; i++) { + byteValue[i] = value[i]; + } + return new CellData(byteValue); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java b/src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java new file mode 100644 index 0000000..991999d --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/bytearray/ByteArrayImageConverter.java @@ -0,0 +1,37 @@ +package com.alibaba.excel.converters.bytearray; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Byte array and image converter + * + * @author Jiaju Zhuang + */ +public class ByteArrayImageConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return byte[].class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.IMAGE; + } + + @Override + public byte[] convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + throw new UnsupportedOperationException("Cannot convert images to byte arrays"); + } + + @Override + public CellData convertToExcelData(byte[] value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(value); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/byteconverter/ByteBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteBooleanConverter.java new file mode 100644 index 0000000..2b62155 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteBooleanConverter.java @@ -0,0 +1,46 @@ +package com.alibaba.excel.converters.byteconverter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Byte and boolean converter + * + * @author Jiaju Zhuang + */ +public class ByteBooleanConverter implements Converter { + private static final Byte ONE = (byte)1; + private static final Byte ZERO = (byte)0; + + @Override + public Class supportJavaTypeKey() { + return Byte.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.BOOLEAN; + } + + @Override + public Byte convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (cellData.getBooleanValue()) { + return ONE; + } + return ZERO; + } + + @Override + public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (ONE.equals(value)) { + return new CellData(Boolean.TRUE); + } + return new CellData(Boolean.FALSE); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java new file mode 100644 index 0000000..c3ecf47 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java @@ -0,0 +1,38 @@ +package com.alibaba.excel.converters.byteconverter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Byte and number converter + * + * @author Jiaju Zhuang + */ +public class ByteNumberConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Byte.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.NUMBER; + } + + @Override + public Byte convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return cellData.getDoubleValue().byteValue(); + } + + @Override + public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(value.doubleValue()); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/byteconverter/ByteStringConverter.java b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteStringConverter.java new file mode 100644 index 0000000..c96114d --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteStringConverter.java @@ -0,0 +1,41 @@ +package com.alibaba.excel.converters.byteconverter; + +import java.text.ParseException; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.NumberUtils; + +/** + * Byte and string converter + * + * @author Jiaju Zhuang + */ +public class ByteStringConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Byte.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Byte convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws ParseException { + return NumberUtils.parseByte(cellData.getStringValue(), contentProperty); + } + + @Override + public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return NumberUtils.formatToCellData(value, contentProperty); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/date/DateNumberConverter.java b/src/main/java/com/alibaba/excel/converters/date/DateNumberConverter.java new file mode 100644 index 0000000..810188a --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/date/DateNumberConverter.java @@ -0,0 +1,46 @@ +package com.alibaba.excel.converters.date; + +import java.util.Date; + +import org.apache.poi.hssf.usermodel.HSSFDateUtil; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Date and number converter + * + * @author Jiaju Zhuang + */ +public class DateNumberConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Date.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.NUMBER; + } + + @Override + public Date convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { + return HSSFDateUtil.getJavaDate(cellData.getDoubleValue(), globalConfiguration.getUse1904windowing(), null); + } else { + return HSSFDateUtil.getJavaDate(cellData.getDoubleValue(), + contentProperty.getDateTimeFormatProperty().getUse1904windowing(), null); + } + } + + @Override + public CellData convertToExcelData(Date value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData((double)(value.getTime())); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/date/DateStringConverter.java b/src/main/java/com/alibaba/excel/converters/date/DateStringConverter.java new file mode 100644 index 0000000..ed7eb0a --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/date/DateStringConverter.java @@ -0,0 +1,49 @@ +package com.alibaba.excel.converters.date; + +import java.text.ParseException; +import java.util.Date; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.DateUtils; + +/** + * Date and string converter + * + * @author Jiaju Zhuang + */ +public class DateStringConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return Date.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Date convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws ParseException { + if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { + return DateUtils.parseDate(cellData.getStringValue(), null); + } else { + return DateUtils.parseDate(cellData.getStringValue(), + contentProperty.getDateTimeFormatProperty().getFormat()); + } + } + + @Override + public CellData convertToExcelData(Date value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) { + return new CellData(DateUtils.format(value, null)); + } else { + return new CellData(DateUtils.format(value, contentProperty.getDateTimeFormatProperty().getFormat())); + } + } +} diff --git a/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleBooleanConverter.java new file mode 100644 index 0000000..cbf0b0b --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleBooleanConverter.java @@ -0,0 +1,46 @@ +package com.alibaba.excel.converters.doubleconverter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Double and boolean converter + * + * @author Jiaju Zhuang + */ +public class DoubleBooleanConverter implements Converter { + private static final Double ONE = 1.0; + private static final Double ZERO = 0.0; + + @Override + public Class supportJavaTypeKey() { + return Double.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.BOOLEAN; + } + + @Override + public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (cellData.getBooleanValue()) { + return ONE; + } + return ZERO; + } + + @Override + public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (ONE.equals(value)) { + return new CellData(Boolean.TRUE); + } + return new CellData(Boolean.FALSE); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleNumberConverter.java b/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleNumberConverter.java new file mode 100644 index 0000000..f272c82 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleNumberConverter.java @@ -0,0 +1,38 @@ +package com.alibaba.excel.converters.doubleconverter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Double and number converter + * + * @author Jiaju Zhuang + */ +public class DoubleNumberConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Double.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.NUMBER; + } + + @Override + public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return cellData.getDoubleValue(); + } + + @Override + public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(value); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleStringConverter.java b/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleStringConverter.java new file mode 100644 index 0000000..2572b4e --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/doubleconverter/DoubleStringConverter.java @@ -0,0 +1,40 @@ +package com.alibaba.excel.converters.doubleconverter; + +import java.text.ParseException; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.NumberUtils; + +/** + * Double and string converter + * + * @author Jiaju Zhuang + */ +public class DoubleStringConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Double.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Double convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws ParseException { + return NumberUtils.parseDouble(cellData.getStringValue(), contentProperty); + } + + @Override + public CellData convertToExcelData(Double value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return NumberUtils.formatToCellData(value, contentProperty); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java b/src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java new file mode 100644 index 0000000..1052215 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/file/FileImageConverter.java @@ -0,0 +1,41 @@ +package com.alibaba.excel.converters.file; + +import java.io.File; +import java.io.IOException; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.FileUtils; + +/** + * File and image converter + * + * @author Jiaju Zhuang + */ +public class FileImageConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return File.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.IMAGE; + } + + @Override + public File convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + throw new UnsupportedOperationException("Cannot convert images to file"); + } + + @Override + public CellData convertToExcelData(File value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws IOException { + return new CellData(FileUtils.readFileToByteArray(value)); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/floatconverter/FloatBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatBooleanConverter.java new file mode 100644 index 0000000..8fa2a64 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatBooleanConverter.java @@ -0,0 +1,46 @@ +package com.alibaba.excel.converters.floatconverter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Float and boolean converter + * + * @author Jiaju Zhuang + */ +public class FloatBooleanConverter implements Converter { + private static final Float ONE = (float)1.0; + private static final Float ZERO = (float)0.0; + + @Override + public Class supportJavaTypeKey() { + return Float.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.BOOLEAN; + } + + @Override + public Float convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (cellData.getBooleanValue()) { + return ONE; + } + return ZERO; + } + + @Override + public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (ONE.equals(value)) { + return new CellData(Boolean.TRUE); + } + return new CellData(Boolean.FALSE); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java new file mode 100644 index 0000000..8913a57 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java @@ -0,0 +1,38 @@ +package com.alibaba.excel.converters.floatconverter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Float and number converter + * + * @author Jiaju Zhuang + */ +public class FloatNumberConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Float.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.NUMBER; + } + + @Override + public Float convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return cellData.getDoubleValue().floatValue(); + } + + @Override + public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(value.doubleValue()); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/floatconverter/FloatStringConverter.java b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatStringConverter.java new file mode 100644 index 0000000..ee2ef55 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatStringConverter.java @@ -0,0 +1,40 @@ +package com.alibaba.excel.converters.floatconverter; + +import java.text.ParseException; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.NumberUtils; + +/** + * Float and string converter + * + * @author Jiaju Zhuang + */ +public class FloatStringConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Float.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Float convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws ParseException { + return NumberUtils.parseFloat(cellData.getStringValue(), contentProperty); + } + + @Override + public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return NumberUtils.formatToCellData(value, contentProperty); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/inputstream/InputStreamImageConverter.java b/src/main/java/com/alibaba/excel/converters/inputstream/InputStreamImageConverter.java new file mode 100644 index 0000000..abc2fe6 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/inputstream/InputStreamImageConverter.java @@ -0,0 +1,41 @@ +package com.alibaba.excel.converters.inputstream; + +import java.io.IOException; +import java.io.InputStream; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.IoUtils; + +/** + * File and image converter + * + * @author Jiaju Zhuang + */ +public class InputStreamImageConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return InputStream.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.IMAGE; + } + + @Override + public InputStream convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + throw new UnsupportedOperationException("Cannot convert images to input stream"); + } + + @Override + public CellData convertToExcelData(InputStream value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws IOException { + return new CellData(IoUtils.toByteArray(value)); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/integer/IntegerBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/integer/IntegerBooleanConverter.java new file mode 100644 index 0000000..541de08 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/integer/IntegerBooleanConverter.java @@ -0,0 +1,46 @@ +package com.alibaba.excel.converters.integer; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Integer and boolean converter + * + * @author Jiaju Zhuang + */ +public class IntegerBooleanConverter implements Converter { + private static final Integer ONE = 1; + private static final Integer ZERO = 0; + + @Override + public Class supportJavaTypeKey() { + return Integer.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.BOOLEAN; + } + + @Override + public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (cellData.getBooleanValue()) { + return ONE; + } + return ZERO; + } + + @Override + public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (ONE.equals(value)) { + return new CellData(Boolean.TRUE); + } + return new CellData(Boolean.FALSE); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java b/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java new file mode 100644 index 0000000..4dff32d --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java @@ -0,0 +1,38 @@ +package com.alibaba.excel.converters.integer; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Integer and number converter + * + * @author Jiaju Zhuang + */ +public class IntegerNumberConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Integer.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.NUMBER; + } + + @Override + public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return cellData.getDoubleValue().intValue(); + } + + @Override + public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(value.doubleValue()); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/integer/IntegerStringConverter.java b/src/main/java/com/alibaba/excel/converters/integer/IntegerStringConverter.java new file mode 100644 index 0000000..07bc1b7 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/integer/IntegerStringConverter.java @@ -0,0 +1,40 @@ +package com.alibaba.excel.converters.integer; + +import java.text.ParseException; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.NumberUtils; + +/** + * Integer and string converter + * + * @author Jiaju Zhuang + */ +public class IntegerStringConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Integer.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Integer convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws ParseException { + return NumberUtils.parseInteger(cellData.getStringValue(), contentProperty); + } + + @Override + public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return NumberUtils.formatToCellData(value, contentProperty); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/longconverter/LongBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/longconverter/LongBooleanConverter.java new file mode 100644 index 0000000..6ee0217 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/longconverter/LongBooleanConverter.java @@ -0,0 +1,46 @@ +package com.alibaba.excel.converters.longconverter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Long and boolean converter + * + * @author Jiaju Zhuang + */ +public class LongBooleanConverter implements Converter { + private static final Long ONE = 1L; + private static final Long ZERO = 0L; + + @Override + public Class supportJavaTypeKey() { + return Long.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.BOOLEAN; + } + + @Override + public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (cellData.getBooleanValue()) { + return ONE; + } + return ZERO; + } + + @Override + public CellData convertToExcelData(Long value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (ONE.equals(value)) { + return new CellData(Boolean.TRUE); + } + return new CellData(Boolean.FALSE); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/longconverter/LongNumberConverter.java b/src/main/java/com/alibaba/excel/converters/longconverter/LongNumberConverter.java new file mode 100644 index 0000000..bceedd5 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/longconverter/LongNumberConverter.java @@ -0,0 +1,38 @@ +package com.alibaba.excel.converters.longconverter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Long and number converter + * + * @author Jiaju Zhuang + */ +public class LongNumberConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Long.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.NUMBER; + } + + @Override + public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return cellData.getDoubleValue().longValue(); + } + + @Override + public CellData convertToExcelData(Long value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(value.doubleValue()); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/longconverter/LongStringConverter.java b/src/main/java/com/alibaba/excel/converters/longconverter/LongStringConverter.java new file mode 100644 index 0000000..06e94f0 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/longconverter/LongStringConverter.java @@ -0,0 +1,40 @@ +package com.alibaba.excel.converters.longconverter; + +import java.text.ParseException; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.NumberUtils; + +/** + * Long and string converter + * + * @author Jiaju Zhuang + */ +public class LongStringConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Long.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Long convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws ParseException { + return NumberUtils.parseLong(cellData.getStringValue(), contentProperty); + } + + @Override + public CellData convertToExcelData(Long value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return NumberUtils.formatToCellData(value, contentProperty); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/shortconverter/ShortBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortBooleanConverter.java new file mode 100644 index 0000000..2c0cc61 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortBooleanConverter.java @@ -0,0 +1,46 @@ +package com.alibaba.excel.converters.shortconverter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Short and boolean converter + * + * @author Jiaju Zhuang + */ +public class ShortBooleanConverter implements Converter { + private static final Short ONE = 1; + private static final Short ZERO = 0; + + @Override + public Class supportJavaTypeKey() { + return Short.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.BOOLEAN; + } + + @Override + public Short convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (cellData.getBooleanValue()) { + return ONE; + } + return ZERO; + } + + @Override + public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + if (ONE.equals(value)) { + return new CellData(Boolean.TRUE); + } + return new CellData(Boolean.FALSE); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java new file mode 100644 index 0000000..91f6579 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java @@ -0,0 +1,38 @@ +package com.alibaba.excel.converters.shortconverter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Short and number converter + * + * @author Jiaju Zhuang + */ +public class ShortNumberConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Short.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.NUMBER; + } + + @Override + public Short convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return cellData.getDoubleValue().shortValue(); + } + + @Override + public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(value.doubleValue()); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/shortconverter/ShortStringConverter.java b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortStringConverter.java new file mode 100644 index 0000000..a683a03 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortStringConverter.java @@ -0,0 +1,40 @@ +package com.alibaba.excel.converters.shortconverter; + +import java.text.ParseException; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.NumberUtils; + +/** + * Short and string converter + * + * @author Jiaju Zhuang + */ +public class ShortStringConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Short.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Short convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws ParseException { + return NumberUtils.parseShort(cellData.getStringValue(), contentProperty); + } + + @Override + public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return NumberUtils.formatToCellData(value, contentProperty); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/string/StringBooleanConverter.java b/src/main/java/com/alibaba/excel/converters/string/StringBooleanConverter.java new file mode 100644 index 0000000..c405de5 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/string/StringBooleanConverter.java @@ -0,0 +1,38 @@ +package com.alibaba.excel.converters.string; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * String and boolean converter + * + * @author Jiaju Zhuang + */ +public class StringBooleanConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return String.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.BOOLEAN; + } + + @Override + public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return cellData.getBooleanValue().toString(); + } + + @Override + public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(Boolean.valueOf(value)); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/string/StringErrorConverter.java b/src/main/java/com/alibaba/excel/converters/string/StringErrorConverter.java new file mode 100644 index 0000000..66112e1 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/string/StringErrorConverter.java @@ -0,0 +1,37 @@ +package com.alibaba.excel.converters.string; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * String and error converter + * + * @author Jiaju Zhuang + */ +public class StringErrorConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return String.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.ERROR; + } + + @Override + public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return cellData.getStringValue(); + } + + @Override + public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(CellDataTypeEnum.ERROR, value); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/string/StringImageConverter.java b/src/main/java/com/alibaba/excel/converters/string/StringImageConverter.java new file mode 100644 index 0000000..931d4fa --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/string/StringImageConverter.java @@ -0,0 +1,41 @@ +package com.alibaba.excel.converters.string; + +import java.io.File; +import java.io.IOException; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.FileUtils; + +/** + * String and image converter + * + * @author Jiaju Zhuang + */ +public class StringImageConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return String.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.IMAGE; + } + + @Override + public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + throw new UnsupportedOperationException("Cannot convert images to string"); + } + + @Override + public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws IOException { + return new CellData(FileUtils.readFileToByteArray(new File(value))); + } + +} diff --git a/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java b/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java new file mode 100644 index 0000000..62b2523 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java @@ -0,0 +1,63 @@ +package com.alibaba.excel.converters.string; + +import org.apache.poi.hssf.usermodel.HSSFDateUtil; +import org.apache.poi.ss.usermodel.DateUtil; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.DateUtils; +import com.alibaba.excel.util.NumberUtils; + +/** + * String and number converter + * + * @author Jiaju Zhuang + */ +public class StringNumberConverter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return String.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.NUMBER; + } + + @Override + public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + // If there are "DateTimeFormat", read as date + if (contentProperty != null && contentProperty.getDateTimeFormatProperty() != null) { + return DateUtils.format( + HSSFDateUtil.getJavaDate(cellData.getDoubleValue(), + contentProperty.getDateTimeFormatProperty().getUse1904windowing(), null), + contentProperty.getDateTimeFormatProperty().getFormat()); + } + // If there are "NumberFormat", read as number + if (contentProperty != null && contentProperty.getNumberFormatProperty() != null) { + return NumberUtils.format(cellData.getDoubleValue(), contentProperty); + } + // Excel defines formatting + if (cellData.getDataFormat() != null) { + if (DateUtil.isADateFormat(cellData.getDataFormat(), cellData.getDataFormatString())) { + return DateUtils.format(HSSFDateUtil.getJavaDate(cellData.getDoubleValue(), + globalConfiguration.getUse1904windowing(), null)); + } else { + return NumberUtils.format(cellData.getDoubleValue(), contentProperty); + } + } + // Default conversion number + return NumberUtils.format(cellData.getDoubleValue(), contentProperty); + } + + @Override + public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(Double.valueOf(value)); + } +} diff --git a/src/main/java/com/alibaba/excel/converters/string/StringStringConverter.java b/src/main/java/com/alibaba/excel/converters/string/StringStringConverter.java new file mode 100644 index 0000000..df1b1e1 --- /dev/null +++ b/src/main/java/com/alibaba/excel/converters/string/StringStringConverter.java @@ -0,0 +1,37 @@ +package com.alibaba.excel.converters.string; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * String and string converter + * + * @author Jiaju Zhuang + */ +public class StringStringConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return String.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return cellData.getStringValue(); + } + + @Override + public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(value); + } + +} diff --git a/src/main/java/com/alibaba/excel/enums/CellDataTypeEnum.java b/src/main/java/com/alibaba/excel/enums/CellDataTypeEnum.java new file mode 100644 index 0000000..44efc17 --- /dev/null +++ b/src/main/java/com/alibaba/excel/enums/CellDataTypeEnum.java @@ -0,0 +1,66 @@ +package com.alibaba.excel.enums; + +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.excel.util.StringUtils; + +/** + * excel internal data type + * + * @author Jiaju Zhuang + */ +public enum CellDataTypeEnum { + /** + * string + */ + STRING, + /** + * This type of data does not need to be read in the 'sharedStrings.xml', it is only used for overuse, and the data + * will be stored as a {@link #STRING} + */ + DIRECT_STRING, + /** + * number + */ + NUMBER, + /** + * boolean + */ + BOOLEAN, + /** + * empty + */ + EMPTY, + /** + * error + */ + ERROR, + /** + * Images are currently supported only when writing + */ + IMAGE; + + private static final Map TYPE_ROUTING_MAP = new HashMap(16); + static { + TYPE_ROUTING_MAP.put("s", STRING); + TYPE_ROUTING_MAP.put("str", DIRECT_STRING); + TYPE_ROUTING_MAP.put("inlineStr", STRING); + TYPE_ROUTING_MAP.put("e", ERROR); + TYPE_ROUTING_MAP.put("b", BOOLEAN); + TYPE_ROUTING_MAP.put("n", NUMBER); + } + + /** + * Build data types + * + * @param cellType + * @return + */ + public static CellDataTypeEnum buildFromCellType(String cellType) { + if (StringUtils.isEmpty(cellType)) { + return EMPTY; + } + return TYPE_ROUTING_MAP.get(cellType); + } +} diff --git a/src/main/java/com/alibaba/excel/enums/HeadKindEnum.java b/src/main/java/com/alibaba/excel/enums/HeadKindEnum.java new file mode 100644 index 0000000..102367a --- /dev/null +++ b/src/main/java/com/alibaba/excel/enums/HeadKindEnum.java @@ -0,0 +1,21 @@ +package com.alibaba.excel.enums; + +/** + * The types of header + * + * @author Jiaju Zhuang + **/ +public enum HeadKindEnum { + /** + * none + */ + NONE, + /** + * class + */ + CLASS, + /** + * String + */ + STRING; +} diff --git a/src/main/java/com/alibaba/excel/enums/HolderEnum.java b/src/main/java/com/alibaba/excel/enums/HolderEnum.java new file mode 100644 index 0000000..ec3f047 --- /dev/null +++ b/src/main/java/com/alibaba/excel/enums/HolderEnum.java @@ -0,0 +1,25 @@ +package com.alibaba.excel.enums; + +/** + * The types of holder + * + * @author Jiaju Zhuang + **/ +public enum HolderEnum { + /** + * workbook + */ + WORKBOOK, + /** + * sheet + */ + SHEET, + /** + * table + */ + TABLE, + /** + * row + */ + ROW; +} diff --git a/src/main/java/com/alibaba/excel/enums/WriteLastRowType.java b/src/main/java/com/alibaba/excel/enums/WriteLastRowType.java new file mode 100644 index 0000000..bd477bd --- /dev/null +++ b/src/main/java/com/alibaba/excel/enums/WriteLastRowType.java @@ -0,0 +1,21 @@ +package com.alibaba.excel.enums; + +/** + * The types of write last row + * + * @author Jiaju Zhuang + **/ +public enum WriteLastRowType { + /** + * Excel are created without templates ,And any data has been written; + */ + COMMON_EMPTY, + /** + * Excel are created with templates ,And any data has been written; + */ + TEMPLATE_EMPTY, + /** + * Any data has been written; + */ + HAS_DATA,; +} diff --git a/src/main/java/com/alibaba/excel/event/AbstractIgnoreExceptionReadListener.java b/src/main/java/com/alibaba/excel/event/AbstractIgnoreExceptionReadListener.java new file mode 100644 index 0000000..22a95f0 --- /dev/null +++ b/src/main/java/com/alibaba/excel/event/AbstractIgnoreExceptionReadListener.java @@ -0,0 +1,27 @@ +package com.alibaba.excel.event; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; + +/** + * Receives the return of each piece of data parsed + * + * @author jipengfei + */ +public abstract class AbstractIgnoreExceptionReadListener implements ReadListener { + + /** + * All listeners receive this method when any one Listener does an error report. If an exception is thrown here, the + * entire read will terminate. + * + * @param exception + * @param context + */ + @Override + public void onException(Exception exception, AnalysisContext context) {} + + @Override + public boolean hasNext(AnalysisContext context) { + return true; + } +} diff --git a/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java b/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java index 2a30da4..4d596db 100644 --- a/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java +++ b/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java @@ -1,26 +1,29 @@ package com.alibaba.excel.event; import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; /** - * + * Receives the return of each piece of data parsed * * @author jipengfei */ -public abstract class AnalysisEventListener { - - /** - * when analysis one row trigger invoke function - * - * @param object one row data - * @param context analysis context - */ - public abstract void invoke(T object, AnalysisContext context); +public abstract class AnalysisEventListener implements ReadListener { /** - * if have something to do after all analysis + * All listeners receive this method when any one Listener does an error report. If an exception is thrown here, the + * entire read will terminate. * + * @param exception * @param context */ - public abstract void doAfterAllAnalysed(AnalysisContext context); + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + throw exception; + } + + @Override + public boolean hasNext(AnalysisContext context) { + return true; + } } diff --git a/src/main/java/com/alibaba/excel/event/AnalysisEventRegisterCenter.java b/src/main/java/com/alibaba/excel/event/AnalysisEventRegisterCenter.java deleted file mode 100644 index 7969f77..0000000 --- a/src/main/java/com/alibaba/excel/event/AnalysisEventRegisterCenter.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.alibaba.excel.event; - -/** - * Event center. - * - * @author jipengfei - */ -public interface AnalysisEventRegisterCenter { - - /** - * Append listener - * - * @param name listener name. - * @param listener Callback method after each row is parsed. - */ - void appendLister(String name, AnalysisEventListener listener); - - /** - * Parse one row to notify all event listeners - * - * @param event parse event - */ - void notifyListeners(OneRowAnalysisFinishEvent event); - - /** - * Clean all listeners. - */ - void cleanAllListeners(); -} diff --git a/src/main/java/com/alibaba/excel/event/Handler.java b/src/main/java/com/alibaba/excel/event/Handler.java new file mode 100644 index 0000000..2fe304f --- /dev/null +++ b/src/main/java/com/alibaba/excel/event/Handler.java @@ -0,0 +1,8 @@ +package com.alibaba.excel.event; + +/** + * Intercepts handle some business logic + * + * @author Jiaju Zhuang + **/ +public interface Handler {} diff --git a/src/main/java/com/alibaba/excel/event/Listener.java b/src/main/java/com/alibaba/excel/event/Listener.java new file mode 100644 index 0000000..e326518 --- /dev/null +++ b/src/main/java/com/alibaba/excel/event/Listener.java @@ -0,0 +1,8 @@ +package com.alibaba.excel.event; + +/** + * Interface to listen for processing results + * + * @author Jiaju Zhuang + */ +public interface Listener {} diff --git a/src/main/java/com/alibaba/excel/event/NotRepeatExecutor.java b/src/main/java/com/alibaba/excel/event/NotRepeatExecutor.java new file mode 100644 index 0000000..451655b --- /dev/null +++ b/src/main/java/com/alibaba/excel/event/NotRepeatExecutor.java @@ -0,0 +1,16 @@ +package com.alibaba.excel.event; + +/** + * There are multiple interceptors that execute only one of them when fired once.If you want to control which one to + * execute please use {@link Order} + * + * @author Jiaju Zhuang + **/ +public interface NotRepeatExecutor { + /** + * To see if it's the same executor + * + * @return + */ + String uniqueValue(); +} diff --git a/src/main/java/com/alibaba/excel/event/OneRowAnalysisFinishEvent.java b/src/main/java/com/alibaba/excel/event/OneRowAnalysisFinishEvent.java deleted file mode 100644 index 048e9d6..0000000 --- a/src/main/java/com/alibaba/excel/event/OneRowAnalysisFinishEvent.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.alibaba.excel.event; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author jipengfei - */ -public class OneRowAnalysisFinishEvent { - - public OneRowAnalysisFinishEvent(Object content) { - this.data = content; - } - - public OneRowAnalysisFinishEvent(String[] content, int length) { - if (content != null) { - List ls = new ArrayList(length); - for (int i = 0; i <= length; i++) { - ls.add(content[i]); - } - data = ls; - } - } - - private Object data; - - public Object getData() { - return data; - } - - public void setData(Object data) { - this.data = data; - } -} diff --git a/src/main/java/com/alibaba/excel/event/Order.java b/src/main/java/com/alibaba/excel/event/Order.java new file mode 100644 index 0000000..06f21a7 --- /dev/null +++ b/src/main/java/com/alibaba/excel/event/Order.java @@ -0,0 +1,15 @@ +package com.alibaba.excel.event; + +/** + * Implement this interface when sorting + * + * @author Jiaju Zhuang + */ +public interface Order { + /** + * The smaller the first implementation + * + * @return + */ + int order(); +} diff --git a/src/main/java/com/alibaba/excel/event/SyncReadListener.java b/src/main/java/com/alibaba/excel/event/SyncReadListener.java new file mode 100644 index 0000000..9de2335 --- /dev/null +++ b/src/main/java/com/alibaba/excel/event/SyncReadListener.java @@ -0,0 +1,31 @@ +package com.alibaba.excel.event; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.context.AnalysisContext; + +/** + * Synchronous data reading + * + * @author Jiaju Zhuang + */ +public class SyncReadListener extends AnalysisEventListener { + private List list = new ArrayList(); + + @Override + public void invoke(Object object, AnalysisContext context) { + list.add(object); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) {} + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } +} diff --git a/src/main/java/com/alibaba/excel/event/WriteHandler.java b/src/main/java/com/alibaba/excel/event/WriteHandler.java index 408799f..8c981ff 100644 --- a/src/main/java/com/alibaba/excel/event/WriteHandler.java +++ b/src/main/java/com/alibaba/excel/event/WriteHandler.java @@ -7,7 +7,9 @@ import org.apache.poi.ss.usermodel.Sheet; /** * * @author jipengfei + * @deprecated please use {@link com.alibaba.excel.write.handler.WriteHandler} */ +@Deprecated public interface WriteHandler { /** @@ -28,6 +30,7 @@ public interface WriteHandler { /** * Custom operation after creating each cell + * * @param cellNum * @param cell */ diff --git a/src/main/java/com/alibaba/excel/exception/ExcelAnalysisException.java b/src/main/java/com/alibaba/excel/exception/ExcelAnalysisException.java index 80d7a25..490c541 100644 --- a/src/main/java/com/alibaba/excel/exception/ExcelAnalysisException.java +++ b/src/main/java/com/alibaba/excel/exception/ExcelAnalysisException.java @@ -6,8 +6,7 @@ package com.alibaba.excel.exception; */ public class ExcelAnalysisException extends RuntimeException { - public ExcelAnalysisException() { - } + public ExcelAnalysisException() {} public ExcelAnalysisException(String message) { super(message); diff --git a/src/main/java/com/alibaba/excel/exception/ExcelAnalysisStopException.java b/src/main/java/com/alibaba/excel/exception/ExcelAnalysisStopException.java new file mode 100644 index 0000000..fd66d5c --- /dev/null +++ b/src/main/java/com/alibaba/excel/exception/ExcelAnalysisStopException.java @@ -0,0 +1,23 @@ +package com.alibaba.excel.exception; + +/** + * Throw the exception when you need to stop + * + * @author Jiaju Zhuang + */ +public class ExcelAnalysisStopException extends ExcelAnalysisException { + + public ExcelAnalysisStopException() {} + + public ExcelAnalysisStopException(String message) { + super(message); + } + + public ExcelAnalysisStopException(String message, Throwable cause) { + super(message, cause); + } + + public ExcelAnalysisStopException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/alibaba/excel/exception/ExcelCommonException.java b/src/main/java/com/alibaba/excel/exception/ExcelCommonException.java new file mode 100644 index 0000000..d861214 --- /dev/null +++ b/src/main/java/com/alibaba/excel/exception/ExcelCommonException.java @@ -0,0 +1,22 @@ +package com.alibaba.excel.exception; + +/** + * + * @author Jiaju Zhuang + */ +public class ExcelCommonException extends RuntimeException { + + public ExcelCommonException() {} + + public ExcelCommonException(String message) { + super(message); + } + + public ExcelCommonException(String message, Throwable cause) { + super(message, cause); + } + + public ExcelCommonException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/alibaba/excel/exception/ExcelDataConvertException.java b/src/main/java/com/alibaba/excel/exception/ExcelDataConvertException.java new file mode 100644 index 0000000..74630f0 --- /dev/null +++ b/src/main/java/com/alibaba/excel/exception/ExcelDataConvertException.java @@ -0,0 +1,21 @@ +package com.alibaba.excel.exception; + +/** + * Data convert exception + * + * @author Jiaju Zhuang + */ +public class ExcelDataConvertException extends RuntimeException { + + public ExcelDataConvertException(String message) { + super(message); + } + + public ExcelDataConvertException(String message, Throwable cause) { + super(message, cause); + } + + public ExcelDataConvertException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/com/alibaba/excel/exception/ExcelGenerateException.java b/src/main/java/com/alibaba/excel/exception/ExcelGenerateException.java index 266cf46..f508b17 100644 --- a/src/main/java/com/alibaba/excel/exception/ExcelGenerateException.java +++ b/src/main/java/com/alibaba/excel/exception/ExcelGenerateException.java @@ -5,7 +5,6 @@ package com.alibaba.excel.exception; */ public class ExcelGenerateException extends RuntimeException { - public ExcelGenerateException(String message) { super(message); } diff --git a/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java b/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java new file mode 100644 index 0000000..37a1942 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java @@ -0,0 +1,118 @@ +package com.alibaba.excel.metadata; + +import java.util.List; +import java.util.Map; + +import com.alibaba.excel.converters.Converter; + +/** + * Write/read holder + * + * @author Jiaju Zhuang + */ +public abstract class AbstractHolder implements ConfigurationHolder { + /** + * Record whether it's new or from cache + */ + private Boolean newInitialization; + /** + * You can only choose one of the {@link AbstractHolder#head} and {@link AbstractHolder#clazz} + */ + private List> head; + /** + * You can only choose one of the {@link AbstractHolder#head} and {@link AbstractHolder#clazz} + */ + private Class clazz; + /** + * Some global variables + */ + private GlobalConfiguration globalConfiguration; + + /** + *

+ * Read key: + *

+ * Write key: + */ + private Map converterMap; + + public AbstractHolder(BasicParameter basicParameter, AbstractHolder prentAbstractHolder) { + this.newInitialization = Boolean.TRUE; + if (basicParameter.getHead() == null && basicParameter.getClazz() == null && prentAbstractHolder != null) { + this.head = prentAbstractHolder.getHead(); + } else { + this.head = basicParameter.getHead(); + } + if (basicParameter.getHead() == null && basicParameter.getClazz() == null && prentAbstractHolder != null) { + this.clazz = prentAbstractHolder.getClazz(); + } else { + this.clazz = basicParameter.getClazz(); + } + this.globalConfiguration = new GlobalConfiguration(); + if (basicParameter.getAutoTrim() == null) { + if (prentAbstractHolder == null) { + globalConfiguration.setAutoTrim(Boolean.TRUE); + } else { + globalConfiguration.setAutoTrim(prentAbstractHolder.getGlobalConfiguration().getAutoTrim()); + } + } else { + globalConfiguration.setAutoTrim(basicParameter.getAutoTrim()); + } + } + + public Boolean getNewInitialization() { + return newInitialization; + } + + public void setNewInitialization(Boolean newInitialization) { + this.newInitialization = newInitialization; + } + + public List> getHead() { + return head; + } + + public void setHead(List> head) { + this.head = head; + } + + public Class getClazz() { + return clazz; + } + + public void setClazz(Class clazz) { + this.clazz = clazz; + } + + public GlobalConfiguration getGlobalConfiguration() { + return globalConfiguration; + } + + public void setGlobalConfiguration(GlobalConfiguration globalConfiguration) { + this.globalConfiguration = globalConfiguration; + } + + public Map getConverterMap() { + return converterMap; + } + + public void setConverterMap(Map converterMap) { + this.converterMap = converterMap; + } + + @Override + public Map converterMap() { + return getConverterMap(); + } + + @Override + public GlobalConfiguration globalConfiguration() { + return getGlobalConfiguration(); + } + + @Override + public boolean isNew() { + return getNewInitialization(); + } + +} diff --git a/src/main/java/com/alibaba/excel/metadata/BaseRowModel.java b/src/main/java/com/alibaba/excel/metadata/BaseRowModel.java index 6f4a805..7df131e 100644 --- a/src/main/java/com/alibaba/excel/metadata/BaseRowModel.java +++ b/src/main/java/com/alibaba/excel/metadata/BaseRowModel.java @@ -5,22 +5,28 @@ import java.util.Map; import org.apache.poi.ss.usermodel.CellStyle; +import com.alibaba.excel.annotation.ExcelIgnore; + /** * Excel基础模型 + * * @author jipengfei + * @deprecated Now you don't need to extend any classes */ +@Deprecated public class BaseRowModel { /** * 每列样式 */ - private Map cellStyleMap = new HashMap(); + @ExcelIgnore + private Map cellStyleMap = new HashMap(); - public void addStyle(Integer row, CellStyle cellStyle){ - cellStyleMap.put(row,cellStyle); + public void addStyle(Integer row, CellStyle cellStyle) { + cellStyleMap.put(row, cellStyle); } - public CellStyle getStyle(Integer row){ + public CellStyle getStyle(Integer row) { return cellStyleMap.get(row); } diff --git a/src/main/java/com/alibaba/excel/metadata/BasicParameter.java b/src/main/java/com/alibaba/excel/metadata/BasicParameter.java new file mode 100644 index 0000000..dfcf782 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/BasicParameter.java @@ -0,0 +1,78 @@ +package com.alibaba.excel.metadata; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.converters.Converter; + +/** + * Basic parameter + * + * @author Jiaju Zhuang + **/ +public class BasicParameter { + /** + * You can only choose one of the {@link BasicParameter#head} and {@link BasicParameter#clazz} + */ + private List> head; + /** + * You can only choose one of the {@link BasicParameter#head} and {@link BasicParameter#clazz} + */ + private Class clazz; + /** + * Custom type conversions override the default + */ + private List customConverterList = new ArrayList(); + /** + * Automatic trim includes sheet name and content + */ + private Boolean autoTrim; + /** + * true if date uses 1904 windowing, or false if using 1900 date windowing. + * + * default is false + * + * @return + */ + private Boolean use1904windowing; + + public List> getHead() { + return head; + } + + public void setHead(List> head) { + this.head = head; + } + + public Class getClazz() { + return clazz; + } + + public void setClazz(Class clazz) { + this.clazz = clazz; + } + + public List getCustomConverterList() { + return customConverterList; + } + + public void setCustomConverterList(List customConverterList) { + this.customConverterList = customConverterList; + } + + public Boolean getAutoTrim() { + return autoTrim; + } + + public void setAutoTrim(Boolean autoTrim) { + this.autoTrim = autoTrim; + } + + public Boolean getUse1904windowing() { + return use1904windowing; + } + + public void setUse1904windowing(Boolean use1904windowing) { + this.use1904windowing = use1904windowing; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/CellData.java b/src/main/java/com/alibaba/excel/metadata/CellData.java new file mode 100644 index 0000000..db73ce8 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/CellData.java @@ -0,0 +1,186 @@ +package com.alibaba.excel.metadata; + +import com.alibaba.excel.enums.CellDataTypeEnum; + +/** + * Excel internal cell data + * + * @author Jiaju Zhuang + */ +public class CellData { + private CellDataTypeEnum type; + /** + * {@link CellDataTypeEnum#NUMBER} + */ + private Double doubleValue; + /** + * {@link CellDataTypeEnum#STRING} and{@link CellDataTypeEnum#ERROR} + */ + private String stringValue; + /** + * {@link CellDataTypeEnum#BOOLEAN} + */ + private Boolean booleanValue; + private Boolean formula; + private String formulaValue; + private byte[] imageValue; + /** + * The number formatting.Currently only supported when reading + */ + private Integer dataFormat; + /** + * The string of number formatting.Currently only supported when reading + */ + private String dataFormatString; + + public CellData(CellData other) { + this.type = other.type; + this.doubleValue = other.doubleValue; + this.stringValue = other.stringValue; + this.booleanValue = other.booleanValue; + this.formula = other.formula; + this.formulaValue = other.formulaValue; + this.imageValue = other.imageValue; + this.dataFormat = other.dataFormat; + this.dataFormatString = other.dataFormatString; + } + + public CellData(String stringValue) { + this(CellDataTypeEnum.STRING, stringValue); + } + + public CellData(CellDataTypeEnum type, String stringValue) { + if (type != CellDataTypeEnum.STRING && type != CellDataTypeEnum.ERROR) { + throw new IllegalArgumentException("Only support CellDataTypeEnum.STRING and CellDataTypeEnum.ERROR"); + } + if (stringValue == null) { + throw new IllegalArgumentException("StringValue can not be null"); + } + this.type = type; + this.stringValue = stringValue; + this.formula = Boolean.FALSE; + } + + public CellData(Double doubleValue) { + if (doubleValue == null) { + throw new IllegalArgumentException("DoubleValue can not be null"); + } + this.type = CellDataTypeEnum.NUMBER; + this.doubleValue = doubleValue; + this.formula = Boolean.FALSE; + } + + public CellData(byte[] imageValue) { + if (imageValue == null) { + throw new IllegalArgumentException("ImageValue can not be null"); + } + this.type = CellDataTypeEnum.IMAGE; + this.imageValue = imageValue; + this.formula = Boolean.FALSE; + } + + public CellData(Boolean booleanValue) { + if (booleanValue == null) { + throw new IllegalArgumentException("BooleanValue can not be null"); + } + this.type = CellDataTypeEnum.BOOLEAN; + this.booleanValue = booleanValue; + this.formula = Boolean.FALSE; + } + + public CellData(CellDataTypeEnum type) { + if (type == null) { + throw new IllegalArgumentException("Type can not be null"); + } + this.type = type; + this.formula = Boolean.FALSE; + } + + public CellDataTypeEnum getType() { + return type; + } + + public void setType(CellDataTypeEnum type) { + this.type = type; + } + + public Double getDoubleValue() { + return doubleValue; + } + + public void setDoubleValue(Double doubleValue) { + this.doubleValue = doubleValue; + } + + public String getStringValue() { + return stringValue; + } + + public void setStringValue(String stringValue) { + this.stringValue = stringValue; + } + + public Boolean getBooleanValue() { + return booleanValue; + } + + public void setBooleanValue(Boolean booleanValue) { + this.booleanValue = booleanValue; + } + + public Boolean getFormula() { + return formula; + } + + public void setFormula(Boolean formula) { + this.formula = formula; + } + + public String getFormulaValue() { + return formulaValue; + } + + public void setFormulaValue(String formulaValue) { + this.formulaValue = formulaValue; + } + + public byte[] getImageValue() { + return imageValue; + } + + public void setImageValue(byte[] imageValue) { + this.imageValue = imageValue; + } + + public Integer getDataFormat() { + return dataFormat; + } + + public void setDataFormat(Integer dataFormat) { + this.dataFormat = dataFormat; + } + + public String getDataFormatString() { + return dataFormatString; + } + + public void setDataFormatString(String dataFormatString) { + this.dataFormatString = dataFormatString; + } + + @Override + public String toString() { + switch (type) { + case NUMBER: + return doubleValue.toString(); + case BOOLEAN: + return booleanValue.toString(); + case STRING: + case ERROR: + return stringValue; + default: + return "empty"; + } + } + +} diff --git a/src/main/java/com/alibaba/excel/metadata/ConfigurationHolder.java b/src/main/java/com/alibaba/excel/metadata/ConfigurationHolder.java new file mode 100644 index 0000000..d84b1d5 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/ConfigurationHolder.java @@ -0,0 +1,36 @@ +package com.alibaba.excel.metadata; + +import java.util.Map; + +import com.alibaba.excel.converters.Converter; + +/** + * + * Get the corresponding holder + * + * @author Jiaju Zhuang + **/ +public interface ConfigurationHolder extends Holder { + + /** + * + * Record whether it's new or from cache + * + * @return Record whether it's new or from cache + */ + boolean isNew(); + + /** + * Some global variables + * + * @return Global configuration + */ + GlobalConfiguration globalConfiguration(); + + /** + * What converter does the currently operated cell need to execute + * + * @return Converter + */ + Map converterMap(); +} diff --git a/src/main/java/com/alibaba/excel/metadata/ExcelColumnProperty.java b/src/main/java/com/alibaba/excel/metadata/ExcelColumnProperty.java deleted file mode 100644 index cc6442f..0000000 --- a/src/main/java/com/alibaba/excel/metadata/ExcelColumnProperty.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.alibaba.excel.metadata; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; - -/** - * @author jipengfei - */ -public class ExcelColumnProperty implements Comparable { - - /** - */ - private Field field; - - /** - */ - private int index = 99999; - - /** - */ - private List head = new ArrayList(); - - /** - */ - private String format; - - public String getFormat() { - return format; - } - - public void setFormat(String format) { - this.format = format; - } - - public Field getField() { - return field; - } - - public void setField(Field field) { - this.field = field; - } - - public int getIndex() { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - - public List getHead() { - return head; - } - - public void setHead(List head) { - this.head = head; - } - - public int compareTo(ExcelColumnProperty o) { - int x = this.index; - int y = o.getIndex(); - return (x < y) ? -1 : ((x == y) ? 0 : 1); - } -} \ No newline at end of file diff --git a/src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java b/src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java deleted file mode 100644 index 95ff9fd..0000000 --- a/src/main/java/com/alibaba/excel/metadata/ExcelHeadProperty.java +++ /dev/null @@ -1,228 +0,0 @@ -package com.alibaba.excel.metadata; - -import com.alibaba.excel.annotation.ExcelColumnNum; -import com.alibaba.excel.annotation.ExcelProperty; -import com.alibaba.excel.util.StringUtils; - -import java.lang.reflect.Field; -import java.util.*; - -/** - * Define the header attribute of excel - * - * @author jipengfei - */ -public class ExcelHeadProperty { - - /** - * Custom class - */ - private Class headClazz; - - /** - * A two-dimensional array describing the header - */ - private List> head = new ArrayList>(); - - /** - * Attributes described by the header - */ - private List columnPropertyList = new ArrayList(); - - /** - * Attributes described by the header - */ - private Map excelColumnPropertyMap1 = new HashMap(); - - public ExcelHeadProperty(Class headClazz, List> head) { - this.headClazz = headClazz; - this.head = head; - initColumnProperties(); - } - - /** - */ - private void initColumnProperties() { - if (this.headClazz != null) { - List fieldList = new ArrayList(); - Class tempClass = this.headClazz; - //When the parent class is null, it indicates that the parent class (Object class) has reached the top - // level. - while (tempClass != null) { - fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields())); - //Get the parent class and give it to yourself - tempClass = tempClass.getSuperclass(); - } - List> headList = new ArrayList>(); - for (Field f : fieldList) { - initOneColumnProperty(f); - } - //对列排序 - Collections.sort(columnPropertyList); - if (head == null || head.size() == 0) { - for (ExcelColumnProperty excelColumnProperty : columnPropertyList) { - headList.add(excelColumnProperty.getHead()); - } - this.head = headList; - } - } - } - - /** - * @param f - */ - private void initOneColumnProperty(Field f) { - ExcelProperty p = f.getAnnotation(ExcelProperty.class); - ExcelColumnProperty excelHeadProperty = null; - if (p != null) { - excelHeadProperty = new ExcelColumnProperty(); - excelHeadProperty.setField(f); - excelHeadProperty.setHead(Arrays.asList(p.value())); - excelHeadProperty.setIndex(p.index()); - excelHeadProperty.setFormat(p.format()); - excelColumnPropertyMap1.put(p.index(), excelHeadProperty); - } else { - ExcelColumnNum columnNum = f.getAnnotation(ExcelColumnNum.class); - if (columnNum != null) { - excelHeadProperty = new ExcelColumnProperty(); - excelHeadProperty.setField(f); - excelHeadProperty.setIndex(columnNum.value()); - excelHeadProperty.setFormat(columnNum.format()); - excelColumnPropertyMap1.put(columnNum.value(), excelHeadProperty); - } - } - if (excelHeadProperty != null) { - this.columnPropertyList.add(excelHeadProperty); - } - - } - - /** - * - */ - public void appendOneRow(List row) { - - for (int i = 0; i < row.size(); i++) { - List list; - if (head.size() <= i) { - list = new ArrayList(); - head.add(list); - } else { - list = head.get(0); - } - list.add(row.get(i)); - } - - } - - /** - * @param columnNum - * @return - */ - public ExcelColumnProperty getExcelColumnProperty(int columnNum) { - return excelColumnPropertyMap1.get(columnNum); - } - - public Class getHeadClazz() { - return headClazz; - } - - public void setHeadClazz(Class headClazz) { - this.headClazz = headClazz; - } - - public List> getHead() { - return this.head; - } - - public void setHead(List> head) { - this.head = head; - } - - public List getColumnPropertyList() { - return columnPropertyList; - } - - public void setColumnPropertyList(List columnPropertyList) { - this.columnPropertyList = columnPropertyList; - } - - /** - * Calculate all cells that need to be merged - * - * @return cells that need to be merged - */ - public List getCellRangeModels() { - List cellRanges = new ArrayList(); - for (int i = 0; i < head.size(); i++) { - List columnValues = head.get(i); - for (int j = 0; j < columnValues.size(); j++) { - int lastRow = getLastRangNum(j, columnValues.get(j), columnValues); - int lastColumn = getLastRangNum(i, columnValues.get(j), getHeadByRowNum(j)); - if ((lastRow > j || lastColumn > i) && lastRow >= 0 && lastColumn >= 0) { - cellRanges.add(new CellRange(j, lastRow, i, lastColumn)); - } - } - } - return cellRanges; - } - - public List getHeadByRowNum(int rowNum) { - List l = new ArrayList(head.size()); - for (List list : head) { - if (list.size() > rowNum) { - l.add(list.get(rowNum)); - } else { - l.add(list.get(list.size() - 1)); - } - } - return l; - } - - /** - * Get the last consecutive string position - * - * @param j current value position - * @param value value content - * @param values values - * @return the last consecutive string position - */ - private int getLastRangNum(int j, String value, List values) { - if (value == null) { - return -1; - } - if (j > 0) { - String preValue = values.get(j - 1); - if (value.equals(preValue)) { - return -1; - } - } - int last = j; - for (int i = last + 1; i < values.size(); i++) { - String current = values.get(i); - if (value.equals(current)) { - last = i; - } else { - // if i>j && !value.equals(current) Indicates that the continuous range is exceeded - if (i > j) { - break; - } - } - } - return last; - - } - - public int getRowNum() { - int headRowNum = 0; - for (List list : head) { - if (list != null && list.size() > 0) { - if (list.size() > headRowNum) { - headRowNum = list.size(); - } - } - } - return headRowNum; - } - -} diff --git a/src/main/java/com/alibaba/excel/metadata/Font.java b/src/main/java/com/alibaba/excel/metadata/Font.java index 4533011..0ba0141 100644 --- a/src/main/java/com/alibaba/excel/metadata/Font.java +++ b/src/main/java/com/alibaba/excel/metadata/Font.java @@ -3,7 +3,9 @@ package com.alibaba.excel.metadata; /** * * @author jipengfei + * @deprecated please use {@link com.alibaba.excel.write.metadata.style.WriteFont} */ +@Deprecated public class Font { /** diff --git a/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java b/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java new file mode 100644 index 0000000..921d70a --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java @@ -0,0 +1,37 @@ +package com.alibaba.excel.metadata; + +/** + * Global configuration + * + * @author Jiaju Zhuang + */ +public class GlobalConfiguration { + /** + * Automatic trim includes sheet name and content + */ + private Boolean autoTrim; + /** + * true if date uses 1904 windowing, or false if using 1900 date windowing. + * + * default is false + * + * @return + */ + private Boolean use1904windowing; + + public Boolean getUse1904windowing() { + return use1904windowing; + } + + public void setUse1904windowing(Boolean use1904windowing) { + this.use1904windowing = use1904windowing; + } + + public Boolean getAutoTrim() { + return autoTrim; + } + + public void setAutoTrim(Boolean autoTrim) { + this.autoTrim = autoTrim; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/Head.java b/src/main/java/com/alibaba/excel/metadata/Head.java new file mode 100644 index 0000000..c1cea10 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/Head.java @@ -0,0 +1,98 @@ +package com.alibaba.excel.metadata; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.metadata.property.ColumnWidthProperty; + +/** + * excel head + * + * @author Jiaju Zhuang + **/ +public class Head { + /** + * Column index of head + */ + private Integer columnIndex; + /** + * It only has values when passed in {@link Sheet#setClazz(Class)} and {@link Table#setClazz(Class)} + */ + private String fieldName; + /** + * Head name + */ + private List headNameList; + /** + * Whether index is specified + */ + private Boolean forceIndex; + /** + * Whether to specify a name + */ + private Boolean forceName; + /** + * column with + */ + private ColumnWidthProperty columnWidthProperty; + + public Head(Integer columnIndex, String fieldName, List headNameList, Boolean forceIndex, + Boolean forceName) { + this.columnIndex = columnIndex; + this.fieldName = fieldName; + if (headNameList == null) { + headNameList = new ArrayList(); + } + this.headNameList = headNameList; + this.forceIndex = forceIndex; + this.forceName = forceName; + } + + public Integer getColumnIndex() { + return columnIndex; + } + + public void setColumnIndex(Integer columnIndex) { + this.columnIndex = columnIndex; + } + + public String getFieldName() { + return fieldName; + } + + public void setFieldName(String fieldName) { + this.fieldName = fieldName; + } + + public List getHeadNameList() { + return headNameList; + } + + public void setHeadNameList(List headNameList) { + this.headNameList = headNameList; + } + + public ColumnWidthProperty getColumnWidthProperty() { + return columnWidthProperty; + } + + public void setColumnWidthProperty(ColumnWidthProperty columnWidthProperty) { + this.columnWidthProperty = columnWidthProperty; + } + + public Boolean getForceIndex() { + return forceIndex; + } + + public void setForceIndex(Boolean forceIndex) { + this.forceIndex = forceIndex; + } + + public Boolean getForceName() { + return forceName; + } + + public void setForceName(Boolean forceName) { + this.forceName = forceName; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/Holder.java b/src/main/java/com/alibaba/excel/metadata/Holder.java new file mode 100644 index 0000000..f2f430f --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/Holder.java @@ -0,0 +1,20 @@ +package com.alibaba.excel.metadata; + +import com.alibaba.excel.enums.HolderEnum; + +/** + * + * Get the corresponding holder + * + * @author Jiaju Zhuang + **/ +public interface Holder { + + /** + * What holder is the return + * + * @return Holder enum. + */ + HolderEnum holderType(); + +} diff --git a/src/main/java/com/alibaba/excel/metadata/IndexValue.java b/src/main/java/com/alibaba/excel/metadata/IndexValue.java deleted file mode 100644 index 2be0427..0000000 --- a/src/main/java/com/alibaba/excel/metadata/IndexValue.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.alibaba.excel.metadata; - -/** - * @author jipengfei - */ -public class IndexValue { - - private String v_index; - private String v_value; - - public IndexValue(String v_index, String v_value) { - super(); - this.v_index = v_index; - this.v_value = v_value; - } - - public String getV_index() { - return v_index; - } - - public void setV_index(String v_index) { - this.v_index = v_index; - } - - public String getV_value() { - return v_value; - } - - public void setV_value(String v_value) { - this.v_value = v_value; - } - - @Override - public String toString() { - return "IndexValue [v_index=" + v_index + ", v_value=" + v_value + "]"; - } - - -} diff --git a/src/main/java/com/alibaba/excel/metadata/Sheet.java b/src/main/java/com/alibaba/excel/metadata/Sheet.java index ef98b9c..38bd30a 100644 --- a/src/main/java/com/alibaba/excel/metadata/Sheet.java +++ b/src/main/java/com/alibaba/excel/metadata/Sheet.java @@ -7,7 +7,10 @@ import java.util.Map; /** * * @author jipengfei + * @deprecated pleas use {@link com.alibaba.excel.write.metadata.WriteSheet} or + * {@link com.alibaba.excel.read.metadata.ReadSheet} */ +@Deprecated public class Sheet { /** @@ -39,7 +42,7 @@ public class Sheet { /** * column with */ - private Map columnWidthMap = new HashMap(); + private Map columnWidthMap = new HashMap(); /** * @@ -51,7 +54,6 @@ public class Sheet { */ private int startRow = 0; - public Sheet(int sheetNo) { this.sheetNo = sheetNo; } @@ -68,7 +70,7 @@ public class Sheet { } public Sheet(int sheetNo, int headLineMun, Class clazz, String sheetName, - List> head) { + List> head) { this.sheetNo = sheetNo; this.clazz = clazz; this.headLineMun = headLineMun; @@ -127,8 +129,6 @@ public class Sheet { this.tableStyle = tableStyle; } - - public Map getColumnWidthMap() { return columnWidthMap; } @@ -139,15 +139,9 @@ public class Sheet { @Override public String toString() { - return "Sheet{" + - "headLineMun=" + headLineMun + - ", sheetNo=" + sheetNo + - ", sheetName='" + sheetName + '\'' + - ", clazz=" + clazz + - ", head=" + head + - ", tableStyle=" + tableStyle + - ", columnWidthMap=" + columnWidthMap + - '}'; + return "Sheet{" + "headLineMun=" + headLineMun + ", sheetNo=" + sheetNo + ", sheetName='" + sheetName + '\'' + + ", clazz=" + clazz + ", head=" + head + ", tableStyle=" + tableStyle + ", columnWidthMap=" + + columnWidthMap + '}'; } public Boolean getAutoWidth() { diff --git a/src/main/java/com/alibaba/excel/metadata/Table.java b/src/main/java/com/alibaba/excel/metadata/Table.java index 6643c46..d4c63ab 100644 --- a/src/main/java/com/alibaba/excel/metadata/Table.java +++ b/src/main/java/com/alibaba/excel/metadata/Table.java @@ -4,7 +4,9 @@ import java.util.List; /** * @author jipengfei + * @deprecated please use {@link com.alibaba.excel.write.metadata.WriteTable} */ +@Deprecated public class Table { /** */ @@ -22,6 +24,10 @@ public class Table { */ private TableStyle tableStyle; + public Table(Integer tableNo) { + this.tableNo = tableNo; + } + public TableStyle getTableStyle() { return tableStyle; } @@ -30,10 +36,6 @@ public class Table { this.tableStyle = tableStyle; } - public Table(Integer tableNo) { - this.tableNo = tableNo; - } - public Class getClazz() { return clazz; } diff --git a/src/main/java/com/alibaba/excel/metadata/TableStyle.java b/src/main/java/com/alibaba/excel/metadata/TableStyle.java index 228019c..fa8905c 100644 --- a/src/main/java/com/alibaba/excel/metadata/TableStyle.java +++ b/src/main/java/com/alibaba/excel/metadata/TableStyle.java @@ -2,9 +2,13 @@ package com.alibaba.excel.metadata; import org.apache.poi.ss.usermodel.IndexedColors; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; + /** * @author jipengfei + * @deprecated please use {@link HorizontalCellStyleStrategy} */ +@Deprecated public class TableStyle { /** diff --git a/src/main/java/com/alibaba/excel/metadata/property/ColumnWidthProperty.java b/src/main/java/com/alibaba/excel/metadata/property/ColumnWidthProperty.java new file mode 100644 index 0000000..f9499f8 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/property/ColumnWidthProperty.java @@ -0,0 +1,31 @@ +package com.alibaba.excel.metadata.property; + +import com.alibaba.excel.annotation.write.style.ColumnWidth; + +/** + * Configuration from annotations + * + * @author Jiaju Zhuang + */ +public class ColumnWidthProperty { + private Integer width; + + public ColumnWidthProperty(Integer width) { + this.width = width; + } + + public static ColumnWidthProperty build(ColumnWidth columnWidth) { + if (columnWidth == null || columnWidth.value() < 0) { + return null; + } + return new ColumnWidthProperty(columnWidth.value()); + } + + public Integer getWidth() { + return width; + } + + public void setWidth(Integer width) { + this.width = width; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/property/DateTimeFormatProperty.java b/src/main/java/com/alibaba/excel/metadata/property/DateTimeFormatProperty.java new file mode 100644 index 0000000..798dca9 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/property/DateTimeFormatProperty.java @@ -0,0 +1,41 @@ +package com.alibaba.excel.metadata.property; + +import com.alibaba.excel.annotation.format.DateTimeFormat; + +/** + * Configuration from annotations + * + * @author Jiaju Zhuang + */ +public class DateTimeFormatProperty { + private String format; + private Boolean use1904windowing; + + public DateTimeFormatProperty(String format, Boolean use1904windowing) { + this.format = format; + this.use1904windowing = use1904windowing; + } + + public static DateTimeFormatProperty build(DateTimeFormat dateTimeFormat) { + if (dateTimeFormat == null) { + return null; + } + return new DateTimeFormatProperty(dateTimeFormat.value(), dateTimeFormat.use1904windowing()); + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public Boolean getUse1904windowing() { + return use1904windowing; + } + + public void setUse1904windowing(Boolean use1904windowing) { + this.use1904windowing = use1904windowing; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/property/ExcelContentProperty.java b/src/main/java/com/alibaba/excel/metadata/property/ExcelContentProperty.java new file mode 100644 index 0000000..fcad87b --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/property/ExcelContentProperty.java @@ -0,0 +1,66 @@ +package com.alibaba.excel.metadata.property; + +import java.lang.reflect.Field; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.metadata.Head; + +/** + * @author jipengfei + */ +public class ExcelContentProperty { + /** + * Java filed + */ + private Field field; + /** + * Excel head + */ + private Head head; + /** + * Custom defined converters + */ + private Converter converter; + private DateTimeFormatProperty dateTimeFormatProperty; + private NumberFormatProperty numberFormatProperty; + + public Field getField() { + return field; + } + + public void setField(Field field) { + this.field = field; + } + + public Head getHead() { + return head; + } + + public void setHead(Head head) { + this.head = head; + } + + public DateTimeFormatProperty getDateTimeFormatProperty() { + return dateTimeFormatProperty; + } + + public void setDateTimeFormatProperty(DateTimeFormatProperty dateTimeFormatProperty) { + this.dateTimeFormatProperty = dateTimeFormatProperty; + } + + public NumberFormatProperty getNumberFormatProperty() { + return numberFormatProperty; + } + + public void setNumberFormatProperty(NumberFormatProperty numberFormatProperty) { + this.numberFormatProperty = numberFormatProperty; + } + + public Converter getConverter() { + return converter; + } + + public void setConverter(Converter converter) { + this.converter = converter; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java b/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java new file mode 100644 index 0000000..2f117e1 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java @@ -0,0 +1,246 @@ +package com.alibaba.excel.metadata.property; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.DateTimeFormat; +import com.alibaba.excel.annotation.format.NumberFormat; +import com.alibaba.excel.converters.AutoConverter; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.HeadKindEnum; +import com.alibaba.excel.exception.ExcelCommonException; +import com.alibaba.excel.exception.ExcelGenerateException; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.util.StringUtils; + +/** + * Define the header attribute of excel + * + * @author jipengfei + */ +public class ExcelHeadProperty { + + private static final Logger LOGGER = LoggerFactory.getLogger(ExcelHeadProperty.class); + /** + * Custom class + */ + private Class headClazz; + /** + * The types of head + */ + private HeadKindEnum headKind; + /** + * The number of rows in the line with the most rows + */ + private int headRowNumber; + + /** + * Configuration header information + */ + private Map headMap; + /** + * Configuration column information + */ + private Map contentPropertyMap; + /** + * Fields ignored + */ + private Map ignoreMap; + + public ExcelHeadProperty(Class headClazz, List> head, Boolean convertAllFiled) { + this.headClazz = headClazz; + headMap = new TreeMap(); + contentPropertyMap = new TreeMap(); + ignoreMap = new HashMap(16); + headKind = HeadKindEnum.NONE; + headRowNumber = 0; + if (head != null && !head.isEmpty()) { + for (int i = 0; i < head.size(); i++) { + headMap.put(i, new Head(i, null, head.get(i), Boolean.FALSE, Boolean.TRUE)); + contentPropertyMap.put(i, null); + } + headKind = HeadKindEnum.STRING; + } else { + // convert headClazz to head + initColumnProperties(convertAllFiled); + } + initHeadRowNumber(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("The initialization sheet/table 'ExcelHeadProperty' is complete , head kind is {}", headKind); + } + if (!hasHead()) { + LOGGER.warn( + "The table has no header set and all annotations will not be read.If you want to use annotations, please use set head class in ExcelWriterBuilder/ExcelWriterSheetBuilder/ExcelWriterTableBuilder"); + } + } + + private void initHeadRowNumber() { + headRowNumber = 0; + for (Head head : headMap.values()) { + List list = head.getHeadNameList(); + if (list != null && list.size() > headRowNumber) { + headRowNumber = list.size(); + } + } + for (Head head : headMap.values()) { + List list = head.getHeadNameList(); + if (list != null && !list.isEmpty() && list.size() < headRowNumber) { + int lack = headRowNumber - list.size(); + int last = list.size() - 1; + for (int i = 0; i < lack; i++) { + list.add(list.get(last)); + } + } + } + } + + private void initColumnProperties(Boolean convertAllFiled) { + if (headClazz == null) { + return; + } + List fieldList = new ArrayList(); + Class tempClass = headClazz; + // When the parent class is null, it indicates that the parent class (Object class) has reached the top + // level. + while (tempClass != null) { + Collections.addAll(fieldList, tempClass.getDeclaredFields()); + // Get the parent class and give it to yourself + tempClass = tempClass.getSuperclass(); + } + + // Screening of field + List defaultFieldList = new ArrayList(); + Map customFiledMap = new TreeMap(); + for (Field field : fieldList) { + ExcelIgnore excelIgnore = field.getAnnotation(ExcelIgnore.class); + if (excelIgnore != null) { + ignoreMap.put(field.getName(), field); + continue; + } + ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); + if (excelProperty == null && convertAllFiled != null && !convertAllFiled) { + ignoreMap.put(field.getName(), field); + continue; + } + if (excelProperty == null || excelProperty.index() < 0) { + defaultFieldList.add(field); + continue; + } + if (customFiledMap.containsKey(excelProperty.index())) { + throw new ExcelGenerateException("The index of " + customFiledMap.get(excelProperty.index()).getName() + + " and " + field.getName() + " must be inconsistent"); + } + customFiledMap.put(excelProperty.index(), field); + } + + int index = 0; + for (Field field : defaultFieldList) { + while (customFiledMap.containsKey(index)) { + initOneColumnProperty(index, customFiledMap.get(index), Boolean.TRUE); + customFiledMap.remove(index); + index++; + } + initOneColumnProperty(index, field, Boolean.FALSE); + index++; + } + for (Map.Entry entry : customFiledMap.entrySet()) { + initOneColumnProperty(entry.getKey(), entry.getValue(), Boolean.TRUE); + } + headKind = HeadKindEnum.CLASS; + } + + private void initOneColumnProperty(int index, Field field, Boolean forceIndex) { + ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); + List tmpHeadList = new ArrayList(); + boolean notForceName = excelProperty == null || excelProperty.value().length <= 0 + || (excelProperty.value().length == 1 && StringUtils.isEmpty((excelProperty.value())[0])); + if (notForceName) { + tmpHeadList.add(field.getName()); + } else { + Collections.addAll(tmpHeadList, excelProperty.value()); + } + Head head = new Head(index, field.getName(), tmpHeadList, forceIndex, !notForceName); + ExcelContentProperty excelContentProperty = new ExcelContentProperty(); + if (excelProperty != null) { + Class convertClazz = excelProperty.converter(); + if (convertClazz != AutoConverter.class) { + try { + Converter converter = convertClazz.newInstance(); + excelContentProperty.setConverter(converter); + } catch (Exception e) { + throw new ExcelCommonException("Can not instance custom converter:" + convertClazz.getName()); + } + } + } + excelContentProperty.setHead(head); + excelContentProperty.setField(field); + excelContentProperty + .setDateTimeFormatProperty(DateTimeFormatProperty.build(field.getAnnotation(DateTimeFormat.class))); + excelContentProperty + .setNumberFormatProperty(NumberFormatProperty.build(field.getAnnotation(NumberFormat.class))); + headMap.put(index, head); + contentPropertyMap.put(index, excelContentProperty); + } + + public Class getHeadClazz() { + return headClazz; + } + + public void setHeadClazz(Class headClazz) { + this.headClazz = headClazz; + } + + public HeadKindEnum getHeadKind() { + return headKind; + } + + public void setHeadKind(HeadKindEnum headKind) { + this.headKind = headKind; + } + + public boolean hasHead() { + return headKind != HeadKindEnum.NONE; + } + + public int getHeadRowNumber() { + return headRowNumber; + } + + public void setHeadRowNumber(int headRowNumber) { + this.headRowNumber = headRowNumber; + } + + public Map getHeadMap() { + return headMap; + } + + public void setHeadMap(Map headMap) { + this.headMap = headMap; + } + + public Map getContentPropertyMap() { + return contentPropertyMap; + } + + public void setContentPropertyMap(Map contentPropertyMap) { + this.contentPropertyMap = contentPropertyMap; + } + + public Map getIgnoreMap() { + return ignoreMap; + } + + public void setIgnoreMap(Map ignoreMap) { + this.ignoreMap = ignoreMap; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/property/NumberFormatProperty.java b/src/main/java/com/alibaba/excel/metadata/property/NumberFormatProperty.java new file mode 100644 index 0000000..f8f1e4a --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/property/NumberFormatProperty.java @@ -0,0 +1,43 @@ +package com.alibaba.excel.metadata.property; + +import java.math.RoundingMode; + +import com.alibaba.excel.annotation.format.NumberFormat; + +/** + * Configuration from annotations + * + * @author Jiaju Zhuang + */ +public class NumberFormatProperty { + private String format; + private RoundingMode roundingMode; + + public NumberFormatProperty(String format, RoundingMode roundingMode) { + this.format = format; + this.roundingMode = roundingMode; + } + + public static NumberFormatProperty build(NumberFormat numberFormat) { + if (numberFormat == null) { + return null; + } + return new NumberFormatProperty(numberFormat.value(), numberFormat.roundingMode()); + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public RoundingMode getRoundingMode() { + return roundingMode; + } + + public void setRoundingMode(RoundingMode roundingMode) { + this.roundingMode = roundingMode; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/property/RowHeightProperty.java b/src/main/java/com/alibaba/excel/metadata/property/RowHeightProperty.java new file mode 100644 index 0000000..1c0af12 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/property/RowHeightProperty.java @@ -0,0 +1,39 @@ +package com.alibaba.excel.metadata.property; + +import com.alibaba.excel.annotation.write.style.ContentRowHeight; +import com.alibaba.excel.annotation.write.style.HeadRowHeight; + +/** + * Configuration from annotations + * + * @author Jiaju Zhuang + */ +public class RowHeightProperty { + private Short height; + + public RowHeightProperty(Short height) { + this.height = height; + } + + public static RowHeightProperty build(HeadRowHeight headRowHeight) { + if (headRowHeight == null || headRowHeight.value() < 0) { + return null; + } + return new RowHeightProperty(headRowHeight.value()); + } + + public static RowHeightProperty build(ContentRowHeight contentRowHeight) { + if (contentRowHeight == null || contentRowHeight.value() < 0) { + return null; + } + return new RowHeightProperty(contentRowHeight.value()); + } + + public Short getHeight() { + return height; + } + + public void setHeight(Short height) { + this.height = height; + } +} diff --git a/src/main/java/com/alibaba/excel/modelbuild/ModelBuildEventListener.java b/src/main/java/com/alibaba/excel/modelbuild/ModelBuildEventListener.java deleted file mode 100644 index bea35c7..0000000 --- a/src/main/java/com/alibaba/excel/modelbuild/ModelBuildEventListener.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.alibaba.excel.modelbuild; - -import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.event.AnalysisEventListener; -import com.alibaba.excel.exception.ExcelGenerateException; -import com.alibaba.excel.metadata.ExcelHeadProperty; -import com.alibaba.excel.util.TypeUtil; -import net.sf.cglib.beans.BeanMap; - -import java.util.List; - -/** - * @author jipengfei - */ -public class ModelBuildEventListener extends AnalysisEventListener { - - @Override - public void invoke(Object object, AnalysisContext context) { - if (context.getExcelHeadProperty() != null && context.getExcelHeadProperty().getHeadClazz() != null) { - try { - Object resultModel = buildUserModel(context, (List)object); - context.setCurrentRowAnalysisResult(resultModel); - } catch (Exception e) { - throw new ExcelGenerateException(e); - } - } - } - - private Object buildUserModel(AnalysisContext context, List stringList) throws Exception { - ExcelHeadProperty excelHeadProperty = context.getExcelHeadProperty(); - Object resultModel = excelHeadProperty.getHeadClazz().newInstance(); - if (excelHeadProperty == null) { - return resultModel; - } - BeanMap.create(resultModel).putAll( - TypeUtil.getFieldValues(stringList, excelHeadProperty, context.use1904WindowDate())); - return resultModel; - } - - @Override - public void doAfterAllAnalysed(AnalysisContext context) { - - } -} diff --git a/src/main/java/com/alibaba/excel/parameter/ExcelWriteParam.java b/src/main/java/com/alibaba/excel/parameter/ExcelWriteParam.java deleted file mode 100644 index 9104e83..0000000 --- a/src/main/java/com/alibaba/excel/parameter/ExcelWriteParam.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.alibaba.excel.parameter; - -import java.io.OutputStream; - -import com.alibaba.excel.support.ExcelTypeEnum; - -/** - * {@link com.alibaba.excel.ExcelWriter} - * - * @author jipengfei - */ -@Deprecated -public class ExcelWriteParam { - - /** - */ - private OutputStream outputStream; - - /** - */ - private ExcelTypeEnum type; - - public ExcelWriteParam(OutputStream outputStream, ExcelTypeEnum type) { - this.outputStream = outputStream; - this.type = type; - - } - - public OutputStream getOutputStream() { - return outputStream; - } - - public void setOutputStream(OutputStream outputStream) { - this.outputStream = outputStream; - } - - public ExcelTypeEnum getType() { - return type; - } - - public void setType(ExcelTypeEnum type) { - this.type = type; - } -} diff --git a/src/main/java/com/alibaba/excel/parameter/GenerateParam.java b/src/main/java/com/alibaba/excel/parameter/GenerateParam.java index 9dfccc5..acbcfbd 100644 --- a/src/main/java/com/alibaba/excel/parameter/GenerateParam.java +++ b/src/main/java/com/alibaba/excel/parameter/GenerateParam.java @@ -6,7 +6,11 @@ import com.alibaba.excel.support.ExcelTypeEnum; /** * Created by jipengfei on 17/2/19. + * + * @author jipengfei + * @deprecated please use {@link com.alibaba.excel.write.builder.ExcelWriterBuilder} build ExcelWriter */ +@Deprecated public class GenerateParam { private OutputStream outputStream; @@ -17,6 +21,8 @@ public class GenerateParam { private ExcelTypeEnum type; + private boolean needHead = true; + public GenerateParam(String sheetName, Class clazz, OutputStream outputStream) { this.outputStream = outputStream; this.sheetName = sheetName; @@ -31,7 +37,6 @@ public class GenerateParam { this.outputStream = outputStream; } - public String getSheetName() { return sheetName; } @@ -55,4 +60,12 @@ public class GenerateParam { public void setType(ExcelTypeEnum type) { this.type = type; } + + public boolean isNeedHead() { + return needHead; + } + + public void setNeedHead(boolean needHead) { + this.needHead = needHead; + } } diff --git a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java new file mode 100644 index 0000000..15d4a02 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java @@ -0,0 +1,228 @@ +package com.alibaba.excel.read.builder; + +import java.io.File; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.cache.ReadCache; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadWorkbook; +import com.alibaba.excel.support.ExcelTypeEnum; + +/** + * Build ExcelWriter + * + * @author Jiaju Zhuang + */ +public class ExcelReaderBuilder { + /** + * Workbook + */ + private ReadWorkbook readWorkbook; + + public ExcelReaderBuilder() { + this.readWorkbook = new ReadWorkbook(); + } + + public ExcelReaderBuilder excelType(ExcelTypeEnum excelType) { + readWorkbook.setExcelType(excelType); + return this; + } + + /** + * Read InputStream + *

+ * If 'inputStream' and 'file' all not empty,file first + */ + public ExcelReaderBuilder file(InputStream inputStream) { + readWorkbook.setInputStream(inputStream); + return this; + } + + /** + * Read file + *

+ * If 'inputStream' and 'file' all not empty,file first + */ + public ExcelReaderBuilder file(File file) { + readWorkbook.setFile(file); + return this; + } + + /** + * Read file + *

+ * If 'inputStream' and 'file' all not empty,file first + */ + public ExcelReaderBuilder file(String pathName) { + return file(new File(pathName)); + } + + /** + * Mandatory use 'inputStream' .Default is false. + *

+ * if false,Will transfer 'inputStream' to temporary files to improve efficiency + */ + public ExcelReaderBuilder mandatoryUseInputStream(Boolean mandatoryUseInputStream) { + readWorkbook.setMandatoryUseInputStream(mandatoryUseInputStream); + return this; + } + + /** + * Default true + * + * @param autoCloseStream + * @return + */ + public ExcelReaderBuilder autoCloseStream(Boolean autoCloseStream) { + readWorkbook.setAutoCloseStream(autoCloseStream); + return this; + } + + /** + * This object can be read in the Listener {@link AnalysisEventListener#invoke(Object, AnalysisContext)} + * {@link AnalysisContext#getCustom()} + * + * @param customObject + * @return + */ + public ExcelReaderBuilder customObject(Object customObject) { + readWorkbook.setCustomObject(customObject); + return this; + } + + /** + * A cache that stores temp data to save memory.Default use {@link com.alibaba.excel.cache.Ehcache} + * + * @param readCache + * @return + */ + public ExcelReaderBuilder readCache(ReadCache readCache) { + readWorkbook.setReadCache(readCache); + return this; + } + + /** + * Count the number of added heads when read sheet. + * + *

+ * 0 - This Sheet has no head ,since the first row are the data + *

+ * 1 - This Sheet has one row head , this is the default + *

+ * 2 - This Sheet has two row head ,since the third row is the data + * + * @param headRowNumber + * @return + */ + public ExcelReaderBuilder headRowNumber(Integer headRowNumber) { + readWorkbook.setHeadRowNumber(headRowNumber); + return this; + } + + /** + * You can only choose one of the {@link ExcelReaderBuilder#head(List)} and {@link ExcelReaderBuilder#head(Class)} + * + * @param head + * @return + */ + public ExcelReaderBuilder head(List> head) { + readWorkbook.setHead(head); + return this; + } + + /** + * You can only choose one of the {@link ExcelReaderBuilder#head(List)} and {@link ExcelReaderBuilder#head(Class)} + * + * @param clazz + * @return + */ + public ExcelReaderBuilder head(Class clazz) { + readWorkbook.setClazz(clazz); + return this; + } + + /** + * Custom type conversions override the default. + * + * @param converter + * @return + */ + public ExcelReaderBuilder registerConverter(Converter converter) { + if (readWorkbook.getCustomConverterList() == null) { + readWorkbook.setCustomConverterList(new ArrayList()); + } + readWorkbook.getCustomConverterList().add(converter); + return this; + } + + /** + * Custom type listener run after default + * + * @param readListener + * @return + */ + public ExcelReaderBuilder registerReadListener(ReadListener readListener) { + if (readWorkbook.getCustomReadListenerList() == null) { + readWorkbook.setCustomReadListenerList(new ArrayList()); + } + readWorkbook.getCustomReadListenerList().add(readListener); + return this; + } + + /** + * true if date uses 1904 windowing, or false if using 1900 date windowing. + * + * default is false + * + * @param use1904windowing + * @return + */ + public ExcelReaderBuilder use1904windowing(Boolean use1904windowing) { + readWorkbook.setUse1904windowing(use1904windowing); + return this; + } + + /** + * Automatic trim includes sheet name and content + * + * @param autoTrim + * @return + */ + public ExcelReaderBuilder autoTrim(Boolean autoTrim) { + readWorkbook.setAutoTrim(autoTrim); + return this; + } + + public ExcelReader build() { + return new ExcelReader(readWorkbook); + } + + public ExcelReaderSheetBuilder sheet() { + return sheet(null, null); + } + + public ExcelReaderSheetBuilder sheet(Integer sheetNo) { + return sheet(sheetNo, null); + } + + public ExcelReaderSheetBuilder sheet(String sheetName) { + return sheet(null, sheetName); + } + + public ExcelReaderSheetBuilder sheet(Integer sheetNo, String sheetName) { + ExcelReaderSheetBuilder excelReaderSheetBuilder = new ExcelReaderSheetBuilder(build()); + if (sheetNo != null) { + excelReaderSheetBuilder.sheetNo(sheetNo); + } + if (sheetName != null) { + excelReaderSheetBuilder.sheetName(sheetName); + } + return excelReaderSheetBuilder; + } +} diff --git a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java new file mode 100644 index 0000000..af3b05e --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java @@ -0,0 +1,180 @@ +package com.alibaba.excel.read.builder; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.event.SyncReadListener; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.exception.ExcelGenerateException; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadSheet; + +/** + * Build sheet + * + * @author Jiaju Zhuang + */ +public class ExcelReaderSheetBuilder { + private ExcelReader excelReader; + /** + * Sheet + */ + private ReadSheet readSheet; + + public ExcelReaderSheetBuilder() { + this.readSheet = new ReadSheet(); + } + + public ExcelReaderSheetBuilder(ExcelReader excelReader) { + this.readSheet = new ReadSheet(); + this.excelReader = excelReader; + } + + /** + * Starting from 0 + * + * @param sheetNo + * @return + */ + public ExcelReaderSheetBuilder sheetNo(Integer sheetNo) { + readSheet.setSheetNo(sheetNo); + return this; + } + + /** + * sheet name + * + * @param sheetName + * @return + */ + public ExcelReaderSheetBuilder sheetName(String sheetName) { + readSheet.setSheetName(sheetName); + return this; + } + + /** + * Count the number of added heads when read sheet. + * + *

+ * 0 - This Sheet has no head ,since the first row are the data + *

+ * 1 - This Sheet has one row head , this is the default + *

+ * 2 - This Sheet has two row head ,since the third row is the data + * + * @param headRowNumber + * @return + */ + public ExcelReaderSheetBuilder headRowNumber(Integer headRowNumber) { + readSheet.setHeadRowNumber(headRowNumber); + return this; + } + + /** + * You can only choose one of the {@link ExcelReaderBuilder#head(List)} and {@link ExcelReaderBuilder#head(Class)} + * + * @param head + * @return + */ + public ExcelReaderSheetBuilder head(List> head) { + readSheet.setHead(head); + return this; + } + + /** + * You can only choose one of the {@link ExcelReaderBuilder#head(List)} and {@link ExcelReaderBuilder#head(Class)} + * + * @param clazz + * @return + */ + public ExcelReaderSheetBuilder head(Class clazz) { + readSheet.setClazz(clazz); + return this; + } + + /** + * Custom type conversions override the default. + * + * @param converter + * @return + */ + public ExcelReaderSheetBuilder registerConverter(Converter converter) { + if (readSheet.getCustomConverterList() == null) { + readSheet.setCustomConverterList(new ArrayList()); + } + readSheet.getCustomConverterList().add(converter); + return this; + } + + /** + * Custom type listener run after default + * + * @param readListener + * @return + */ + public ExcelReaderSheetBuilder registerReadListener(ReadListener readListener) { + if (readSheet.getCustomReadListenerList() == null) { + readSheet.setCustomReadListenerList(new ArrayList()); + } + readSheet.getCustomReadListenerList().add(readListener); + return this; + } + + /** + * true if date uses 1904 windowing, or false if using 1900 date windowing. + * + * default is false + * + * @param use1904windowing + * @return + */ + public ExcelReaderSheetBuilder use1904windowing(Boolean use1904windowing) { + readSheet.setUse1904windowing(use1904windowing); + return this; + } + + /** + * Automatic trim includes sheet name and content + * + * @param autoTrim + * @return + */ + public ExcelReaderSheetBuilder autoTrim(Boolean autoTrim) { + readSheet.setAutoTrim(autoTrim); + return this; + } + + public ReadSheet build() { + return readSheet; + } + + /** + * Sax read + */ + public void doRead() { + if (excelReader == null) { + throw new ExcelGenerateException("Must use 'EasyExcelFactory.read().sheet()' to call this method"); + } + excelReader.read(build()); + excelReader.finish(); + } + + /** + * Synchronous reads return results + * + * @return + */ + public List doReadSync() { + if (excelReader == null) { + throw new ExcelAnalysisException("Must use 'EasyExcelFactory.read().sheet()' to call this method"); + } + SyncReadListener syncReadListener = new SyncReadListener(); + registerReadListener(syncReadListener); + excelReader.read(build()); + excelReader.finish(); + return syncReadListener.getList(); + } + +} diff --git a/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java b/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java new file mode 100644 index 0000000..bf4a8cf --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java @@ -0,0 +1,128 @@ +package com.alibaba.excel.read.listener; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.converters.ConverterKeyBuild; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.enums.HeadKindEnum; +import com.alibaba.excel.event.AbstractIgnoreExceptionReadListener; +import com.alibaba.excel.exception.ExcelDataConvertException; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.read.metadata.holder.ReadHolder; +import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty; + +import net.sf.cglib.beans.BeanMap; + +/** + * Convert to the object the user needs + * + * @author jipengfei + */ +public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener> { + + @Override + public void invoke(Map cellDataMap, AnalysisContext context) { + ReadHolder currentReadHolder = context.currentReadHolder(); + if (HeadKindEnum.CLASS.equals(currentReadHolder.excelReadHeadProperty().getHeadKind())) { + context.readRowHolder().setCurrentRowAnalysisResult(buildUserModel(cellDataMap, currentReadHolder)); + return; + } + context.readRowHolder().setCurrentRowAnalysisResult(buildStringList(cellDataMap, currentReadHolder, context)); + } + + private Object buildStringList(Map cellDataMap, ReadHolder currentReadHolder, + AnalysisContext context) { + if (context.readWorkbookHolder().getDefaultReturnMap()) { + Map map = new HashMap(cellDataMap.size() * 4 / 3 + 1); + for (Map.Entry entry : cellDataMap.entrySet()) { + CellData cellData = entry.getValue(); + if (cellData.getType() == CellDataTypeEnum.EMPTY) { + map.put(entry.getKey(), null); + continue; + } + map.put(entry.getKey(), (String)convertValue(cellData, String.class, null, + currentReadHolder.converterMap(), currentReadHolder.globalConfiguration())); + } + return map; + } else { + // Compatible with the old code the old code returns a list + List list = new ArrayList(); + for (Map.Entry entry : cellDataMap.entrySet()) { + CellData cellData = entry.getValue(); + if (cellData.getType() == CellDataTypeEnum.EMPTY) { + list.add(null); + continue; + } + list.add((String)convertValue(cellData, String.class, null, currentReadHolder.converterMap(), + currentReadHolder.globalConfiguration())); + } + return list; + } + } + + private Object buildUserModel(Map cellDataMap, ReadHolder currentReadHolder) { + ExcelReadHeadProperty excelReadHeadProperty = currentReadHolder.excelReadHeadProperty(); + Object resultModel; + try { + resultModel = excelReadHeadProperty.getHeadClazz().newInstance(); + } catch (Exception e) { + throw new ExcelDataConvertException( + "Can not instance class: " + excelReadHeadProperty.getHeadClazz().getName(), e); + } + Map headMap = excelReadHeadProperty.getHeadMap(); + Map map = new HashMap(headMap.size() * 4 / 3 + 1); + Map contentPropertyMap = excelReadHeadProperty.getContentPropertyMap(); + for (Map.Entry entry : headMap.entrySet()) { + Integer index = entry.getKey(); + if (!cellDataMap.containsKey(index)) { + continue; + } + CellData cellData = cellDataMap.get(index); + if (cellData.getType() == CellDataTypeEnum.EMPTY) { + continue; + } + ExcelContentProperty excelContentProperty = contentPropertyMap.get(index); + Object value = convertValue(cellData, excelContentProperty.getField().getType(), excelContentProperty, + currentReadHolder.converterMap(), currentReadHolder.globalConfiguration()); + if (value != null) { + map.put(excelContentProperty.getField().getName(), value); + } + } + BeanMap.create(resultModel).putAll(map); + return resultModel; + } + + private Object convertValue(CellData cellData, Class clazz, ExcelContentProperty contentProperty, + Map converterMap, GlobalConfiguration globalConfiguration) { + if (clazz == CellData.class) { + return new CellData(cellData); + } + Converter converter = null; + if (contentProperty != null) { + converter = contentProperty.getConverter(); + } + if (converter == null) { + converter = converterMap.get(ConverterKeyBuild.buildKey(clazz, cellData.getType())); + } + if (converter == null) { + throw new ExcelDataConvertException( + "Converter not found, convert " + cellData.getType() + " to " + clazz.getName()); + } + try { + return converter.convertToJavaData(cellData, contentProperty, globalConfiguration); + } catch (Exception e) { + throw new ExcelDataConvertException("Convert data " + cellData + " to " + clazz + " error ", e); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) {} +} diff --git a/src/main/java/com/alibaba/excel/read/listener/ReadListener.java b/src/main/java/com/alibaba/excel/read/listener/ReadListener.java new file mode 100644 index 0000000..09ce3c7 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/listener/ReadListener.java @@ -0,0 +1,46 @@ +package com.alibaba.excel.read.listener; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.Listener; + +/** + * Interface to listen for read results + * + * @author Jiaju Zhuang + */ +public interface ReadListener extends Listener { + /** + * All listeners receive this method when any one Listener does an error report. If an exception is thrown here, the + * entire read will terminate. + * + * @param exception + * @param context + * @throws Exception + */ + void onException(Exception exception, AnalysisContext context) throws Exception; + + /** + * when analysis one row trigger invoke function. + * + * @param data + * one row value. Is is same as {@link AnalysisContext#readRowHolder()} + * @param context + * analysis context + */ + void invoke(T data, AnalysisContext context); + + /** + * if have something to do after all analysis + * + * @param context + */ + void doAfterAllAnalysed(AnalysisContext context); + + /** + * Verify that there is another piece of data.You can stop the read by returning false + * + * @param context + * @return + */ + boolean hasNext(AnalysisContext context); +} diff --git a/src/main/java/com/alibaba/excel/read/listener/ReadListenerRegistryCenter.java b/src/main/java/com/alibaba/excel/read/listener/ReadListenerRegistryCenter.java new file mode 100644 index 0000000..07bc68c --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/listener/ReadListenerRegistryCenter.java @@ -0,0 +1,39 @@ +package com.alibaba.excel.read.listener; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.read.listener.event.AnalysisFinishEvent; + +/** + * Registry center. + * + * @author jipengfei + */ +public interface ReadListenerRegistryCenter { + + /** + * register + * + * @param listener + * Analysis listener + */ + void register(AnalysisEventListener listener); + + /** + * Parse one row to notify all event listeners + * + * @param event + * parse event + * @param analysisContext + * Analysis context + */ + void notifyEndOneRow(AnalysisFinishEvent event, AnalysisContext analysisContext); + + /** + * Notify after all analysed + * + * @param analysisContext + * Analysis context + */ + void notifyAfterAllAnalysed(AnalysisContext analysisContext); +} diff --git a/src/main/java/com/alibaba/excel/read/listener/event/AnalysisFinishEvent.java b/src/main/java/com/alibaba/excel/read/listener/event/AnalysisFinishEvent.java new file mode 100644 index 0000000..9749cf0 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/listener/event/AnalysisFinishEvent.java @@ -0,0 +1,20 @@ +package com.alibaba.excel.read.listener.event; + +import java.util.Map; + +import com.alibaba.excel.metadata.CellData; + +/** + * + * Event + * + * @author jipengfei + */ +public interface AnalysisFinishEvent { + /** + * Get result + * + * @return + */ + Map getAnalysisResult(); +} diff --git a/src/main/java/com/alibaba/excel/read/listener/event/EachRowAnalysisFinishEvent.java b/src/main/java/com/alibaba/excel/read/listener/event/EachRowAnalysisFinishEvent.java new file mode 100644 index 0000000..879a59a --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/listener/event/EachRowAnalysisFinishEvent.java @@ -0,0 +1,21 @@ +package com.alibaba.excel.read.listener.event; + +import java.util.Map; + +import com.alibaba.excel.metadata.CellData; + +/** + * @author jipengfei + */ +public class EachRowAnalysisFinishEvent implements AnalysisFinishEvent { + private Map result; + + public EachRowAnalysisFinishEvent(Map content) { + this.result = content; + } + + @Override + public Map getAnalysisResult() { + return result; + } +} diff --git a/src/main/java/com/alibaba/excel/read/metadata/ReadBasicParameter.java b/src/main/java/com/alibaba/excel/read/metadata/ReadBasicParameter.java new file mode 100644 index 0000000..d403587 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/metadata/ReadBasicParameter.java @@ -0,0 +1,46 @@ +package com.alibaba.excel.read.metadata; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.metadata.BasicParameter; +import com.alibaba.excel.read.listener.ReadListener; + +/** + * Read basic parameter + * + * @author Jiaju Zhuang + **/ +public class ReadBasicParameter extends BasicParameter { + /** + * Count the number of added heads when read sheet. + * + *

+ * 0 - This Sheet has no head ,since the first row are the data + *

+ * 1 - This Sheet has one row head , this is the default + *

+ * 2 - This Sheet has two row head ,since the third row is the data + */ + private Integer headRowNumber; + /** + * Custom type listener run after default + */ + private List customReadListenerList = new ArrayList(); + + public Integer getHeadRowNumber() { + return headRowNumber; + } + + public void setHeadRowNumber(Integer headRowNumber) { + this.headRowNumber = headRowNumber; + } + + public List getCustomReadListenerList() { + return customReadListenerList; + } + + public void setCustomReadListenerList(List customReadListenerList) { + this.customReadListenerList = customReadListenerList; + } +} diff --git a/src/main/java/com/alibaba/excel/read/metadata/ReadSheet.java b/src/main/java/com/alibaba/excel/read/metadata/ReadSheet.java new file mode 100644 index 0000000..f3a3a7b --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/metadata/ReadSheet.java @@ -0,0 +1,49 @@ +package com.alibaba.excel.read.metadata; + +/** + * Read sheet + * + * @author jipengfei + */ +public class ReadSheet extends ReadBasicParameter { + /** + * Starting from 0 + */ + private Integer sheetNo; + /** + * sheet name + */ + private String sheetName; + + public ReadSheet() {} + + public ReadSheet(Integer sheetNo) { + this.sheetNo = sheetNo; + } + + public ReadSheet(Integer sheetNo, String sheetName) { + this.sheetNo = sheetNo; + this.sheetName = sheetName; + } + + public Integer getSheetNo() { + return sheetNo; + } + + public void setSheetNo(Integer sheetNo) { + this.sheetNo = sheetNo; + } + + public String getSheetName() { + return sheetName; + } + + public void setSheetName(String sheetName) { + this.sheetName = sheetName; + } + + @Override + public String toString() { + return "ReadSheet{" + "sheetNo=" + sheetNo + ", sheetName='" + sheetName + '\'' + "} " + super.toString(); + } +} diff --git a/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java b/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java new file mode 100644 index 0000000..360f941 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java @@ -0,0 +1,142 @@ +package com.alibaba.excel.read.metadata; + +import java.io.File; +import java.io.InputStream; + +import com.alibaba.excel.cache.ReadCache; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.support.ExcelTypeEnum; + +/** + * Workbook + * + * @author Jiaju Zhuang + **/ +public class ReadWorkbook extends ReadBasicParameter { + /** + * Excel type + */ + private ExcelTypeEnum excelType; + /** + * Read InputStream + *

+ * If 'inputStream' and 'file' all not empty,file first + */ + private InputStream inputStream; + /** + * Read file + *

+ * If 'inputStream' and 'file' all not empty,file first + */ + private File file; + /** + * Mandatory use 'inputStream' .Default is false. + *

+ * if false,Will transfer 'inputStream' to temporary files to improve efficiency + */ + private Boolean mandatoryUseInputStream; + /** + * Default true + */ + private Boolean autoCloseStream; + /** + * This object can be read in the Listener {@link AnalysisEventListener#invoke(Object, AnalysisContext)} + * {@link AnalysisContext#getCustom()} + * + */ + private Object customObject; + /** + * A cache that stores temp data to save memory.Default use {@link com.alibaba.excel.cache.Ehcache} + */ + private ReadCache readCache; + /** + * The default is all excel objects.Default is true. + *

+ * if true , you can use {@link com.alibaba.excel.annotation.ExcelIgnore} ignore a field. + *

+ * if false , you must use {@link com.alibaba.excel.annotation.ExcelProperty} to use a filed. + * + * @deprecated Just to be compatible with historical data, The default is always going to be convert all filed. + */ + @Deprecated + private Boolean convertAllFiled; + + /** + * List is returned by default, now map is returned by default + */ + @Deprecated + private Boolean defaultReturnMap; + + public ExcelTypeEnum getExcelType() { + return excelType; + } + + public void setExcelType(ExcelTypeEnum excelType) { + this.excelType = excelType; + } + + public InputStream getInputStream() { + return inputStream; + } + + public void setInputStream(InputStream inputStream) { + this.inputStream = inputStream; + } + + public File getFile() { + return file; + } + + public void setFile(File file) { + this.file = file; + } + + public Boolean getAutoCloseStream() { + return autoCloseStream; + } + + public void setAutoCloseStream(Boolean autoCloseStream) { + this.autoCloseStream = autoCloseStream; + } + + public Object getCustomObject() { + return customObject; + } + + public void setCustomObject(Object customObject) { + this.customObject = customObject; + } + + public Boolean getMandatoryUseInputStream() { + return mandatoryUseInputStream; + } + + public void setMandatoryUseInputStream(Boolean mandatoryUseInputStream) { + this.mandatoryUseInputStream = mandatoryUseInputStream; + } + + public ReadCache getReadCache() { + return readCache; + } + + public void setReadCache(ReadCache readCache) { + this.readCache = readCache; + } + + public Boolean getConvertAllFiled() { + return convertAllFiled; + } + + public void setConvertAllFiled(Boolean convertAllFiled) { + this.convertAllFiled = convertAllFiled; + } + + public Boolean getDefaultReturnMap() { + return defaultReturnMap; + } + + public void setDefaultReturnMap(Boolean defaultReturnMap) { + this.defaultReturnMap = defaultReturnMap; + } +} diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java new file mode 100644 index 0000000..61aa813 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java @@ -0,0 +1,253 @@ +package com.alibaba.excel.read.metadata.holder; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.converters.ConverterKeyBuild; +import com.alibaba.excel.converters.DefaultConverterLoader; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.enums.HeadKindEnum; +import com.alibaba.excel.enums.HolderEnum; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.exception.ExcelAnalysisStopException; +import com.alibaba.excel.exception.ExcelDataConvertException; +import com.alibaba.excel.metadata.AbstractHolder; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.read.listener.ModelBuildEventListener; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.listener.ReadListenerRegistryCenter; +import com.alibaba.excel.read.listener.event.AnalysisFinishEvent; +import com.alibaba.excel.read.metadata.ReadBasicParameter; +import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty; +import com.alibaba.excel.util.StringUtils; + +/** + * Read Holder + * + * @author Jiaju Zhuang + */ +public abstract class AbstractReadHolder extends AbstractHolder implements ReadHolder, ReadListenerRegistryCenter { + /** + * Count the number of added heads when read sheet. + * + *

+ * 0 - This Sheet has no head ,since the first row are the data + *

+ * 1 - This Sheet has one row head , this is the default + *

+ * 2 - This Sheet has two row head ,since the third row is the data + */ + private Integer headRowNumber; + /** + * Excel head property + */ + private ExcelReadHeadProperty excelReadHeadProperty; + /** + * Read listener + */ + private List readListenerList; + + public AbstractReadHolder(ReadBasicParameter readBasicParameter, AbstractReadHolder parentAbstractReadHolder, + Boolean convertAllFiled) { + super(readBasicParameter, parentAbstractReadHolder); + if (readBasicParameter.getUse1904windowing() == null && parentAbstractReadHolder != null) { + getGlobalConfiguration() + .setUse1904windowing(parentAbstractReadHolder.getGlobalConfiguration().getUse1904windowing()); + } else { + getGlobalConfiguration().setUse1904windowing(readBasicParameter.getUse1904windowing()); + } + + // Initialization property + this.excelReadHeadProperty = new ExcelReadHeadProperty(getClazz(), getHead(), convertAllFiled); + if (readBasicParameter.getHeadRowNumber() == null) { + if (parentAbstractReadHolder == null) { + if (excelReadHeadProperty.hasHead()) { + this.headRowNumber = excelReadHeadProperty.getHeadRowNumber(); + } else { + this.headRowNumber = 1; + } + } else { + this.headRowNumber = parentAbstractReadHolder.getHeadRowNumber(); + } + } else { + this.headRowNumber = readBasicParameter.getHeadRowNumber(); + } + + if (parentAbstractReadHolder == null) { + this.readListenerList = new ArrayList(); + } else { + this.readListenerList = new ArrayList(parentAbstractReadHolder.getReadListenerList()); + } + if (HolderEnum.WORKBOOK.equals(holderType())) { + readListenerList.add(new ModelBuildEventListener()); + } + if (readBasicParameter.getCustomReadListenerList() != null + && !readBasicParameter.getCustomReadListenerList().isEmpty()) { + this.readListenerList.addAll(readBasicParameter.getCustomReadListenerList()); + } + + if (parentAbstractReadHolder == null) { + setConverterMap(DefaultConverterLoader.loadDefaultReadConverter()); + } else { + setConverterMap(new HashMap(parentAbstractReadHolder.getConverterMap())); + } + if (readBasicParameter.getCustomConverterList() != null + && !readBasicParameter.getCustomConverterList().isEmpty()) { + for (Converter converter : readBasicParameter.getCustomConverterList()) { + getConverterMap().put( + ConverterKeyBuild.buildKey(converter.supportJavaTypeKey(), converter.supportExcelTypeKey()), + converter); + } + } + } + + @Override + public void register(AnalysisEventListener listener) { + readListenerList.add(listener); + } + + @Override + public void notifyEndOneRow(AnalysisFinishEvent event, AnalysisContext analysisContext) { + Map cellDataMap = event.getAnalysisResult(); + ReadRowHolder readRowHolder = analysisContext.readRowHolder(); + readRowHolder.setCurrentRowAnalysisResult(cellDataMap); + + if (readRowHolder.getRowIndex() >= analysisContext.readSheetHolder().getHeadRowNumber()) { + for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) { + try { + readListener.invoke(readRowHolder.getCurrentRowAnalysisResult(), analysisContext); + } catch (Exception e) { + for (ReadListener readListenerException : analysisContext.currentReadHolder().readListenerList()) { + try { + readListenerException.onException(e, analysisContext); + } catch (Exception exception) { + throw new ExcelAnalysisException("Listen error!", exception); + } + } + } + if (!readListener.hasNext(analysisContext)) { + throw new ExcelAnalysisStopException(); + } + } + return; + } + // Now is header + if (analysisContext.readSheetHolder().getHeadRowNumber().equals(readRowHolder.getRowIndex() + 1)) { + buildHead(analysisContext, cellDataMap); + } + } + + @Override + public void notifyAfterAllAnalysed(AnalysisContext analysisContext) { + for (ReadListener readListener : readListenerList) { + readListener.doAfterAllAnalysed(analysisContext); + } + } + + private void buildHead(AnalysisContext analysisContext, Map cellDataMap) { + if (!HeadKindEnum.CLASS.equals(analysisContext.currentReadHolder().excelReadHeadProperty().getHeadKind())) { + return; + } + Map dataMap = buildStringMap(cellDataMap, analysisContext.currentReadHolder()); + ExcelReadHeadProperty excelHeadPropertyData = analysisContext.readSheetHolder().excelReadHeadProperty(); + Map headMapData = excelHeadPropertyData.getHeadMap(); + Map contentPropertyMapData = excelHeadPropertyData.getContentPropertyMap(); + Map tmpHeadMap = new HashMap(headMapData.size() * 4 / 3 + 1); + Map tmpContentPropertyMap = + new HashMap(contentPropertyMapData.size() * 4 / 3 + 1); + for (Map.Entry entry : headMapData.entrySet()) { + Head headData = entry.getValue(); + if (headData.getForceIndex() || !headData.getForceName()) { + tmpHeadMap.put(entry.getKey(), headData); + tmpContentPropertyMap.put(entry.getKey(), contentPropertyMapData.get(entry.getKey())); + continue; + } + String headName = headData.getHeadNameList().get(0); + + for (Map.Entry stringEntry : dataMap.entrySet()) { + String headString = stringEntry.getValue(); + Integer stringKey = stringEntry.getKey(); + if (StringUtils.isEmpty(headString)) { + continue; + } + if (analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()) { + headString = headString.trim(); + } + if (headName.equals(headString)) { + headData.setColumnIndex(stringKey); + tmpHeadMap.put(stringKey, headData); + tmpContentPropertyMap.put(stringKey, contentPropertyMapData.get(entry.getKey())); + break; + } + } + } + excelHeadPropertyData.setHeadMap(tmpHeadMap); + excelHeadPropertyData.setContentPropertyMap(tmpContentPropertyMap); + } + + private Map buildStringMap(Map cellDataMap, ReadHolder readHolder) { + Map stringMap = new HashMap(cellDataMap.size() * 4 / 3 + 1); + for (Map.Entry entry : cellDataMap.entrySet()) { + CellData cellData = entry.getValue(); + if (cellData.getType() == CellDataTypeEnum.EMPTY) { + stringMap.put(entry.getKey(), null); + continue; + } + Converter converter = + readHolder.converterMap().get(ConverterKeyBuild.buildKey(String.class, cellData.getType())); + if (converter == null) { + throw new ExcelDataConvertException( + "Converter not found, convert " + cellData.getType() + " to String"); + } + try { + stringMap.put(entry.getKey(), + (String)(converter.convertToJavaData(cellData, null, readHolder.globalConfiguration()))); + } catch (Exception e) { + throw new ExcelDataConvertException("Convert data " + cellData + " to String error ", e); + } + } + return stringMap; + } + + public List getReadListenerList() { + return readListenerList; + } + + public void setReadListenerList(List readListenerList) { + this.readListenerList = readListenerList; + } + + public ExcelReadHeadProperty getExcelReadHeadProperty() { + return excelReadHeadProperty; + } + + public void setExcelReadHeadProperty(ExcelReadHeadProperty excelReadHeadProperty) { + this.excelReadHeadProperty = excelReadHeadProperty; + } + + public Integer getHeadRowNumber() { + return headRowNumber; + } + + public void setHeadRowNumber(Integer headRowNumber) { + this.headRowNumber = headRowNumber; + } + + @Override + public List readListenerList() { + return getReadListenerList(); + } + + @Override + public ExcelReadHeadProperty excelReadHeadProperty() { + return getExcelReadHeadProperty(); + } + +} diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadHolder.java new file mode 100644 index 0000000..43e1301 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadHolder.java @@ -0,0 +1,30 @@ +package com.alibaba.excel.read.metadata.holder; + +import java.util.List; + +import com.alibaba.excel.metadata.ConfigurationHolder; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty; + +/** + * + * Get the corresponding Holder + * + * @author Jiaju Zhuang + **/ +public interface ReadHolder extends ConfigurationHolder { + /** + * What handler does the currently operated cell need to execute + * + * @return Current {@link ReadListener} + */ + List readListenerList(); + + /** + * What {@link ExcelReadHeadProperty} does the currently operated cell need to execute + * + * @return Current {@link ExcelReadHeadProperty} + */ + ExcelReadHeadProperty excelReadHeadProperty(); + +} diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java new file mode 100644 index 0000000..c135c12 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java @@ -0,0 +1,60 @@ +package com.alibaba.excel.read.metadata.holder; + +import com.alibaba.excel.enums.HolderEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.Holder; + +/** + * sheet holder + * + * @author Jiaju Zhuang + */ +public class ReadRowHolder implements Holder { + /** + * Returns row index of a row in the sheet that contains this cell.Start form 0. + */ + private int rowIndex; + + /** + * The result of the previous listener + */ + private Object currentRowAnalysisResult; + /** + * Some global variables + */ + private GlobalConfiguration globalConfiguration; + + public ReadRowHolder(int rowIndex, GlobalConfiguration globalConfiguration) { + this.rowIndex = rowIndex; + this.globalConfiguration = globalConfiguration; + } + + public GlobalConfiguration getGlobalConfiguration() { + return globalConfiguration; + } + + public void setGlobalConfiguration(GlobalConfiguration globalConfiguration) { + this.globalConfiguration = globalConfiguration; + } + + public Object getCurrentRowAnalysisResult() { + return currentRowAnalysisResult; + } + + public void setCurrentRowAnalysisResult(Object currentRowAnalysisResult) { + this.currentRowAnalysisResult = currentRowAnalysisResult; + } + + public int getRowIndex() { + return rowIndex; + } + + public void setRowIndex(int rowIndex) { + this.rowIndex = rowIndex; + } + + @Override + public HolderEnum holderType() { + return HolderEnum.ROW; + } +} diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java new file mode 100644 index 0000000..64d1d6c --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java @@ -0,0 +1,91 @@ +package com.alibaba.excel.read.metadata.holder; + +import com.alibaba.excel.enums.HolderEnum; +import com.alibaba.excel.read.metadata.ReadSheet; + +/** + * sheet holder + * + * @author Jiaju Zhuang + */ +public class ReadSheetHolder extends AbstractReadHolder { + /** + * current param + */ + private ReadSheet readSheet; + /*** + * parent + */ + private ReadWorkbookHolder parentReadWorkbookHolder; + /*** + * sheetNo + */ + private Integer sheetNo; + /*** + * sheetName + */ + private String sheetName; + /** + * get total row , Data may be inaccurate + */ + @Deprecated + private Integer total; + + public ReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { + super(readSheet, readWorkbookHolder, readWorkbookHolder.getReadWorkbook().getConvertAllFiled()); + this.readSheet = readSheet; + this.parentReadWorkbookHolder = readWorkbookHolder; + this.sheetNo = readSheet.getSheetNo(); + this.sheetName = readSheet.getSheetName(); + } + + public ReadSheet getReadSheet() { + return readSheet; + } + + public void setReadSheet(ReadSheet readSheet) { + this.readSheet = readSheet; + } + + public ReadWorkbookHolder getParentReadWorkbookHolder() { + return parentReadWorkbookHolder; + } + + public void setParentReadWorkbookHolder(ReadWorkbookHolder parentReadWorkbookHolder) { + this.parentReadWorkbookHolder = parentReadWorkbookHolder; + } + + public Integer getSheetNo() { + return sheetNo; + } + + public void setSheetNo(Integer sheetNo) { + this.sheetNo = sheetNo; + } + + public String getSheetName() { + return sheetName; + } + + public void setSheetName(String sheetName) { + this.sheetName = sheetName; + } + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } + + @Override + public HolderEnum holderType() { + return HolderEnum.SHEET; + } + + @Override + public String toString() { + return "ReadSheetHolder{" + "sheetNo=" + sheetNo + ", sheetName='" + sheetName + '\'' + "} " + super.toString(); + } +} diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java new file mode 100644 index 0000000..bfcc050 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java @@ -0,0 +1,239 @@ +package com.alibaba.excel.read.metadata.holder; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.InputStream; +import java.util.HashSet; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.cache.ReadCache; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.enums.HolderEnum; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.read.metadata.ReadWorkbook; +import com.alibaba.excel.support.ExcelTypeEnum; + +/** + * Workbook holder + * + * @author Jiaju Zhuang + */ +public class ReadWorkbookHolder extends AbstractReadHolder { + private static final Logger LOGGER = LoggerFactory.getLogger(ReadWorkbookHolder.class); + + /** + * current param + */ + private ReadWorkbook readWorkbook; + /** + * Read InputStream + *

+ * If 'inputStream' and 'file' all not empty,file first + */ + private InputStream inputStream; + /** + * Read file + *

+ * If 'inputStream' and 'file' all not empty,file first + */ + private File file; + /** + * Mandatory use 'inputStream' .Default is false. + *

+ * if false,Will transfer 'inputStream' to temporary files to improve efficiency + */ + private Boolean mandatoryUseInputStream; + /** + * Default true + */ + private Boolean autoCloseStream; + /** + * Excel type + */ + private ExcelTypeEnum excelType; + /** + * This object can be read in the Listener {@link AnalysisEventListener#invoke(Object, AnalysisContext)} + * {@link AnalysisContext#getCustom()} + * + */ + private Object customObject; + /** + * A cache that stores temp data to save memory.Default use {@link com.alibaba.excel.cache.Ehcache} + */ + private ReadCache readCache; + + /** + * Temporary files when reading excel + */ + private File tempFile; + + /** + * The default is all excel objects.if true , you can use {@link com.alibaba.excel.annotation.ExcelIgnore} ignore a + * field. if false , you must use {@link com.alibaba.excel.annotation.ExcelProperty} to use a filed. + * + * @deprecated Just to be compatible with historical data, The default is always going to be convert all filed. + */ + @Deprecated + private Boolean convertAllFiled; + + /** + * List is returned by default, now map is returned by default + */ + @Deprecated + private Boolean defaultReturnMap; + + /** + * Prevent repeating sheet + */ + private Set hasReadSheet; + + public ReadWorkbookHolder(ReadWorkbook readWorkbook) { + super(readWorkbook, null, readWorkbook.getConvertAllFiled()); + this.readWorkbook = readWorkbook; + if (readWorkbook.getInputStream() != null) { + if (readWorkbook.getInputStream().markSupported()) { + this.inputStream = readWorkbook.getInputStream(); + } else { + this.inputStream = new BufferedInputStream(readWorkbook.getInputStream()); + } + } + this.file = readWorkbook.getFile(); + if (file == null && inputStream == null) { + throw new ExcelAnalysisException("File and inputStream must be a non-null."); + } + if (readWorkbook.getMandatoryUseInputStream() == null) { + this.mandatoryUseInputStream = Boolean.FALSE; + } else { + this.mandatoryUseInputStream = readWorkbook.getMandatoryUseInputStream(); + } + if (readWorkbook.getAutoCloseStream() == null) { + this.autoCloseStream = Boolean.TRUE; + } else { + this.autoCloseStream = readWorkbook.getAutoCloseStream(); + } + if (readWorkbook.getExcelType() == null) { + this.excelType = ExcelTypeEnum.valueOf(file, inputStream); + } else { + this.excelType = readWorkbook.getExcelType(); + } + if (ExcelTypeEnum.XLS == excelType && getGlobalConfiguration().getUse1904windowing() == null) { + getGlobalConfiguration().setUse1904windowing(Boolean.FALSE); + } + this.customObject = readWorkbook.getCustomObject(); + this.readCache = readWorkbook.getReadCache(); + if (readCache != null && ExcelTypeEnum.XLS == excelType) { + LOGGER.warn("Xls not support 'readCache'!"); + } + if (readWorkbook.getDefaultReturnMap() == null) { + this.defaultReturnMap = Boolean.TRUE; + } else { + this.defaultReturnMap = readWorkbook.getDefaultReturnMap(); + } + this.hasReadSheet = new HashSet(); + } + + public ReadWorkbook getReadWorkbook() { + return readWorkbook; + } + + public void setReadWorkbook(ReadWorkbook readWorkbook) { + this.readWorkbook = readWorkbook; + } + + public InputStream getInputStream() { + return inputStream; + } + + public void setInputStream(InputStream inputStream) { + this.inputStream = inputStream; + } + + public File getFile() { + return file; + } + + public void setFile(File file) { + this.file = file; + } + + public Boolean getAutoCloseStream() { + return autoCloseStream; + } + + public void setAutoCloseStream(Boolean autoCloseStream) { + this.autoCloseStream = autoCloseStream; + } + + public ExcelTypeEnum getExcelType() { + return excelType; + } + + public void setExcelType(ExcelTypeEnum excelType) { + this.excelType = excelType; + } + + public Object getCustomObject() { + return customObject; + } + + public void setCustomObject(Object customObject) { + this.customObject = customObject; + } + + public ReadCache getReadCache() { + return readCache; + } + + public void setReadCache(ReadCache readCache) { + this.readCache = readCache; + } + + public Boolean getMandatoryUseInputStream() { + return mandatoryUseInputStream; + } + + public void setMandatoryUseInputStream(Boolean mandatoryUseInputStream) { + this.mandatoryUseInputStream = mandatoryUseInputStream; + } + + public File getTempFile() { + return tempFile; + } + + public void setTempFile(File tempFile) { + this.tempFile = tempFile; + } + + public Boolean getConvertAllFiled() { + return convertAllFiled; + } + + public void setConvertAllFiled(Boolean convertAllFiled) { + this.convertAllFiled = convertAllFiled; + } + + public Set getHasReadSheet() { + return hasReadSheet; + } + + public void setHasReadSheet(Set hasReadSheet) { + this.hasReadSheet = hasReadSheet; + } + + public Boolean getDefaultReturnMap() { + return defaultReturnMap; + } + + public void setDefaultReturnMap(Boolean defaultReturnMap) { + this.defaultReturnMap = defaultReturnMap; + } + + @Override + public HolderEnum holderType() { + return HolderEnum.WORKBOOK; + } +} diff --git a/src/main/java/com/alibaba/excel/read/metadata/property/ExcelReadHeadProperty.java b/src/main/java/com/alibaba/excel/read/metadata/property/ExcelReadHeadProperty.java new file mode 100644 index 0000000..fdc5562 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/metadata/property/ExcelReadHeadProperty.java @@ -0,0 +1,17 @@ +package com.alibaba.excel.read.metadata.property; + +import java.util.List; + +import com.alibaba.excel.metadata.property.ExcelHeadProperty; + +/** + * Define the header attribute of excel + * + * @author jipengfei + */ +public class ExcelReadHeadProperty extends ExcelHeadProperty { + + public ExcelReadHeadProperty(Class headClazz, List> head, Boolean convertAllFiled) { + super(headClazz, head, convertAllFiled); + } +} diff --git a/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java b/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java index 57882b9..a267e1d 100644 --- a/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java +++ b/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java @@ -1,16 +1,25 @@ package com.alibaba.excel.support; -import org.apache.poi.poifs.filesystem.FileMagic; - +import java.io.File; import java.io.IOException; import java.io.InputStream; +import org.apache.poi.poifs.filesystem.FileMagic; + +import com.alibaba.excel.exception.ExcelCommonException; + /** * @author jipengfei */ public enum ExcelTypeEnum { - - XLS(".xls"), XLSX(".xlsx"); + /** + * xls + */ + XLS(".xls"), + /** + * xlsx + */ + XLSX(".xlsx"); private String value; @@ -18,29 +27,43 @@ public enum ExcelTypeEnum { this.setValue(value); } - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public static ExcelTypeEnum valueOf(InputStream inputStream){ + public static ExcelTypeEnum valueOf(File file, InputStream inputStream) { try { - if (!inputStream.markSupported()) { - return null; + FileMagic fileMagic; + if (file != null) { + fileMagic = FileMagic.valueOf(file); + if (!FileMagic.OLE2.equals(fileMagic) && !FileMagic.OOXML.equals(fileMagic)) { + String fileName = file.getName(); + if (fileName.endsWith(XLSX.getValue())) { + return XLSX; + } else if (fileName.endsWith(XLS.getValue())) { + return XLS; + } else { + throw new ExcelCommonException("Unknown excel type."); + } + } + } else { + fileMagic = FileMagic.valueOf(inputStream); } - FileMagic fileMagic = FileMagic.valueOf(inputStream); - if(FileMagic.OLE2.equals(fileMagic)){ + if (FileMagic.OLE2.equals(fileMagic)) { return XLS; } - if(FileMagic.OOXML.equals(fileMagic)){ + if (FileMagic.OOXML.equals(fileMagic)) { return XLSX; } - return null; } catch (IOException e) { - throw new RuntimeException(e); + throw new ExcelCommonException( + "Convert excel format exception.You can try specifying the 'excelType' yourself", e); } + throw new ExcelCommonException( + "Convert excel format exception.You can try specifying the 'excelType' yourself"); + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; } } diff --git a/src/main/java/com/alibaba/excel/util/BooleanUtils.java b/src/main/java/com/alibaba/excel/util/BooleanUtils.java new file mode 100644 index 0000000..afd1495 --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/BooleanUtils.java @@ -0,0 +1,27 @@ +package com.alibaba.excel.util; + +/** + * boolean util + * + * @author Jiaju Zhuang + */ +public class BooleanUtils { + + private static final String TRUE_NUMBER = "1"; + private static final String FALSE_NUMBER = "0"; + + /** + * String to boolean + * + * @param str + * @return + */ + public static Boolean valueOf(String str) { + if (TRUE_NUMBER.equals(str)) { + return Boolean.TRUE; + } else { + return Boolean.FALSE; + } + } + +} diff --git a/src/main/java/com/alibaba/excel/util/CollectionUtils.java b/src/main/java/com/alibaba/excel/util/CollectionUtils.java index 3b9025f..fff57ff 100644 --- a/src/main/java/com/alibaba/excel/util/CollectionUtils.java +++ b/src/main/java/com/alibaba/excel/util/CollectionUtils.java @@ -1,340 +1,20 @@ package com.alibaba.excel.util; -import java.util.*; +import java.util.Collection; +import java.util.Map; /** - * Miscellaneous collection utility methods. - * Mainly for internal use within the framework. - * - * @author Juergen Hoeller - * @author Rob Harrop - * @author Arjen Poutsma - * @since 1.1.3 + * Collection utils + * + * @author jipengfei */ -public abstract class CollectionUtils { +public class CollectionUtils { - /** - * Return {@code true} if the supplied Collection is {@code null} or empty. - * Otherwise, return {@code false}. - * @param collection the Collection to check - * @return whether the given Collection is empty - */ public static boolean isEmpty(Collection collection) { return (collection == null || collection.isEmpty()); } - /** - * Return {@code true} if the supplied Map is {@code null} or empty. - * Otherwise, return {@code false}. - * @param map the Map to check - * @return whether the given Map is empty - */ public static boolean isEmpty(Map map) { return (map == null || map.isEmpty()); } - - /** - * Convert the supplied array into a List. A primitive array gets converted - * into a List of the appropriate wrapper type. - *

NOTE: Generally prefer the standard {@link Arrays#asList} method. - * This {@code arrayToList} method is just meant to deal with an incoming Object - * value that might be an {@code Object[]} or a primitive array at runtime. - *

A {@code null} source value will be converted to an empty List. - * @param source the (potentially primitive) array - * @return the converted List result - * @see ObjectUtils#toObjectArray(Object) - * @see Arrays#asList(Object[]) - */ - @SuppressWarnings("rawtypes") - public static List arrayToList(Object source) { - return Arrays.asList(ObjectUtils.toObjectArray(source)); - } - - /** - * Merge the given array into the given Collection. - * @param array the array to merge (may be {@code null}) - * @param collection the target Collection to merge the array into - */ - @SuppressWarnings("unchecked") - public static void mergeArrayIntoCollection(Object array, Collection collection) { - if (collection == null) { - throw new IllegalArgumentException("Collection must not be null"); - } - Object[] arr = ObjectUtils.toObjectArray(array); - for (Object elem : arr) { - collection.add((E) elem); - } - } - - /** - * Merge the given Properties instance into the given Map, - * copying all properties (key-value pairs) over. - *

Uses {@code Properties.propertyNames()} to even catch - * default properties linked into the original Properties instance. - * @param props the Properties instance to merge (may be {@code null}) - * @param map the target Map to merge the properties into - */ - @SuppressWarnings("unchecked") - public static void mergePropertiesIntoMap(Properties props, Map map) { - if (map == null) { - throw new IllegalArgumentException("Map must not be null"); - } - if (props != null) { - for (Enumeration en = props.propertyNames(); en.hasMoreElements();) { - String key = (String) en.nextElement(); - Object value = props.get(key); - if (value == null) { - // Allow for defaults fallback or potentially overridden accessor... - value = props.getProperty(key); - } - map.put((K) key, (V) value); - } - } - } - - - /** - * Check whether the given Iterator contains the given element. - * @param iterator the Iterator to check - * @param element the element to look for - * @return {@code true} if found, {@code false} else - */ - public static boolean contains(Iterator iterator, Object element) { - if (iterator != null) { - while (iterator.hasNext()) { - Object candidate = iterator.next(); - if (ObjectUtils.nullSafeEquals(candidate, element)) { - return true; - } - } - } - return false; - } - - /** - * Check whether the given Enumeration contains the given element. - * @param enumeration the Enumeration to check - * @param element the element to look for - * @return {@code true} if found, {@code false} else - */ - public static boolean contains(Enumeration enumeration, Object element) { - if (enumeration != null) { - while (enumeration.hasMoreElements()) { - Object candidate = enumeration.nextElement(); - if (ObjectUtils.nullSafeEquals(candidate, element)) { - return true; - } - } - } - return false; - } - - /** - * Check whether the given Collection contains the given element instance. - *

Enforces the given instance to be present, rather than returning - * {@code true} for an equal element as well. - * @param collection the Collection to check - * @param element the element to look for - * @return {@code true} if found, {@code false} else - */ - public static boolean containsInstance(Collection collection, Object element) { - if (collection != null) { - for (Object candidate : collection) { - if (candidate == element) { - return true; - } - } - } - return false; - } - - /** - * Return {@code true} if any element in '{@code candidates}' is - * contained in '{@code source}'; otherwise returns {@code false}. - * @param source the source Collection - * @param candidates the candidates to search for - * @return whether any of the candidates has been found - */ - public static boolean containsAny(Collection source, Collection candidates) { - if (isEmpty(source) || isEmpty(candidates)) { - return false; - } - for (Object candidate : candidates) { - if (source.contains(candidate)) { - return true; - } - } - return false; - } - - /** - * Return the first element in '{@code candidates}' that is contained in - * '{@code source}'. If no element in '{@code candidates}' is present in - * '{@code source}' returns {@code null}. Iteration order is - * {@link Collection} implementation specific. - * @param source the source Collection - * @param candidates the candidates to search for - * @return the first present object, or {@code null} if not found - */ - @SuppressWarnings("unchecked") - public static E findFirstMatch(Collection source, Collection candidates) { - if (isEmpty(source) || isEmpty(candidates)) { - return null; - } - for (Object candidate : candidates) { - if (source.contains(candidate)) { - return (E) candidate; - } - } - return null; - } - - /** - * Find a single value of the given type in the given Collection. - * @param collection the Collection to search - * @param type the type to look for - * @return a value of the given type found if there is a clear match, - * or {@code null} if none or more than one such value found - */ - @SuppressWarnings("unchecked") - public static T findValueOfType(Collection collection, Class type) { - if (isEmpty(collection)) { - return null; - } - T value = null; - for (Object element : collection) { - if (type == null || type.isInstance(element)) { - if (value != null) { - // More than one value found... no clear single value. - return null; - } - value = (T) element; - } - } - return value; - } - - /** - * Find a single value of one of the given types in the given Collection: - * searching the Collection for a value of the first type, then - * searching for a value of the second type, etc. - * @param collection the collection to search - * @param types the types to look for, in prioritized order - * @return a value of one of the given types found if there is a clear match, - * or {@code null} if none or more than one such value found - */ - public static Object findValueOfType(Collection collection, Class[] types) { - if (isEmpty(collection) || ObjectUtils.isEmpty(types)) { - return null; - } - for (Class type : types) { - Object value = findValueOfType(collection, type); - if (value != null) { - return value; - } - } - return null; - } - - /** - * Determine whether the given Collection only contains a single unique object. - * @param collection the Collection to check - * @return {@code true} if the collection contains a single reference or - * multiple references to the same instance, {@code false} else - */ - public static boolean hasUniqueObject(Collection collection) { - if (isEmpty(collection)) { - return false; - } - boolean hasCandidate = false; - Object candidate = null; - for (Object elem : collection) { - if (!hasCandidate) { - hasCandidate = true; - candidate = elem; - } - else if (candidate != elem) { - return false; - } - } - return true; - } - - /** - * Find the common element type of the given Collection, if any. - * @param collection the Collection to check - * @return the common element type, or {@code null} if no clear - * common type has been found (or the collection was empty) - */ - public static Class findCommonElementType(Collection collection) { - if (isEmpty(collection)) { - return null; - } - Class candidate = null; - for (Object val : collection) { - if (val != null) { - if (candidate == null) { - candidate = val.getClass(); - } - else if (candidate != val.getClass()) { - return null; - } - } - } - return candidate; - } - - /** - * Marshal the elements from the given enumeration into an array of the given type. - * Enumeration elements must be assignable to the type of the given array. The array - * returned will be a different instance than the array given. - */ - public static A[] toArray(Enumeration enumeration, A[] array) { - ArrayList elements = new ArrayList(); - while (enumeration.hasMoreElements()) { - elements.add(enumeration.nextElement()); - } - return elements.toArray(array); - } - - /** - * Adapt an enumeration to an iterator. - * @param enumeration the enumeration - * @return the iterator - */ - public static Iterator toIterator(Enumeration enumeration) { - return new EnumerationIterator(enumeration); - } - - - - /** - * Iterator wrapping an Enumeration. - */ - private static class EnumerationIterator implements Iterator { - - private final Enumeration enumeration; - - public EnumerationIterator(Enumeration enumeration) { - this.enumeration = enumeration; - } - - @Override - public boolean hasNext() { - return this.enumeration.hasMoreElements(); - } - - @Override - public E next() { - return this.enumeration.nextElement(); - } - - @Override - public void remove() throws UnsupportedOperationException { - throw new UnsupportedOperationException("Not supported"); - } - } - - } - diff --git a/src/main/java/com/alibaba/excel/util/DateUtils.java b/src/main/java/com/alibaba/excel/util/DateUtils.java new file mode 100644 index 0000000..1ea05c0 --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/DateUtils.java @@ -0,0 +1,101 @@ +package com.alibaba.excel.util; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import com.alibaba.excel.exception.ExcelDataConvertException; + +/** + * Date utils + * + * @author Jiaju Zhuang + **/ +public class DateUtils { + public static final String DATE_FORMAT_14 = "yyyyMMddHHmmss"; + public static final String DATE_FORMAT_17 = "yyyyMMdd HH:mm:ss"; + public static final String DATE_FORMAT_19 = "yyyy-MM-dd HH:mm:ss"; + public static final String DATE_FORMAT_19_FORWARD_SLASH = "yyyy/MM/dd HH:mm:ss"; + private static final String MINUS = "-"; + + private DateUtils() {} + + /** + * convert string to date + * + * @param dateString + * @param dateFormat + * @return + * @throws ParseException + */ + public static Date parseDate(String dateString, String dateFormat) throws ParseException { + if (StringUtils.isEmpty(dateFormat)) { + dateFormat = switchDateFormat(dateString); + } + return new SimpleDateFormat(dateFormat).parse(dateString); + } + + /** + * convert string to date + * + * @param dateString + * @return + * @throws ParseException + */ + public static Date parseDate(String dateString) throws ParseException { + return parseDate(dateString, switchDateFormat(dateString)); + } + + /** + * switch date format + * + * @param dateString + * @return + */ + private static String switchDateFormat(String dateString) { + int length = dateString.length(); + switch (length) { + case 19: + if (dateString.contains(MINUS)) { + return DATE_FORMAT_19; + } else { + return DATE_FORMAT_19_FORWARD_SLASH; + } + case 17: + return DATE_FORMAT_17; + case 14: + return DATE_FORMAT_14; + default: + throw new ExcelDataConvertException("can not find date format for:" + dateString); + } + } + + /** + * Format date + *

+ * yyyy-MM-dd HH:mm:ss + * + * @param date + * @return + */ + public static String format(Date date) { + return format(date, null); + } + + /** + * Format date + * + * @param date + * @param dateFormat + * @return + */ + public static String format(Date date, String dateFormat) { + if (date == null) { + return ""; + } + if (StringUtils.isEmpty(dateFormat)) { + dateFormat = DATE_FORMAT_19; + } + return new SimpleDateFormat(dateFormat).format(date); + } +} diff --git a/src/main/java/com/alibaba/excel/util/FileUtils.java b/src/main/java/com/alibaba/excel/util/FileUtils.java new file mode 100644 index 0000000..717ddfe --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/FileUtils.java @@ -0,0 +1,167 @@ +package com.alibaba.excel.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.UUID; + +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.exception.ExcelGenerateException; + +/** + * + * @author jipengfei + */ +public class FileUtils { + + private static final String JAVA_IO_TMPDIR = "java.io.tmpdir"; + + private static final String POIFILES = "poifiles"; + + private static final String CACHE = "excache"; + private static final int WRITE_BUFF_SIZE = 8192; + + /** + * Reads the contents of a file into a byte array. * The file is always closed. + * + * @param file + * @return + * @throws IOException + */ + public static byte[] readFileToByteArray(final File file) throws IOException { + InputStream in = openInputStream(file); + try { + final long fileLength = file.length(); + return fileLength > 0 ? IoUtils.toByteArray(in, (int)fileLength) : IoUtils.toByteArray(in); + } finally { + in.close(); + } + } + + /** + * Opens a {@link FileInputStream} for the specified file, providing better error messages than simply calling + * new FileInputStream(file). + *

+ * At the end of the method either the stream will be successfully opened, or an exception will have been thrown. + *

+ * An exception is thrown if the file does not exist. An exception is thrown if the file object exists but is a + * directory. An exception is thrown if the file exists but cannot be read. + * + * @param file + * @return + * @throws IOException + */ + public static FileInputStream openInputStream(final File file) throws IOException { + if (file.exists()) { + if (file.isDirectory()) { + throw new IOException("File '" + file + "' exists but is a directory"); + } + if (file.canRead() == false) { + throw new IOException("File '" + file + "' cannot be read"); + } + } else { + throw new FileNotFoundException("File '" + file + "' does not exist"); + } + return new FileInputStream(file); + } + + /** + * Write inputStream to file + * + * @param file + * @param inputStream + */ + public static void writeToFile(File file, InputStream inputStream) { + OutputStream outputStream = null; + try { + outputStream = new FileOutputStream(file); + int bytesRead; + byte[] buffer = new byte[WRITE_BUFF_SIZE]; + while ((bytesRead = inputStream.read(buffer, 0, WRITE_BUFF_SIZE)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + } catch (Exception e) { + throw new ExcelAnalysisException("Can not create temporary file!", e); + } finally { + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + throw new ExcelAnalysisException("Can not close 'outputStream'!", e); + } + } + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + throw new ExcelAnalysisException("Can not close 'inputStream'", e); + } + } + } + } + + /** + */ + public static void createPoiFilesDirectory() { + createTmpDirectory(POIFILES); + } + + public static File createCacheTmpFile() { + File directory = createTmpDirectory(CACHE); + File cache = new File(directory.getPath(), UUID.randomUUID().toString()); + if (!cache.mkdir()) { + throw new ExcelGenerateException("Can not create temp file!"); + } + return cache; + } + + /** + * delete file + * + * @param file + */ + public static void delete(File file) { + if (file.isFile()) { + file.delete(); + return; + } + if (file.isDirectory()) { + File[] childFiles = file.listFiles(); + if (childFiles == null || childFiles.length == 0) { + file.delete(); + return; + } + for (int i = 0; i < childFiles.length; i++) { + delete(childFiles[i]); + } + file.delete(); + } + } + + public static File createTmpDirectory(String path) { + String tmpDir = System.getProperty(JAVA_IO_TMPDIR); + if (tmpDir == null) { + throw new RuntimeException( + "Systems temporary directory not defined - set the -D" + JAVA_IO_TMPDIR + " jvm property!"); + } + File directory = new File(tmpDir, path); + if (!directory.exists()) { + syncCreatePoiFilesDirectory(directory); + } + return directory; + } + + /** + * + * @param directory + */ + private static synchronized void syncCreatePoiFilesDirectory(File directory) { + if (!directory.exists()) { + directory.mkdirs(); + } + } +} diff --git a/src/main/java/com/alibaba/excel/util/IndexValueConverter.java b/src/main/java/com/alibaba/excel/util/IndexValueConverter.java deleted file mode 100644 index a0c1529..0000000 --- a/src/main/java/com/alibaba/excel/util/IndexValueConverter.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.alibaba.excel.util; - -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; - -import com.alibaba.excel.metadata.IndexValue; - -/** - * 去除空Cell - * @author jipengfei - */ -public class IndexValueConverter { - public static List converter(List i_list) { - - List tem = new ArrayList(); - - char[] start = {'@'}; - int j = 0; - for (; j < i_list.size(); j++) { - IndexValue currentIndexValue = i_list.get(j); - char[] currentIndex = currentIndexValue.getV_index().replaceAll("[0-9]", "").toCharArray(); - if (j > 0) { - start = i_list.get(j - 1).getV_index().replaceAll("[0-9]", "").toCharArray(); - } - int deep = subtraction26(currentIndex, start); - int k = 0; - for (; k < deep - 1; k++) { - tem.add(null); - } - tem.add(currentIndexValue.getV_value()); - } - return tem; - } - - private static int subtraction26(char[] currentIndex, char[] beforeIndex) { - int result = 0; - - Stack currentStack = new Stack(); - Stack berforStack = new Stack(); - - for (int i = 0; i < currentIndex.length; i++) { - currentStack.push(currentIndex[i]); - } - for (int i = 0; i < beforeIndex.length; i++) { - berforStack.push(beforeIndex[i]); - } - int i = 0; - char beforechar = '@'; - while (!currentStack.isEmpty()) { - char currentChar = currentStack.pop(); - if (!berforStack.isEmpty()) { - beforechar = berforStack.pop(); - } - int n = currentChar - beforechar; - if(n<0){ - n = n+26; - if(!currentStack.isEmpty()){ - char borrow = currentStack.pop(); - char newBorrow =(char)(borrow -1); - currentStack.push(newBorrow); - } - } - - - result += n * Math.pow(26, i); - i++; - beforechar='@'; - } - - return result; - } -} diff --git a/src/main/java/com/alibaba/excel/util/IoUtils.java b/src/main/java/com/alibaba/excel/util/IoUtils.java new file mode 100644 index 0000000..9405c91 --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/IoUtils.java @@ -0,0 +1,85 @@ +package com.alibaba.excel.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * IO Utils + * + * @author Jiaju Zhuang + */ +public class IoUtils { + public static final int EOF = -1; + /** + * The default buffer size ({@value}) to use for + */ + private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; + + /** + * Gets the contents of an InputStream as a byte[]. + * + * @param input + * @return + * @throws IOException + */ + public static byte[] toByteArray(final InputStream input) throws IOException { + final ByteArrayOutputStream output = new ByteArrayOutputStream(); + try { + copy(input, output); + return output.toByteArray(); + } finally { + output.toByteArray(); + } + } + + /** + * Gets the contents of an InputStream as a byte[]. + * + * @param input + * @param size + * @return + * @throws IOException + */ + public static byte[] toByteArray(final InputStream input, final int size) throws IOException { + if (size < 0) { + throw new IllegalArgumentException("Size must be equal or greater than zero: " + size); + } + if (size == 0) { + return new byte[0]; + } + final byte[] data = new byte[size]; + int offset = 0; + int read; + while (offset < size && (read = input.read(data, offset, size - offset)) != EOF) { + offset += read; + } + if (offset != size) { + throw new IOException("Unexpected read size. current: " + offset + ", expected: " + size); + } + return data; + } + + /** + * Copies bytes + * + * @param input + * @param output + * @return + * @throws IOException + */ + public static int copy(final InputStream input, final OutputStream output) throws IOException { + long count = 0; + int n; + byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; + while (EOF != (n = input.read(buffer))) { + output.write(buffer, 0, n); + count += n; + } + if (count > Integer.MAX_VALUE) { + return -1; + } + return (int)count; + } +} diff --git a/src/main/java/com/alibaba/excel/util/NumberUtils.java b/src/main/java/com/alibaba/excel/util/NumberUtils.java new file mode 100644 index 0000000..791687d --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/NumberUtils.java @@ -0,0 +1,168 @@ +package com.alibaba.excel.util; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.text.ParseException; + +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * Number utils + * + * @author Jiaju Zhuang + */ +public class NumberUtils { + private NumberUtils() {} + + /** + * format + * + * @param num + * @param contentProperty + * @return + */ + public static String format(Number num, ExcelContentProperty contentProperty) { + if (contentProperty == null || contentProperty.getNumberFormatProperty() == null + || StringUtils.isEmpty(contentProperty.getNumberFormatProperty().getFormat())) { + return num.toString(); + } + String format = contentProperty.getNumberFormatProperty().getFormat(); + RoundingMode roundingMode = contentProperty.getNumberFormatProperty().getRoundingMode(); + DecimalFormat decimalFormat = new DecimalFormat(format); + decimalFormat.setRoundingMode(roundingMode); + return decimalFormat.format(num); + } + + /** + * format + * + * @param num + * @param contentProperty + * @return + */ + public static CellData formatToCellData(Number num, ExcelContentProperty contentProperty) { + return new CellData(format(num, contentProperty)); + } + + /** + * parse + * + * @param string + * @param contentProperty + * @return + */ + public static Short parseShort(String string, ExcelContentProperty contentProperty) throws ParseException { + if (!hasFormat(contentProperty)) { + return Short.valueOf(string); + } + return parse(string, contentProperty).shortValue(); + } + + /** + * parse + * + * @param string + * @param contentProperty + * @return + */ + public static Long parseLong(String string, ExcelContentProperty contentProperty) throws ParseException { + if (!hasFormat(contentProperty)) { + return Long.valueOf(string); + } + return parse(string, contentProperty).longValue(); + } + + /** + * parse + * + * @param string + * @param contentProperty + * @return + */ + public static Integer parseInteger(String string, ExcelContentProperty contentProperty) throws ParseException { + if (!hasFormat(contentProperty)) { + return Integer.valueOf(string); + } + return parse(string, contentProperty).intValue(); + } + + /** + * parse + * + * @param string + * @param contentProperty + * @return + */ + public static Float parseFloat(String string, ExcelContentProperty contentProperty) throws ParseException { + if (!hasFormat(contentProperty)) { + return Float.valueOf(string); + } + return parse(string, contentProperty).floatValue(); + } + + /** + * parse + * + * @param string + * @param contentProperty + * @return + */ + public static BigDecimal parseBigDecimal(String string, ExcelContentProperty contentProperty) + throws ParseException { + if (!hasFormat(contentProperty)) { + return new BigDecimal(string); + } + return BigDecimal.valueOf(parse(string, contentProperty).doubleValue()); + } + + /** + * parse + * + * @param string + * @param contentProperty + * @return + */ + public static Byte parseByte(String string, ExcelContentProperty contentProperty) throws ParseException { + if (!hasFormat(contentProperty)) { + return Byte.valueOf(string); + } + return parse(string, contentProperty).byteValue(); + } + + /** + * parse + * + * @param string + * @param contentProperty + * @return + */ + public static Double parseDouble(String string, ExcelContentProperty contentProperty) throws ParseException { + if (!hasFormat(contentProperty)) { + return Double.valueOf(string); + } + return parse(string, contentProperty).doubleValue(); + } + + private static boolean hasFormat(ExcelContentProperty contentProperty) { + return contentProperty != null && contentProperty.getNumberFormatProperty() != null + && !StringUtils.isEmpty(contentProperty.getNumberFormatProperty().getFormat()); + } + + /** + * parse + * + * @param string + * @param contentProperty + * @return + * @throws ParseException + */ + private static Number parse(String string, ExcelContentProperty contentProperty) throws ParseException { + String format = contentProperty.getNumberFormatProperty().getFormat(); + RoundingMode roundingMode = contentProperty.getNumberFormatProperty().getRoundingMode(); + DecimalFormat decimalFormat = new DecimalFormat(format); + decimalFormat.setRoundingMode(roundingMode); + return decimalFormat.parse(string); + } +} diff --git a/src/main/java/com/alibaba/excel/util/ObjectUtils.java b/src/main/java/com/alibaba/excel/util/ObjectUtils.java deleted file mode 100644 index 8b8556c..0000000 --- a/src/main/java/com/alibaba/excel/util/ObjectUtils.java +++ /dev/null @@ -1,945 +0,0 @@ -package com.alibaba.excel.util; - -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import java.lang.reflect.Array; -import java.util.Arrays; -import java.util.Collection; -import java.util.Map; - -/** - * Miscellaneous object utility methods. - * - *

Mainly for internal use within the framework. - * - *

Thanks to Alex Ruiz for contributing several enhancements to this class! - * - * @author Juergen Hoeller - * @author Keith Donald - * @author Rod Johnson - * @author Rob Harrop - * @author Chris Beams - * @author Sam Brannen - * @since 19.03.2004 - * @see CollectionUtils - */ -public abstract class ObjectUtils { - - private static final int INITIAL_HASH = 7; - private static final int MULTIPLIER = 31; - - private static final String EMPTY_STRING = ""; - private static final String NULL_STRING = "null"; - private static final String ARRAY_START = "{"; - private static final String ARRAY_END = "}"; - private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END; - private static final String ARRAY_ELEMENT_SEPARATOR = ", "; - - - /** - * Return whether the given throwable is a checked exception: - * that is, neither a RuntimeException nor an Error. - * @param ex the throwable to check - * @return whether the throwable is a checked exception - * @see Exception - * @see RuntimeException - * @see Error - */ - public static boolean isCheckedException(Throwable ex) { - return !(ex instanceof RuntimeException || ex instanceof Error); - } - - /** - * Check whether the given exception is compatible with the specified - * exception types, as declared in a throws clause. - * @param ex the exception to check - * @param declaredExceptions the exception types declared in the throws clause - * @return whether the given exception is compatible - */ - public static boolean isCompatibleWithThrowsClause(Throwable ex, Class... declaredExceptions) { - if (!isCheckedException(ex)) { - return true; - } - if (declaredExceptions != null) { - for (Class declaredException : declaredExceptions) { - if (declaredException.isInstance(ex)) { - return true; - } - } - } - return false; - } - - /** - * Determine whether the given object is an array: - * either an Object array or a primitive array. - * @param obj the object to check - */ - public static boolean isArray(Object obj) { - return (obj != null && obj.getClass().isArray()); - } - - /** - * Determine whether the given array is empty: - * i.e. {@code null} or of zero length. - * @param array the array to check - * @see #isEmpty(Object) - */ - public static boolean isEmpty(Object[] array) { - return (array == null || array.length == 0); - } - - /** - * Determine whether the given object is empty. - *

This method supports the following object types. - *

- *

If the given object is non-null and not one of the aforementioned - * supported types, this method returns {@code false}. - * @param obj the object to check - * @return {@code true} if the object is {@code null} or empty - * @since 4.2 - * @see ObjectUtils#isEmpty(Object[]) - * @see StringUtils#hasLength(CharSequence) - * @see StringUtils#isEmpty(Object) - * @see CollectionUtils#isEmpty(Collection) - * @see CollectionUtils#isEmpty(Map) - */ - @SuppressWarnings("rawtypes") - public static boolean isEmpty(Object obj) { - if (obj == null) { - return true; - } - - if (obj instanceof CharSequence) { - return ((CharSequence) obj).length() == 0; - } - if (obj.getClass().isArray()) { - return Array.getLength(obj) == 0; - } - if (obj instanceof Collection) { - return ((Collection) obj).isEmpty(); - } - if (obj instanceof Map) { - return ((Map) obj).isEmpty(); - } - - // else - return false; - } - - /** - * Check whether the given array contains the given element. - * @param array the array to check (may be {@code null}, - * in which case the return value will always be {@code false}) - * @param element the element to check for - * @return whether the element has been found in the given array - */ - public static boolean containsElement(Object[] array, Object element) { - if (array == null) { - return false; - } - for (Object arrayEle : array) { - if (nullSafeEquals(arrayEle, element)) { - return true; - } - } - return false; - } - - /** - * Check whether the given array of enum constants contains a constant with the given name, - * ignoring case when determining a match. - * @param enumValues the enum values to check, typically the product of a call to MyEnum.values() - * @param constant the constant name to find (must not be null or empty string) - * @return whether the constant has been found in the given array - */ - public static boolean containsConstant(Enum[] enumValues, String constant) { - return containsConstant(enumValues, constant, false); - } - - /** - * Check whether the given array of enum constants contains a constant with the given name. - * @param enumValues the enum values to check, typically the product of a call to MyEnum.values() - * @param constant the constant name to find (must not be null or empty string) - * @param caseSensitive whether case is significant in determining a match - * @return whether the constant has been found in the given array - */ - public static boolean containsConstant(Enum[] enumValues, String constant, boolean caseSensitive) { - for (Enum candidate : enumValues) { - if (caseSensitive ? - candidate.toString().equals(constant) : - candidate.toString().equalsIgnoreCase(constant)) { - return true; - } - } - return false; - } - - /** - * Case insensitive alternative to {@link Enum#valueOf(Class, String)}. - * @param the concrete Enum type - * @param enumValues the array of all Enum constants in question, usually per Enum.values() - * @param constant the constant to get the enum value of - * @throws IllegalArgumentException if the given constant is not found in the given array - * of enum values. Use {@link #containsConstant(Enum[], String)} as a guard to avoid this exception. - */ - public static > E caseInsensitiveValueOf(E[] enumValues, String constant) { - for (E candidate : enumValues) { - if (candidate.toString().equalsIgnoreCase(constant)) { - return candidate; - } - } - throw new IllegalArgumentException( - String.format("constant [%s] does not exist in enum type %s", - constant, enumValues.getClass().getComponentType().getName())); - } - - /** - * Append the given object to the given array, returning a new array - * consisting of the input array contents plus the given object. - * @param array the array to append to (can be {@code null}) - * @param obj the object to append - * @return the new array (of the same component type; never {@code null}) - */ - public static A[] addObjectToArray(A[] array, O obj) { - Class compType = Object.class; - if (array != null) { - compType = array.getClass().getComponentType(); - } - else if (obj != null) { - compType = obj.getClass(); - } - int newArrLength = (array != null ? array.length + 1 : 1); - @SuppressWarnings("unchecked") - A[] newArr = (A[]) Array.newInstance(compType, newArrLength); - if (array != null) { - System.arraycopy(array, 0, newArr, 0, array.length); - } - newArr[newArr.length - 1] = obj; - return newArr; - } - - /** - * Convert the given array (which may be a primitive array) to an - * object array (if necessary of primitive wrapper objects). - *

A {@code null} source value will be converted to an - * empty Object array. - * @param source the (potentially primitive) array - * @return the corresponding object array (never {@code null}) - * @throws IllegalArgumentException if the parameter is not an array - */ - public static Object[] toObjectArray(Object source) { - if (source instanceof Object[]) { - return (Object[]) source; - } - if (source == null) { - return new Object[0]; - } - if (!source.getClass().isArray()) { - throw new IllegalArgumentException("Source is not an array: " + source); - } - int length = Array.getLength(source); - if (length == 0) { - return new Object[0]; - } - Class wrapperType = Array.get(source, 0).getClass(); - Object[] newArray = (Object[]) Array.newInstance(wrapperType, length); - for (int i = 0; i < length; i++) { - newArray[i] = Array.get(source, i); - } - return newArray; - } - - - //--------------------------------------------------------------------- - // Convenience methods for content-based equality/hash-code handling - //--------------------------------------------------------------------- - - /** - * Determine if the given objects are equal, returning {@code true} if - * both are {@code null} or {@code false} if only one is {@code null}. - *

Compares arrays with {@code Arrays.equals}, performing an equality - * check based on the array elements rather than the array reference. - * @param o1 first Object to compare - * @param o2 second Object to compare - * @return whether the given objects are equal - * @see Object#equals(Object) - * @see Arrays#equals - */ - public static boolean nullSafeEquals(Object o1, Object o2) { - if (o1 == o2) { - return true; - } - if (o1 == null || o2 == null) { - return false; - } - if (o1.equals(o2)) { - return true; - } - if (o1.getClass().isArray() && o2.getClass().isArray()) { - return arrayEquals(o1, o2); - } - return false; - } - - /** - * Compare the given arrays with {@code Arrays.equals}, performing an equality - * check based on the array elements rather than the array reference. - * @param o1 first array to compare - * @param o2 second array to compare - * @return whether the given objects are equal - * @see #nullSafeEquals(Object, Object) - * @see Arrays#equals - */ - private static boolean arrayEquals(Object o1, Object o2) { - if (o1 instanceof Object[] && o2 instanceof Object[]) { - return Arrays.equals((Object[]) o1, (Object[]) o2); - } - if (o1 instanceof boolean[] && o2 instanceof boolean[]) { - return Arrays.equals((boolean[]) o1, (boolean[]) o2); - } - if (o1 instanceof byte[] && o2 instanceof byte[]) { - return Arrays.equals((byte[]) o1, (byte[]) o2); - } - if (o1 instanceof char[] && o2 instanceof char[]) { - return Arrays.equals((char[]) o1, (char[]) o2); - } - if (o1 instanceof double[] && o2 instanceof double[]) { - return Arrays.equals((double[]) o1, (double[]) o2); - } - if (o1 instanceof float[] && o2 instanceof float[]) { - return Arrays.equals((float[]) o1, (float[]) o2); - } - if (o1 instanceof int[] && o2 instanceof int[]) { - return Arrays.equals((int[]) o1, (int[]) o2); - } - if (o1 instanceof long[] && o2 instanceof long[]) { - return Arrays.equals((long[]) o1, (long[]) o2); - } - if (o1 instanceof short[] && o2 instanceof short[]) { - return Arrays.equals((short[]) o1, (short[]) o2); - } - return false; - } - - /** - * Return as hash code for the given object; typically the value of - * {@code Object#hashCode()}}. If the object is an array, - * this method will delegate to any of the {@code nullSafeHashCode} - * methods for arrays in this class. If the object is {@code null}, - * this method returns 0. - * @see Object#hashCode() - * @see #nullSafeHashCode(Object[]) - * @see #nullSafeHashCode(boolean[]) - * @see #nullSafeHashCode(byte[]) - * @see #nullSafeHashCode(char[]) - * @see #nullSafeHashCode(double[]) - * @see #nullSafeHashCode(float[]) - * @see #nullSafeHashCode(int[]) - * @see #nullSafeHashCode(long[]) - * @see #nullSafeHashCode(short[]) - */ - public static int nullSafeHashCode(Object obj) { - if (obj == null) { - return 0; - } - if (obj.getClass().isArray()) { - if (obj instanceof Object[]) { - return nullSafeHashCode((Object[]) obj); - } - if (obj instanceof boolean[]) { - return nullSafeHashCode((boolean[]) obj); - } - if (obj instanceof byte[]) { - return nullSafeHashCode((byte[]) obj); - } - if (obj instanceof char[]) { - return nullSafeHashCode((char[]) obj); - } - if (obj instanceof double[]) { - return nullSafeHashCode((double[]) obj); - } - if (obj instanceof float[]) { - return nullSafeHashCode((float[]) obj); - } - if (obj instanceof int[]) { - return nullSafeHashCode((int[]) obj); - } - if (obj instanceof long[]) { - return nullSafeHashCode((long[]) obj); - } - if (obj instanceof short[]) { - return nullSafeHashCode((short[]) obj); - } - } - return obj.hashCode(); - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(Object[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (Object element : array) { - hash = MULTIPLIER * hash + nullSafeHashCode(element); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(boolean[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (boolean element : array) { - hash = MULTIPLIER * hash + hashCode(element); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(byte[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (byte element : array) { - hash = MULTIPLIER * hash + element; - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(char[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (char element : array) { - hash = MULTIPLIER * hash + element; - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(double[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (double element : array) { - hash = MULTIPLIER * hash + hashCode(element); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(float[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (float element : array) { - hash = MULTIPLIER * hash + hashCode(element); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(int[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (int element : array) { - hash = MULTIPLIER * hash + element; - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(long[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (long element : array) { - hash = MULTIPLIER * hash + hashCode(element); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If {@code array} is {@code null}, this method returns 0. - */ - public static int nullSafeHashCode(short[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - for (short element : array) { - hash = MULTIPLIER * hash + element; - } - return hash; - } - - /** - * Return the same value as {@link Boolean#hashCode()}}. - * @see Boolean#hashCode() - */ - public static int hashCode(boolean bool) { - return (bool ? 1231 : 1237); - } - - /** - * Return the same value as {@link Double#hashCode()}}. - * @see Double#hashCode() - */ - public static int hashCode(double dbl) { - return hashCode(Double.doubleToLongBits(dbl)); - } - - /** - * Return the same value as {@link Float#hashCode()}}. - * @see Float#hashCode() - */ - public static int hashCode(float flt) { - return Float.floatToIntBits(flt); - } - - /** - * Return the same value as {@link Long#hashCode()}}. - * @see Long#hashCode() - */ - public static int hashCode(long lng) { - return (int) (lng ^ (lng >>> 32)); - } - - - //--------------------------------------------------------------------- - // Convenience methods for toString output - //--------------------------------------------------------------------- - - /** - * Return a String representation of an object's overall identity. - * @param obj the object (may be {@code null}) - * @return the object's identity as String representation, - * or an empty String if the object was {@code null} - */ - public static String identityToString(Object obj) { - if (obj == null) { - return EMPTY_STRING; - } - return obj.getClass().getName() + "@" + getIdentityHexString(obj); - } - - /** - * Return a hex String form of an object's identity hash code. - * @param obj the object - * @return the object's identity code in hex notation - */ - public static String getIdentityHexString(Object obj) { - return Integer.toHexString(System.identityHashCode(obj)); - } - - /** - * Return a content-based String representation if {@code obj} is - * not {@code null}; otherwise returns an empty String. - *

Differs from {@link #nullSafeToString(Object)} in that it returns - * an empty String rather than "null" for a {@code null} value. - * @param obj the object to build a display String for - * @return a display String representation of {@code obj} - * @see #nullSafeToString(Object) - */ - public static String getDisplayString(Object obj) { - if (obj == null) { - return EMPTY_STRING; - } - return nullSafeToString(obj); - } - - /** - * Determine the class name for the given object. - *

Returns {@code "null"} if {@code obj} is {@code null}. - * @param obj the object to introspect (may be {@code null}) - * @return the corresponding class name - */ - public static String nullSafeClassName(Object obj) { - return (obj != null ? obj.getClass().getName() : NULL_STRING); - } - - /** - * Return a String representation of the specified Object. - *

Builds a String representation of the contents in case of an array. - * Returns {@code "null"} if {@code obj} is {@code null}. - * @param obj the object to build a String representation for - * @return a String representation of {@code obj} - */ - public static String nullSafeToString(Object obj) { - if (obj == null) { - return NULL_STRING; - } - if (obj instanceof String) { - return (String) obj; - } - if (obj instanceof Object[]) { - return nullSafeToString((Object[]) obj); - } - if (obj instanceof boolean[]) { - return nullSafeToString((boolean[]) obj); - } - if (obj instanceof byte[]) { - return nullSafeToString((byte[]) obj); - } - if (obj instanceof char[]) { - return nullSafeToString((char[]) obj); - } - if (obj instanceof double[]) { - return nullSafeToString((double[]) obj); - } - if (obj instanceof float[]) { - return nullSafeToString((float[]) obj); - } - if (obj instanceof int[]) { - return nullSafeToString((int[]) obj); - } - if (obj instanceof long[]) { - return nullSafeToString((long[]) obj); - } - if (obj instanceof short[]) { - return nullSafeToString((short[]) obj); - } - String str = obj.toString(); - return (str != null ? str : EMPTY_STRING); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(Object[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - sb.append(String.valueOf(array[i])); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(boolean[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - - sb.append(array[i]); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(byte[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - sb.append(array[i]); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(char[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - sb.append("'").append(array[i]).append("'"); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(double[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - - sb.append(array[i]); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(float[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - - sb.append(array[i]); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(int[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - sb.append(array[i]); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(long[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - sb.append(array[i]); - } - sb.append(ARRAY_END); - return sb.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ({@code "{}"}). Adjacent elements are separated - * by the characters {@code ", "} (a comma followed by a space). Returns - * {@code "null"} if {@code array} is {@code null}. - * @param array the array to build a String representation for - * @return a String representation of {@code array} - */ - public static String nullSafeToString(short[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i == 0) { - sb.append(ARRAY_START); - } - else { - sb.append(ARRAY_ELEMENT_SEPARATOR); - } - sb.append(array[i]); - } - sb.append(ARRAY_END); - return sb.toString(); - } - -} diff --git a/src/main/java/com/alibaba/excel/util/POITempFile.java b/src/main/java/com/alibaba/excel/util/POITempFile.java deleted file mode 100644 index 6382255..0000000 --- a/src/main/java/com/alibaba/excel/util/POITempFile.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.alibaba.excel.util; - -import java.io.File; - -/** - * - * @author jipengfei - */ -public class POITempFile { - - private static final String JAVA_IO_TMPDIR = "java.io.tmpdir"; - - private static final String POIFILES = "poifiles"; - - /** - */ - public static void createPOIFilesDirectory() { - - String tmpDir = System.getProperty(JAVA_IO_TMPDIR); - if (tmpDir == null) { - throw new RuntimeException( - "Systems temporary directory not defined - set the -D" + JAVA_IO_TMPDIR + " jvm property!"); - } - File directory = new File(tmpDir, POIFILES); - if (!directory.exists()) { - syncCreatePOIFilesDirectory(directory); - } - - } - - /** - * - * @param directory - */ - private static synchronized void syncCreatePOIFilesDirectory(File directory) { - if (!directory.exists()) { - directory.mkdirs(); - } - } -} diff --git a/src/main/java/com/alibaba/excel/util/PositionUtils.java b/src/main/java/com/alibaba/excel/util/PositionUtils.java index 37a87dd..3151040 100644 --- a/src/main/java/com/alibaba/excel/util/PositionUtils.java +++ b/src/main/java/com/alibaba/excel/util/PositionUtils.java @@ -9,7 +9,7 @@ public class PositionUtils { int row = 0; if (currentCellIndex != null) { String rowStr = currentCellIndex.replaceAll("[A-Z]", "").replaceAll("[a-z]", ""); - row = Integer.parseInt(rowStr)-1; + row = Integer.parseInt(rowStr) - 1; } return row; } @@ -23,6 +23,6 @@ public class PositionUtils { col += (currentIndex[i] - '@') * Math.pow(26, (currentIndex.length - i - 1)); } } - return col-1; + return col - 1; } } diff --git a/src/main/java/com/alibaba/excel/util/RowUtil.java b/src/main/java/com/alibaba/excel/util/RowUtil.java deleted file mode 100644 index dc5ea01..0000000 --- a/src/main/java/com/alibaba/excel/util/RowUtil.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.alibaba.excel.util; - -import org.apache.poi.ss.usermodel.Workbook; - -public class RowUtil { - - //public static int computeNextRow(Workbook workbook,int startRow){ - // - //} -} diff --git a/src/main/java/com/alibaba/excel/util/StringUtils.java b/src/main/java/com/alibaba/excel/util/StringUtils.java index 83ddd18..8210a19 100644 --- a/src/main/java/com/alibaba/excel/util/StringUtils.java +++ b/src/main/java/com/alibaba/excel/util/StringUtils.java @@ -1,1221 +1,13 @@ package com.alibaba.excel.util; -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Properties; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.TimeZone; - /** - * Miscellaneous {@link String} utility methods. - * - *

Mainly for internal use within the framework; consider - * Apache's Commons Lang - * for a more comprehensive suite of {@code String} utilities. - * - *

This class delivers some simple functionality that should really be - * provided by the core Java {@link String} and {@link StringBuilder} - * classes. It also provides easy-to-use methods to convert between - * delimited strings, such as CSV strings, and collections and arrays. - * - * @author Rod Johnson - * @author Juergen Hoeller - * @author Keith Donald - * @author Rob Harrop - * @author Rick Evans - * @author Arjen Poutsma - * @author Sam Brannen - * @author Brian Clozel - * @since 16 April 2001 + * String utils + * + * @author jipengfei */ -public abstract class StringUtils { - - private static final String FOLDER_SEPARATOR = "/"; - - private static final String WINDOWS_FOLDER_SEPARATOR = "\\"; +public class StringUtils { - private static final String TOP_PATH = ".."; - - private static final String CURRENT_PATH = "."; - - private static final char EXTENSION_SEPARATOR = '.'; - - - //--------------------------------------------------------------------- - // General convenience methods for working with Strings - //--------------------------------------------------------------------- - - /** - * Check whether the given {@code String} is empty. - *

This method accepts any Object as an argument, comparing it to - * {@code null} and the empty String. As a consequence, this method - * will never return {@code true} for a non-null non-String object. - *

The Object signature is useful for general attribute handling code - * that commonly deals with Strings but generally has to iterate over - * Objects since attributes may e.g. be primitive value objects as well. - * @param str the candidate String - * @since 3.2.1 - */ public static boolean isEmpty(Object str) { return (str == null || "".equals(str)); } - - /** - * Check that the given {@code CharSequence} is neither {@code null} nor - * of length 0. - *

Note: this method returns {@code true} for a {@code CharSequence} - * that purely consists of whitespace. - *

-     * StringUtils.hasLength(null) = false
-     * StringUtils.hasLength("") = false
-     * StringUtils.hasLength(" ") = true
-     * StringUtils.hasLength("Hello") = true
-     * 
- * @param str the {@code CharSequence} to check (may be {@code null}) - * @return {@code true} if the {@code CharSequence} is not {@code null} and has length - * @see #hasText(String) - */ - public static boolean hasLength(CharSequence str) { - return (str != null && str.length() > 0); - } - - /** - * Check that the given {@code String} is neither {@code null} nor of length 0. - *

Note: this method returns {@code true} for a {@code String} that - * purely consists of whitespace. - * @param str the {@code String} to check (may be {@code null}) - * @return {@code true} if the {@code String} is not {@code null} and has length - * @see #hasLength(CharSequence) - * @see #hasText(String) - */ - public static boolean hasLength(String str) { - return (str != null && !str.isEmpty()); - } - - /** - * Check whether the given {@code CharSequence} contains actual text. - *

More specifically, this method returns {@code true} if the - * {@code CharSequence} is not {@code null}, its length is greater than - * 0, and it contains at least one non-whitespace character. - *

-     * StringUtils.hasText(null) = false
-     * StringUtils.hasText("") = false
-     * StringUtils.hasText(" ") = false
-     * StringUtils.hasText("12345") = true
-     * StringUtils.hasText(" 12345 ") = true
-     * 
- * @param str the {@code CharSequence} to check (may be {@code null}) - * @return {@code true} if the {@code CharSequence} is not {@code null}, - * its length is greater than 0, and it does not contain whitespace only - * @see Character#isWhitespace - */ - public static boolean hasText(CharSequence str) { - return (hasLength(str) && containsText(str)); - } - - /** - * Check whether the given {@code String} contains actual text. - *

More specifically, this method returns {@code true} if the - * {@code String} is not {@code null}, its length is greater than 0, - * and it contains at least one non-whitespace character. - * @param str the {@code String} to check (may be {@code null}) - * @return {@code true} if the {@code String} is not {@code null}, its - * length is greater than 0, and it does not contain whitespace only - * @see #hasText(CharSequence) - */ - public static boolean hasText(String str) { - return (hasLength(str) && containsText(str)); - } - - private static boolean containsText(CharSequence str) { - int strLen = str.length(); - for (int i = 0; i < strLen; i++) { - if (!Character.isWhitespace(str.charAt(i))) { - return true; - } - } - return false; - } - - /** - * Check whether the given {@code CharSequence} contains any whitespace characters. - * @param str the {@code CharSequence} to check (may be {@code null}) - * @return {@code true} if the {@code CharSequence} is not empty and - * contains at least 1 whitespace character - * @see Character#isWhitespace - */ - public static boolean containsWhitespace(CharSequence str) { - if (!hasLength(str)) { - return false; - } - - int strLen = str.length(); - for (int i = 0; i < strLen; i++) { - if (Character.isWhitespace(str.charAt(i))) { - return true; - } - } - return false; - } - - /** - * Check whether the given {@code String} contains any whitespace characters. - * @param str the {@code String} to check (may be {@code null}) - * @return {@code true} if the {@code String} is not empty and - * contains at least 1 whitespace character - * @see #containsWhitespace(CharSequence) - */ - public static boolean containsWhitespace(String str) { - return containsWhitespace((CharSequence) str); - } - - /** - * Trim leading and trailing whitespace from the given {@code String}. - * @param str the {@code String} to check - * @return the trimmed {@code String} - * @see Character#isWhitespace - */ - public static String trimWhitespace(String str) { - if (!hasLength(str)) { - return str; - } - - StringBuilder sb = new StringBuilder(str); - while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) { - sb.deleteCharAt(0); - } - while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) { - sb.deleteCharAt(sb.length() - 1); - } - return sb.toString(); - } - - /** - * Trim all whitespace from the given {@code String}: - * leading, trailing, and in between characters. - * @param str the {@code String} to check - * @return the trimmed {@code String} - * @see Character#isWhitespace - */ - public static String trimAllWhitespace(String str) { - if (!hasLength(str)) { - return str; - } - - int len = str.length(); - StringBuilder sb = new StringBuilder(str.length()); - for (int i = 0; i < len; i++) { - char c = str.charAt(i); - if (!Character.isWhitespace(c)) { - sb.append(c); - } - } - return sb.toString(); - } - - /** - * Trim leading whitespace from the given {@code String}. - * @param str the {@code String} to check - * @return the trimmed {@code String} - * @see Character#isWhitespace - */ - public static String trimLeadingWhitespace(String str) { - if (!hasLength(str)) { - return str; - } - - StringBuilder sb = new StringBuilder(str); - while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) { - sb.deleteCharAt(0); - } - return sb.toString(); - } - - /** - * Trim trailing whitespace from the given {@code String}. - * @param str the {@code String} to check - * @return the trimmed {@code String} - * @see Character#isWhitespace - */ - public static String trimTrailingWhitespace(String str) { - if (!hasLength(str)) { - return str; - } - - StringBuilder sb = new StringBuilder(str); - while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) { - sb.deleteCharAt(sb.length() - 1); - } - return sb.toString(); - } - - /** - * Trim all occurrences of the supplied leading character from the given {@code String}. - * @param str the {@code String} to check - * @param leadingCharacter the leading character to be trimmed - * @return the trimmed {@code String} - */ - public static String trimLeadingCharacter(String str, char leadingCharacter) { - if (!hasLength(str)) { - return str; - } - - StringBuilder sb = new StringBuilder(str); - while (sb.length() > 0 && sb.charAt(0) == leadingCharacter) { - sb.deleteCharAt(0); - } - return sb.toString(); - } - - /** - * Trim all occurrences of the supplied trailing character from the given {@code String}. - * @param str the {@code String} to check - * @param trailingCharacter the trailing character to be trimmed - * @return the trimmed {@code String} - */ - public static String trimTrailingCharacter(String str, char trailingCharacter) { - if (!hasLength(str)) { - return str; - } - - StringBuilder sb = new StringBuilder(str); - while (sb.length() > 0 && sb.charAt(sb.length() - 1) == trailingCharacter) { - sb.deleteCharAt(sb.length() - 1); - } - return sb.toString(); - } - - /** - * Test if the given {@code String} starts with the specified prefix, - * ignoring upper/lower case. - * @param str the {@code String} to check - * @param prefix the prefix to look for - * @see String#startsWith - */ - public static boolean startsWithIgnoreCase(String str, String prefix) { - return (str != null && prefix != null && str.length() >= prefix.length() && - str.regionMatches(true, 0, prefix, 0, prefix.length())); - } - - /** - * Test if the given {@code String} ends with the specified suffix, - * ignoring upper/lower case. - * @param str the {@code String} to check - * @param suffix the suffix to look for - * @see String#endsWith - */ - public static boolean endsWithIgnoreCase(String str, String suffix) { - return (str != null && suffix != null && str.length() >= suffix.length() && - str.regionMatches(true, str.length() - suffix.length(), suffix, 0, suffix.length())); - } - - /** - * Test whether the given string matches the given substring - * at the given index. - * @param str the original string (or StringBuilder) - * @param index the index in the original string to start matching against - * @param substring the substring to match at the given index - */ - public static boolean substringMatch(CharSequence str, int index, CharSequence substring) { - if (index + substring.length() > str.length()) { - return false; - } - for (int i = 0; i < substring.length(); i++) { - if (str.charAt(index + i) != substring.charAt(i)) { - return false; - } - } - return true; - } - - /** - * Count the occurrences of the substring {@code sub} in string {@code str}. - * @param str string to search in - * @param sub string to search for - */ - public static int countOccurrencesOf(String str, String sub) { - if (!hasLength(str) || !hasLength(sub)) { - return 0; - } - - int count = 0; - int pos = 0; - int idx; - while ((idx = str.indexOf(sub, pos)) != -1) { - ++count; - pos = idx + sub.length(); - } - return count; - } - - /** - * Replace all occurrences of a substring within a string with another string. - * @param inString {@code String} to examine - * @param oldPattern {@code String} to replace - * @param newPattern {@code String} to insert - * @return a {@code String} with the replacements - */ - public static String replace(String inString, String oldPattern, String newPattern) { - if (!hasLength(inString) || !hasLength(oldPattern) || newPattern == null) { - return inString; - } - int index = inString.indexOf(oldPattern); - if (index == -1) { - // no occurrence -> can return input as-is - return inString; - } - - int capacity = inString.length(); - if (newPattern.length() > oldPattern.length()) { - capacity += 16; - } - StringBuilder sb = new StringBuilder(capacity); - - int pos = 0; // our position in the old string - int patLen = oldPattern.length(); - while (index >= 0) { - sb.append(inString.substring(pos, index)); - sb.append(newPattern); - pos = index + patLen; - index = inString.indexOf(oldPattern, pos); - } - - // append any characters to the right of a match - sb.append(inString.substring(pos)); - return sb.toString(); - } - - /** - * Delete all occurrences of the given substring. - * @param inString the original {@code String} - * @param pattern the pattern to delete all occurrences of - * @return the resulting {@code String} - */ - public static String delete(String inString, String pattern) { - return replace(inString, pattern, ""); - } - - /** - * Delete any character in a given {@code String}. - * @param inString the original {@code String} - * @param charsToDelete a set of characters to delete. - * E.g. "az\n" will delete 'a's, 'z's and new lines. - * @return the resulting {@code String} - */ - public static String deleteAny(String inString, String charsToDelete) { - if (!hasLength(inString) || !hasLength(charsToDelete)) { - return inString; - } - - StringBuilder sb = new StringBuilder(inString.length()); - for (int i = 0; i < inString.length(); i++) { - char c = inString.charAt(i); - if (charsToDelete.indexOf(c) == -1) { - sb.append(c); - } - } - return sb.toString(); - } - - - //--------------------------------------------------------------------- - // Convenience methods for working with formatted Strings - //--------------------------------------------------------------------- - - /** - * Quote the given {@code String} with single quotes. - * @param str the input {@code String} (e.g. "myString") - * @return the quoted {@code String} (e.g. "'myString'"), - * or {@code null} if the input was {@code null} - */ - public static String quote(String str) { - return (str != null ? "'" + str + "'" : null); - } - - /** - * Turn the given Object into a {@code String} with single quotes - * if it is a {@code String}; keeping the Object as-is else. - * @param obj the input Object (e.g. "myString") - * @return the quoted {@code String} (e.g. "'myString'"), - * or the input object as-is if not a {@code String} - */ - public static Object quoteIfString(Object obj) { - return (obj instanceof String ? quote((String) obj) : obj); - } - - /** - * Unqualify a string qualified by a '.' dot character. For example, - * "this.name.is.qualified", returns "qualified". - * @param qualifiedName the qualified name - */ - public static String unqualify(String qualifiedName) { - return unqualify(qualifiedName, '.'); - } - - /** - * Unqualify a string qualified by a separator character. For example, - * "this:name:is:qualified" returns "qualified" if using a ':' separator. - * @param qualifiedName the qualified name - * @param separator the separator - */ - public static String unqualify(String qualifiedName, char separator) { - return qualifiedName.substring(qualifiedName.lastIndexOf(separator) + 1); - } - - /** - * Capitalize a {@code String}, changing the first letter to - * upper case as per {@link Character#toUpperCase(char)}. - * No other letters are changed. - * @param str the {@code String} to capitalize - * @return the capitalized {@code String} - */ - public static String capitalize(String str) { - return changeFirstCharacterCase(str, true); - } - - /** - * Uncapitalize a {@code String}, changing the first letter to - * lower case as per {@link Character#toLowerCase(char)}. - * No other letters are changed. - * @param str the {@code String} to uncapitalize - * @return the uncapitalized {@code String} - */ - public static String uncapitalize(String str) { - return changeFirstCharacterCase(str, false); - } - - private static String changeFirstCharacterCase(String str, boolean capitalize) { - if (!hasLength(str)) { - return str; - } - - char baseChar = str.charAt(0); - char updatedChar; - if (capitalize) { - updatedChar = Character.toUpperCase(baseChar); - } - else { - updatedChar = Character.toLowerCase(baseChar); - } - if (baseChar == updatedChar) { - return str; - } - - char[] chars = str.toCharArray(); - chars[0] = updatedChar; - return new String(chars, 0, chars.length); - } - - /** - * Extract the filename from the given Java resource path, - * e.g. {@code "mypath/myfile.txt" -> "myfile.txt"}. - * @param path the file path (may be {@code null}) - * @return the extracted filename, or {@code null} if none - */ - public static String getFilename(String path) { - if (path == null) { - return null; - } - - int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); - return (separatorIndex != -1 ? path.substring(separatorIndex + 1) : path); - } - - /** - * Extract the filename extension from the given Java resource path, - * - * @param path the file path (may be {@code null}) - * @return the extracted filename extension, or {@code null} if none - */ - public static String getFilenameExtension(String path) { - if (path == null) { - return null; - } - - int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR); - if (extIndex == -1) { - return null; - } - - int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR); - if (folderIndex > extIndex) { - return null; - } - - return path.substring(extIndex + 1); - } - - /** - * Strip the filename extension from the given Java resource path, - * - * @param path the file path - * @return the path with stripped filename extension - */ - public static String stripFilenameExtension(String path) { - if (path == null) { - return null; - } - - int extIndex = path.lastIndexOf(EXTENSION_SEPARATOR); - if (extIndex == -1) { - return path; - } - - int folderIndex = path.lastIndexOf(FOLDER_SEPARATOR); - if (folderIndex > extIndex) { - return path; - } - - return path.substring(0, extIndex); - } - - /** - * Apply the given relative path to the given Java resource path, - * assuming standard Java folder separation (i.e. "/" separators). - * @param path the path to start from (usually a full file path) - * @param relativePath the relative path to apply - * (relative to the full file path above) - * @return the full file path that results from applying the relative path - */ - public static String applyRelativePath(String path, String relativePath) { - int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); - if (separatorIndex != -1) { - String newPath = path.substring(0, separatorIndex); - if (!relativePath.startsWith(FOLDER_SEPARATOR)) { - newPath += FOLDER_SEPARATOR; - } - return newPath + relativePath; - } - else { - return relativePath; - } - } - - /** - * Normalize the path by suppressing sequences like "path/.." and - * inner simple dots. - *

The result is convenient for path comparison. For other uses, - * notice that Windows separators ("\") are replaced by simple slashes. - * @param path the original path - * @return the normalized path - */ - public static String cleanPath(String path) { - if (path == null) { - return null; - } - String pathToUse = replace(path, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR); - - // Strip prefix from path to analyze, to not treat it as part of the - // first path element. This is necessary to correctly parse paths like - // "file:core/../core/io/Resource.class", where the ".." should just - // strip the first "core" directory while keeping the "file:" prefix. - int prefixIndex = pathToUse.indexOf(":"); - String prefix = ""; - if (prefixIndex != -1) { - prefix = pathToUse.substring(0, prefixIndex + 1); - if (prefix.contains("/")) { - prefix = ""; - } - else { - pathToUse = pathToUse.substring(prefixIndex + 1); - } - } - if (pathToUse.startsWith(FOLDER_SEPARATOR)) { - prefix = prefix + FOLDER_SEPARATOR; - pathToUse = pathToUse.substring(1); - } - - String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR); - List pathElements = new LinkedList(); - int tops = 0; - - for (int i = pathArray.length - 1; i >= 0; i--) { - String element = pathArray[i]; - if (CURRENT_PATH.equals(element)) { - // Points to current directory - drop it. - } - else if (TOP_PATH.equals(element)) { - // Registering top path found. - tops++; - } - else { - if (tops > 0) { - // Merging path element with element corresponding to top path. - tops--; - } - else { - // Normal path element found. - pathElements.add(0, element); - } - } - } - - // Remaining top paths need to be retained. - for (int i = 0; i < tops; i++) { - pathElements.add(0, TOP_PATH); - } - - return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR); - } - - /** - * Compare two paths after normalization of them. - * @param path1 first path for comparison - * @param path2 second path for comparison - * @return whether the two paths are equivalent after normalization - */ - public static boolean pathEquals(String path1, String path2) { - return cleanPath(path1).equals(cleanPath(path2)); - } - - /** - * Parse the given {@code localeString} value into a {@link Locale}. - *

This is the inverse operation of {@link Locale#toString Locale's toString}. - * @param localeString the locale {@code String}, following {@code Locale's} - * {@code toString()} format ("en", "en_UK", etc); - * also accepts spaces as separators, as an alternative to underscores - * @return a corresponding {@code Locale} instance, or {@code null} if none - * @throws IllegalArgumentException in case of an invalid locale specification - */ - public static Locale parseLocaleString(String localeString) { - String[] parts = tokenizeToStringArray(localeString, "_ ", false, false); - String language = (parts.length > 0 ? parts[0] : ""); - String country = (parts.length > 1 ? parts[1] : ""); - - validateLocalePart(language); - validateLocalePart(country); - - String variant = ""; - if (parts.length > 2) { - // There is definitely a variant, and it is everything after the country - // code sans the separator between the country code and the variant. - int endIndexOfCountryCode = localeString.indexOf(country, language.length()) + country.length(); - // Strip off any leading '_' and whitespace, what's left is the variant. - variant = trimLeadingWhitespace(localeString.substring(endIndexOfCountryCode)); - if (variant.startsWith("_")) { - variant = trimLeadingCharacter(variant, '_'); - } - } - return (language.length() > 0 ? new Locale(language, country, variant) : null); - } - - private static void validateLocalePart(String localePart) { - for (int i = 0; i < localePart.length(); i++) { - char ch = localePart.charAt(i); - if (ch != ' ' && ch != '_' && ch != '#' && !Character.isLetterOrDigit(ch)) { - throw new IllegalArgumentException( - "Locale part \"" + localePart + "\" contains invalid characters"); - } - } - } - - /** - * Determine the RFC 3066 compliant language tag, - * as used for the HTTP "Accept-Language" header. - * @param locale the Locale to transform to a language tag - * @return the RFC 3066 compliant language tag as {@code String} - */ - public static String toLanguageTag(Locale locale) { - return locale.getLanguage() + (hasText(locale.getCountry()) ? "-" + locale.getCountry() : ""); - } - - /** - * Parse the given {@code timeZoneString} value into a {@link TimeZone}. - * @param timeZoneString the time zone {@code String}, following {@link TimeZone#getTimeZone(String)} - * but throwing {@link IllegalArgumentException} in case of an invalid time zone specification - * @return a corresponding {@link TimeZone} instance - * @throws IllegalArgumentException in case of an invalid time zone specification - */ - public static TimeZone parseTimeZoneString(String timeZoneString) { - TimeZone timeZone = TimeZone.getTimeZone(timeZoneString); - if ("GMT".equals(timeZone.getID()) && !timeZoneString.startsWith("GMT")) { - // We don't want that GMT fallback... - throw new IllegalArgumentException("Invalid time zone specification '" + timeZoneString + "'"); - } - return timeZone; - } - - - //--------------------------------------------------------------------- - // Convenience methods for working with String arrays - //--------------------------------------------------------------------- - - /** - * Append the given {@code String} to the given {@code String} array, - * returning a new array consisting of the input array contents plus - * the given {@code String}. - * @param array the array to append to (can be {@code null}) - * @param str the {@code String} to append - * @return the new array (never {@code null}) - */ - public static String[] addStringToArray(String[] array, String str) { - if (ObjectUtils.isEmpty(array)) { - return new String[] {str}; - } - - String[] newArr = new String[array.length + 1]; - System.arraycopy(array, 0, newArr, 0, array.length); - newArr[array.length] = str; - return newArr; - } - - /** - * Concatenate the given {@code String} arrays into one, - * with overlapping array elements included twice. - *

The order of elements in the original arrays is preserved. - * @param array1 the first array (can be {@code null}) - * @param array2 the second array (can be {@code null}) - * @return the new array ({@code null} if both given arrays were {@code null}) - */ - public static String[] concatenateStringArrays(String[] array1, String[] array2) { - if (ObjectUtils.isEmpty(array1)) { - return array2; - } - if (ObjectUtils.isEmpty(array2)) { - return array1; - } - - String[] newArr = new String[array1.length + array2.length]; - System.arraycopy(array1, 0, newArr, 0, array1.length); - System.arraycopy(array2, 0, newArr, array1.length, array2.length); - return newArr; - } - - /** - * Merge the given {@code String} arrays into one, with overlapping - * array elements only included once. - *

The order of elements in the original arrays is preserved - * (with the exception of overlapping elements, which are only - * included on their first occurrence). - * @param array1 the first array (can be {@code null}) - * @param array2 the second array (can be {@code null}) - * @return the new array ({@code null} if both given arrays were {@code null}) - */ - public static String[] mergeStringArrays(String[] array1, String[] array2) { - if (ObjectUtils.isEmpty(array1)) { - return array2; - } - if (ObjectUtils.isEmpty(array2)) { - return array1; - } - - List result = new ArrayList(); - result.addAll(Arrays.asList(array1)); - for (String str : array2) { - if (!result.contains(str)) { - result.add(str); - } - } - return toStringArray(result); - } - - /** - * Turn given source {@code String} array into sorted array. - * @param array the source array - * @return the sorted array (never {@code null}) - */ - public static String[] sortStringArray(String[] array) { - if (ObjectUtils.isEmpty(array)) { - return new String[0]; - } - - Arrays.sort(array); - return array; - } - - /** - * Copy the given {@code Collection} into a {@code String} array. - *

The {@code Collection} must contain {@code String} elements only. - * @param collection the {@code Collection} to copy - * @return the {@code String} array - */ - public static String[] toStringArray(Collection collection) { - if (collection == null) { - return null; - } - - return collection.toArray(new String[collection.size()]); - } - - /** - * Copy the given Enumeration into a {@code String} array. - * The Enumeration must contain {@code String} elements only. - * @param enumeration the Enumeration to copy - * @return the {@code String} array - */ - public static String[] toStringArray(Enumeration enumeration) { - if (enumeration == null) { - return null; - } - - List list = Collections.list(enumeration); - return list.toArray(new String[list.size()]); - } - - /** - * Trim the elements of the given {@code String} array, - * calling {@code String.trim()} on each of them. - * @param array the original {@code String} array - * @return the resulting array (of the same size) with trimmed elements - */ - public static String[] trimArrayElements(String[] array) { - if (ObjectUtils.isEmpty(array)) { - return new String[0]; - } - - String[] result = new String[array.length]; - for (int i = 0; i < array.length; i++) { - String element = array[i]; - result[i] = (element != null ? element.trim() : null); - } - return result; - } - - /** - * Remove duplicate strings from the given array. - *

As of 4.2, it preserves the original order, as it uses a {@link LinkedHashSet}. - * @param array the {@code String} array - * @return an array without duplicates, in natural sort order - */ - public static String[] removeDuplicateStrings(String[] array) { - if (ObjectUtils.isEmpty(array)) { - return array; - } - - Set set = new LinkedHashSet(); - for (String element : array) { - set.add(element); - } - return toStringArray(set); - } - - /** - * Split a {@code String} at the first occurrence of the delimiter. - * Does not include the delimiter in the result. - * @param toSplit the string to split - * @param delimiter to split the string up with - * @return a two element array with index 0 being before the delimiter, and - * index 1 being after the delimiter (neither element includes the delimiter); - * or {@code null} if the delimiter wasn't found in the given input {@code String} - */ - public static String[] split(String toSplit, String delimiter) { - if (!hasLength(toSplit) || !hasLength(delimiter)) { - return null; - } - int offset = toSplit.indexOf(delimiter); - if (offset < 0) { - return null; - } - - String beforeDelimiter = toSplit.substring(0, offset); - String afterDelimiter = toSplit.substring(offset + delimiter.length()); - return new String[] {beforeDelimiter, afterDelimiter}; - } - - /** - * Take an array of strings and split each element based on the given delimiter. - * A {@code Properties} instance is then generated, with the left of the - * delimiter providing the key, and the right of the delimiter providing the value. - *

Will trim both the key and value before adding them to the - * {@code Properties} instance. - * @param array the array to process - * @param delimiter to split each element using (typically the equals symbol) - * @return a {@code Properties} instance representing the array contents, - * or {@code null} if the array to process was {@code null} or empty - */ - public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter) { - return splitArrayElementsIntoProperties(array, delimiter, null); - } - - /** - * Take an array of strings and split each element based on the given delimiter. - * A {@code Properties} instance is then generated, with the left of the - * delimiter providing the key, and the right of the delimiter providing the value. - *

Will trim both the key and value before adding them to the - * {@code Properties} instance. - * @param array the array to process - * @param delimiter to split each element using (typically the equals symbol) - * @param charsToDelete one or more characters to remove from each element - * prior to attempting the split operation (typically the quotation mark - * symbol), or {@code null} if no removal should occur - * @return a {@code Properties} instance representing the array contents, - * or {@code null} if the array to process was {@code null} or empty - */ - public static Properties splitArrayElementsIntoProperties( - String[] array, String delimiter, String charsToDelete) { - - if (ObjectUtils.isEmpty(array)) { - return null; - } - - Properties result = new Properties(); - for (String element : array) { - if (charsToDelete != null) { - element = deleteAny(element, charsToDelete); - } - String[] splittedElement = split(element, delimiter); - if (splittedElement == null) { - continue; - } - result.setProperty(splittedElement[0].trim(), splittedElement[1].trim()); - } - return result; - } - - /** - * Tokenize the given {@code String} into a {@code String} array via a - * {@link StringTokenizer}. - *

Trims tokens and omits empty tokens. - *

The given {@code delimiters} string can consist of any number of - * delimiter characters. Each of those characters can be used to separate - * tokens. A delimiter is always a single character; for multi-character - * delimiters, consider using {@link #delimitedListToStringArray}. - * @param str the {@code String} to tokenize - * @param delimiters the delimiter characters, assembled as a {@code String} - * (each of the characters is individually considered as a delimiter) - * @return an array of the tokens - * @see StringTokenizer - * @see String#trim() - * @see #delimitedListToStringArray - */ - public static String[] tokenizeToStringArray(String str, String delimiters) { - return tokenizeToStringArray(str, delimiters, true, true); - } - - /** - * Tokenize the given {@code String} into a {@code String} array via a - * {@link StringTokenizer}. - *

The given {@code delimiters} string can consist of any number of - * delimiter characters. Each of those characters can be used to separate - * tokens. A delimiter is always a single character; for multi-character - * delimiters, consider using {@link #delimitedListToStringArray}. - * @param str the {@code String} to tokenize - * @param delimiters the delimiter characters, assembled as a {@code String} - * (each of the characters is individually considered as a delimiter) - * @param trimTokens trim the tokens via {@link String#trim()} - * @param ignoreEmptyTokens omit empty tokens from the result array - * (only applies to tokens that are empty after trimming; StringTokenizer - * will not consider subsequent delimiters as token in the first place). - * @return an array of the tokens - * @see StringTokenizer - * @see String#trim() - * @see #delimitedListToStringArray - */ - public static String[] tokenizeToStringArray( - String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) { - - if (str == null) { - return null; - } - - StringTokenizer st = new StringTokenizer(str, delimiters); - List tokens = new ArrayList(); - while (st.hasMoreTokens()) { - String token = st.nextToken(); - if (trimTokens) { - token = token.trim(); - } - if (!ignoreEmptyTokens || token.length() > 0) { - tokens.add(token); - } - } - return toStringArray(tokens); - } - - /** - * Take a {@code String} that is a delimited list and convert it into a - * {@code String} array. - *

A single {@code delimiter} may consist of more than one character, - * but it will still be considered as a single delimiter string, rather - * than as bunch of potential delimiter characters, in contrast to - * {@link #tokenizeToStringArray}. - * @param str the input {@code String} - * @param delimiter the delimiter between elements (this is a single delimiter, - * rather than a bunch individual delimiter characters) - * @return an array of the tokens in the list - * @see #tokenizeToStringArray - */ - public static String[] delimitedListToStringArray(String str, String delimiter) { - return delimitedListToStringArray(str, delimiter, null); - } - - /** - * Take a {@code String} that is a delimited list and convert it into - * a {@code String} array. - *

A single {@code delimiter} may consist of more than one character, - * but it will still be considered as a single delimiter string, rather - * than as bunch of potential delimiter characters, in contrast to - * {@link #tokenizeToStringArray}. - * @param str the input {@code String} - * @param delimiter the delimiter between elements (this is a single delimiter, - * rather than a bunch individual delimiter characters) - * @param charsToDelete a set of characters to delete; useful for deleting unwanted - * line breaks: e.g. "\r\n\f" will delete all new lines and line feeds in a {@code String} - * @return an array of the tokens in the list - * @see #tokenizeToStringArray - */ - public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) { - if (str == null) { - return new String[0]; - } - if (delimiter == null) { - return new String[] {str}; - } - - List result = new ArrayList(); - if ("".equals(delimiter)) { - for (int i = 0; i < str.length(); i++) { - result.add(deleteAny(str.substring(i, i + 1), charsToDelete)); - } - } - else { - int pos = 0; - int delPos; - while ((delPos = str.indexOf(delimiter, pos)) != -1) { - result.add(deleteAny(str.substring(pos, delPos), charsToDelete)); - pos = delPos + delimiter.length(); - } - if (str.length() > 0 && pos <= str.length()) { - // Add rest of String, but not in case of empty input. - result.add(deleteAny(str.substring(pos), charsToDelete)); - } - } - return toStringArray(result); - } - - /** - * Convert a comma delimited list (e.g., a row from a CSV file) into an - * array of strings. - * @param str the input {@code String} - * @return an array of strings, or the empty array in case of empty input - */ - public static String[] commaDelimitedListToStringArray(String str) { - return delimitedListToStringArray(str, ","); - } - - /** - * Convert a comma delimited list (e.g., a row from a CSV file) into a set. - *

Note that this will suppress duplicates, and as of 4.2, the elements in - * the returned set will preserve the original order in a {@link LinkedHashSet}. - * @param str the input {@code String} - * @return a set of {@code String} entries in the list - * @see #removeDuplicateStrings(String[]) - */ - public static Set commaDelimitedListToSet(String str) { - Set set = new LinkedHashSet(); - String[] tokens = commaDelimitedListToStringArray(str); - for (String token : tokens) { - set.add(token); - } - return set; - } - - /** - * Convert a {@link Collection} to a delimited {@code String} (e.g. CSV). - *

Useful for {@code toString()} implementations. - * @param coll the {@code Collection} to convert - * @param delim the delimiter to use (typically a ",") - * @param prefix the {@code String} to start each element with - * @param suffix the {@code String} to end each element with - * @return the delimited {@code String} - */ - public static String collectionToDelimitedString(Collection coll, String delim, String prefix, String suffix) { - if (CollectionUtils.isEmpty(coll)) { - return ""; - } - - StringBuilder sb = new StringBuilder(); - Iterator it = coll.iterator(); - while (it.hasNext()) { - sb.append(prefix).append(it.next()).append(suffix); - if (it.hasNext()) { - sb.append(delim); - } - } - return sb.toString(); - } - - /** - * Convert a {@code Collection} into a delimited {@code String} (e.g. CSV). - *

Useful for {@code toString()} implementations. - * @param coll the {@code Collection} to convert - * @param delim the delimiter to use (typically a ",") - * @return the delimited {@code String} - */ - public static String collectionToDelimitedString(Collection coll, String delim) { - return collectionToDelimitedString(coll, delim, "", ""); - } - - /** - * Convert a {@code Collection} into a delimited {@code String} (e.g., CSV). - *

Useful for {@code toString()} implementations. - * @param coll the {@code Collection} to convert - * @return the delimited {@code String} - */ - public static String collectionToCommaDelimitedString(Collection coll) { - return collectionToDelimitedString(coll, ","); - } - - /** - * Convert a {@code String} array into a delimited {@code String} (e.g. CSV). - *

Useful for {@code toString()} implementations. - * @param arr the array to display - * @param delim the delimiter to use (typically a ",") - * @return the delimited {@code String} - */ - public static String arrayToDelimitedString(Object[] arr, String delim) { - if (ObjectUtils.isEmpty(arr)) { - return ""; - } - if (arr.length == 1) { - return ObjectUtils.nullSafeToString(arr[0]); - } - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < arr.length; i++) { - if (i > 0) { - sb.append(delim); - } - sb.append(arr[i]); - } - return sb.toString(); - } - - /** - * Convert a {@code String} array into a comma delimited {@code String} - * (i.e., CSV). - *

Useful for {@code toString()} implementations. - * @param arr the array to display - * @return the delimited {@code String} - */ - public static String arrayToCommaDelimitedString(Object[] arr) { - return arrayToDelimitedString(arr, ","); - } - } diff --git a/src/main/java/com/alibaba/excel/util/StyleUtil.java b/src/main/java/com/alibaba/excel/util/StyleUtil.java index cfb9c12..3031048 100644 --- a/src/main/java/com/alibaba/excel/util/StyleUtil.java +++ b/src/main/java/com/alibaba/excel/util/StyleUtil.java @@ -1,8 +1,16 @@ package com.alibaba.excel.util; -import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.VerticalAlignment; +import org.apache.poi.ss.usermodel.Workbook; -import java.util.Map; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; /** * @author jipengfei @@ -10,58 +18,167 @@ import java.util.Map; public class StyleUtil { /** - * * @param workbook * @return */ public static CellStyle buildDefaultCellStyle(Workbook workbook) { CellStyle newCellStyle = workbook.createCellStyle(); - Font font = workbook.createFont(); - font.setFontName("宋体"); - font.setFontHeightInPoints((short)14); - font.setBold(true); - newCellStyle.setFont(font); newCellStyle.setWrapText(true); newCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); newCellStyle.setAlignment(HorizontalAlignment.CENTER); newCellStyle.setLocked(true); newCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); newCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + newCellStyle.setBorderTop(BorderStyle.THIN); newCellStyle.setBorderBottom(BorderStyle.THIN); newCellStyle.setBorderLeft(BorderStyle.THIN); + newCellStyle.setBorderRight(BorderStyle.THIN); return newCellStyle; } /** + * Build head cell style * * @param workbook - * @param f - * @param indexedColors + * @param writeCellStyle * @return */ - public static CellStyle buildCellStyle(Workbook workbook, com.alibaba.excel.metadata.Font f, - IndexedColors indexedColors) { + public static CellStyle buildHeadCellStyle(Workbook workbook, WriteCellStyle writeCellStyle) { CellStyle cellStyle = buildDefaultCellStyle(workbook); - if (f != null) { - Font font = workbook.createFont(); - font.setFontName(f.getFontName()); - font.setFontHeightInPoints(f.getFontHeightInPoints()); - font.setBold(f.isBold()); - cellStyle.setFont(font); + if (writeCellStyle == null) { + return cellStyle; } - if (indexedColors != null) { - cellStyle.setFillForegroundColor(indexedColors.getIndex()); + buildCellStyle(workbook, cellStyle, writeCellStyle, true); + return cellStyle; + } + + /** + * Build content cell style + * + * @param workbook + * @param writeCellStyle + * @return + */ + public static CellStyle buildContentCellStyle(Workbook workbook, WriteCellStyle writeCellStyle) { + CellStyle cellStyle = workbook.createCellStyle(); + if (writeCellStyle == null) { + return cellStyle; } + buildCellStyle(workbook, cellStyle, writeCellStyle, false); return cellStyle; } - public static Sheet buildSheetStyle(Sheet currentSheet, Map sheetWidthMap){ - currentSheet.setDefaultColumnWidth(20); - for (Map.Entry entry : sheetWidthMap.entrySet()) { - currentSheet.setColumnWidth(entry.getKey(), entry.getValue()); + private static void buildCellStyle(Workbook workbook, CellStyle cellStyle, WriteCellStyle writeCellStyle, + boolean isHead) { + buildFont(workbook, cellStyle, writeCellStyle.getWriteFont(), isHead); + if (writeCellStyle.getDataFormat() != null) { + cellStyle.setDataFormat(writeCellStyle.getDataFormat()); + } + if (writeCellStyle.getHidden() != null) { + cellStyle.setHidden(writeCellStyle.getHidden()); + } + if (writeCellStyle.getLocked() != null) { + cellStyle.setLocked(writeCellStyle.getLocked()); + } + if (writeCellStyle.getQuotePrefix() != null) { + cellStyle.setQuotePrefixed(writeCellStyle.getQuotePrefix()); + } + if (writeCellStyle.getHorizontalAlignment() != null) { + cellStyle.setAlignment(writeCellStyle.getHorizontalAlignment()); + } + if (writeCellStyle.getWrapped() != null) { + cellStyle.setWrapText(writeCellStyle.getWrapped()); + } + if (writeCellStyle.getVerticalAlignment() != null) { + cellStyle.setVerticalAlignment(writeCellStyle.getVerticalAlignment()); + } + if (writeCellStyle.getRotation() != null) { + cellStyle.setRotation(writeCellStyle.getRotation()); + } + if (writeCellStyle.getIndent() != null) { + cellStyle.setIndention(writeCellStyle.getIndent()); + } + if (writeCellStyle.getBorderLeft() != null) { + cellStyle.setBorderLeft(writeCellStyle.getBorderLeft()); + } + if (writeCellStyle.getBorderRight() != null) { + cellStyle.setBorderRight(writeCellStyle.getBorderRight()); + } + if (writeCellStyle.getBorderTop() != null) { + cellStyle.setBorderTop(writeCellStyle.getBorderTop()); + } + if (writeCellStyle.getBorderBottom() != null) { + cellStyle.setBorderBottom(writeCellStyle.getBorderBottom()); + } + if (writeCellStyle.getLeftBorderColor() != null) { + cellStyle.setLeftBorderColor(writeCellStyle.getLeftBorderColor()); + } + if (writeCellStyle.getRightBorderColor() != null) { + cellStyle.setRightBorderColor(writeCellStyle.getRightBorderColor()); + } + if (writeCellStyle.getTopBorderColor() != null) { + cellStyle.setTopBorderColor(writeCellStyle.getTopBorderColor()); + } + if (writeCellStyle.getBottomBorderColor() != null) { + cellStyle.setBottomBorderColor(writeCellStyle.getBottomBorderColor()); + } + if (writeCellStyle.getFillPatternType() != null) { + cellStyle.setFillPattern(writeCellStyle.getFillPatternType()); + } + if (writeCellStyle.getFillBackgroundColor() != null) { + cellStyle.setFillBackgroundColor(writeCellStyle.getFillBackgroundColor()); + } + if (writeCellStyle.getFillForegroundColor() != null) { + cellStyle.setFillForegroundColor(writeCellStyle.getFillForegroundColor()); + } + if (writeCellStyle.getShrinkToFit() != null) { + cellStyle.setShrinkToFit(writeCellStyle.getShrinkToFit()); } - return currentSheet; } + private static void buildFont(Workbook workbook, CellStyle cellStyle, WriteFont writeFont, boolean isHead) { + Font font = null; + if (isHead) { + font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short)14); + font.setBold(true); + cellStyle.setFont(font); + } + if (writeFont == null) { + return; + } + if (!isHead) { + font = workbook.createFont(); + cellStyle.setFont(font); + } + if (writeFont.getFontName() != null) { + font.setFontName(writeFont.getFontName()); + } + if (writeFont.getFontHeightInPoints() != null) { + font.setFontHeightInPoints(writeFont.getFontHeightInPoints()); + } + if (writeFont.getItalic() != null) { + font.setItalic(writeFont.getItalic()); + } + if (writeFont.getStrikeout() != null) { + font.setStrikeout(writeFont.getStrikeout()); + } + if (writeFont.getColor() != null) { + font.setColor(writeFont.getColor()); + } + if (writeFont.getTypeOffset() != null) { + font.setTypeOffset(writeFont.getTypeOffset()); + } + if (writeFont.getUnderline() != null) { + font.setUnderline(writeFont.getUnderline()); + } + if (writeFont.getCharset() != null) { + font.setCharSet(writeFont.getCharset()); + } + if (writeFont.getBold() != null) { + font.setBold(writeFont.getBold()); + } + } } diff --git a/src/main/java/com/alibaba/excel/util/TypeUtil.java b/src/main/java/com/alibaba/excel/util/TypeUtil.java deleted file mode 100644 index b79d623..0000000 --- a/src/main/java/com/alibaba/excel/util/TypeUtil.java +++ /dev/null @@ -1,237 +0,0 @@ -package com.alibaba.excel.util; - -import com.alibaba.excel.metadata.ExcelColumnProperty; -import com.alibaba.excel.metadata.ExcelHeadProperty; -import net.sf.cglib.beans.BeanMap; -import org.apache.poi.hssf.usermodel.HSSFDateUtil; - -import java.lang.reflect.Field; -import java.math.BigDecimal; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * @author jipengfei - */ -public class TypeUtil { - - private static List DATE_FORMAT_LIST = new ArrayList(4); - - static { - DATE_FORMAT_LIST.add("yyyy/MM/dd HH:mm:ss"); - DATE_FORMAT_LIST.add("yyyy-MM-dd HH:mm:ss"); - DATE_FORMAT_LIST.add("yyyyMMdd HH:mm:ss"); - } - - private static int getCountOfChar(String value, char c) { - int n = 0; - if (value == null) { - return 0; - } - char[] chars = value.toCharArray(); - for (char cc : chars) { - if (cc == c) { - n++; - } - } - return n; - } - - public static Object convert(String value, Field field, String format, boolean us) { - if (!StringUtils.isEmpty(value)) { - if (Float.class.equals(field.getType())) { - return Float.parseFloat(value); - } - if (Integer.class.equals(field.getType()) || int.class.equals(field.getType())) { - return Integer.parseInt(value); - } - if (Double.class.equals(field.getType()) || double.class.equals(field.getType())) { - if (null != format && !"".equals(format)) { - int n = getCountOfChar(value, '0'); - return Double.parseDouble(TypeUtil.formatFloat0(value, n)); - } else { - return Double.parseDouble(TypeUtil.formatFloat(value)); - } - } - if (Boolean.class.equals(field.getType()) || boolean.class.equals(field.getType())) { - String valueLower = value.toLowerCase(); - if (valueLower.equals("true") || valueLower.equals("false")) { - return Boolean.parseBoolean(value.toLowerCase()); - } - Integer integer = Integer.parseInt(value); - if (integer == 0) { - return false; - } else { - return true; - } - } - if (Long.class.equals(field.getType()) || long.class.equals(field.getType())) { - return Long.parseLong(value); - } - if (Date.class.equals(field.getType())) { - if (value.contains("-") || value.contains("/") || value.contains(":")) { - return getSimpleDateFormatDate(value, format); - } else { - Double d = Double.parseDouble(value); - return HSSFDateUtil.getJavaDate(d, us); - } - } - if (BigDecimal.class.equals(field.getType())) { - return new BigDecimal(value); - } - if(String.class.equals(field.getType())){ - return formatFloat(value); - } - - } - return null; - } - - public static Boolean isNum(Field field) { - if (field == null) { - return false; - } - if (Integer.class.equals(field.getType()) || int.class.equals(field.getType())) { - return true; - } - if (Double.class.equals(field.getType()) || double.class.equals(field.getType())) { - return true; - } - - if (Long.class.equals(field.getType()) || long.class.equals(field.getType())) { - return true; - } - - if (BigDecimal.class.equals(field.getType())) { - return true; - } - return false; - } - - public static Boolean isNum(Object cellValue) { - if (cellValue instanceof Integer - || cellValue instanceof Double - || cellValue instanceof Short - || cellValue instanceof Long - || cellValue instanceof Float - || cellValue instanceof BigDecimal) { - return true; - } - return false; - } - - public static String getDefaultDateString(Date date) { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - return simpleDateFormat.format(date); - - } - - public static Date getSimpleDateFormatDate(String value, String format) { - if (!StringUtils.isEmpty(value)) { - Date date = null; - if (!StringUtils.isEmpty(format)) { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); - try { - date = simpleDateFormat.parse(value); - return date; - } catch (ParseException e) { - } - } - for (String dateFormat : DATE_FORMAT_LIST) { - try { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat); - date = simpleDateFormat.parse(value); - } catch (ParseException e) { - } - if (date != null) { - break; - } - } - - return date; - - } - return null; - - } - - - public static String formatFloat(String value) { - if (null != value && value.contains(".")) { - if (isNumeric(value)) { - try { - BigDecimal decimal = new BigDecimal(value); - BigDecimal setScale = decimal.setScale(10, BigDecimal.ROUND_HALF_DOWN).stripTrailingZeros(); - return setScale.toPlainString(); - } catch (Exception e) { - } - } - } - return value; - } - - public static String formatFloat0(String value, int n) { - if (null != value && value.contains(".")) { - if (isNumeric(value)) { - try { - BigDecimal decimal = new BigDecimal(value); - BigDecimal setScale = decimal.setScale(n, BigDecimal.ROUND_HALF_DOWN); - return setScale.toPlainString(); - } catch (Exception e) { - } - } - } - return value; - } - - public static final Pattern pattern = Pattern.compile("[\\+\\-]?[\\d]+([\\.][\\d]*)?([Ee][+-]?[\\d]+)?$"); - - private static boolean isNumeric(String str) { - Matcher isNum = pattern.matcher(str); - if (!isNum.matches()) { - return false; - } - return true; - } - - public static String formatDate(Date cellValue, String format) { - SimpleDateFormat simpleDateFormat; - if(!StringUtils.isEmpty(format)) { - simpleDateFormat = new SimpleDateFormat(format); - }else { - simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - } - return simpleDateFormat.format(cellValue); - } - - public static String getFieldStringValue(BeanMap beanMap, String fieldName, String format) { - String cellValue = null; - Object value = beanMap.get(fieldName); - if (value != null) { - if (value instanceof Date) { - cellValue = TypeUtil.formatDate((Date)value, format); - } else { - cellValue = value.toString(); - } - } - return cellValue; - } - - public static Map getFieldValues(List stringList, ExcelHeadProperty excelHeadProperty, Boolean use1904WindowDate) { - Map map = new HashMap(); - for (int i = 0; i < stringList.size(); i++) { - ExcelColumnProperty columnProperty = excelHeadProperty.getExcelColumnProperty(i); - if (columnProperty != null) { - Object value = TypeUtil.convert(stringList.get(i), columnProperty.getField(), - columnProperty.getFormat(), use1904WindowDate); - if (value != null) { - map.put(columnProperty.getField().getName(),value); - } - } - } - return map; - } -} diff --git a/src/main/java/com/alibaba/excel/util/WorkBookUtil.java b/src/main/java/com/alibaba/excel/util/WorkBookUtil.java index 5536929..1fa7834 100644 --- a/src/main/java/com/alibaba/excel/util/WorkBookUtil.java +++ b/src/main/java/com/alibaba/excel/util/WorkBookUtil.java @@ -1,75 +1,83 @@ package com.alibaba.excel.util; -import com.alibaba.excel.support.ExcelTypeEnum; +import java.io.IOException; + import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.poifs.filesystem.POIFSFileSystem; -import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; -import java.io.IOException; -import java.io.InputStream; - -import static com.alibaba.excel.util.StyleUtil.buildSheetStyle; +import com.alibaba.excel.support.ExcelTypeEnum; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; /** - * + * * @author jipengfei */ public class WorkBookUtil { - public static Workbook createWorkBook(InputStream templateInputStream, ExcelTypeEnum excelType) throws IOException { - Workbook workbook; - if (ExcelTypeEnum.XLS.equals(excelType)) { - workbook = (templateInputStream == null) ? new HSSFWorkbook() : new HSSFWorkbook( - new POIFSFileSystem(templateInputStream)); - } else { - workbook = (templateInputStream == null) ? new SXSSFWorkbook(500) : new SXSSFWorkbook( - new XSSFWorkbook(templateInputStream)); - } - return workbook; - } - - public static Sheet createOrGetSheet(Workbook workbook, com.alibaba.excel.metadata.Sheet sheet) { - Sheet sheet1 = null; - try { - try { - sheet1 = workbook.getSheetAt(sheet.getSheetNo()-1); - } catch (Exception e) { + public static Workbook createWorkBook(WriteWorkbookHolder writeWorkbookHolder) + throws IOException, InvalidFormatException { + if (ExcelTypeEnum.XLSX.equals(writeWorkbookHolder.getExcelType())) { + XSSFWorkbook xssfWorkbook = null; + if (writeWorkbookHolder.getTemplateFile() != null) { + xssfWorkbook = new XSSFWorkbook(writeWorkbookHolder.getTemplateFile()); } - if (null == sheet1) { - sheet1 = createSheet(workbook, sheet); - buildSheetStyle(sheet1,sheet.getColumnWidthMap()); + if (writeWorkbookHolder.getTemplateInputStream() != null) { + xssfWorkbook = new XSSFWorkbook(writeWorkbookHolder.getTemplateInputStream()); } - } catch (Exception e) { - throw new RuntimeException("constructCurrentSheet error", e); + // When using SXSSFWorkbook, you can't get the actual last line.But we need to read the last line when we + // are using the template, so we cache it + if (xssfWorkbook != null) { + for (int i = 0; i < xssfWorkbook.getNumberOfSheets(); i++) { + writeWorkbookHolder.getTemplateLastRowMap().put(i, xssfWorkbook.getSheetAt(i).getLastRowNum()); + } + return new SXSSFWorkbook(xssfWorkbook); + } + return new SXSSFWorkbook(500); + } + if (writeWorkbookHolder.getTemplateFile() != null) { + return new HSSFWorkbook(new POIFSFileSystem(writeWorkbookHolder.getTemplateFile())); } - return sheet1; + if (writeWorkbookHolder.getTemplateInputStream() != null) { + return new HSSFWorkbook(new POIFSFileSystem(writeWorkbookHolder.getTemplateInputStream())); + } + return new HSSFWorkbook(); } - public static Sheet createSheet(Workbook workbook, com.alibaba.excel.metadata.Sheet sheet) { - return workbook.createSheet(sheet.getSheetName() != null ? sheet.getSheetName() : sheet.getSheetNo() + ""); + public static Sheet createSheet(Workbook workbook, String sheetName) { + return workbook.createSheet(sheetName); } public static Row createRow(Sheet sheet, int rowNum) { return sheet.createRow(rowNum); } - public static Cell createCell(Row row, int colNum, CellStyle cellStyle, String cellValue) { - return createCell(row, colNum, cellStyle, cellValue, false); + public static Cell createCell(Row row, int colNum) { + return row.createCell(colNum); } - public static Cell createCell(Row row, int colNum, CellStyle cellStyle, Object cellValue, Boolean isNum) { + public static Cell createCell(Row row, int colNum, CellStyle cellStyle) { Cell cell = row.createCell(colNum); cell.setCellStyle(cellStyle); - if (null != cellValue) { - if (isNum) { - cell.setCellValue(Double.parseDouble(cellValue.toString())); - } else { - cell.setCellValue(cellValue.toString()); - } - } return cell; } + public static Cell createCell(Row row, int colNum, CellStyle cellStyle, String cellValue) { + Cell cell = createCell(row, colNum, cellStyle); + cell.setCellValue(cellValue); + return cell; + } + + public static Cell createCell(Row row, int colNum, String cellValue) { + Cell cell = row.createCell(colNum); + cell.setCellValue(cellValue); + return cell; + } } diff --git a/src/main/java/com/alibaba/excel/write/ExcelBuilder.java b/src/main/java/com/alibaba/excel/write/ExcelBuilder.java index c016018..119854a 100644 --- a/src/main/java/com/alibaba/excel/write/ExcelBuilder.java +++ b/src/main/java/com/alibaba/excel/write/ExcelBuilder.java @@ -1,48 +1,54 @@ package com.alibaba.excel.write; -import com.alibaba.excel.metadata.Sheet; -import com.alibaba.excel.metadata.Table; - import java.util.List; +import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.WriteTable; + /** * @author jipengfei */ public interface ExcelBuilder { /** - * workBook increase data - * - * @param data java basic type or java model extend BaseModel - * @param startRow Start row number - */ - void addContent(List data, int startRow); - - /** - * WorkBook increase data + * WorkBook increase value * - * @param data java basic type or java model extend BaseModel - * @param sheetParam Write the sheet + * @param data + * java basic type or java model extend BaseModel + * @param writeSheet + * Write the sheet + * @deprecated please use{@link ExcelBuilder#addContent(List, WriteSheet, WriteTable)} */ - void addContent(List data, Sheet sheetParam); + @Deprecated + void addContent(List data, WriteSheet writeSheet); /** - * WorkBook increase data + * WorkBook increase value * - * @param data java basic type or java model extend BaseModel - * @param sheetParam Write the sheet - * @param table Write the table + * @param data + * java basic type or java model extend BaseModel + * @param writeSheet + * Write the sheet + * @param writeTable + * Write the table */ - void addContent(List data, Sheet sheetParam, Table table); + void addContent(List data, WriteSheet writeSheet, WriteTable writeTable); /** * Creates new cell range. Indexes are zero-based. * - * @param firstRow Index of first row - * @param lastRow Index of last row (inclusive), must be equal to or larger than {@code firstRow} - * @param firstCol Index of first column - * @param lastCol Index of last column (inclusive), must be equal to or larger than {@code firstCol} + * @param firstRow + * Index of first row + * @param lastRow + * Index of last row (inclusive), must be equal to or larger than {@code firstRow} + * @param firstCol + * Index of first column + * @param lastCol + * Index of last column (inclusive), must be equal to or larger than {@code firstCol} + * @deprecated please use{@link OnceAbsoluteMergeStrategy} */ + @Deprecated void merge(int firstRow, int lastRow, int firstCol, int lastCol); /** diff --git a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java index 02b37cb..e619e37 100644 --- a/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java +++ b/src/main/java/com/alibaba/excel/write/ExcelBuilderImpl.java @@ -1,27 +1,45 @@ package com.alibaba.excel.write; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.ClientAnchor; +import org.apache.poi.ss.usermodel.CreationHelper; +import org.apache.poi.ss.usermodel.Drawing; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; + import com.alibaba.excel.context.WriteContext; -import com.alibaba.excel.event.WriteHandler; +import com.alibaba.excel.context.WriteContextImpl; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.converters.ConverterKeyBuild; +import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.metadata.BaseRowModel; -import com.alibaba.excel.metadata.ExcelColumnProperty; -import com.alibaba.excel.metadata.Sheet; -import com.alibaba.excel.metadata.Table; -import com.alibaba.excel.support.ExcelTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.util.CollectionUtils; -import com.alibaba.excel.util.POITempFile; -import com.alibaba.excel.util.TypeUtil; +import com.alibaba.excel.util.FileUtils; import com.alibaba.excel.util.WorkBookUtil; -import net.sf.cglib.beans.BeanMap; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.util.CellRangeAddress; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.RowWriteHandler; +import com.alibaba.excel.write.handler.WriteHandler; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.WriteTable; +import com.alibaba.excel.write.metadata.WriteWorkbook; +import com.alibaba.excel.write.metadata.holder.WriteHolder; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.List; +import net.sf.cglib.beans.BeanMap; /** * @author jipengfei @@ -30,113 +48,320 @@ public class ExcelBuilderImpl implements ExcelBuilder { private WriteContext context; - public ExcelBuilderImpl(InputStream templateInputStream, - OutputStream out, - ExcelTypeEnum excelType, - boolean needHead, WriteHandler writeHandler) { + public ExcelBuilderImpl(WriteWorkbook writeWorkbook) { try { - //初始化时候创建临时缓存目录,用于规避POI在并发写bug - POITempFile.createPOIFilesDirectory(); - context = new WriteContext(templateInputStream, out, excelType, needHead, writeHandler); - } catch (Exception e) { - throw new RuntimeException(e); + // Create temporary cache directory at initialization time to avoid POI concurrent write bugs + FileUtils.createPoiFilesDirectory(); + context = new WriteContextImpl(writeWorkbook); + } catch (RuntimeException e) { + finish(); + throw e; + } catch (Throwable e) { + finish(); + throw new ExcelGenerateException(e); } } - @Override - public void addContent(List data, int startRow) { + private void doAddContent(List data) { if (CollectionUtils.isEmpty(data)) { return; } - int rowNum = context.getCurrentSheet().getLastRowNum(); - if (rowNum == 0) { - Row row = context.getCurrentSheet().getRow(0); - if (row == null) { - if (context.getExcelHeadProperty() == null || !context.needHead()) { - rowNum = -1; - } - } - } - if (rowNum < startRow) { - rowNum = startRow; + WriteSheetHolder writeSheetHolder = context.writeSheetHolder(); + int newRowIndex = writeSheetHolder.getNewRowIndexAndStartDoWrite(); + if (writeSheetHolder.isNew() && !writeSheetHolder.getExcelWriteHeadProperty().hasHead()) { + newRowIndex += context.currentWriteHolder().relativeHeadRowIndex(); } - for (int i = 0; i < data.size(); i++) { - int n = i + rowNum + 1; - addOneRowOfDataToExcel(data.get(i), n); + // BeanMap is out of order,so use fieldList + List fieldList = new ArrayList(); + for (int relativeRowIndex = 0; relativeRowIndex < data.size(); relativeRowIndex++) { + int n = relativeRowIndex + newRowIndex; + addOneRowOfDataToExcel(data.get(relativeRowIndex), n, relativeRowIndex, fieldList); } } @Override - public void addContent(List data, Sheet sheetParam) { - context.currentSheet(sheetParam); - addContent(data, sheetParam.getStartRow()); + public void addContent(List data, WriteSheet writeSheet) { + addContent(data, writeSheet, null); } @Override - public void addContent(List data, Sheet sheetParam, Table table) { - context.currentSheet(sheetParam); - context.currentTable(table); - addContent(data, sheetParam.getStartRow()); + public void addContent(List data, WriteSheet writeSheet, WriteTable writeTable) { + try { + context.currentSheet(writeSheet); + context.currentTable(writeTable); + doAddContent(data); + } catch (RuntimeException e) { + finish(); + throw e; + } catch (Throwable e) { + finish(); + throw new ExcelGenerateException(e); + } + } + + @Override + public void finish() { + if (context != null) { + context.finish(); + } } @Override public void merge(int firstRow, int lastRow, int firstCol, int lastCol) { CellRangeAddress cra = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol); - context.getCurrentSheet().addMergedRegion(cra); + context.writeSheetHolder().getSheet().addMergedRegion(cra); } - @Override - public void finish() { - try { - context.getWorkbook().write(context.getOutputStream()); - context.getWorkbook().close(); - } catch (IOException e) { - throw new ExcelGenerateException("IO error", e); + private void addOneRowOfDataToExcel(Object oneRowData, int n, int relativeRowIndex, List fieldList) { + beforeRowCreate(n, relativeRowIndex); + Row row = WorkBookUtil.createRow(context.writeSheetHolder().getSheet(), n); + afterRowCreate(row, relativeRowIndex); + if (oneRowData instanceof List) { + addBasicTypeToExcel((List)oneRowData, row, relativeRowIndex); + } else { + addJavaObjectToExcel(oneRowData, row, relativeRowIndex, fieldList); + } + } + + private void beforeRowCreate(int rowIndex, int relativeRowIndex) { + List handlerList = context.currentWriteHolder().writeHandlerMap().get(RowWriteHandler.class); + if (handlerList == null || handlerList.isEmpty()) { + return; + } + for (WriteHandler writeHandler : handlerList) { + if (writeHandler instanceof RowWriteHandler) { + ((RowWriteHandler)writeHandler).beforeRowCreate(context.writeSheetHolder(), context.writeTableHolder(), + rowIndex, relativeRowIndex, false); + } } } - private void addBasicTypeToExcel(List oneRowData, Row row) { + private void afterRowCreate(Row row, int relativeRowIndex) { + List handlerList = context.currentWriteHolder().writeHandlerMap().get(RowWriteHandler.class); + if (handlerList == null || handlerList.isEmpty()) { + return; + } + for (WriteHandler writeHandler : handlerList) { + if (writeHandler instanceof RowWriteHandler) { + ((RowWriteHandler)writeHandler).afterRowCreate(context.writeSheetHolder(), context.writeTableHolder(), + row, relativeRowIndex, false); + } + } + if (null != context.writeWorkbookHolder().getWriteWorkbook().getWriteHandler()) { + context.writeWorkbookHolder().getWriteWorkbook().getWriteHandler().row(row.getRowNum(), row); + } + } + + private void addBasicTypeToExcel(List oneRowData, Row row, int relativeRowIndex) { if (CollectionUtils.isEmpty(oneRowData)) { return; } - for (int i = 0; i < oneRowData.size(); i++) { - Object cellValue = oneRowData.get(i); - Cell cell = WorkBookUtil.createCell(row, i, context.getCurrentContentStyle(), cellValue, - TypeUtil.isNum(cellValue)); - if (null != context.getAfterWriteHandler()) { - context.getAfterWriteHandler().cell(i, cell); + Map headMap = context.currentWriteHolder().excelWriteHeadProperty().getHeadMap(); + int dataIndex = 0; + int cellIndex = 0; + for (Map.Entry entry : headMap.entrySet()) { + if (dataIndex >= oneRowData.size()) { + return; } + cellIndex = entry.getKey(); + Head head = entry.getValue(); + doAddBasicTypeToExcel(oneRowData, head, row, relativeRowIndex, dataIndex++, cellIndex); + } + // Finish + if (dataIndex >= oneRowData.size()) { + return; + } + if (cellIndex != 0) { + cellIndex++; + } + for (int i = 0; i < oneRowData.size() - dataIndex; i++) { + doAddBasicTypeToExcel(oneRowData, null, row, relativeRowIndex, dataIndex++, cellIndex++); } } - private void addJavaObjectToExcel(Object oneRowData, Row row) { - int i = 0; + private void doAddBasicTypeToExcel(List oneRowData, Head head, Row row, int relativeRowIndex, int dataIndex, + int cellIndex) { + beforeCellCreate(row, head, relativeRowIndex); + Cell cell = WorkBookUtil.createCell(row, cellIndex); + Object value = oneRowData.get(dataIndex); + CellData cellData = converterAndSet(context.currentWriteHolder(), value.getClass(), cell, value, null); + afterCellCreate(head, cellData, cell, relativeRowIndex); + } + + private void addJavaObjectToExcel(Object oneRowData, Row row, int relativeRowIndex, List fieldList) { + WriteHolder currentWriteHolder = context.currentWriteHolder(); BeanMap beanMap = BeanMap.create(oneRowData); - for (ExcelColumnProperty excelHeadProperty : context.getExcelHeadProperty().getColumnPropertyList()) { - BaseRowModel baseRowModel = (BaseRowModel)oneRowData; - String cellValue = TypeUtil.getFieldStringValue(beanMap, excelHeadProperty.getField().getName(), - excelHeadProperty.getFormat()); - CellStyle cellStyle = baseRowModel.getStyle(i) != null ? baseRowModel.getStyle(i) - : context.getCurrentContentStyle(); - Cell cell = WorkBookUtil.createCell(row, i, cellStyle, cellValue, - TypeUtil.isNum(excelHeadProperty.getField())); - if (null != context.getAfterWriteHandler()) { - context.getAfterWriteHandler().cell(i, cell); + Set beanMapHandledSet = new HashSet(); + Map headMap = context.currentWriteHolder().excelWriteHeadProperty().getHeadMap(); + Map contentPropertyMap = + context.currentWriteHolder().excelWriteHeadProperty().getContentPropertyMap(); + int cellIndex = 0; + for (Map.Entry entry : contentPropertyMap.entrySet()) { + cellIndex = entry.getKey(); + ExcelContentProperty excelContentProperty = entry.getValue(); + String name = excelContentProperty.getField().getName(); + if (!beanMap.containsKey(name)) { + continue; } - i++; + Head head = headMap.get(cellIndex); + beforeCellCreate(row, head, relativeRowIndex); + Cell cell = WorkBookUtil.createCell(row, cellIndex); + Object value = beanMap.get(name); + CellData cellData = converterAndSet(currentWriteHolder, excelContentProperty.getField().getType(), cell, + value, excelContentProperty); + afterCellCreate(head, cellData, cell, relativeRowIndex); + beanMapHandledSet.add(name); + } + // Finish + if (beanMapHandledSet.size() == beanMap.size()) { + return; + } + if (cellIndex != 0) { + cellIndex++; } + Map ignoreMap = context.currentWriteHolder().excelWriteHeadProperty().getIgnoreMap(); + initFieldList(oneRowData.getClass(), fieldList); + for (Field field : fieldList) { + String filedName = field.getName(); + boolean uselessData = !beanMap.containsKey(filedName) || beanMapHandledSet.contains(filedName) + || ignoreMap.containsKey(filedName); + if (uselessData) { + continue; + } + Object value = beanMap.get(filedName); + if (value == null) { + continue; + } + beforeCellCreate(row, null, relativeRowIndex); + Cell cell = WorkBookUtil.createCell(row, cellIndex++); + CellData cellData = converterAndSet(currentWriteHolder, value.getClass(), cell, value, null); + afterCellCreate(null, cellData, cell, relativeRowIndex); + } + } + private void initFieldList(Class clazz, List fieldList) { + if (!fieldList.isEmpty()) { + return; + } + Class tempClass = clazz; + while (tempClass != null) { + if (tempClass != BaseRowModel.class) { + Collections.addAll(fieldList, tempClass.getDeclaredFields()); + } + tempClass = tempClass.getSuperclass(); + } } - private void addOneRowOfDataToExcel(Object oneRowData, int n) { - Row row = WorkBookUtil.createRow(context.getCurrentSheet(), n); - if (null != context.getAfterWriteHandler()) { - context.getAfterWriteHandler().row(n, row); + private void beforeCellCreate(Row row, Head head, int relativeRowIndex) { + List handlerList = context.currentWriteHolder().writeHandlerMap().get(CellWriteHandler.class); + if (handlerList == null || handlerList.isEmpty()) { + return; } - if (oneRowData instanceof List) { - addBasicTypeToExcel((List)oneRowData, row); - } else { - addJavaObjectToExcel(oneRowData, row); + for (WriteHandler writeHandler : handlerList) { + if (writeHandler instanceof CellWriteHandler) { + ((CellWriteHandler)writeHandler).beforeCellCreate(context.writeSheetHolder(), + context.writeTableHolder(), row, head, relativeRowIndex, false); + } + } + + } + + private void afterCellCreate(Head head, CellData cellData, Cell cell, int relativeRowIndex) { + List handlerList = context.currentWriteHolder().writeHandlerMap().get(CellWriteHandler.class); + if (handlerList == null || handlerList.isEmpty()) { + return; + } + for (WriteHandler writeHandler : handlerList) { + if (writeHandler instanceof CellWriteHandler) { + ((CellWriteHandler)writeHandler).afterCellCreate(context.writeSheetHolder(), context.writeTableHolder(), + cellData, cell, head, relativeRowIndex, false); + } + } + if (null != context.writeWorkbookHolder().getWriteWorkbook().getWriteHandler()) { + context.writeWorkbookHolder().getWriteWorkbook().getWriteHandler().cell(cell.getRowIndex(), cell); + } + } + + private CellData converterAndSet(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value, + ExcelContentProperty excelContentProperty) { + if (value == null) { + return null; + } + if (value instanceof String && currentWriteHolder.globalConfiguration().getAutoTrim()) { + value = ((String)value).trim(); + } + CellData cellData = convert(currentWriteHolder, clazz, cell, value, excelContentProperty); + if (cellData == null || cellData.getType() == null) { + throw new ExcelDataConvertException( + "Convert data:" + value + " return null,at row:" + cell.getRow().getRowNum()); + } + if (cellData.getFormula() != null && cellData.getFormula()) { + cell.setCellFormula(cellData.getFormulaValue()); + } + switch (cellData.getType()) { + case STRING: + cell.setCellValue(cellData.getStringValue()); + return cellData; + case BOOLEAN: + cell.setCellValue(cellData.getBooleanValue()); + return cellData; + case NUMBER: + cell.setCellValue(cellData.getDoubleValue()); + return cellData; + case IMAGE: + setImageValue(cellData, cell); + return cellData; + default: + throw new ExcelDataConvertException("Not supported data:" + value + " return type:" + cell.getCellType() + + "at row:" + cell.getRow().getRowNum()); + } + } + + private void setImageValue(CellData cellData, Cell cell) { + Sheet sheet = cell.getSheet(); + int index = sheet.getWorkbook().addPicture(cellData.getImageValue(), HSSFWorkbook.PICTURE_TYPE_PNG); + Drawing drawing = sheet.getDrawingPatriarch(); + if (drawing == null) { + drawing = sheet.createDrawingPatriarch(); + } + CreationHelper helper = sheet.getWorkbook().getCreationHelper(); + ClientAnchor anchor = helper.createClientAnchor(); + anchor.setDx1(0); + anchor.setDx2(0); + anchor.setDy1(0); + anchor.setDy2(0); + anchor.setCol1(cell.getColumnIndex()); + anchor.setCol2(cell.getColumnIndex() + 1); + anchor.setRow1(cell.getRowIndex()); + anchor.setRow2(cell.getRowIndex() + 1); + anchor.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE); + drawing.createPicture(anchor, index); + } + + private CellData convert(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value, + ExcelContentProperty excelContentProperty) { + if (value instanceof CellData) { + return (CellData)value; + } + Converter converter = null; + if (excelContentProperty != null) { + converter = excelContentProperty.getConverter(); + } + if (converter == null) { + converter = currentWriteHolder.converterMap().get(ConverterKeyBuild.buildKey(clazz)); + } + if (converter == null) { + throw new ExcelDataConvertException( + "Can not find 'Converter' support class " + clazz.getSimpleName() + "."); + } + CellData cellData; + try { + cellData = + converter.convertToExcelData(value, excelContentProperty, currentWriteHolder.globalConfiguration()); + } catch (Exception e) { + throw new ExcelDataConvertException("Convert data:" + value + " error,at row:" + cell.getRow().getRowNum(), + e); } + return cellData; } } diff --git a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java new file mode 100644 index 0000000..5e699c3 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java @@ -0,0 +1,198 @@ +package com.alibaba.excel.write.builder; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.support.ExcelTypeEnum; +import com.alibaba.excel.write.handler.WriteHandler; +import com.alibaba.excel.write.metadata.WriteWorkbook; + +/** + * Build ExcelBuilder + * + * @author Jiaju Zhuang + */ +public class ExcelWriterBuilder { + /** + * Workbook + */ + private WriteWorkbook writeWorkbook; + + public ExcelWriterBuilder() { + this.writeWorkbook = new WriteWorkbook(); + } + + /** + * Writes the head relative to the existing contents of the sheet. Indexes are zero-based. + * + * @param relativeHeadRowIndex + * @return + */ + public ExcelWriterBuilder relativeHeadRowIndex(Integer relativeHeadRowIndex) { + writeWorkbook.setRelativeHeadRowIndex(relativeHeadRowIndex); + return this; + } + + /** + * You can only choose one of the {@link ExcelWriterBuilder#head(List)} and {@link ExcelWriterBuilder#head(Class)} + * + * @param head + * @return + */ + public ExcelWriterBuilder head(List> head) { + writeWorkbook.setHead(head); + return this; + } + + /** + * You can only choose one of the {@link ExcelWriterBuilder#head(List)} and {@link ExcelWriterBuilder#head(Class)} + * + * @param clazz + * @return + */ + public ExcelWriterBuilder head(Class clazz) { + writeWorkbook.setClazz(clazz); + return this; + } + + /** + * Need Head + */ + public ExcelWriterBuilder needHead(Boolean needHead) { + writeWorkbook.setNeedHead(needHead); + return this; + } + + /** + * Default true + * + * @param autoCloseStream + * @return + */ + public ExcelWriterBuilder autoCloseStream(Boolean autoCloseStream) { + writeWorkbook.setAutoCloseStream(autoCloseStream); + return this; + } + + /** + * The default is all excel objects.if true , you can use {@link com.alibaba.excel.annotation.ExcelIgnore} ignore a + * field. if false , you must use {@link com.alibaba.excel.annotation.ExcelProperty} to use a filed. + *

+ * Default true + * + * @param convertAllFiled + * @return + * @deprecated Just to be compatible with historical data, The default is always going to be convert all filed. + */ + @Deprecated + public ExcelWriterBuilder convertAllFiled(Boolean convertAllFiled) { + writeWorkbook.setConvertAllFiled(convertAllFiled); + return this; + } + + /** + * Custom type conversions override the default. + * + * @param converter + * @return + */ + public ExcelWriterBuilder registerConverter(Converter converter) { + if (writeWorkbook.getCustomConverterList() == null) { + writeWorkbook.setCustomConverterList(new ArrayList()); + } + writeWorkbook.getCustomConverterList().add(converter); + return this; + } + + /** + * Custom write handler + * + * @param writeHandler + * @return + */ + public ExcelWriterBuilder registerWriteHandler(WriteHandler writeHandler) { + if (writeWorkbook.getCustomWriteHandlerList() == null) { + writeWorkbook.setCustomWriteHandlerList(new ArrayList()); + } + writeWorkbook.getCustomWriteHandlerList().add(writeHandler); + return this; + } + + public ExcelWriterBuilder excelType(ExcelTypeEnum excelType) { + writeWorkbook.setExcelType(excelType); + return this; + } + + public ExcelWriterBuilder file(OutputStream outputStream) { + writeWorkbook.setOutputStream(outputStream); + return this; + } + + public ExcelWriterBuilder file(File outputFile) { + writeWorkbook.setFile(outputFile); + return this; + } + + public ExcelWriterBuilder file(String outputPathName) { + return file(new File(outputPathName)); + } + + public ExcelWriterBuilder withTemplate(InputStream templateInputStream) { + writeWorkbook.setTemplateInputStream(templateInputStream); + return this; + } + + public ExcelWriterBuilder withTemplate(File templateFile) { + writeWorkbook.setTemplateFile(templateFile); + return this; + } + + public ExcelWriterBuilder withTemplate(String pathName) { + return withTemplate(new File(pathName)); + } + + /** + * Write handler + * + * @deprecated please use {@link WriteHandler} + */ + @Deprecated + public ExcelWriterBuilder registerWriteHandler(com.alibaba.excel.event.WriteHandler writeHandler) { + writeWorkbook.setWriteHandler(writeHandler); + return this; + } + + public ExcelWriter build() { + return new ExcelWriter(writeWorkbook); + } + + public ExcelWriterSheetBuilder sheet() { + return sheet(null, null); + } + + public ExcelWriterSheetBuilder sheet(Integer sheetNo) { + return sheet(sheetNo, null); + } + + public ExcelWriterSheetBuilder sheet(String sheetName) { + return sheet(null, sheetName); + } + + public ExcelWriterSheetBuilder sheet(Integer sheetNo, String sheetName) { + ExcelWriter excelWriter = build(); + ExcelWriterSheetBuilder excelWriterSheetBuilder = new ExcelWriterSheetBuilder(excelWriter); + if (sheetNo != null) { + excelWriterSheetBuilder.sheetNo(sheetNo); + } + if (sheetName != null) { + excelWriterSheetBuilder.sheetName(sheetName); + } + return excelWriterSheetBuilder; + } + +} diff --git a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java new file mode 100644 index 0000000..bab837d --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java @@ -0,0 +1,150 @@ +package com.alibaba.excel.write.builder; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.exception.ExcelGenerateException; +import com.alibaba.excel.write.handler.WriteHandler; +import com.alibaba.excel.write.metadata.WriteSheet; + +/** + * Build sheet + * + * @author Jiaju Zhuang + */ +public class ExcelWriterSheetBuilder { + private ExcelWriter excelWriter; + /** + * Sheet + */ + private WriteSheet writeSheet; + + public ExcelWriterSheetBuilder() { + this.writeSheet = new WriteSheet(); + } + + public ExcelWriterSheetBuilder(ExcelWriter excelWriter) { + this.writeSheet = new WriteSheet(); + this.excelWriter = excelWriter; + } + + /** + * Writes the head relative to the existing contents of the sheet. Indexes are zero-based. + * + * @param relativeHeadRowIndex + * @return + */ + public ExcelWriterSheetBuilder relativeHeadRowIndex(Integer relativeHeadRowIndex) { + writeSheet.setRelativeHeadRowIndex(relativeHeadRowIndex); + return this; + } + + /** + * You can only choose one of the {@link ExcelWriterSheetBuilder#head(List)} and + * {@link ExcelWriterSheetBuilder#head(Class)} + * + * @param head + * @return + */ + public ExcelWriterSheetBuilder head(List> head) { + writeSheet.setHead(head); + return this; + } + + /** + * You can only choose one of the {@link ExcelWriterSheetBuilder#head(List)} and + * {@link ExcelWriterSheetBuilder#head(Class)} + * + * @param clazz + * @return + */ + public ExcelWriterSheetBuilder head(Class clazz) { + writeSheet.setClazz(clazz); + return this; + } + + /** + * Need Head + */ + public ExcelWriterSheetBuilder needHead(Boolean needHead) { + writeSheet.setNeedHead(needHead); + return this; + } + + /** + * Custom type conversions override the default. + * + * @param converter + * @return + */ + public ExcelWriterSheetBuilder registerConverter(Converter converter) { + if (writeSheet.getCustomConverterList() == null) { + writeSheet.setCustomConverterList(new ArrayList()); + } + writeSheet.getCustomConverterList().add(converter); + return this; + } + + /** + * Custom write handler + * + * @param writeHandler + * @return + */ + public ExcelWriterSheetBuilder registerWriteHandler(WriteHandler writeHandler) { + if (writeSheet.getCustomWriteHandlerList() == null) { + writeSheet.setCustomWriteHandlerList(new ArrayList()); + } + writeSheet.getCustomWriteHandlerList().add(writeHandler); + return this; + } + + /** + * Starting from 0 + * + * @param sheetNo + * @return + */ + public ExcelWriterSheetBuilder sheetNo(Integer sheetNo) { + writeSheet.setSheetNo(sheetNo); + return this; + } + + /** + * sheet name + * + * @param sheetName + * @return + */ + public ExcelWriterSheetBuilder sheetName(String sheetName) { + writeSheet.setSheetName(sheetName); + return this; + } + + public WriteSheet build() { + return writeSheet; + } + + public void doWrite(List data) { + if (excelWriter == null) { + throw new ExcelGenerateException("Must use 'EasyExcelFactory.write().sheet()' to call this method"); + } + excelWriter.write(data, build()); + excelWriter.finish(); + } + + public ExcelWriterTableBuilder table() { + return table(null); + } + + public ExcelWriterTableBuilder table(Integer tableNo) { + ExcelWriterTableBuilder excelWriterTableBuilder = new ExcelWriterTableBuilder(excelWriter, build()); + if (tableNo != null) { + excelWriterTableBuilder.tableNo(tableNo); + } + return excelWriterTableBuilder; + } + +} diff --git a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java new file mode 100644 index 0000000..14f755a --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java @@ -0,0 +1,132 @@ +package com.alibaba.excel.write.builder; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.exception.ExcelGenerateException; +import com.alibaba.excel.write.handler.WriteHandler; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.WriteTable; + +/** + * Build sheet + * + * @author Jiaju Zhuang + */ +public class ExcelWriterTableBuilder { + + private ExcelWriter excelWriter; + + private WriteSheet writeSheet; + /** + * table + */ + private WriteTable writeTable; + + public ExcelWriterTableBuilder() { + this.writeTable = new WriteTable(); + } + + public ExcelWriterTableBuilder(ExcelWriter excelWriter, WriteSheet writeSheet) { + this.excelWriter = excelWriter; + this.writeSheet = writeSheet; + this.writeTable = new WriteTable(); + } + + /** + * Writes the head relative to the existing contents of the sheet. Indexes are zero-based. + * + * @param relativeHeadRowIndex + * @return + */ + public ExcelWriterTableBuilder relativeHeadRowIndex(Integer relativeHeadRowIndex) { + writeTable.setRelativeHeadRowIndex(relativeHeadRowIndex); + return this; + } + + /** + * You can only choose one of the {@link ExcelWriterTableBuilder#head(List)} and + * {@link ExcelWriterTableBuilder#head(Class)} + * + * @param head + * @return + */ + public ExcelWriterTableBuilder head(List> head) { + writeTable.setHead(head); + return this; + } + + /** + * You can only choose one of the {@link ExcelWriterTableBuilder#head(List)} and + * {@link ExcelWriterTableBuilder#head(Class)} + * + * @param clazz + * @return + */ + public ExcelWriterTableBuilder head(Class clazz) { + writeTable.setClazz(clazz); + return this; + } + + /** + * Need Head + */ + public ExcelWriterTableBuilder needHead(Boolean needHead) { + writeTable.setNeedHead(needHead); + return this; + } + + /** + * Custom type conversions override the default. + * + * @param converter + * @return + */ + public ExcelWriterTableBuilder registerConverter(Converter converter) { + if (writeTable.getCustomConverterList() == null) { + writeTable.setCustomConverterList(new ArrayList()); + } + writeTable.getCustomConverterList().add(converter); + return this; + } + + /** + * Custom write handler + * + * @param writeHandler + * @return + */ + public ExcelWriterTableBuilder registerWriteHandler(WriteHandler writeHandler) { + if (writeTable.getCustomWriteHandlerList() == null) { + writeTable.setCustomWriteHandlerList(new ArrayList()); + } + writeTable.getCustomWriteHandlerList().add(writeHandler); + return this; + } + + /** + * Starting from 0 + * + * @param tableNo + * @return + */ + public ExcelWriterTableBuilder tableNo(Integer tableNo) { + writeTable.setTableNo(tableNo); + return this; + } + + public WriteTable build() { + return writeTable; + } + + public void doWrite(List data) { + if (excelWriter == null) { + throw new ExcelGenerateException("Must use 'EasyExcelFactory.write().sheet().table()' to call this method"); + } + excelWriter.write(data, writeSheet, build()); + excelWriter.finish(); + } + +} diff --git a/src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java new file mode 100644 index 0000000..9e8af22 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java @@ -0,0 +1,47 @@ +package com.alibaba.excel.write.handler; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; + +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; + +/** + * intercepts handle cell creation + * + * @author Jiaju Zhuang + */ +public interface CellWriteHandler extends WriteHandler { + + /** + * called before create the cell + * + * @param writeSheetHolder + * @param writeTableHolder + * Nullable + * @param row + * @param head + * @param relativeRowIndex + * @param isHead + */ + void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, + int relativeRowIndex, boolean isHead); + + /** + * called after the cell is created + * + * @param writeSheetHolder + * @param writeTableHolder + * Nullable + * @param cell + * @param head + * @param cellData + * Nullable. + * @param relativeRowIndex + * @param isHead + */ + void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, + Cell cell, Head head, int relativeRowIndex, boolean isHead); +} diff --git a/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java b/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java new file mode 100644 index 0000000..f52af6b --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/handler/DefaultWriteHandlerLoader.java @@ -0,0 +1,37 @@ +package com.alibaba.excel.write.handler; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.poi.ss.usermodel.IndexedColors; + +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; + +/** + * Load default handler + * + * @author Jiaju Zhuang + */ +public class DefaultWriteHandlerLoader { + + /** + * Load default handler + * + * @return + */ + public static List loadDefaultHandler() { + List handlerList = new ArrayList(); + WriteCellStyle headWriteCellStyle = new WriteCellStyle(); + headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + WriteFont headWriteFont = new WriteFont(); + headWriteFont.setFontName("宋体"); + headWriteFont.setFontHeightInPoints((short)14); + headWriteFont.setBold(true); + headWriteCellStyle.setWriteFont(headWriteFont); + handlerList.add(new HorizontalCellStyleStrategy(headWriteCellStyle, new ArrayList())); + return handlerList; + } + +} diff --git a/src/main/java/com/alibaba/excel/write/handler/RowWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/RowWriteHandler.java new file mode 100644 index 0000000..1630bd3 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/handler/RowWriteHandler.java @@ -0,0 +1,40 @@ +package com.alibaba.excel.write.handler; + +import org.apache.poi.ss.usermodel.Row; + +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; + +/** + * intercepts handle row creation + * + * @author Jiaju Zhuang + */ +public interface RowWriteHandler extends WriteHandler { + + /** + * called before create the row + * + * @param writeSheetHolder + * @param writeTableHolder + * Nullable + * @param rowIndex + * @param relativeRowIndex + * @param isHead + */ + void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, int rowIndex, + int relativeRowIndex, boolean isHead); + + /** + * called after the row is created + * + * @param writeSheetHolder + * @param writeTableHolder + * Nullable + * @param row + * @param relativeRowIndex + * @param isHead + */ + void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + int relativeRowIndex, boolean isHead); +} diff --git a/src/main/java/com/alibaba/excel/write/handler/SheetWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/SheetWriteHandler.java new file mode 100644 index 0000000..080abbf --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/handler/SheetWriteHandler.java @@ -0,0 +1,28 @@ +package com.alibaba.excel.write.handler; + +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; + +/** + * intercepts handle sheet creation + * + * @author Jiaju Zhuang + */ +public interface SheetWriteHandler extends WriteHandler { + + /** + * called before create the sheet + * + * @param writeWorkbookHolder + * @param writeSheetHolder + */ + void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder); + + /** + * called after the sheet is created + * + * @param writeWorkbookHolder + * @param writeSheetHolder + */ + void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder); +} diff --git a/src/main/java/com/alibaba/excel/write/handler/WorkbookWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/WorkbookWriteHandler.java new file mode 100644 index 0000000..508c9c5 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/handler/WorkbookWriteHandler.java @@ -0,0 +1,23 @@ +package com.alibaba.excel.write.handler; + +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; + +/** + * intercepts handle Workbook creation + * + * @author Jiaju Zhuang + */ +public interface WorkbookWriteHandler extends WriteHandler { + + /** + * called before create the sheet + */ + void beforeWorkbookCreate(); + + /** + * called after the sheet is created + * + * @param writeWorkbookHolder + */ + void afterWorkbookCreate(WriteWorkbookHolder writeWorkbookHolder); +} diff --git a/src/main/java/com/alibaba/excel/write/handler/WriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/WriteHandler.java new file mode 100644 index 0000000..3864ac7 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/handler/WriteHandler.java @@ -0,0 +1,10 @@ +package com.alibaba.excel.write.handler; + +import com.alibaba.excel.event.Handler; + +/** + * intercepts handle excel write + * + * @author Jiaju Zhuang + */ +public interface WriteHandler extends Handler {} diff --git a/src/main/java/com/alibaba/excel/write/merge/AbstractMergeStrategy.java b/src/main/java/com/alibaba/excel/write/merge/AbstractMergeStrategy.java new file mode 100644 index 0000000..7b95f1c --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/merge/AbstractMergeStrategy.java @@ -0,0 +1,43 @@ +package com.alibaba.excel.write.merge; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; + +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; + +/** + * Merge strategy + * + * @author Jiaju Zhuang + */ +public abstract class AbstractMergeStrategy implements CellWriteHandler { + @Override + public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Head head, int relativeRowIndex, boolean isHead) { + + } + + @Override + public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, + Cell cell, Head head, int relativeRowIndex, boolean isHead) { + if (isHead) { + return; + } + merge(writeSheetHolder.getSheet(), cell, head, relativeRowIndex); + } + + /** + * merge + * + * @param sheet + * @param cell + * @param head + * @param relativeRowIndex + */ + protected abstract void merge(Sheet sheet, Cell cell, Head head, int relativeRowIndex); +} diff --git a/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java b/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java new file mode 100644 index 0000000..85694a8 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java @@ -0,0 +1,37 @@ +package com.alibaba.excel.write.merge; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; + +import com.alibaba.excel.metadata.Head; + +/** + * The regions of the loop merge + * + * @author Jiaju Zhuang + */ +public class LoopMergeStrategy extends AbstractMergeStrategy { + private int eachRow; + private int columnIndex; + + public LoopMergeStrategy(int eachRow, int columnIndex) { + if (eachRow < 1) { + throw new IllegalArgumentException("EachRows must be greater than 1"); + } + if (columnIndex < 0) { + throw new IllegalArgumentException("ColumnIndex must be greater than 0"); + } + this.eachRow = eachRow; + this.columnIndex = columnIndex; + } + + @Override + protected void merge(Sheet sheet, Cell cell, Head head, int relativeRowIndex) { + if (head.getColumnIndex() == columnIndex && relativeRowIndex % eachRow == 0) { + CellRangeAddress cellRangeAddress = new CellRangeAddress(cell.getRowIndex(), + cell.getRowIndex() + eachRow - 1, cell.getColumnIndex(), cell.getColumnIndex()); + sheet.addMergedRegion(cellRangeAddress); + } + } +} diff --git a/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java b/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java new file mode 100644 index 0000000..6717b76 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java @@ -0,0 +1,39 @@ +package com.alibaba.excel.write.merge; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; + +import com.alibaba.excel.metadata.Head; + +/** + * It only merges once when create cell(firstRowIndex,lastRowIndex) + * + * @author Jiaju Zhuang + */ +public class OnceAbsoluteMergeStrategy extends AbstractMergeStrategy { + + private int firstRowIndex; + private int lastRowIndex; + private int firstColumnIndex; + private int lastColumnIndex; + + public OnceAbsoluteMergeStrategy(int firstRowIndex, int lastRowIndex, int firstColumnIndex, int lastColumnIndex) { + if (firstRowIndex < 0 || lastRowIndex < 0 || firstColumnIndex < 0 || lastColumnIndex < 0) { + throw new IllegalArgumentException("All parameters must be greater than 0"); + } + this.firstRowIndex = firstRowIndex; + this.lastRowIndex = lastRowIndex; + this.firstColumnIndex = firstColumnIndex; + this.lastColumnIndex = lastColumnIndex; + } + + @Override + protected void merge(Sheet sheet, Cell cell, Head head, int relativeRowIndex) { + if (cell.getRowIndex() == firstRowIndex && cell.getColumnIndex() == firstColumnIndex) { + CellRangeAddress cellRangeAddress = + new CellRangeAddress(firstRowIndex, lastRowIndex, firstColumnIndex, lastColumnIndex); + sheet.addMergedRegion(cellRangeAddress); + } + } +} diff --git a/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java b/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java new file mode 100644 index 0000000..3a43ff6 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java @@ -0,0 +1,51 @@ +package com.alibaba.excel.write.metadata; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.excel.metadata.BasicParameter; +import com.alibaba.excel.write.handler.WriteHandler; + +/** + * Write basic parameter + * + * @author Jiaju Zhuang + **/ +public class WriteBasicParameter extends BasicParameter { + /** + * Writes the head relative to the existing contents of the sheet. Indexes are zero-based. + */ + private Integer relativeHeadRowIndex; + /** + * Need Head + */ + private Boolean needHead; + /** + * Custom type handler override the default + */ + private List customWriteHandlerList = new ArrayList(); + + public Integer getRelativeHeadRowIndex() { + return relativeHeadRowIndex; + } + + public void setRelativeHeadRowIndex(Integer relativeHeadRowIndex) { + this.relativeHeadRowIndex = relativeHeadRowIndex; + } + + public Boolean getNeedHead() { + return needHead; + } + + public void setNeedHead(Boolean needHead) { + this.needHead = needHead; + } + + public List getCustomWriteHandlerList() { + return customWriteHandlerList; + } + + public void setCustomWriteHandlerList(List customWriteHandlerList) { + this.customWriteHandlerList = customWriteHandlerList; + } +} diff --git a/src/main/java/com/alibaba/excel/write/metadata/WriteSheet.java b/src/main/java/com/alibaba/excel/write/metadata/WriteSheet.java new file mode 100644 index 0000000..62fac75 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/WriteSheet.java @@ -0,0 +1,74 @@ +package com.alibaba.excel.write.metadata; + +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.excel.metadata.TableStyle; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; +import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy; + +/** + * Write sheet + * + * @author jipengfei + */ +public class WriteSheet extends WriteBasicParameter { + /** + * Starting from 0 + */ + private Integer sheetNo; + /** + * sheet name + */ + private String sheetName; + /** + * column with + * + * @deprecated please use {@link SimpleColumnWidthStyleStrategy} + */ + @Deprecated + private Map columnWidthMap = new HashMap(); + /** + * + * @deprecated please use{@link HorizontalCellStyleStrategy} + */ + @Deprecated + private TableStyle tableStyle; + + public Integer getSheetNo() { + return sheetNo; + } + + public void setSheetNo(Integer sheetNo) { + this.sheetNo = sheetNo; + } + + public String getSheetName() { + return sheetName; + } + + public void setSheetName(String sheetName) { + this.sheetName = sheetName; + } + + public Map getColumnWidthMap() { + return columnWidthMap; + } + + public void setColumnWidthMap(Map columnWidthMap) { + this.columnWidthMap = columnWidthMap; + } + + public TableStyle getTableStyle() { + return tableStyle; + } + + public void setTableStyle(TableStyle tableStyle) { + this.tableStyle = tableStyle; + } + + @Override + public String toString() { + return "WriteSheet{" + "sheetNo=" + sheetNo + ", sheetName='" + sheetName + '\'' + "} " + super.toString(); + } +} diff --git a/src/main/java/com/alibaba/excel/write/metadata/WriteTable.java b/src/main/java/com/alibaba/excel/write/metadata/WriteTable.java new file mode 100644 index 0000000..ec7933c --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/WriteTable.java @@ -0,0 +1,38 @@ +package com.alibaba.excel.write.metadata; + +import com.alibaba.excel.metadata.TableStyle; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; + +/** + * table + * + * @author jipengfei + */ +public class WriteTable extends WriteBasicParameter { + /** + * Starting from 0 + */ + private Integer tableNo; + /** + * + * @deprecated please use{@link HorizontalCellStyleStrategy} + */ + @Deprecated + private TableStyle tableStyle; + + public Integer getTableNo() { + return tableNo; + } + + public void setTableNo(Integer tableNo) { + this.tableNo = tableNo; + } + + public TableStyle getTableStyle() { + return tableStyle; + } + + public void setTableStyle(TableStyle tableStyle) { + this.tableStyle = tableStyle; + } +} diff --git a/src/main/java/com/alibaba/excel/write/metadata/WriteWorkbook.java b/src/main/java/com/alibaba/excel/write/metadata/WriteWorkbook.java new file mode 100644 index 0000000..8ea5209 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/WriteWorkbook.java @@ -0,0 +1,143 @@ +package com.alibaba.excel.write.metadata; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; + +import com.alibaba.excel.support.ExcelTypeEnum; +import com.alibaba.excel.write.handler.WriteHandler; + +/** + * Workbook + * + * @author Jiaju Zhuang + **/ +public class WriteWorkbook extends WriteBasicParameter { + /** + * Excel type.The default is xlsx + */ + private ExcelTypeEnum excelType; + /** + * Final output file + *

+ * If 'outputStream' and 'file' all not empty,file first + */ + private File file; + /** + * Final output stream + *

+ * If 'outputStream' and 'file' all not empty,file first + */ + private OutputStream outputStream; + /** + * Template input stream + *

+ * If 'inputStream' and 'file' all not empty,file first + */ + private InputStream templateInputStream; + + /** + * Template file + *

+ * If 'inputStream' and 'file' all not empty,file first + */ + private File templateFile; + /** + * Default true + */ + private Boolean autoCloseStream; + /** + * Mandatory use 'inputStream' .Default is false + */ + private Boolean mandatoryUseInputStream; + /** + * The default is all excel objects.Default is true. + *

+ * if true , you can use {@link com.alibaba.excel.annotation.ExcelIgnore} ignore a field. + *

+ * if false , you must use {@link com.alibaba.excel.annotation.ExcelProperty} to use a filed. + * + * @deprecated Just to be compatible with historical data, The default is always going to be convert all filed. + */ + @Deprecated + private Boolean convertAllFiled; + /** + * Write handler + * + * @deprecated please use {@link WriteHandler} + */ + @Deprecated + private com.alibaba.excel.event.WriteHandler writeHandler; + + public ExcelTypeEnum getExcelType() { + return excelType; + } + + public void setExcelType(ExcelTypeEnum excelType) { + this.excelType = excelType; + } + + public File getFile() { + return file; + } + + public void setFile(File file) { + this.file = file; + } + + public OutputStream getOutputStream() { + return outputStream; + } + + public void setOutputStream(OutputStream outputStream) { + this.outputStream = outputStream; + } + + public InputStream getTemplateInputStream() { + return templateInputStream; + } + + public void setTemplateInputStream(InputStream templateInputStream) { + this.templateInputStream = templateInputStream; + } + + public File getTemplateFile() { + return templateFile; + } + + public void setTemplateFile(File templateFile) { + this.templateFile = templateFile; + } + + public Boolean getAutoCloseStream() { + return autoCloseStream; + } + + public void setAutoCloseStream(Boolean autoCloseStream) { + this.autoCloseStream = autoCloseStream; + } + + public Boolean getMandatoryUseInputStream() { + return mandatoryUseInputStream; + } + + public void setMandatoryUseInputStream(Boolean mandatoryUseInputStream) { + this.mandatoryUseInputStream = mandatoryUseInputStream; + } + + public Boolean getConvertAllFiled() { + return convertAllFiled; + } + + public void setConvertAllFiled(Boolean convertAllFiled) { + this.convertAllFiled = convertAllFiled; + } + + public com.alibaba.excel.event.WriteHandler getWriteHandler() { + return writeHandler; + } + + public void setWriteHandler(com.alibaba.excel.event.WriteHandler writeHandler) { + this.writeHandler = writeHandler; + } +} diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java new file mode 100644 index 0000000..c210f28 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java @@ -0,0 +1,384 @@ +package com.alibaba.excel.write.metadata.holder; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.IndexedColors; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.converters.ConverterKeyBuild; +import com.alibaba.excel.converters.DefaultConverterLoader; +import com.alibaba.excel.enums.HeadKindEnum; +import com.alibaba.excel.event.NotRepeatExecutor; +import com.alibaba.excel.event.Order; +import com.alibaba.excel.metadata.AbstractHolder; +import com.alibaba.excel.metadata.Font; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.metadata.TableStyle; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.metadata.property.RowHeightProperty; +import com.alibaba.excel.util.CollectionUtils; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.DefaultWriteHandlerLoader; +import com.alibaba.excel.write.handler.RowWriteHandler; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.handler.WorkbookWriteHandler; +import com.alibaba.excel.write.handler.WriteHandler; +import com.alibaba.excel.write.metadata.WriteBasicParameter; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.WriteTable; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import com.alibaba.excel.write.property.ExcelWriteHeadProperty; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; +import com.alibaba.excel.write.style.column.AbstractHeadColumnWidthStyleStrategy; +import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy; + +/** + * Write holder configuration + * + * @author Jiaju Zhuang + */ +public abstract class AbstractWriteHolder extends AbstractHolder implements WriteHolder { + /** + * Need Head + */ + private Boolean needHead; + /** + * Writes the head relative to the existing contents of the sheet. Indexes are zero-based. + */ + private Integer relativeHeadRowIndex; + /** + * Excel head property + */ + private ExcelWriteHeadProperty excelWriteHeadProperty; + /** + * Write handler for workbook + */ + private Map, List> writeHandlerMap; + + public AbstractWriteHolder(WriteBasicParameter writeBasicParameter, AbstractWriteHolder parentAbstractWriteHolder, + Boolean convertAllFiled) { + super(writeBasicParameter, parentAbstractWriteHolder); + if (writeBasicParameter.getUse1904windowing() == null) { + if (parentAbstractWriteHolder == null) { + getGlobalConfiguration().setUse1904windowing(Boolean.FALSE); + } else { + getGlobalConfiguration() + .setUse1904windowing(parentAbstractWriteHolder.getGlobalConfiguration().getUse1904windowing()); + } + } else { + getGlobalConfiguration().setUse1904windowing(writeBasicParameter.getUse1904windowing()); + } + + if (writeBasicParameter.getNeedHead() == null) { + if (parentAbstractWriteHolder == null) { + this.needHead = Boolean.TRUE; + } else { + this.needHead = parentAbstractWriteHolder.getNeedHead(); + } + } else { + this.needHead = writeBasicParameter.getNeedHead(); + } + + if (writeBasicParameter.getRelativeHeadRowIndex() == null) { + if (parentAbstractWriteHolder == null) { + this.relativeHeadRowIndex = 0; + } else { + this.relativeHeadRowIndex = parentAbstractWriteHolder.getRelativeHeadRowIndex(); + } + } else { + this.relativeHeadRowIndex = writeBasicParameter.getRelativeHeadRowIndex(); + } + + // Initialization property + this.excelWriteHeadProperty = new ExcelWriteHeadProperty(getClazz(), getHead(), convertAllFiled); + + // Compatible with old code + compatibleOldCode(writeBasicParameter); + + // Set writeHandlerMap + List handlerList = new ArrayList(); + + // Initialization Annotation + initAnnotationConfig(handlerList); + + if (writeBasicParameter.getCustomWriteHandlerList() != null + && !writeBasicParameter.getCustomWriteHandlerList().isEmpty()) { + handlerList.addAll(writeBasicParameter.getCustomWriteHandlerList()); + } + + Map, List> parentWriteHandlerMap = null; + if (parentAbstractWriteHolder != null) { + parentWriteHandlerMap = parentAbstractWriteHolder.getWriteHandlerMap(); + } else { + handlerList.addAll(DefaultWriteHandlerLoader.loadDefaultHandler()); + } + + this.writeHandlerMap = sortAndClearUpHandler(handlerList, parentWriteHandlerMap); + + // Set converterMap + if (parentAbstractWriteHolder == null) { + setConverterMap(DefaultConverterLoader.loadDefaultWriteConverter()); + } else { + setConverterMap(new HashMap(parentAbstractWriteHolder.getConverterMap())); + } + if (writeBasicParameter.getCustomConverterList() != null + && !writeBasicParameter.getCustomConverterList().isEmpty()) { + for (Converter converter : writeBasicParameter.getCustomConverterList()) { + getConverterMap().put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter); + } + } + } + + /** + * Compatible with old code + */ + @Deprecated + private void compatibleOldCode(WriteBasicParameter writeBasicParameter) { + switch (holderType()) { + case SHEET: + compatibleOldCodeCreateRowCellStyleStrategy(writeBasicParameter, + ((WriteSheet)writeBasicParameter).getTableStyle()); + compatibleOldCodeCreateHeadColumnWidthStyleStrategy(writeBasicParameter, + ((WriteSheet)writeBasicParameter).getColumnWidthMap()); + return; + case TABLE: + compatibleOldCodeCreateRowCellStyleStrategy(writeBasicParameter, + ((WriteTable)writeBasicParameter).getTableStyle()); + return; + default: + } + } + + @Deprecated + private void compatibleOldCodeCreateRowCellStyleStrategy(WriteBasicParameter writeBasicParameter, + TableStyle tableStyle) { + if (tableStyle == null) { + return; + } + if (writeBasicParameter.getCustomWriteHandlerList() == null) { + writeBasicParameter.setCustomWriteHandlerList(new ArrayList()); + } + writeBasicParameter.getCustomWriteHandlerList() + .add(new HorizontalCellStyleStrategy( + buildWriteCellStyle(tableStyle.getTableHeadFont(), tableStyle.getTableHeadBackGroundColor()), + buildWriteCellStyle(tableStyle.getTableContentFont(), tableStyle.getTableContentBackGroundColor()))); + } + + @Deprecated + private WriteCellStyle buildWriteCellStyle(Font font, IndexedColors indexedColors) { + WriteCellStyle writeCellStyle = new WriteCellStyle(); + if (indexedColors != null) { + writeCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); + writeCellStyle.setFillForegroundColor(indexedColors.getIndex()); + } + if (font != null) { + WriteFont writeFont = new WriteFont(); + writeFont.setFontName(font.getFontName()); + writeFont.setFontHeightInPoints(font.getFontHeightInPoints()); + writeFont.setBold(font.isBold()); + writeCellStyle.setWriteFont(writeFont); + } + return writeCellStyle; + } + + @Deprecated + private void compatibleOldCodeCreateHeadColumnWidthStyleStrategy(WriteBasicParameter writeBasicParameter, + final Map columnWidthMap) { + if (columnWidthMap == null || columnWidthMap.isEmpty()) { + return; + } + if (writeBasicParameter.getCustomWriteHandlerList() == null) { + writeBasicParameter.setCustomWriteHandlerList(new ArrayList()); + } + writeBasicParameter.getCustomWriteHandlerList().add(new AbstractHeadColumnWidthStyleStrategy() { + @Override + protected Integer columnWidth(Head head) { + if (columnWidthMap.containsKey(head.getColumnIndex())) { + return columnWidthMap.get(head.getColumnIndex()) / 256; + } + return 20; + } + }); + } + + protected void initAnnotationConfig(List handlerList) { + if (!HeadKindEnum.CLASS.equals(getExcelWriteHeadProperty().getHeadKind())) { + return; + } + Map headMap = getExcelWriteHeadProperty().getHeadMap(); + Map contentPropertyMap = getExcelWriteHeadProperty().getContentPropertyMap(); + + boolean hasColumnWidth = false; + for (Map.Entry entry : headMap.entrySet()) { + if (entry.getValue().getColumnWidthProperty() != null) { + hasColumnWidth = true; + break; + } + } + + if (hasColumnWidth) { + dealColumnWidth(handlerList); + } + dealRowHigh(handlerList, contentPropertyMap); + } + + private void dealRowHigh(List handlerList, Map contentPropertyMap) { + RowHeightProperty headRowHeightProperty = getExcelWriteHeadProperty().getHeadRowHeightProperty(); + RowHeightProperty contentRowHeightProperty = getExcelWriteHeadProperty().getContentRowHeightProperty(); + if (headRowHeightProperty == null && contentRowHeightProperty == null) { + return; + } + Short headRowHeight = null; + if (headRowHeightProperty != null) { + headRowHeight = headRowHeightProperty.getHeight(); + } + Short contentRowHeight = null; + if (contentRowHeightProperty != null) { + contentRowHeight = contentRowHeightProperty.getHeight(); + } + handlerList.add(new SimpleRowHeightStyleStrategy(headRowHeight, contentRowHeight)); + } + + private void dealColumnWidth(List handlerList) { + WriteHandler columnWidthStyleStrategy = new AbstractHeadColumnWidthStyleStrategy() { + @Override + protected Integer columnWidth(Head head) { + if (head == null) { + return null; + } + if (head.getColumnWidthProperty() != null) { + return head.getColumnWidthProperty().getWidth(); + } + return null; + } + }; + handlerList.add(columnWidthStyleStrategy); + } + + protected Map, List> sortAndClearUpHandler( + List handlerList, Map, List> parentHandlerMap) { + + // add + if (parentHandlerMap != null) { + List parentWriteHandler = parentHandlerMap.get(WriteHandler.class); + if (!CollectionUtils.isEmpty(parentWriteHandler)) { + handlerList.addAll(parentWriteHandler); + } + } + + // sort + Map> orderExcelWriteHandlerMap = new TreeMap>(); + for (WriteHandler handler : handlerList) { + int order = Integer.MIN_VALUE; + if (handler instanceof Order) { + order = ((Order)handler).order(); + } + if (orderExcelWriteHandlerMap.containsKey(order)) { + orderExcelWriteHandlerMap.get(order).add(handler); + } else { + List tempHandlerList = new ArrayList(); + tempHandlerList.add(handler); + orderExcelWriteHandlerMap.put(order, tempHandlerList); + } + } + // clean up + Set alreadyExistedHandlerSet = new HashSet(); + List cleanUpHandlerList = new ArrayList(); + for (Map.Entry> entry : orderExcelWriteHandlerMap.entrySet()) { + for (WriteHandler handler : entry.getValue()) { + if (handler instanceof NotRepeatExecutor) { + String uniqueValue = ((NotRepeatExecutor)handler).uniqueValue(); + if (alreadyExistedHandlerSet.contains(uniqueValue)) { + continue; + } + alreadyExistedHandlerSet.add(uniqueValue); + } + cleanUpHandlerList.add(handler); + } + } + // classify + Map, List> result = + new HashMap, List>(16); + result.put(WriteHandler.class, new ArrayList()); + result.put(WorkbookWriteHandler.class, new ArrayList()); + result.put(SheetWriteHandler.class, new ArrayList()); + result.put(RowWriteHandler.class, new ArrayList()); + result.put(CellWriteHandler.class, new ArrayList()); + for (WriteHandler writeHandler : cleanUpHandlerList) { + if (writeHandler instanceof CellWriteHandler) { + result.get(CellWriteHandler.class).add(writeHandler); + } + if (writeHandler instanceof RowWriteHandler) { + result.get(RowWriteHandler.class).add(writeHandler); + } + if (writeHandler instanceof SheetWriteHandler) { + result.get(SheetWriteHandler.class).add(writeHandler); + } + if (writeHandler instanceof WorkbookWriteHandler) { + result.get(WorkbookWriteHandler.class).add(writeHandler); + } + result.get(WriteHandler.class).add(writeHandler); + } + return result; + } + + public Boolean getNeedHead() { + return needHead; + } + + public void setNeedHead(Boolean needHead) { + this.needHead = needHead; + } + + public Map, List> getWriteHandlerMap() { + return writeHandlerMap; + } + + public void setWriteHandlerMap(Map, List> writeHandlerMap) { + this.writeHandlerMap = writeHandlerMap; + } + + public ExcelWriteHeadProperty getExcelWriteHeadProperty() { + return excelWriteHeadProperty; + } + + public void setExcelWriteHeadProperty(ExcelWriteHeadProperty excelWriteHeadProperty) { + this.excelWriteHeadProperty = excelWriteHeadProperty; + } + + public Integer getRelativeHeadRowIndex() { + return relativeHeadRowIndex; + } + + public void setRelativeHeadRowIndex(Integer relativeHeadRowIndex) { + this.relativeHeadRowIndex = relativeHeadRowIndex; + } + + @Override + public ExcelWriteHeadProperty excelWriteHeadProperty() { + return getExcelWriteHeadProperty(); + } + + @Override + public Map, List> writeHandlerMap() { + return getWriteHandlerMap(); + } + + @Override + public boolean needHead() { + return getNeedHead(); + } + + @Override + public int relativeHeadRowIndex() { + return getRelativeHeadRowIndex(); + } +} diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java new file mode 100644 index 0000000..53c11db --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java @@ -0,0 +1,44 @@ +package com.alibaba.excel.write.metadata.holder; + +import java.util.List; +import java.util.Map; + +import com.alibaba.excel.metadata.ConfigurationHolder; +import com.alibaba.excel.write.handler.WriteHandler; +import com.alibaba.excel.write.property.ExcelWriteHeadProperty; + +/** + * + * Get the corresponding Holder + * + * @author Jiaju Zhuang + **/ +public interface WriteHolder extends ConfigurationHolder { + /** + * What 'ExcelWriteHeadProperty' does the currently operated cell need to execute + * + * @return + */ + ExcelWriteHeadProperty excelWriteHeadProperty(); + + /** + * What handler does the currently operated cell need to execute + * + * @return + */ + Map, List> writeHandlerMap(); + + /** + * Whether a header is required for the currently operated cell + * + * @return + */ + boolean needHead(); + + /** + * Writes the head relative to the existing contents of the sheet. Indexes are zero-based. + * + * @return + */ + int relativeHeadRowIndex(); +} diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java new file mode 100644 index 0000000..7cce9f1 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java @@ -0,0 +1,160 @@ +package com.alibaba.excel.write.metadata.holder; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.poi.ss.usermodel.Sheet; + +import com.alibaba.excel.enums.HolderEnum; +import com.alibaba.excel.enums.WriteLastRowType; +import com.alibaba.excel.support.ExcelTypeEnum; +import com.alibaba.excel.write.metadata.WriteSheet; + +/** + * sheet holder + * + * @author Jiaju Zhuang + */ +public class WriteSheetHolder extends AbstractWriteHolder { + /** + * current param + */ + private WriteSheet writeSheet; + /*** + * poi sheet + */ + private Sheet sheet; + /*** + * sheetNo + */ + private Integer sheetNo; + /*** + * sheetName + */ + private String sheetName; + /*** + * poi sheet + */ + private WriteWorkbookHolder parentWriteWorkbookHolder; + /*** + * has been initialized table + */ + private Map hasBeenInitializedTable; + + /** + * last column type + * + * @param writeSheet + * @param writeWorkbookHolder + */ + private WriteLastRowType writeLastRowType; + + public WriteSheetHolder(WriteSheet writeSheet, WriteWorkbookHolder writeWorkbookHolder) { + super(writeSheet, writeWorkbookHolder, writeWorkbookHolder.getWriteWorkbook().getConvertAllFiled()); + this.writeSheet = writeSheet; + this.sheetNo = writeSheet.getSheetNo(); + if (writeSheet.getSheetName() == null) { + this.sheetName = writeSheet.getSheetNo().toString(); + } else { + this.sheetName = writeSheet.getSheetName(); + } + this.parentWriteWorkbookHolder = writeWorkbookHolder; + this.hasBeenInitializedTable = new HashMap(); + if (writeWorkbookHolder.getTemplateInputStream() == null && writeWorkbookHolder.getTemplateFile() == null) { + writeLastRowType = WriteLastRowType.COMMON_EMPTY; + } else { + writeLastRowType = WriteLastRowType.TEMPLATE_EMPTY; + } + } + + public WriteSheet getWriteSheet() { + return writeSheet; + } + + public void setWriteSheet(WriteSheet writeSheet) { + this.writeSheet = writeSheet; + } + + public Sheet getSheet() { + return sheet; + } + + public void setSheet(Sheet sheet) { + this.sheet = sheet; + } + + public Integer getSheetNo() { + return sheetNo; + } + + public void setSheetNo(Integer sheetNo) { + this.sheetNo = sheetNo; + } + + public String getSheetName() { + return sheetName; + } + + public void setSheetName(String sheetName) { + this.sheetName = sheetName; + } + + public WriteWorkbookHolder getParentWriteWorkbookHolder() { + return parentWriteWorkbookHolder; + } + + public void setParentWriteWorkbookHolder(WriteWorkbookHolder parentWriteWorkbookHolder) { + this.parentWriteWorkbookHolder = parentWriteWorkbookHolder; + } + + public Map getHasBeenInitializedTable() { + return hasBeenInitializedTable; + } + + public void setHasBeenInitializedTable(Map hasBeenInitializedTable) { + this.hasBeenInitializedTable = hasBeenInitializedTable; + } + + public WriteLastRowType getWriteLastRowType() { + return writeLastRowType; + } + + public void setWriteLastRowType(WriteLastRowType writeLastRowType) { + this.writeLastRowType = writeLastRowType; + } + + /** + * Get the last line of index,you have to make sure that the data is written next + * + * @return + */ + public int getNewRowIndexAndStartDoWrite() { + // 'getLastRowNum' doesn't matter if it has one or zero,is's zero + int newRowIndex = 0; + switch (writeLastRowType) { + case TEMPLATE_EMPTY: + if (parentWriteWorkbookHolder.getExcelType() == ExcelTypeEnum.XLSX) { + if (parentWriteWorkbookHolder.getTemplateLastRowMap().containsKey(sheetNo)) { + newRowIndex = parentWriteWorkbookHolder.getTemplateLastRowMap().get(sheetNo); + } + } else { + newRowIndex = sheet.getLastRowNum(); + } + newRowIndex++; + break; + case HAS_DATA: + newRowIndex = sheet.getLastRowNum(); + newRowIndex++; + break; + default: + break; + } + writeLastRowType = WriteLastRowType.HAS_DATA; + return newRowIndex; + } + + @Override + public HolderEnum holderType() { + return HolderEnum.SHEET; + } +} diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteTableHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteTableHolder.java new file mode 100644 index 0000000..f7242a2 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteTableHolder.java @@ -0,0 +1,61 @@ +package com.alibaba.excel.write.metadata.holder; + +import com.alibaba.excel.enums.HolderEnum; +import com.alibaba.excel.write.metadata.WriteTable; + +/** + * sheet holder + * + * @author Jiaju Zhuang + */ +public class WriteTableHolder extends AbstractWriteHolder { + /*** + * poi sheet + */ + private WriteSheetHolder parentWriteSheetHolder; + /*** + * tableNo + */ + private Integer tableNo; + /** + * current table param + */ + private WriteTable writeTable; + + public WriteTableHolder(WriteTable writeTable, WriteSheetHolder writeSheetHolder, + WriteWorkbookHolder writeWorkbookHolder) { + super(writeTable, writeSheetHolder, writeWorkbookHolder.getWriteWorkbook().getConvertAllFiled()); + this.parentWriteSheetHolder = writeSheetHolder; + this.tableNo = writeTable.getTableNo(); + this.writeTable = writeTable; + } + + public WriteSheetHolder getParentWriteSheetHolder() { + return parentWriteSheetHolder; + } + + public void setParentWriteSheetHolder(WriteSheetHolder parentWriteSheetHolder) { + this.parentWriteSheetHolder = parentWriteSheetHolder; + } + + public Integer getTableNo() { + return tableNo; + } + + public void setTableNo(Integer tableNo) { + this.tableNo = tableNo; + } + + public WriteTable getWriteTable() { + return writeTable; + } + + public void setWriteTable(WriteTable writeTable) { + this.writeTable = writeTable; + } + + @Override + public HolderEnum holderType() { + return HolderEnum.TABLE; + } +} diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java new file mode 100644 index 0000000..d3c07f5 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java @@ -0,0 +1,217 @@ +package com.alibaba.excel.write.metadata.holder; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; + +import org.apache.poi.ss.usermodel.Workbook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.enums.HolderEnum; +import com.alibaba.excel.exception.ExcelGenerateException; +import com.alibaba.excel.support.ExcelTypeEnum; +import com.alibaba.excel.write.metadata.WriteWorkbook; + +/** + * Workbook holder + * + * @author Jiaju Zhuang + */ +public class WriteWorkbookHolder extends AbstractWriteHolder { + private static final Logger LOGGER = LoggerFactory.getLogger(WriteWorkbookHolder.class); + /*** + * poi Workbook + */ + private Workbook workbook; + + /** + * current param + */ + private WriteWorkbook writeWorkbook; + /** + * Final output file + *

+ * If 'outputStream' and 'file' all not empty,file first + */ + private File file; + /** + * Final output stream + */ + private OutputStream outputStream; + /** + * Template input stream + *

+ * If 'inputStream' and 'file' all not empty,file first + */ + private InputStream templateInputStream; + /** + * Template file + *

+ * If 'inputStream' and 'file' all not empty,file first + */ + private File templateFile; + /** + * Default true + */ + private Boolean autoCloseStream; + /** + * Excel type + */ + private ExcelTypeEnum excelType; + /** + * Mandatory use 'inputStream' + */ + private Boolean mandatoryUseInputStream; + /** + * prevent duplicate creation of sheet objects + */ + private Map hasBeenInitializedSheet; + /** + * When using SXSSFWorkbook, you can't get the actual last line.But we need to read the last line when we are using + * the template, so we cache it + */ + private Map templateLastRowMap; + + public WriteWorkbookHolder(WriteWorkbook writeWorkbook) { + super(writeWorkbook, null, writeWorkbook.getConvertAllFiled()); + this.writeWorkbook = writeWorkbook; + this.file = writeWorkbook.getFile(); + if (file != null) { + try { + this.outputStream = new FileOutputStream(file); + } catch (FileNotFoundException e) { + throw new ExcelGenerateException("Can not found file.", e); + } + } else { + this.outputStream = writeWorkbook.getOutputStream(); + } + if (writeWorkbook.getTemplateInputStream() != null) { + if (writeWorkbook.getTemplateInputStream().markSupported()) { + this.templateInputStream = writeWorkbook.getTemplateInputStream(); + } else { + this.templateInputStream = new BufferedInputStream(writeWorkbook.getTemplateInputStream()); + } + } + this.templateFile = writeWorkbook.getTemplateFile(); + if (writeWorkbook.getAutoCloseStream() == null) { + this.autoCloseStream = Boolean.TRUE; + } else { + this.autoCloseStream = writeWorkbook.getAutoCloseStream(); + } + if (writeWorkbook.getExcelType() == null) { + if (file != null && file.getName().endsWith(ExcelTypeEnum.XLS.getValue())) { + this.excelType = ExcelTypeEnum.XLS; + } else { + this.excelType = ExcelTypeEnum.XLSX; + } + } else { + this.excelType = writeWorkbook.getExcelType(); + } + if (writeWorkbook.getMandatoryUseInputStream() == null) { + this.mandatoryUseInputStream = Boolean.FALSE; + } else { + this.mandatoryUseInputStream = writeWorkbook.getMandatoryUseInputStream(); + } + this.hasBeenInitializedSheet = new HashMap(); + this.templateLastRowMap = new HashMap(8); + } + + public Workbook getWorkbook() { + return workbook; + } + + public void setWorkbook(Workbook workbook) { + this.workbook = workbook; + } + + public Map getHasBeenInitializedSheet() { + return hasBeenInitializedSheet; + } + + public void setHasBeenInitializedSheet(Map hasBeenInitializedSheet) { + this.hasBeenInitializedSheet = hasBeenInitializedSheet; + } + + public WriteWorkbook getWriteWorkbook() { + return writeWorkbook; + } + + public void setWriteWorkbook(WriteWorkbook writeWorkbook) { + this.writeWorkbook = writeWorkbook; + } + + public File getFile() { + return file; + } + + public void setFile(File file) { + this.file = file; + } + + public OutputStream getOutputStream() { + return outputStream; + } + + public void setOutputStream(OutputStream outputStream) { + this.outputStream = outputStream; + } + + public InputStream getTemplateInputStream() { + return templateInputStream; + } + + public void setTemplateInputStream(InputStream templateInputStream) { + this.templateInputStream = templateInputStream; + } + + public File getTemplateFile() { + return templateFile; + } + + public void setTemplateFile(File templateFile) { + this.templateFile = templateFile; + } + + public Boolean getAutoCloseStream() { + return autoCloseStream; + } + + public void setAutoCloseStream(Boolean autoCloseStream) { + this.autoCloseStream = autoCloseStream; + } + + public ExcelTypeEnum getExcelType() { + return excelType; + } + + public void setExcelType(ExcelTypeEnum excelType) { + this.excelType = excelType; + } + + public Boolean getMandatoryUseInputStream() { + return mandatoryUseInputStream; + } + + public void setMandatoryUseInputStream(Boolean mandatoryUseInputStream) { + this.mandatoryUseInputStream = mandatoryUseInputStream; + } + + public Map getTemplateLastRowMap() { + return templateLastRowMap; + } + + public void setTemplateLastRowMap(Map templateLastRowMap) { + this.templateLastRowMap = templateLastRowMap; + } + + @Override + public HolderEnum holderType() { + return HolderEnum.WORKBOOK; + } +} diff --git a/src/main/java/com/alibaba/excel/write/metadata/style/WriteCellStyle.java b/src/main/java/com/alibaba/excel/write/metadata/style/WriteCellStyle.java new file mode 100644 index 0000000..01786ce --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/style/WriteCellStyle.java @@ -0,0 +1,315 @@ +package com.alibaba.excel.write.metadata.style; + +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.BuiltinFormats; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IgnoredErrorType; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.VerticalAlignment; + +/** + * Cell style when writing + * + * @author Jiaju Zhuang + */ +public class WriteCellStyle { + /** + * Set the data format (must be a valid format). Built in formats are defined at {@link BuiltinFormats}. + */ + private Short dataFormat; + /** + * Set the font for this style + */ + private WriteFont writeFont; + /** + * Set the cell's using this style to be hidden + */ + private Boolean hidden; + + /** + * Set the cell's using this style to be locked + */ + private Boolean locked; + /** + * Turn on or off "Quote Prefix" or "123 Prefix" for the style, which is used to tell Excel that the thing which + * looks like a number or a formula shouldn't be treated as on. Turning this on is somewhat (but not completely, see + * {@link IgnoredErrorType}) like prefixing the cell value with a ' in Excel + */ + private Boolean quotePrefix; + /** + * Set the type of horizontal alignment for the cell + */ + private HorizontalAlignment horizontalAlignment; + /** + * Set whether the text should be wrapped. Setting this flag to true make all content visible within a + * cell by displaying it on multiple lines + * + */ + private Boolean wrapped; + /** + * Set the type of vertical alignment for the cell + */ + private VerticalAlignment verticalAlignment; + /** + * Set the degree of rotation for the text in the cell. + * + * Note: HSSF uses values from -90 to 90 degrees, whereas XSSF uses values from 0 to 180 degrees. The + * implementations of this method will map between these two value-ranges accordingly, however the corresponding + * getter is returning values in the range mandated by the current type of Excel file-format that this CellStyle is + * applied to. + */ + private Short rotation; + /** + * Set the number of spaces to indent the text in the cell + */ + private Short indent; + /** + * Set the type of border to use for the left border of the cell + */ + private BorderStyle borderLeft; + /** + * Set the type of border to use for the right border of the cell + */ + private BorderStyle borderRight; + /** + * Set the type of border to use for the top border of the cell + */ + private BorderStyle borderTop; + + /** + * Set the type of border to use for the bottom border of the cell + */ + private BorderStyle borderBottom; + /** + * Set the color to use for the left border + * + * @see IndexedColors + */ + private Short leftBorderColor; + + /** + * Set the color to use for the right border + * + * @see IndexedColors + * + */ + private Short rightBorderColor; + + /** + * Set the color to use for the top border + * + * @see IndexedColors + * + */ + private Short topBorderColor; + /** + * Set the color to use for the bottom border + * + * @see IndexedColors + * + */ + private Short bottomBorderColor; + /** + * Setting to one fills the cell with the foreground color... No idea about other values + * + * @see FillPatternType#SOLID_FOREGROUND + */ + private FillPatternType fillPatternType; + + /** + * Set the background fill color. + * + * @see IndexedColors + * + */ + private Short fillBackgroundColor; + + /** + * Set the foreground fill color Note: Ensure Foreground color is set prior to background color. + * + * @see IndexedColors + * + */ + private Short fillForegroundColor; + /** + * Controls if the Cell should be auto-sized to shrink to fit if the text is too long + */ + private Boolean shrinkToFit; + + public Short getDataFormat() { + return dataFormat; + } + + public void setDataFormat(Short dataFormat) { + this.dataFormat = dataFormat; + } + + public WriteFont getWriteFont() { + return writeFont; + } + + public void setWriteFont(WriteFont writeFont) { + this.writeFont = writeFont; + } + + public Boolean getHidden() { + return hidden; + } + + public void setHidden(Boolean hidden) { + this.hidden = hidden; + } + + public Boolean getLocked() { + return locked; + } + + public void setLocked(Boolean locked) { + this.locked = locked; + } + + public Boolean getQuotePrefix() { + return quotePrefix; + } + + public void setQuotePrefix(Boolean quotePrefix) { + this.quotePrefix = quotePrefix; + } + + public HorizontalAlignment getHorizontalAlignment() { + return horizontalAlignment; + } + + public void setHorizontalAlignment(HorizontalAlignment horizontalAlignment) { + this.horizontalAlignment = horizontalAlignment; + } + + public Boolean getWrapped() { + return wrapped; + } + + public void setWrapped(Boolean wrapped) { + this.wrapped = wrapped; + } + + public VerticalAlignment getVerticalAlignment() { + return verticalAlignment; + } + + public void setVerticalAlignment(VerticalAlignment verticalAlignment) { + this.verticalAlignment = verticalAlignment; + } + + public Short getRotation() { + return rotation; + } + + public void setRotation(Short rotation) { + this.rotation = rotation; + } + + public Short getIndent() { + return indent; + } + + public void setIndent(Short indent) { + this.indent = indent; + } + + public BorderStyle getBorderLeft() { + return borderLeft; + } + + public void setBorderLeft(BorderStyle borderLeft) { + this.borderLeft = borderLeft; + } + + public BorderStyle getBorderRight() { + return borderRight; + } + + public void setBorderRight(BorderStyle borderRight) { + this.borderRight = borderRight; + } + + public BorderStyle getBorderTop() { + return borderTop; + } + + public void setBorderTop(BorderStyle borderTop) { + this.borderTop = borderTop; + } + + public BorderStyle getBorderBottom() { + return borderBottom; + } + + public void setBorderBottom(BorderStyle borderBottom) { + this.borderBottom = borderBottom; + } + + public Short getLeftBorderColor() { + return leftBorderColor; + } + + public void setLeftBorderColor(Short leftBorderColor) { + this.leftBorderColor = leftBorderColor; + } + + public Short getRightBorderColor() { + return rightBorderColor; + } + + public void setRightBorderColor(Short rightBorderColor) { + this.rightBorderColor = rightBorderColor; + } + + public Short getTopBorderColor() { + return topBorderColor; + } + + public void setTopBorderColor(Short topBorderColor) { + this.topBorderColor = topBorderColor; + } + + public Short getBottomBorderColor() { + return bottomBorderColor; + } + + public void setBottomBorderColor(Short bottomBorderColor) { + this.bottomBorderColor = bottomBorderColor; + } + + public FillPatternType getFillPatternType() { + return fillPatternType; + } + + public void setFillPatternType(FillPatternType fillPatternType) { + this.fillPatternType = fillPatternType; + } + + public Short getFillBackgroundColor() { + return fillBackgroundColor; + } + + public void setFillBackgroundColor(Short fillBackgroundColor) { + this.fillBackgroundColor = fillBackgroundColor; + } + + public Short getFillForegroundColor() { + return fillForegroundColor; + } + + public void setFillForegroundColor(Short fillForegroundColor) { + this.fillForegroundColor = fillForegroundColor; + } + + public Boolean getShrinkToFit() { + return shrinkToFit; + } + + public void setShrinkToFit(Boolean shrinkToFit) { + this.shrinkToFit = shrinkToFit; + } +} diff --git a/src/main/java/com/alibaba/excel/write/metadata/style/WriteFont.java b/src/main/java/com/alibaba/excel/write/metadata/style/WriteFont.java new file mode 100644 index 0000000..6ed4c2a --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/style/WriteFont.java @@ -0,0 +1,143 @@ +package com.alibaba.excel.write.metadata.style; + +import org.apache.poi.common.usermodel.fonts.FontCharset; +import org.apache.poi.hssf.usermodel.HSSFPalette; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.IndexedColors; + +/** + * Font when writing + * + * @author jipengfei + */ +public class WriteFont { + /** + * The name for the font (i.e. Arial) + */ + private String fontName; + /** + * Height in the familiar unit of measure - points + */ + private Short fontHeightInPoints; + /** + * Whether to use italics or not + */ + private Boolean italic; + /** + * Whether to use a strikeout horizontal line through the text or not + */ + private Boolean strikeout; + /** + * The color for the font + * + * @see Font#COLOR_NORMAL + * @see Font#COLOR_RED + * @see HSSFPalette#getColor(short) + * @see IndexedColors + */ + private Short color; + /** + * Set normal,super or subscript. + * + * @see Font#SS_NONE + * @see Font#SS_SUPER + * @see Font#SS_SUB + */ + private Short typeOffset; + /** + * set type of text underlining to use + * + * @see Font#U_NONE + * @see Font#U_SINGLE + * @see Font#U_DOUBLE + * @see Font#U_SINGLE_ACCOUNTING + * @see Font#U_DOUBLE_ACCOUNTING + */ + + private Byte underline; + /** + * Set character-set to use. + * + * @see FontCharset + * @see Font#ANSI_CHARSET + * @see Font#DEFAULT_CHARSET + * @see Font#SYMBOL_CHARSET + */ + private Integer charset; + /** + * Bold + */ + private Boolean bold; + + public String getFontName() { + return fontName; + } + + public void setFontName(String fontName) { + this.fontName = fontName; + } + + public Short getFontHeightInPoints() { + return fontHeightInPoints; + } + + public void setFontHeightInPoints(Short fontHeightInPoints) { + this.fontHeightInPoints = fontHeightInPoints; + } + + public Boolean getItalic() { + return italic; + } + + public void setItalic(Boolean italic) { + this.italic = italic; + } + + public Boolean getStrikeout() { + return strikeout; + } + + public void setStrikeout(Boolean strikeout) { + this.strikeout = strikeout; + } + + public Short getColor() { + return color; + } + + public void setColor(Short color) { + this.color = color; + } + + public Short getTypeOffset() { + return typeOffset; + } + + public void setTypeOffset(Short typeOffset) { + this.typeOffset = typeOffset; + } + + public Byte getUnderline() { + return underline; + } + + public void setUnderline(Byte underline) { + this.underline = underline; + } + + public Integer getCharset() { + return charset; + } + + public void setCharset(Integer charset) { + this.charset = charset; + } + + public Boolean getBold() { + return bold; + } + + public void setBold(Boolean bold) { + this.bold = bold; + } +} diff --git a/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java b/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java new file mode 100644 index 0000000..fbd33c4 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java @@ -0,0 +1,132 @@ +package com.alibaba.excel.write.property; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.alibaba.excel.annotation.format.NumberFormat; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.ContentRowHeight; +import com.alibaba.excel.annotation.write.style.HeadRowHeight; +import com.alibaba.excel.converters.ConverterKeyBuild; +import com.alibaba.excel.converters.DefaultConverterLoader; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.enums.HeadKindEnum; +import com.alibaba.excel.metadata.CellRange; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.metadata.property.ColumnWidthProperty; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.metadata.property.ExcelHeadProperty; +import com.alibaba.excel.metadata.property.RowHeightProperty; + +/** + * Define the header attribute of excel + * + * @author jipengfei + */ +public class ExcelWriteHeadProperty extends ExcelHeadProperty { + private RowHeightProperty headRowHeightProperty; + private RowHeightProperty contentRowHeightProperty; + + public ExcelWriteHeadProperty(Class headClazz, List> head, Boolean convertAllFiled) { + super(headClazz, head, convertAllFiled); + if (getHeadKind() != HeadKindEnum.CLASS) { + return; + } + this.headRowHeightProperty = + RowHeightProperty.build((HeadRowHeight)headClazz.getAnnotation(HeadRowHeight.class)); + this.contentRowHeightProperty = + RowHeightProperty.build((ContentRowHeight)headClazz.getAnnotation(ContentRowHeight.class)); + + ColumnWidth parentColumnWidth = (ColumnWidth)headClazz.getAnnotation(ColumnWidth.class); + for (Map.Entry entry : getContentPropertyMap().entrySet()) { + Integer index = entry.getKey(); + ExcelContentProperty excelContentPropertyData = entry.getValue(); + Field field = excelContentPropertyData.getField(); + Head headData = getHeadMap().get(index); + ColumnWidth columnWidth = field.getAnnotation(ColumnWidth.class); + if (columnWidth == null) { + columnWidth = parentColumnWidth; + } + headData.setColumnWidthProperty(ColumnWidthProperty.build(columnWidth)); + + // If have @NumberFormat, 'NumberStringConverter' is specified by default + if (excelContentPropertyData.getConverter() == null) { + NumberFormat numberFormat = field.getAnnotation(NumberFormat.class); + if (numberFormat != null) { + excelContentPropertyData.setConverter(DefaultConverterLoader.loadAllConverter() + .get(ConverterKeyBuild.buildKey(field.getType(), CellDataTypeEnum.STRING))); + } + } + } + } + + public RowHeightProperty getHeadRowHeightProperty() { + return headRowHeightProperty; + } + + public void setHeadRowHeightProperty(RowHeightProperty headRowHeightProperty) { + this.headRowHeightProperty = headRowHeightProperty; + } + + public RowHeightProperty getContentRowHeightProperty() { + return contentRowHeightProperty; + } + + public void setContentRowHeightProperty(RowHeightProperty contentRowHeightProperty) { + this.contentRowHeightProperty = contentRowHeightProperty; + } + + /** + * Calculate all cells that need to be merged + * + * @return cells that need to be merged + */ + public List headCellRangeList() { + List cellRangeList = new ArrayList(); + Set alreadyRangeSet = new HashSet(); + List headList = new ArrayList(getHeadMap().values()); + for (int i = 0; i < headList.size(); i++) { + Head head = headList.get(i); + List headNameList = head.getHeadNameList(); + for (int j = 0; j < headNameList.size(); j++) { + if (alreadyRangeSet.contains(i + "-" + j)) { + continue; + } + alreadyRangeSet.add(i + "-" + j); + String headName = headNameList.get(j); + int lastCol = i; + int lastRow = j; + for (int k = i + 1; k < headList.size(); k++) { + if (headList.get(k).getHeadNameList().get(j).equals(headName)) { + alreadyRangeSet.add(k + "-" + j); + lastCol = k; + } else { + break; + } + } + Set tempAlreadyRangeSet = new HashSet(); + outer: + for (int k = j + 1; k < headNameList.size(); k++) { + for (int l = i; l <= lastCol; l++) { + if (headList.get(l).getHeadNameList().get(k).equals(headName)) { + tempAlreadyRangeSet.add(l + "-" + k); + } else { + break outer; + } + } + lastRow = k; + alreadyRangeSet.addAll(tempAlreadyRangeSet); + } + if (j == lastRow && i == lastCol) { + continue; + } + cellRangeList.add(new CellRange(j, lastRow, i, lastCol)); + } + } + return cellRangeList; + } +} diff --git a/src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java new file mode 100644 index 0000000..51b03d1 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java @@ -0,0 +1,84 @@ +package com.alibaba.excel.write.style; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Workbook; + +import com.alibaba.excel.event.NotRepeatExecutor; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; + +/** + * Cell style strategy + * + * @author Jiaju Zhuang + */ +public abstract class AbstractCellStyleStrategy implements CellWriteHandler, SheetWriteHandler, NotRepeatExecutor { + boolean hasInitialized = false; + + @Override + public String uniqueValue() { + return "CellStyleStrategy"; + } + + @Override + public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + + } + + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + initCellStyle(writeWorkbookHolder.getWorkbook()); + hasInitialized = true; + } + + @Override + public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Head head, int relativeRowIndex, boolean isHead) { + if (!hasInitialized) { + initCellStyle(writeSheetHolder.getParentWriteWorkbookHolder().getWorkbook()); + hasInitialized = true; + } + } + + @Override + public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, + Cell cell, Head head, int relativeRowIndex, boolean isHead) { + if (isHead) { + setHeadCellStyle(cell, head, relativeRowIndex); + } else { + setContentCellStyle(cell, head, relativeRowIndex); + } + } + + /** + * Initialization cell style + * + * @param workbook + */ + protected abstract void initCellStyle(Workbook workbook); + + /** + * Sets the cell style of header + * + * @param cell + * @param head + * @param relativeRowIndex + */ + protected abstract void setHeadCellStyle(Cell cell, Head head, int relativeRowIndex); + + /** + * Sets the cell style of content + * + * @param cell + * @param head + * @param relativeRowIndex + */ + protected abstract void setContentCellStyle(Cell cell, Head head, int relativeRowIndex); + +} diff --git a/src/main/java/com/alibaba/excel/write/style/AbstractVerticalCellStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/AbstractVerticalCellStyleStrategy.java new file mode 100644 index 0000000..083d9cf --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/style/AbstractVerticalCellStyleStrategy.java @@ -0,0 +1,89 @@ +package com.alibaba.excel.write.style; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Workbook; + +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.util.StyleUtil; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; + +/** + * + * Use the same style for the column + * + * @author Jiaju Zhuang + */ +public abstract class AbstractVerticalCellStyleStrategy extends AbstractCellStyleStrategy { + + private Workbook workbook; + private Map headCellStyleCache = new HashMap(); + private Map contentCellStyleCache = new HashMap(); + + @Override + protected void initCellStyle(Workbook workbook) { + this.workbook = workbook; + } + + @Override + protected void setHeadCellStyle(Cell cell, Head head, int relativeRowIndex) { + int columnIndex = head.getColumnIndex(); + if (headCellStyleCache.containsKey(columnIndex)) { + CellStyle cellStyle = headCellStyleCache.get(columnIndex); + if (cellStyle != null) { + cell.setCellStyle(cellStyle); + } + return; + } + WriteCellStyle headCellStyle = headCellStyle(head); + if (headCellStyle == null) { + headCellStyleCache.put(columnIndex, null); + } else { + CellStyle cellStyle = StyleUtil.buildHeadCellStyle(workbook, headCellStyle); + headCellStyleCache.put(columnIndex, cellStyle); + cell.setCellStyle(cellStyle); + } + } + + @Override + protected void setContentCellStyle(Cell cell, Head head, int relativeRowIndex) { + int columnIndex = head.getColumnIndex(); + if (contentCellStyleCache.containsKey(columnIndex)) { + CellStyle cellStyle = contentCellStyleCache.get(columnIndex); + if (cellStyle != null) { + cell.setCellStyle(cellStyle); + } + return; + } + WriteCellStyle contentCellStyle = contentCellStyle(head); + if (contentCellStyle == null) { + contentCellStyleCache.put(columnIndex, null); + } else { + CellStyle cellStyle = StyleUtil.buildContentCellStyle(workbook, contentCellStyle); + contentCellStyleCache.put(columnIndex, cellStyle); + cell.setCellStyle(cellStyle); + } + } + + /** + * Returns the column width corresponding to each column head + * + * @param head + * Nullable + * @return + */ + protected abstract WriteCellStyle headCellStyle(Head head); + + /** + * Returns the column width corresponding to each column head + * + * @param head + * Nullable + * @return + */ + protected abstract WriteCellStyle contentCellStyle(Head head); + +} diff --git a/src/main/java/com/alibaba/excel/write/style/HorizontalCellStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/HorizontalCellStyleStrategy.java new file mode 100644 index 0000000..da5e53b --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/style/HorizontalCellStyleStrategy.java @@ -0,0 +1,69 @@ +package com.alibaba.excel.write.style; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Workbook; + +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.util.StyleUtil; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; + +/** + * + * Use the same style for the row + * + * @author Jiaju Zhuang + */ +public class HorizontalCellStyleStrategy extends AbstractCellStyleStrategy { + + private WriteCellStyle headWriteCellStyle; + private List contentWriteCellStyleList; + + private CellStyle headCellStyle; + private List contentCellStyleList; + + public HorizontalCellStyleStrategy(WriteCellStyle headWriteCellStyle, + List contentWriteCellStyleList) { + this.headWriteCellStyle = headWriteCellStyle; + this.contentWriteCellStyleList = contentWriteCellStyleList; + } + + public HorizontalCellStyleStrategy(WriteCellStyle headWriteCellStyle, WriteCellStyle contentWriteCellStyle) { + this.headWriteCellStyle = headWriteCellStyle; + contentWriteCellStyleList = new ArrayList(); + contentWriteCellStyleList.add(contentWriteCellStyle); + } + + @Override + protected void initCellStyle(Workbook workbook) { + if (headWriteCellStyle != null) { + headCellStyle = StyleUtil.buildHeadCellStyle(workbook, headWriteCellStyle); + } + if (contentWriteCellStyleList != null && !contentWriteCellStyleList.isEmpty()) { + contentCellStyleList = new ArrayList(); + for (WriteCellStyle writeCellStyle : contentWriteCellStyleList) { + contentCellStyleList.add(StyleUtil.buildContentCellStyle(workbook, writeCellStyle)); + } + } + } + + @Override + protected void setHeadCellStyle(Cell cell, Head head, int relativeRowIndex) { + if (headCellStyle == null) { + return; + } + cell.setCellStyle(headCellStyle); + } + + @Override + protected void setContentCellStyle(Cell cell, Head head, int relativeRowIndex) { + if (contentCellStyleList == null || contentCellStyleList.isEmpty()) { + return; + } + cell.setCellStyle(contentCellStyleList.get(relativeRowIndex % contentCellStyleList.size())); + } + +} diff --git a/src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java new file mode 100644 index 0000000..67e9733 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java @@ -0,0 +1,50 @@ +package com.alibaba.excel.write.style.column; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; + +import com.alibaba.excel.event.NotRepeatExecutor; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; + +/** + * Column width style strategy + * + * @author Jiaju Zhuang + */ +public abstract class AbstractColumnWidthStyleStrategy implements CellWriteHandler, NotRepeatExecutor { + + @Override + public String uniqueValue() { + return "ColumnWidthStyleStrategy"; + } + + @Override + public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Head head, int relativeRowIndex, boolean isHead) { + + } + + @Override + public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, + Cell cell, Head head, int relativeRowIndex, boolean isHead) { + setColumnWidth(writeSheetHolder, cellData, cell, head, relativeRowIndex, isHead); + } + + /** + * Sets the column width when head create + * + * @param writeSheetHolder + * @param cellData + * @param cell + * @param head + * @param relativeRowIndex + * @param isHead + */ + protected abstract void setColumnWidth(WriteSheetHolder writeSheetHolder, CellData cellData, Cell cell, Head head, + int relativeRowIndex, boolean isHead); + +} diff --git a/src/main/java/com/alibaba/excel/write/style/column/AbstractHeadColumnWidthStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/column/AbstractHeadColumnWidthStyleStrategy.java new file mode 100644 index 0000000..da9b7da --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/style/column/AbstractHeadColumnWidthStyleStrategy.java @@ -0,0 +1,39 @@ +package com.alibaba.excel.write.style.column; + +import org.apache.poi.ss.usermodel.Cell; + +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; + +/** + * Returns the column width according to each column header + * + * @author Jiaju Zhuang + */ +public abstract class AbstractHeadColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy { + @Override + protected void setColumnWidth(WriteSheetHolder writeSheetHolder, CellData cellData, Cell cell, Head head, + int relativeRowIndex, boolean isHead) { + if (!isHead && relativeRowIndex != 0) { + return; + } + Integer width = columnWidth(head); + if (width != null) { + width = width * 256; + writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), width); + } + } + + /** + * Returns the column width corresponding to each column head. + * + *

+ * if return null,ignore + * + * @param head + * Nullable + * @return + */ + protected abstract Integer columnWidth(Head head); +} diff --git a/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java new file mode 100644 index 0000000..5c6ec8c --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java @@ -0,0 +1,66 @@ +package com.alibaba.excel.write.style.column; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.poi.ss.usermodel.Cell; + +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; + +/** + * Take the width of the longest column as the width. + *

+ * This is not very useful at the moment, for example if you have Numbers it will cause a newline.And the length is not + * exactly the same as the actual length. + * + * @author Jiaju Zhuang + */ +public class LongestMatchColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy { + + private static final int MAX_COLUMN_WIDTH = 256; + + Map> cache = new HashMap>(8); + + @Override + protected void setColumnWidth(WriteSheetHolder writeSheetHolder, CellData cellData, Cell cell, Head head, + int relativeRowIndex, boolean isHead) { + if (!isHead && cellData == null) { + return; + } + Map maxColumnWidthMap = cache.get(writeSheetHolder.getSheetNo()); + if (maxColumnWidthMap == null) { + maxColumnWidthMap = new HashMap(16); + cache.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap); + } + Integer columnWidth = dataLength(cellData, cell, isHead); + if (columnWidth < 0) { + return; + } + if (columnWidth > MAX_COLUMN_WIDTH) { + columnWidth = MAX_COLUMN_WIDTH; + } + Integer maxColumnWidth = maxColumnWidthMap.get(head.getColumnIndex()); + if (maxColumnWidth == null || columnWidth > maxColumnWidth) { + maxColumnWidthMap.put(head.getColumnIndex(), columnWidth); + writeSheetHolder.getSheet().setColumnWidth(head.getColumnIndex(), columnWidth * 256); + } + } + + private Integer dataLength(CellData cellData, Cell cell, boolean isHead) { + if (isHead) { + return cell.getStringCellValue().getBytes().length; + } + switch (cellData.getType()) { + case STRING: + return cellData.getStringValue().getBytes().length; + case BOOLEAN: + return cellData.getBooleanValue().toString().getBytes().length; + case NUMBER: + return cellData.getDoubleValue().toString().getBytes().length; + default: + return -1; + } + } +} diff --git a/src/main/java/com/alibaba/excel/write/style/column/SimpleColumnWidthStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/column/SimpleColumnWidthStyleStrategy.java new file mode 100644 index 0000000..1f3ae78 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/style/column/SimpleColumnWidthStyleStrategy.java @@ -0,0 +1,25 @@ +package com.alibaba.excel.write.style.column; + +import com.alibaba.excel.metadata.Head; + +/** + * All the columns are the same width + * + * @author Jiaju Zhuang + */ +public class SimpleColumnWidthStyleStrategy extends AbstractHeadColumnWidthStyleStrategy { + private Integer columnWidth; + + /** + * + * @param columnWidth + */ + public SimpleColumnWidthStyleStrategy(Integer columnWidth) { + this.columnWidth = columnWidth; + } + + @Override + protected Integer columnWidth(Head head) { + return columnWidth; + } +} diff --git a/src/main/java/com/alibaba/excel/write/style/row/AbstractRowHeightStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/row/AbstractRowHeightStyleStrategy.java new file mode 100644 index 0000000..3a6a343 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/style/row/AbstractRowHeightStyleStrategy.java @@ -0,0 +1,54 @@ +package com.alibaba.excel.write.style.row; + +import org.apache.poi.ss.usermodel.Row; + +import com.alibaba.excel.event.NotRepeatExecutor; +import com.alibaba.excel.write.handler.RowWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; + +/** + * Set the row height strategy + * + * @author Jiaju Zhuang + */ +public abstract class AbstractRowHeightStyleStrategy implements RowWriteHandler, NotRepeatExecutor { + + @Override + public String uniqueValue() { + return "RowHighStyleStrategy"; + } + + @Override + public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, int rowIndex, + int relativeRowIndex, boolean isHead) { + + } + + @Override + public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + int relativeRowIndex, boolean isHead) { + if (isHead) { + setHeadColumnHeight(row, relativeRowIndex); + } else { + setContentColumnHeight(row, relativeRowIndex); + } + } + + /** + * Sets the height of header + * + * @param row + * @param relativeRowIndex + */ + protected abstract void setHeadColumnHeight(Row row, int relativeRowIndex); + + /** + * Sets the height of content + * + * @param row + * @param relativeRowIndex + */ + protected abstract void setContentColumnHeight(Row row, int relativeRowIndex); + +} diff --git a/src/main/java/com/alibaba/excel/write/style/row/SimpleRowHeightStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/row/SimpleRowHeightStyleStrategy.java new file mode 100644 index 0000000..313cf21 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/style/row/SimpleRowHeightStyleStrategy.java @@ -0,0 +1,33 @@ +package com.alibaba.excel.write.style.row; + +import org.apache.poi.ss.usermodel.Row; + +/** + * Set the head column high and content column high + * + * @author Jiaju Zhuang + */ +public class SimpleRowHeightStyleStrategy extends AbstractRowHeightStyleStrategy { + private Short headRowHeight; + private Short contentRowHeight; + + public SimpleRowHeightStyleStrategy(Short headRowHeight, Short contentRowHeight) { + this.headRowHeight = headRowHeight; + this.contentRowHeight = contentRowHeight; + } + + @Override + protected void setHeadColumnHeight(Row row, int relativeRowIndex) { + if (headRowHeight != null) { + row.setHeightInPoints(headRowHeight); + } + } + + @Override + protected void setContentColumnHeight(Row row, int relativeRowIndex) { + if (contentRowHeight != null) { + row.setHeightInPoints(contentRowHeight); + } + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/ReadTest.java b/src/test/java/com/alibaba/easyexcel/test/ReadTest.java deleted file mode 100644 index f92fede..0000000 --- a/src/test/java/com/alibaba/easyexcel/test/ReadTest.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.alibaba.easyexcel.test; - -import com.alibaba.easyexcel.test.listen.ExcelListener; -import com.alibaba.easyexcel.test.model.ReadModel; -import com.alibaba.easyexcel.test.model.ReadModel2; -import com.alibaba.easyexcel.test.util.FileUtil; -import com.alibaba.excel.EasyExcelFactory; -import com.alibaba.excel.ExcelReader; -import com.alibaba.excel.metadata.Sheet; -import org.junit.Test; - -import java.io.IOException; -import java.io.InputStream; -import java.util.List; - -public class ReadTest { - - - /** - * 07版本excel读数据量少于1千行数据,内部采用回调方法. - * - * @throws IOException 简单抛出异常,真实环境需要catch异常,同时在finally中关闭流 - */ - @Test - public void simpleReadListStringV2007() throws IOException { - InputStream inputStream = FileUtil.getResourcesFileInputStream("2007.xlsx"); - List data = EasyExcelFactory.read(inputStream, new Sheet(1, 0)); - inputStream.close(); - print(data); - } - - - /** - * 07版本excel读数据量少于1千行数据自动转成javamodel,内部采用回调方法. - * - * @throws IOException 简单抛出异常,真实环境需要catch异常,同时在finally中关闭流 - */ - @Test - public void simpleReadJavaModelV2007() throws IOException { - InputStream inputStream = FileUtil.getResourcesFileInputStream("2007.xlsx"); - List data = EasyExcelFactory.read(inputStream, new Sheet(2, 1, ReadModel.class)); - inputStream.close(); - print(data); - } - - /** - * 07版本excel读数据量大于1千行,内部采用回调方法. - * - * @throws IOException 简单抛出异常,真实环境需要catch异常,同时在finally中关闭流 - */ - @Test - public void saxReadListStringV2007() throws IOException { - InputStream inputStream = FileUtil.getResourcesFileInputStream("2007.xlsx"); - ExcelListener excelListener = new ExcelListener(); - EasyExcelFactory.readBySax(inputStream, new Sheet(1, 1), excelListener); - inputStream.close(); - - } - /** - * 07版本excel读数据量大于1千行,内部采用回调方法. - * - * @throws IOException 简单抛出异常,真实环境需要catch异常,同时在finally中关闭流 - */ - @Test - public void saxReadJavaModelV2007() throws IOException { - InputStream inputStream = FileUtil.getResourcesFileInputStream("2007.xlsx"); - ExcelListener excelListener = new ExcelListener(); - EasyExcelFactory.readBySax(inputStream, new Sheet(2, 1, ReadModel.class), excelListener); - inputStream.close(); - } - - /** - * 07版本excel读取sheet - * - * @throws IOException 简单抛出异常,真实环境需要catch异常,同时在finally中关闭流 - */ - @Test - public void saxReadSheetsV2007() throws IOException { - InputStream inputStream = FileUtil.getResourcesFileInputStream("2007.xlsx"); - ExcelListener excelListener = new ExcelListener(); - ExcelReader excelReader = EasyExcelFactory.getReader(inputStream,excelListener); - List sheets = excelReader.getSheets(); - System.out.println("llll****"+sheets); - System.out.println(); - for (Sheet sheet:sheets) { - if(sheet.getSheetNo() ==1) { - excelReader.read(sheet); - }else if(sheet.getSheetNo() ==2){ - sheet.setHeadLineMun(1); - sheet.setClazz(ReadModel.class); - excelReader.read(sheet); - }else if(sheet.getSheetNo() ==3){ - sheet.setHeadLineMun(1); - sheet.setClazz(ReadModel2.class); - excelReader.read(sheet); - } - } - inputStream.close(); - } - - - - /** - * 03版本excel读数据量少于1千行数据,内部采用回调方法. - * - * @throws IOException 简单抛出异常,真实环境需要catch异常,同时在finally中关闭流 - */ - @Test - public void simpleReadListStringV2003() throws IOException { - InputStream inputStream = FileUtil.getResourcesFileInputStream("2003.xls"); - List data = EasyExcelFactory.read(inputStream, new Sheet(1, 0)); - inputStream.close(); - print(data); - } - - /** - * 03版本excel读数据量少于1千行数据转成javamodel,内部采用回调方法. - * - * @throws IOException 简单抛出异常,真实环境需要catch异常,同时在finally中关闭流 - */ - @Test - public void simpleReadJavaModelV2003() throws IOException { - InputStream inputStream = FileUtil.getResourcesFileInputStream("2003.xls"); - List data = EasyExcelFactory.read(inputStream, new Sheet(2, 1, ReadModel.class)); - inputStream.close(); - print(data); - } - - /** - * 03版本excel读数据量大于1千行数据,内部采用回调方法. - * - * @throws IOException 简单抛出异常,真实环境需要catch异常,同时在finally中关闭流 - */ - @Test - public void saxReadListStringV2003() throws IOException { - InputStream inputStream = FileUtil.getResourcesFileInputStream("2003.xls"); - ExcelListener excelListener = new ExcelListener(); - EasyExcelFactory.readBySax(inputStream, new Sheet(2, 1), excelListener); - inputStream.close(); - } - - /** - * 03版本excel读数据量大于1千行数据转成javamodel,内部采用回调方法. - * - * @throws IOException 简单抛出异常,真实环境需要catch异常,同时在finally中关闭流 - */ - @Test - public void saxReadJavaModelV2003() throws IOException { - InputStream inputStream = FileUtil.getResourcesFileInputStream("2003.xls"); - ExcelListener excelListener = new ExcelListener(); - EasyExcelFactory.readBySax(inputStream, new Sheet(2, 1, ReadModel.class), excelListener); - inputStream.close(); - } - - /** - * 00版本excel读取sheet - * - * @throws IOException 简单抛出异常,真实环境需要catch异常,同时在finally中关闭流 - */ - @Test - public void saxReadSheetsV2003() throws IOException { - InputStream inputStream = FileUtil.getResourcesFileInputStream("2003.xls"); - ExcelListener excelListener = new ExcelListener(); - ExcelReader excelReader = EasyExcelFactory.getReader(inputStream,excelListener); - List sheets = excelReader.getSheets(); - System.out.println(); - for (Sheet sheet:sheets) { - if(sheet.getSheetNo() == 1) { - excelReader.read(sheet); - }else { - sheet.setHeadLineMun(2); - sheet.setClazz(ReadModel.class); - excelReader.read(sheet); - } - } - inputStream.close(); - } - - - public void print(List datas){ - int i=0; - for (Object ob:datas) { - System.out.println(i++); - System.out.println(ob); - } - } - -} diff --git a/src/test/java/com/alibaba/easyexcel/test/WriteTest.java b/src/test/java/com/alibaba/easyexcel/test/WriteTest.java deleted file mode 100644 index 6b481b6..0000000 --- a/src/test/java/com/alibaba/easyexcel/test/WriteTest.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.alibaba.easyexcel.test; - -import com.alibaba.easyexcel.test.listen.AfterWriteHandlerImpl; -import com.alibaba.easyexcel.test.model.WriteModel; -import com.alibaba.easyexcel.test.util.FileUtil; -import com.alibaba.excel.EasyExcelFactory; -import com.alibaba.excel.ExcelWriter; -import com.alibaba.excel.metadata.Sheet; -import com.alibaba.excel.metadata.Table; -import com.alibaba.excel.support.ExcelTypeEnum; -import org.junit.Test; - -import java.io.*; -import java.util.HashMap; -import java.util.Map; - -import static com.alibaba.easyexcel.test.util.DataUtil.*; - -public class WriteTest { - - @Test - public void writeV2007() throws IOException { - OutputStream out = new FileOutputStream("/Users/jipengfei/2007.xlsx"); - ExcelWriter writer = EasyExcelFactory.getWriter(out); - //写第一个sheet, sheet1 数据全是List 无模型映射关系 - Sheet sheet1 = new Sheet(1, 3); - sheet1.setSheetName("第一个sheet"); - - //设置列宽 设置每列的宽度 - Map columnWidth = new HashMap(); - columnWidth.put(0,10000);columnWidth.put(1,40000);columnWidth.put(2,10000);columnWidth.put(3,10000); - sheet1.setColumnWidthMap(columnWidth); - sheet1.setHead(createTestListStringHead()); - //or 设置自适应宽度 - //sheet1.setAutoWidth(Boolean.TRUE); - writer.write1(createTestListObject(), sheet1); - - //写第二个sheet sheet2 模型上打有表头的注解,合并单元格 - Sheet sheet2 = new Sheet(2, 3, WriteModel.class, "第二个sheet", null); - sheet2.setTableStyle(createTableStyle()); - //writer.write1(null, sheet2); - writer.write(createTestListJavaMode(), sheet2); - //需要合并单元格 - writer.merge(5,20,1,1); - - //写第三个sheet包含多个table情况 - Sheet sheet3 = new Sheet(3, 0); - sheet3.setSheetName("第三个sheet"); - Table table1 = new Table(1); - table1.setHead(createTestListStringHead()); - writer.write1(createTestListObject(), sheet3, table1); - - //写sheet2 模型上打有表头的注解 - Table table2 = new Table(2); - table2.setTableStyle(createTableStyle()); - table2.setClazz(WriteModel.class); - writer.write(createTestListJavaMode(), sheet3, table2); - - writer.finish(); - out.close(); - - } - - - @Test - public void writeV2007WithTemplate() throws IOException { - InputStream inputStream = FileUtil.getResourcesFileInputStream("temp.xlsx"); - OutputStream out = new FileOutputStream("/Users/jipengfei/2007.xlsx"); - ExcelWriter writer = EasyExcelFactory.getWriterWithTemp(inputStream,out,ExcelTypeEnum.XLSX,true); - //写第一个sheet, sheet1 数据全是List 无模型映射关系 - Sheet sheet1 = new Sheet(1, 3); - sheet1.setSheetName("第一个sheet"); - sheet1.setStartRow(20); - - //设置列宽 设置每列的宽度 - Map columnWidth = new HashMap(); - columnWidth.put(0,10000);columnWidth.put(1,40000);columnWidth.put(2,10000);columnWidth.put(3,10000); - sheet1.setColumnWidthMap(columnWidth); - sheet1.setHead(createTestListStringHead()); - //or 设置自适应宽度 - //sheet1.setAutoWidth(Boolean.TRUE); - writer.write1(createTestListObject(), sheet1); - - //写第二个sheet sheet2 模型上打有表头的注解,合并单元格 - Sheet sheet2 = new Sheet(2, 3, WriteModel.class, "第二个sheet", null); - sheet2.setTableStyle(createTableStyle()); - sheet2.setStartRow(20); - writer.write(createTestListJavaMode(), sheet2); - - //写第三个sheet包含多个table情况 - Sheet sheet3 = new Sheet(3, 0); - sheet3.setSheetName("第三个sheet"); - sheet3.setStartRow(30); - Table table1 = new Table(1); - table1.setHead(createTestListStringHead()); - writer.write1(createTestListObject(), sheet3, table1); - - //写sheet2 模型上打有表头的注解 - Table table2 = new Table(2); - table2.setTableStyle(createTableStyle()); - table2.setClazz(WriteModel.class); - writer.write(createTestListJavaMode(), sheet3, table2); - - writer.finish(); - out.close(); - - } - - @Test - public void writeV2007WithTemplateAndHandler() throws IOException { - InputStream inputStream = FileUtil.getResourcesFileInputStream("temp.xlsx"); - OutputStream out = new FileOutputStream("/Users/jipengfei/2007.xlsx"); - ExcelWriter writer = EasyExcelFactory.getWriterWithTempAndHandler(inputStream,out,ExcelTypeEnum.XLSX,true, - new AfterWriteHandlerImpl()); - //写第一个sheet, sheet1 数据全是List 无模型映射关系 - Sheet sheet1 = new Sheet(1, 3); - sheet1.setSheetName("第一个sheet"); - sheet1.setStartRow(20); - - //设置列宽 设置每列的宽度 - Map columnWidth = new HashMap(); - columnWidth.put(0,10000);columnWidth.put(1,40000);columnWidth.put(2,10000);columnWidth.put(3,10000); - sheet1.setColumnWidthMap(columnWidth); - sheet1.setHead(createTestListStringHead()); - //or 设置自适应宽度 - //sheet1.setAutoWidth(Boolean.TRUE); - writer.write1(createTestListObject(), sheet1); - - //写第二个sheet sheet2 模型上打有表头的注解,合并单元格 - Sheet sheet2 = new Sheet(2, 3, WriteModel.class, "第二个sheet", null); - sheet2.setTableStyle(createTableStyle()); - sheet2.setStartRow(20); - writer.write(createTestListJavaMode(), sheet2); - - //写第三个sheet包含多个table情况 - Sheet sheet3 = new Sheet(3, 0); - sheet3.setSheetName("第三个sheet"); - sheet3.setStartRow(30); - Table table1 = new Table(1); - table1.setHead(createTestListStringHead()); - writer.write1(createTestListObject(), sheet3, table1); - - //写sheet2 模型上打有表头的注解 - Table table2 = new Table(2); - table2.setTableStyle(createTableStyle()); - table2.setClazz(WriteModel.class); - writer.write(createTestListJavaMode(), sheet3, table2); - - writer.finish(); - out.close(); - - } - - - - @Test - public void writeV2003() throws IOException { - OutputStream out = new FileOutputStream("/Users/jipengfei/2003.xls"); - ExcelWriter writer = EasyExcelFactory.getWriter(out, ExcelTypeEnum.XLS,true); - //写第一个sheet, sheet1 数据全是List 无模型映射关系 - Sheet sheet1 = new Sheet(1, 3); - sheet1.setSheetName("第一个sheet"); - - //设置列宽 设置每列的宽度 - Map columnWidth = new HashMap(); - columnWidth.put(0,10000);columnWidth.put(1,40000);columnWidth.put(2,10000);columnWidth.put(3,10000); - sheet1.setColumnWidthMap(columnWidth); - sheet1.setHead(createTestListStringHead()); - //or 设置自适应宽度 - //sheet1.setAutoWidth(Boolean.TRUE); - writer.write1(createTestListObject(), sheet1); - - //写第二个sheet sheet2 模型上打有表头的注解,合并单元格 - Sheet sheet2 = new Sheet(2, 3, WriteModel.class, "第二个sheet", null); - sheet2.setTableStyle(createTableStyle()); - writer.write(createTestListJavaMode(), sheet2); - - //写第三个sheet包含多个table情况 - Sheet sheet3 = new Sheet(3, 0); - sheet3.setSheetName("第三个sheet"); - Table table1 = new Table(1); - table1.setHead(createTestListStringHead()); - writer.write1(createTestListObject(), sheet3, table1); - - //写sheet2 模型上打有表头的注解 - Table table2 = new Table(2); - table2.setTableStyle(createTableStyle()); - table2.setClazz(WriteModel.class); - writer.write(createTestListJavaMode(), sheet3, table2); - - writer.finish(); - out.close(); - } -} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationData.java b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationData.java new file mode 100644 index 0000000..2a028f3 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationData.java @@ -0,0 +1,32 @@ +package com.alibaba.easyexcel.test.core.annotation; + +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.DateTimeFormat; +import com.alibaba.excel.annotation.format.NumberFormat; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.ContentRowHeight; +import com.alibaba.excel.annotation.write.style.HeadRowHeight; +import com.alibaba.excel.converters.doubleconverter.DoubleStringConverter; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +@ColumnWidth(30) +@HeadRowHeight(15) +@ContentRowHeight(20) +public class AnnotationData { + @ExcelProperty("日期") + @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒") + private Date date; + @ExcelProperty(value = "数字", converter = DoubleStringConverter.class) + @NumberFormat("#.##%") + private Double number; + @ExcelIgnore + private String ignore; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationDataListener.java new file mode 100644 index 0000000..09bfc52 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationDataListener.java @@ -0,0 +1,41 @@ +package com.alibaba.easyexcel.test.core.annotation; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelCommonException; +import com.alibaba.excel.util.DateUtils; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class AnnotationDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(AnnotationDataListener.class); + List list = new ArrayList(); + + @Override + public void invoke(AnnotationData data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 1); + AnnotationData data = list.get(0); + try { + Assert.assertEquals(data.getDate(), DateUtils.parseDate("2020-01-01 01:01:01")); + } catch (ParseException e) { + throw new ExcelCommonException("Test Exception", e); + } + Assert.assertEquals(data.getNumber(), 99.99, 0.00); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationDataTest.java new file mode 100644 index 0000000..62fea8a --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationDataTest.java @@ -0,0 +1,54 @@ +package com.alibaba.easyexcel.test.core.annotation; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.util.DateUtils; + +/** + * + * @author Jiaju Zhuang + */ +public class AnnotationDataTest { + + private static File file07; + private static File file03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("annotation07.xlsx"); + file03 = TestFileUtil.createNewFile("annotation03.xls"); + } + + @Test + public void T01ReadAndWrite07() throws Exception { + readAndWrite(file07); + } + + @Test + public void T02ReadAndWrite03() throws Exception { + readAndWrite(file03); + } + + private void readAndWrite(File file) throws Exception { + EasyExcel.write().file(file).head(AnnotationData.class).sheet().doWrite(data()); + EasyExcel.read().file(file).head(AnnotationData.class).registerReadListener(new AnnotationDataListener()) + .sheet().doRead(); + } + + private List data() throws Exception { + List list = new ArrayList(); + AnnotationData data = new AnnotationData(); + data.setDate(DateUtils.parseDate("2020-01-01 01:01:01")); + data.setNumber(99.99); + data.setIgnore("忽略"); + list.add(data); + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationIndexAndNameData.java b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationIndexAndNameData.java new file mode 100644 index 0000000..b41f093 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationIndexAndNameData.java @@ -0,0 +1,20 @@ +package com.alibaba.easyexcel.test.core.annotation; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class AnnotationIndexAndNameData { + @ExcelProperty(value = "第四个", index = 4) + private String index4; + @ExcelProperty(value = "第二个") + private String index2; + @ExcelProperty(index = 0) + private String index0; + @ExcelProperty(value = "第一个", index = 1) + private String index1; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationIndexAndNameDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationIndexAndNameDataListener.java new file mode 100644 index 0000000..115b1b0 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationIndexAndNameDataListener.java @@ -0,0 +1,36 @@ +package com.alibaba.easyexcel.test.core.annotation; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class AnnotationIndexAndNameDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(AnnotationIndexAndNameDataListener.class); + List list = new ArrayList(); + + @Override + public void invoke(AnnotationIndexAndNameData data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 1); + AnnotationIndexAndNameData data = list.get(0); + Assert.assertEquals(data.getIndex0(), "第0个"); + Assert.assertEquals(data.getIndex1(), "第1个"); + Assert.assertEquals(data.getIndex2(), "第2个"); + Assert.assertEquals(data.getIndex4(), "第4个"); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationIndexAndNameDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationIndexAndNameDataTest.java new file mode 100644 index 0000000..148f719 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/annotation/AnnotationIndexAndNameDataTest.java @@ -0,0 +1,55 @@ +package com.alibaba.easyexcel.test.core.annotation; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; + +/** + * Annotation data test + * + * @author Jiaju Zhuang + */ +public class AnnotationIndexAndNameDataTest { + + private static File file07; + private static File file03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("annotationIndexAndName07.xlsx"); + file03 = TestFileUtil.createNewFile("annotationIndexAndName03.xls"); + } + + @Test + public void T01ReadAndWrite07() { + readAndWrite(file07); + } + + @Test + public void T02ReadAndWrite03() { + readAndWrite(file03); + } + + private void readAndWrite(File file) { + EasyExcel.write(file, AnnotationIndexAndNameData.class).sheet().doWrite(data()); + EasyExcel.read(file, AnnotationIndexAndNameData.class, new AnnotationIndexAndNameDataListener()).sheet() + .doRead(); + } + + private List data() { + List list = new ArrayList(); + AnnotationIndexAndNameData data = new AnnotationIndexAndNameData(); + data.setIndex0("第0个"); + data.setIndex1("第1个"); + data.setIndex2("第2个"); + data.setIndex4("第4个"); + list.add(data); + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityData.java b/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityData.java new file mode 100644 index 0000000..45b7f63 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityData.java @@ -0,0 +1,17 @@ +package com.alibaba.easyexcel.test.core.compatibility; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.metadata.BaseRowModel; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class CompatibilityData extends BaseRowModel { + @ExcelProperty("字符串标题0") + private String string0; + @ExcelProperty("字符串标题1") + private String string1; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityDataListener.java new file mode 100644 index 0000000..29774ba --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityDataListener.java @@ -0,0 +1,34 @@ +package com.alibaba.easyexcel.test.core.compatibility; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.core.annotation.AnnotationDataListener; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class CompatibilityDataListener extends AnalysisEventListener> { + private static final Logger LOGGER = LoggerFactory.getLogger(AnnotationDataListener.class); + List> list = new ArrayList>(); + + @Override + public void invoke(List data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 10); + List data = list.get(0); + Assert.assertEquals(data.get(0), "字符串00"); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityDataTest.java new file mode 100644 index 0000000..49af7fe --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityDataTest.java @@ -0,0 +1,160 @@ +package com.alibaba.easyexcel.test.core.compatibility; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.poi.ss.usermodel.IndexedColors; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.metadata.Font; +import com.alibaba.excel.metadata.Sheet; +import com.alibaba.excel.metadata.Table; +import com.alibaba.excel.metadata.TableStyle; +import com.alibaba.excel.parameter.AnalysisParam; +import com.alibaba.excel.parameter.GenerateParam; + +/** + * + * @author Jiaju Zhuang + */ +public class CompatibilityDataTest { + + private static File file07; + private static File file03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("compatibility07.xlsx"); + file03 = TestFileUtil.createNewFile("compatibility03.xls"); + } + + @Test + public void T01ReadAndWrite07() throws Exception { + readAndWrite(file07); + } + + @Test + public void T02ReadAndWrite03() throws Exception { + readAndWrite(file03); + } + + private void readAndWrite(File file) throws Exception { + OutputStream out = new FileOutputStream(file); + GenerateParam generateParam = new GenerateParam("", null, out); + generateParam.setSheetName(""); + generateParam.setOutputStream(out); + generateParam.setClazz(null); + ExcelWriter writer = new ExcelWriter(generateParam); + // sheet1 width,string head,string data + Sheet sheet1 = new Sheet(1, 3); + sheet1.setSheetName("第一个sheet"); + Map columnWidth = new HashMap(); + columnWidth.put(0, 10000); + columnWidth.put(1, 50000); + sheet1.setColumnWidthMap(columnWidth); + sheet1.setHead(head()); + writer.write1(listData(), sheet1); + + // sheet2 style,class head + Sheet sheet2 = new Sheet(2, 3, CompatibilityData.class, "第二个sheet", null); + sheet2.setStartRow(5); + sheet2.setTableStyle(style()); + writer.write(data(), sheet2); + writer.merge(8, 8, 0, 1); + + // sheet3 table + Sheet sheet3 = new Sheet(3, 0); + sheet3.setSheetName("第三个sheet"); + + Table table1 = new Table(1); + table1.setHead(head()); + writer.write1(listData(), sheet3, table1); + + Table table2 = new Table(2); + table2.setClazz(CompatibilityData.class); + writer.write(data(), sheet3, table2); + + writer.finish(); + out.close(); + + InputStream inputStream = new FileInputStream(file); + List data = EasyExcel.read(inputStream, new Sheet(1, 1)); + Assert.assertEquals(data.size(), 1); + List dataList = (List)data.get(0); + Assert.assertEquals(dataList.get(0), "字符串00"); + inputStream.close(); + + inputStream = new FileInputStream(file); + AnalysisParam param = new AnalysisParam(inputStream, null, new Object()); + param.setIn(inputStream); + param.setExcelTypeEnum(null); + param.setCustomContent(null); + ExcelReader excelReader = new ExcelReader(param, new CompatibilityDataListener()); + excelReader.read(new Sheet(2, 6)); + Assert.assertEquals(excelReader.getSheets().size(), 3); + Assert.assertTrue(excelReader.getAnalysisContext() != null); + inputStream.close(); + } + + private List> head() { + List> list = new ArrayList>(); + List head0 = new ArrayList(); + head0.add("字符串标题0"); + List head1 = new ArrayList(); + head1.add("字符串标题1"); + list.add(head0); + list.add(head1); + return list; + } + + private List> listData() { + List> list = new ArrayList>(); + List data0 = new ArrayList(); + data0.add("字符串00"); + data0.add(11); + list.add(data0); + return list; + } + + private List data() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + CompatibilityData data = new CompatibilityData(); + data.setString0("字符串0" + i); + data.setString1("字符串1" + i); + list.add(data); + } + return list; + } + + public TableStyle style() { + TableStyle tableStyle = new TableStyle(); + Font headFont = new Font(); + headFont.setBold(true); + headFont.setFontHeightInPoints((short)22); + headFont.setFontName("楷体"); + tableStyle.setTableHeadFont(headFont); + tableStyle.setTableHeadBackGroundColor(IndexedColors.BLUE); + + Font contentFont = new Font(); + contentFont.setBold(true); + contentFont.setFontHeightInPoints((short)22); + contentFont.setFontName("黑体"); + tableStyle.setTableContentFont(contentFont); + tableStyle.setTableContentBackGroundColor(IndexedColors.GREEN); + return tableStyle; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityParameterDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityParameterDataTest.java new file mode 100644 index 0000000..d075f33 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityParameterDataTest.java @@ -0,0 +1,143 @@ +package com.alibaba.easyexcel.test.core.compatibility; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.metadata.Sheet; + +/** + * + * @author Jiaju Zhuang + */ +public class CompatibilityParameterDataTest { + + private static File file; + + @BeforeClass + public static void init() { + file = TestFileUtil.createNewFile("compatibilityParameter.xlsx"); + } + + @Test + public void T01ReadAndWrite() throws Exception { + readAndWrite1(file); + readAndWrite2(file); + readAndWrite3(file); + readAndWrite4(file); + readAndWrite5(file); + readAndWrite6(file); + } + + private void readAndWrite1(File file) throws Exception { + OutputStream out = new FileOutputStream(file); + ExcelWriter writer = EasyExcel.getWriter(out); + Sheet sheet1 = new Sheet(1, 0); + sheet1.setSheetName("第一个sheet"); + writer.write0(data(), sheet1); + writer.finish(); + out.close(); + + InputStream inputStream = new FileInputStream(file); + EasyExcel.readBySax(inputStream, new Sheet(1, 0), new CompatibilityDataListener()); + inputStream.close(); + } + + private void readAndWrite2(File file) throws Exception { + OutputStream out = new FileOutputStream(file); + ExcelWriter writer = EasyExcel.getWriter(out, null, false); + Sheet sheet1 = new Sheet(1, 0); + sheet1.setSheetName("第一个sheet"); + writer.write0(data(), sheet1); + writer.finish(); + out.close(); + + InputStream inputStream = new FileInputStream(file); + EasyExcel.readBySax(inputStream, new Sheet(1, 0), new CompatibilityDataListener()); + inputStream.close(); + } + + private void readAndWrite3(File file) throws Exception { + OutputStream out = new FileOutputStream(file); + ExcelWriter writer = new ExcelWriter(out, null); + Sheet sheet1 = new Sheet(1, 0); + sheet1.setSheetName("第一个sheet"); + writer.write0(data(), sheet1); + writer.finish(); + out.close(); + + InputStream inputStream = new FileInputStream(file); + ExcelReader excelReader = new ExcelReader(inputStream, null, null, new CompatibilityDataListener()); + excelReader.read(new Sheet(1, 0)); + inputStream.close(); + + } + + private void readAndWrite4(File file) throws Exception { + OutputStream out = new FileOutputStream(file); + ExcelWriter writer = new ExcelWriter(null, out, null, null); + Sheet sheet1 = new Sheet(1, 0); + sheet1.setSheetName("第一个sheet"); + writer.write0(data(), sheet1, null); + writer.finish(); + out.close(); + + InputStream inputStream = new FileInputStream(file); + ExcelReader excelReader = new ExcelReader(inputStream, null, new CompatibilityDataListener()); + excelReader.read(new Sheet(1, 0)); + inputStream.close(); + } + + private void readAndWrite5(File file) throws Exception { + OutputStream out = new FileOutputStream(file); + ExcelWriter writer = EasyExcel.getWriterWithTemp(null, out, null, false); + Sheet sheet1 = new Sheet(1, 0); + sheet1.setSheetName("第一个sheet"); + writer.write0(data(), sheet1, null); + writer.finish(); + out.close(); + + InputStream inputStream = new FileInputStream(file); + ExcelReader excelReader = EasyExcel.getReader(inputStream, new CompatibilityDataListener()); + excelReader.read(new Sheet(1, 0)); + inputStream.close(); + } + + private void readAndWrite6(File file) throws Exception { + OutputStream out = new FileOutputStream(file); + ExcelWriter writer = EasyExcel.getWriterWithTempAndHandler(null, out, null, false, null); + Sheet sheet1 = new Sheet(1, 0); + sheet1.setSheetName("第一个sheet"); + writer.write0(data(), sheet1, null); + writer.finish(); + out.close(); + + InputStream inputStream = new FileInputStream(file); + ExcelReader excelReader = EasyExcel.getReader(inputStream, new CompatibilityDataListener()); + excelReader.read(new Sheet(1, 0)); + inputStream.close(); + } + + private List data() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + CompatibilityData data = new CompatibilityData(); + data.setString0("字符串0" + i); + data.setString1("字符串1" + i); + list.add(data); + } + return list; + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityReadData.java b/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityReadData.java new file mode 100644 index 0000000..ba062a5 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/compatibility/CompatibilityReadData.java @@ -0,0 +1,14 @@ +package com.alibaba.easyexcel.test.core.compatibility; + +import com.alibaba.excel.metadata.BaseRowModel; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class CompatibilityReadData extends BaseRowModel { + private String string0; + private String string1; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterData.java b/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterData.java new file mode 100644 index 0000000..8846947 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterData.java @@ -0,0 +1,38 @@ +package com.alibaba.easyexcel.test.core.converter; + +import java.math.BigDecimal; +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.metadata.CellData; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class ConverterData { + @ExcelProperty("日期") + private Date date; + @ExcelProperty("布尔") + private Boolean booleanData; + @ExcelProperty("大数") + private BigDecimal bigDecimal; + @ExcelProperty("长整型") + private long longData; + @ExcelProperty("整型") + private Integer integerData; + @ExcelProperty("短整型") + private Short shortData; + @ExcelProperty("字节型") + private Byte byteData; + @ExcelProperty("双精度浮点型") + private double doubleData; + @ExcelProperty("浮点型") + private Float floatData; + @ExcelProperty("字符串") + private String string; + @ExcelProperty("自定义") + private CellData cellData; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterDataListener.java new file mode 100644 index 0000000..abd5e1c --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterDataListener.java @@ -0,0 +1,51 @@ +package com.alibaba.easyexcel.test.core.converter; + +import java.math.BigDecimal; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelCommonException; +import com.alibaba.excel.util.DateUtils; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class ConverterDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(ConverterDataListener.class); + List list = new ArrayList(); + + @Override + public void invoke(ConverterData data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 1); + ConverterData data = list.get(0); + try { + Assert.assertEquals(data.getDate(), DateUtils.parseDate("2020-01-01 01:01:01")); + } catch (ParseException e) { + throw new ExcelCommonException("Test Exception", e); + } + Assert.assertEquals(data.getBooleanData(), Boolean.TRUE); + Assert.assertEquals(data.getBigDecimal().doubleValue(), BigDecimal.ONE.doubleValue(), 0.0); + Assert.assertEquals((long)data.getLongData(), 1L); + Assert.assertEquals((long)data.getIntegerData(), 1L); + Assert.assertEquals((long)data.getShortData(), 1L); + Assert.assertEquals((long)data.getByteData(), 1L); + Assert.assertEquals(data.getDoubleData(), 1.0, 0.0); + Assert.assertEquals(data.getFloatData(), (float)1.0, 0.0); + Assert.assertEquals(data.getString(), "测试"); + Assert.assertEquals(data.getCellData().getStringValue(), "自定义"); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterDataTest.java new file mode 100644 index 0000000..a223e25 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterDataTest.java @@ -0,0 +1,117 @@ +package com.alibaba.easyexcel.test.core.converter; + +import java.io.File; +import java.io.InputStream; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.util.DateUtils; +import com.alibaba.excel.util.FileUtils; + +/** + * + * @author Jiaju Zhuang + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class ConverterDataTest { + + private static File file07; + private static File file03; + private static File fileImage07; + private static File fileImage03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("converter07.xlsx"); + file03 = TestFileUtil.createNewFile("converter03.xls"); + fileImage07 = TestFileUtil.createNewFile("converterImage07.xlsx"); + fileImage03 = TestFileUtil.createNewFile("converterImage03.xls"); + } + + @Test + public void T01ReadAndWrite07() throws Exception { + readAndWrite(file07); + } + + @Test + public void T02ReadAndWrite03() throws Exception { + readAndWrite(file03); + } + + private void readAndWrite(File file) throws Exception { + EasyExcel.write(file, ConverterData.class).sheet().doWrite(data()); + EasyExcel.read(file, ConverterData.class, new ConverterDataListener()).sheet().doRead(); + } + + @Test + public void T03ReadAllConverter07() { + readAllConverter("converter" + File.separator + "converter07.xlsx"); + } + + @Test + public void T04ReadAllConverter03() { + readAllConverter("converter" + File.separator + "converter03.xls"); + } + + @Test + public void T05WriteImage07() throws Exception { + writeImage(fileImage07); + } + + @Test + public void T06WriteImage03() throws Exception { + writeImage(fileImage03); + } + + private void writeImage(File file) throws Exception { + InputStream inputStream = null; + try { + List list = new ArrayList(); + ImageData imageData = new ImageData(); + list.add(imageData); + String imagePath = TestFileUtil.getPath() + "converter" + File.separator + "img.jpg"; + imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath))); + imageData.setFile(new File(imagePath)); + imageData.setString(imagePath); + inputStream = FileUtils.openInputStream(new File(imagePath)); + imageData.setInputStream(inputStream); + EasyExcel.write(file, ImageData.class).sheet().doWrite(list); + } finally { + if (inputStream != null) { + inputStream.close(); + } + } + } + + private void readAllConverter(String fileName) { + EasyExcel.read(TestFileUtil.readFile(fileName), ReadAllConverterData.class, new ReadAllConverterDataListener()) + .sheet().doRead(); + } + + private List data() throws Exception { + List list = new ArrayList(); + ConverterData converterData = new ConverterData(); + converterData.setDate(DateUtils.parseDate("2020-01-01 01:01:01")); + converterData.setBooleanData(Boolean.TRUE); + converterData.setBigDecimal(BigDecimal.ONE); + converterData.setLongData(1L); + converterData.setIntegerData(1); + converterData.setShortData((short)1); + converterData.setByteData((byte)1); + converterData.setDoubleData(1.0); + converterData.setFloatData((float)1.0); + converterData.setString("测试"); + converterData.setCellData(new CellData("自定义")); + list.add(converterData); + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/converter/ImageData.java b/src/test/java/com/alibaba/easyexcel/test/core/converter/ImageData.java new file mode 100644 index 0000000..f8d6ac2 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/converter/ImageData.java @@ -0,0 +1,25 @@ +package com.alibaba.easyexcel.test.core.converter; + +import java.io.File; +import java.io.InputStream; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.ContentRowHeight; +import com.alibaba.excel.converters.string.StringImageConverter; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +@ContentRowHeight(500) +@ColumnWidth(500 / 8) +public class ImageData { + private File file; + private InputStream inputStream; + @ExcelProperty(converter = StringImageConverter.class) + private String string; + private byte[] byteArray; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterData.java b/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterData.java new file mode 100644 index 0000000..4f758a0 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterData.java @@ -0,0 +1,46 @@ +package com.alibaba.easyexcel.test.core.converter; + +import java.math.BigDecimal; +import java.util.Date; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class ReadAllConverterData { + private BigDecimal bigDecimalBoolean; + private BigDecimal bigDecimalNumber; + private BigDecimal bigDecimalString; + private Boolean booleanBoolean; + private Boolean booleanNumber; + private Boolean booleanString; + private Byte byteBoolean; + private Byte byteNumber; + private Byte byteString; + private Date dateNumber; + private Date dateString; + private Double doubleBoolean; + private Double doubleNumber; + private Double doubleString; + private Float floatBoolean; + private Float floatNumber; + private Float floatString; + private Integer integerBoolean; + private Integer integerNumber; + private Integer integerString; + private Long longBoolean; + private Long longNumber; + private Long longString; + private Short shortBoolean; + private Short shortNumber; + private Short shortString; + private String stringBoolean; + private String stringNumber; + private String stringString; + private String stringError; + private String stringFormulaNumber; + private String stringFormulaString; + private String stringNumberDate; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterDataListener.java new file mode 100644 index 0000000..f4f0a1e --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterDataListener.java @@ -0,0 +1,72 @@ +package com.alibaba.easyexcel.test.core.converter; + +import java.math.BigDecimal; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelCommonException; +import com.alibaba.excel.util.DateUtils; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class ReadAllConverterDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(ReadAllConverterDataListener.class); + List list = new ArrayList(); + + @Override + public void invoke(ReadAllConverterData data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 1); + ReadAllConverterData data = list.get(0); + Assert.assertEquals(data.getBigDecimalBoolean().doubleValue(), BigDecimal.ONE.doubleValue(), 0.0); + Assert.assertEquals(data.getBigDecimalNumber().doubleValue(), BigDecimal.ONE.doubleValue(), 0.0); + Assert.assertEquals(data.getBigDecimalString().doubleValue(), BigDecimal.ONE.doubleValue(), 0.0); + Assert.assertTrue(data.getBooleanBoolean()); + Assert.assertTrue(data.getBooleanNumber()); + Assert.assertTrue(data.getBooleanString()); + Assert.assertEquals((long)data.getByteBoolean(), 1L); + Assert.assertEquals((long)data.getByteNumber(), 1L); + Assert.assertEquals((long)data.getByteString(), 1L); + try { + Assert.assertEquals(data.getDateNumber(), DateUtils.parseDate("2020-01-01 01:01:01")); + Assert.assertEquals(data.getDateString(), DateUtils.parseDate("2020-01-01 01:01:01")); + } catch (ParseException e) { + throw new ExcelCommonException("Test Exception", e); + } + Assert.assertEquals(data.getDoubleBoolean(), 1.0, 0.0); + Assert.assertEquals(data.getDoubleNumber(), 1.0, 0.0); + Assert.assertEquals(data.getDoubleString(), 1.0, 0.0); + Assert.assertEquals(data.getFloatBoolean(), (float)1.0, 0.0); + Assert.assertEquals(data.getFloatNumber(), (float)1.0, 0.0); + Assert.assertEquals(data.getFloatString(), (float)1.0, 0.0); + Assert.assertEquals((long)data.getIntegerBoolean(), 1L); + Assert.assertEquals((long)data.getIntegerNumber(), 1L); + Assert.assertEquals((long)data.getIntegerString(), 1L); + Assert.assertEquals((long)data.getLongBoolean(), 1L); + Assert.assertEquals((long)data.getLongNumber(), 1L); + Assert.assertEquals((long)data.getLongString(), 1L); + Assert.assertEquals((long)data.getShortBoolean(), 1L); + Assert.assertEquals((long)data.getShortNumber(), 1L); + Assert.assertEquals((long)data.getShortString(), 1L); + Assert.assertEquals(data.getStringBoolean(), "true"); + Assert.assertEquals(data.getStringString(), "测试"); + Assert.assertEquals(data.getStringError(), "#VALUE!"); + Assert.assertEquals(data.getStringNumberDate(), "2020-01-01 01:01:01"); + Assert.assertEquals(data.getStringFormulaNumber(), "2.0"); + Assert.assertEquals(data.getStringFormulaString(), "1测试"); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/exception/ExceptionData.java b/src/test/java/com/alibaba/easyexcel/test/core/exception/ExceptionData.java new file mode 100644 index 0000000..28d273e --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/exception/ExceptionData.java @@ -0,0 +1,14 @@ +package com.alibaba.easyexcel.test.core.exception; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class ExceptionData { + @ExcelProperty("姓名") + private String name; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/exception/ExceptionDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/exception/ExceptionDataListener.java new file mode 100644 index 0000000..ffad838 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/exception/ExceptionDataListener.java @@ -0,0 +1,48 @@ +package com.alibaba.easyexcel.test.core.exception; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class ExceptionDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionData.class); + List list = new ArrayList(); + + @Override + public void onException(Exception exception, AnalysisContext context) { + LOGGER.info("抛出异常,忽略:{}", exception.getMessage()); + } + + @Override + public boolean hasNext(AnalysisContext context) { + return list.size() != 8; + } + + @Override + public void invoke(ExceptionData data, AnalysisContext context) { + list.add(data); + if (list.size() == 5) { + int i = 5 / 0; + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 8); + Assert.assertEquals(list.get(0).getName(), "姓名0"); + Assert.assertEquals((int)(context.readSheetHolder().getSheetNo()), 0); + Assert.assertEquals( + context.readSheetHolder().getExcelReadHeadProperty().getHeadMap().get(0).getHeadNameList().get(0), "姓名"); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/exception/ExceptionDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/exception/ExceptionDataTest.java new file mode 100644 index 0000000..93210cf --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/exception/ExceptionDataTest.java @@ -0,0 +1,57 @@ +package com.alibaba.easyexcel.test.core.exception; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; + +/** + * + * @author Jiaju Zhuang + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class ExceptionDataTest { + + private static File file07; + private static File file03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("simple07.xlsx"); + file03 = TestFileUtil.createNewFile("simple03.xls"); + } + + @Test + public void T01ReadAndWrite07() throws Exception { + readAndWrite(file07); + } + + @Test + public void T02ReadAndWrite03() throws Exception { + readAndWrite(file03); + } + + private void readAndWrite(File file) throws Exception { + EasyExcel.write(new FileOutputStream(file), ExceptionData.class).sheet().doWrite(data()); + EasyExcel.read(new FileInputStream(file), ExceptionData.class, new ExceptionDataListener()).sheet().doRead(); + } + + private List data() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + ExceptionData simpleData = new ExceptionData(); + simpleData.setName("姓名" + i); + list.add(simpleData); + } + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/head/ComplexDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/head/ComplexDataListener.java new file mode 100644 index 0000000..a3441d5 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/head/ComplexDataListener.java @@ -0,0 +1,33 @@ +package com.alibaba.easyexcel.test.core.head; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class ComplexDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(ComplexHeadData.class); + List list = new ArrayList(); + + @Override + public void invoke(ComplexHeadData data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 1); + ComplexHeadData data = list.get(0); + Assert.assertEquals(data.getString4(), "字符串4"); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/head/ComplexHeadData.java b/src/test/java/com/alibaba/easyexcel/test/core/head/ComplexHeadData.java new file mode 100644 index 0000000..30e7e81 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/head/ComplexHeadData.java @@ -0,0 +1,22 @@ +package com.alibaba.easyexcel.test.core.head; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class ComplexHeadData { + @ExcelProperty({"顶格", "顶格", "两格"}) + private String string0; + @ExcelProperty({"顶格", "顶格", "两格"}) + private String string1; + @ExcelProperty({"顶格", "四联", "四联"}) + private String string2; + @ExcelProperty({"顶格", "四联", "四联"}) + private String string3; + @ExcelProperty({"顶格"}) + private String string4; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/head/ComplexHeadDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/head/ComplexHeadDataTest.java new file mode 100644 index 0000000..9e654fd --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/head/ComplexHeadDataTest.java @@ -0,0 +1,54 @@ +package com.alibaba.easyexcel.test.core.head; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; + +/** + * + * @author Jiaju Zhuang + */ +public class ComplexHeadDataTest { + + private static File file07; + private static File file03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("complexHead07.xlsx"); + file03 = TestFileUtil.createNewFile("complexHead03.xls"); + } + + @Test + public void T01ReadAndWrite07() { + readAndWrite(file07); + } + + @Test + public void T02ReadAndWrite03() { + readAndWrite(file03); + } + + private void readAndWrite(File file) { + EasyExcel.write(file, ComplexHeadData.class).sheet().doWrite(data()); + EasyExcel.read(file, ComplexHeadData.class, new ComplexDataListener()).sheet().doRead(); + } + + private List data() { + List list = new ArrayList(); + ComplexHeadData data = new ComplexHeadData(); + data.setString0("字符串0"); + data.setString1("字符串1"); + data.setString2("字符串2"); + data.setString3("字符串3"); + data.setString4("字符串4"); + list.add(data); + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/head/ListHeadDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/head/ListHeadDataListener.java new file mode 100644 index 0000000..81e85ae --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/head/ListHeadDataListener.java @@ -0,0 +1,38 @@ +package com.alibaba.easyexcel.test.core.head; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class ListHeadDataListener extends AnalysisEventListener> { + + private static final Logger LOGGER = LoggerFactory.getLogger(NoHeadData.class); + List> list = new ArrayList>(); + + @Override + public void invoke(Map data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 1); + Map data = list.get(0); + Assert.assertEquals(data.get(0), "字符串0"); + Assert.assertEquals(data.get(1), "1.0"); + Assert.assertEquals(data.get(2), "2020-01-01 01:01:01"); + Assert.assertEquals(data.get(3), "额外数据"); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/head/ListHeadDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/head/ListHeadDataTest.java new file mode 100644 index 0000000..9b5330d --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/head/ListHeadDataTest.java @@ -0,0 +1,69 @@ +package com.alibaba.easyexcel.test.core.head; + +import java.io.File; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.util.DateUtils; + +/** + * + * @author Jiaju Zhuang + */ +public class ListHeadDataTest { + + private static File file07; + private static File file03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("listHead07.xlsx"); + file03 = TestFileUtil.createNewFile("listHead03.xls"); + } + + @Test + public void T01ReadAndWrite07() throws Exception { + readAndWrite(file07); + } + + @Test + public void T02ReadAndWrite03() throws Exception { + readAndWrite(file03); + } + + private void readAndWrite(File file) throws Exception { + EasyExcel.write(file).head(head()).sheet().doWrite(data()); + EasyExcel.read(file).registerReadListener(new ListHeadDataListener()).sheet().doRead(); + } + + private List> head() { + List> list = new ArrayList>(); + List head0 = new ArrayList(); + head0.add("字符串"); + List head1 = new ArrayList(); + head1.add("数字"); + List head2 = new ArrayList(); + head2.add("日期"); + list.add(head0); + list.add(head1); + list.add(head2); + return list; + } + + private List> data() throws ParseException { + List> list = new ArrayList>(); + List data0 = new ArrayList(); + data0.add("字符串0"); + data0.add(1); + data0.add(DateUtils.parseDate("2020-01-01 01:01:01")); + data0.add("额外数据"); + list.add(data0); + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/head/NoHeadData.java b/src/test/java/com/alibaba/easyexcel/test/core/head/NoHeadData.java new file mode 100644 index 0000000..7e19af1 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/head/NoHeadData.java @@ -0,0 +1,14 @@ +package com.alibaba.easyexcel.test.core.head; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class NoHeadData { + @ExcelProperty("字符串") + private String string; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/head/NoHeadDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/head/NoHeadDataListener.java new file mode 100644 index 0000000..f09c899 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/head/NoHeadDataListener.java @@ -0,0 +1,33 @@ +package com.alibaba.easyexcel.test.core.head; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class NoHeadDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(NoHeadData.class); + List list = new ArrayList(); + + @Override + public void invoke(NoHeadData data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 1); + NoHeadData data = list.get(0); + Assert.assertEquals(data.getString(), "字符串0"); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/head/NoHeadDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/head/NoHeadDataTest.java new file mode 100644 index 0000000..934750c --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/head/NoHeadDataTest.java @@ -0,0 +1,50 @@ +package com.alibaba.easyexcel.test.core.head; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; + +/** + * + * @author Jiaju Zhuang + */ +public class NoHeadDataTest { + + private static File file07; + private static File file03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("noHead07.xlsx"); + file03 = TestFileUtil.createNewFile("noHead03.xls"); + } + + @Test + public void T01ReadAndWrite07() { + readAndWrite(file07); + } + + @Test + public void T02ReadAndWrite03() { + readAndWrite(file03); + } + + private void readAndWrite(File file) { + EasyExcel.write(file, NoHeadData.class).needHead(Boolean.FALSE).sheet().doWrite(data()); + EasyExcel.read(file, NoHeadData.class, new NoHeadDataListener()).headRowNumber(0).sheet().doRead(); + } + + private List data() { + List list = new ArrayList(); + NoHeadData data = new NoHeadData(); + data.setString("字符串0"); + list.add(data); + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/large/LargeData.java b/src/test/java/com/alibaba/easyexcel/test/core/large/LargeData.java new file mode 100644 index 0000000..246f9cb --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/large/LargeData.java @@ -0,0 +1,60 @@ +package com.alibaba.easyexcel.test.core.large; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class LargeData { + + private String str1; + + private String str2; + + private String str3; + + private String str4; + + private String str5; + + private String str6; + + private String str7; + + private String str8; + + private String str9; + + private String str10; + + private String str11; + + private String str12; + + private String str13; + + private String str14; + + private String str15; + + private String str16; + + private String str17; + + private String str18; + + private String str19; + + private String str20; + + private String str21; + + private String str22; + + private String str23; + + private String str24; + + private String str25; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/large/LargeDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/large/LargeDataListener.java new file mode 100644 index 0000000..23a8843 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/large/LargeDataListener.java @@ -0,0 +1,34 @@ +package com.alibaba.easyexcel.test.core.large; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class LargeDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(LargeDataListener.class); + private int count = 0; + + @Override + public void invoke(LargeData data, AnalysisContext context) { + if (count == 0) { + LOGGER.info("First row:{}", JSON.toJSONString(data)); + } + count++; + if (count % 100000 == 0) { + LOGGER.info("Already read:{}", count); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + LOGGER.info("Large row count:{}", count); + Assert.assertEquals(count, 464509); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/large/LargeDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/large/LargeDataTest.java new file mode 100644 index 0000000..b7ba56b --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/large/LargeDataTest.java @@ -0,0 +1,26 @@ +package com.alibaba.easyexcel.test.core.large; + +import java.io.File; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; + +/** + * + * @author Jiaju Zhuang + */ +public class LargeDataTest { + private static final Logger LOGGER = LoggerFactory.getLogger(LargeDataTest.class); + + @Test + public void read() { + long start = System.currentTimeMillis(); + EasyExcel.read(TestFileUtil.getPath() + "large" + File.separator + "large07.xlsx", LargeData.class, + new LargeDataListener()).headRowNumber(2).sheet().doRead(); + LOGGER.info("Large data total time spent:{}", System.currentTimeMillis() - start); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/parameter/ParameterData.java b/src/test/java/com/alibaba/easyexcel/test/core/parameter/ParameterData.java new file mode 100644 index 0000000..7e22a2e --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/parameter/ParameterData.java @@ -0,0 +1,14 @@ +package com.alibaba.easyexcel.test.core.parameter; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class ParameterData { + @ExcelProperty("姓名") + private String name; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/parameter/ParameterDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/parameter/ParameterDataListener.java new file mode 100644 index 0000000..57cca66 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/parameter/ParameterDataListener.java @@ -0,0 +1,35 @@ +package com.alibaba.easyexcel.test.core.parameter; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class ParameterDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(ParameterDataListener.class); + List list = new ArrayList(); + + @Override + public void invoke(ParameterData data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 10); + Assert.assertEquals(list.get(0).getName(), "姓名0"); + Assert.assertEquals((int)(context.readSheetHolder().getSheetNo()), 0); + Assert.assertEquals( + context.readSheetHolder().getExcelReadHeadProperty().getHeadMap().get(0).getHeadNameList().get(0), "姓名"); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/parameter/ParameterDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/parameter/ParameterDataTest.java new file mode 100644 index 0000000..cc97cd0 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/parameter/ParameterDataTest.java @@ -0,0 +1,130 @@ +package com.alibaba.easyexcel.test.core.parameter; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.cache.MapCache; +import com.alibaba.excel.converters.string.StringStringConverter; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.WriteTable; + +/** + * + * @author Jiaju Zhuang + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class ParameterDataTest { + + private static File file; + + @BeforeClass + public static void init() { + file = TestFileUtil.createNewFile("parameter07.xlsx"); + } + + @Test + public void T01ReadAndWrite() throws Exception { + readAndWrite1(); + readAndWrite2(); + readAndWrite3(); + readAndWrite4(); + readAndWrite5(); + readAndWrite6(); + readAndWrite7(); + } + + private void readAndWrite1() { + EasyExcel.write(file.getPath()).head(ParameterData.class).sheet().doWrite(data()); + EasyExcel.read(file.getPath()).head(ParameterData.class).registerReadListener(new ParameterDataListener()) + .sheet().doRead(); + } + + private void readAndWrite2() { + EasyExcel.write(file.getPath(), ParameterData.class).sheet().doWrite(data()); + EasyExcel.read(file.getPath(), ParameterData.class, new ParameterDataListener()).sheet().doRead(); + } + + private void readAndWrite3() throws Exception { + EasyExcel.write(new FileOutputStream(file)).head(ParameterData.class).sheet().doWrite(data()); + EasyExcel.read(file.getPath()).head(ParameterData.class).registerReadListener(new ParameterDataListener()) + .sheet().doRead(); + } + + private void readAndWrite4() throws Exception { + EasyExcel.write(new FileOutputStream(file), ParameterData.class).sheet().doWrite(data()); + EasyExcel.read(file.getPath(), new ParameterDataListener()).head(ParameterData.class).sheet().doRead(); + } + + private void readAndWrite5() throws Exception { + ExcelWriter excelWriter = + EasyExcel.write(new FileOutputStream(file)).head(ParameterData.class).relativeHeadRowIndex(0).build(); + WriteSheet writeSheet = EasyExcel.writerSheet(0).relativeHeadRowIndex(0).needHead(Boolean.FALSE).build(); + WriteTable writeTable = EasyExcel.writerTable(0).relativeHeadRowIndex(0).needHead(Boolean.TRUE).build(); + excelWriter.write(data(), writeSheet, writeTable); + excelWriter.finish(); + + ExcelReader excelReader = EasyExcel.read(file.getPath(), new ParameterDataListener()).head(ParameterData.class) + .mandatoryUseInputStream(Boolean.FALSE).autoCloseStream(Boolean.TRUE).readCache(new MapCache()).build(); + ReadSheet readSheet = EasyExcel.readSheet().head(ParameterData.class).use1904windowing(Boolean.FALSE) + .headRowNumber(1).sheetNo(0).sheetName("0").build(); + excelReader.read(readSheet); + excelReader.finish(); + + excelReader = EasyExcel.read(file.getPath(), new ParameterDataListener()).head(ParameterData.class) + .mandatoryUseInputStream(Boolean.FALSE).autoCloseStream(Boolean.TRUE).readCache(new MapCache()).build(); + excelReader.read(); + excelReader.finish(); + } + + private void readAndWrite6() throws Exception { + ExcelWriter excelWriter = + EasyExcel.write(new FileOutputStream(file)).head(ParameterData.class).relativeHeadRowIndex(0).build(); + WriteSheet writeSheet = EasyExcel.writerSheet(0).relativeHeadRowIndex(0).needHead(Boolean.FALSE).build(); + WriteTable writeTable = EasyExcel.writerTable(0).registerConverter(new StringStringConverter()) + .relativeHeadRowIndex(0).needHead(Boolean.TRUE).build(); + excelWriter.write(data(), writeSheet, writeTable); + excelWriter.finish(); + + ExcelReader excelReader = EasyExcel.read(file.getPath(), new ParameterDataListener()).head(ParameterData.class) + .mandatoryUseInputStream(Boolean.FALSE).autoCloseStream(Boolean.TRUE).readCache(new MapCache()).build(); + ReadSheet readSheet = EasyExcel.readSheet("0").head(ParameterData.class).use1904windowing(Boolean.FALSE) + .headRowNumber(1).sheetNo(0).build(); + excelReader.read(readSheet); + excelReader.finish(); + + excelReader = EasyExcel.read(file.getPath(), new ParameterDataListener()).head(ParameterData.class) + .mandatoryUseInputStream(Boolean.FALSE).autoCloseStream(Boolean.TRUE).readCache(new MapCache()).build(); + excelReader.read(); + excelReader.finish(); + } + + private void readAndWrite7() { + EasyExcel.write(file, ParameterData.class).registerConverter(new StringStringConverter()).sheet() + .registerConverter(new StringStringConverter()).needHead(Boolean.FALSE).table(0).needHead(Boolean.TRUE) + .doWrite(data()); + EasyExcel.read(file.getPath()).head(ParameterData.class).registerReadListener(new ParameterDataListener()) + .sheet().registerConverter(new StringStringConverter()).doRead(); + } + + private List data() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + ParameterData simpleData = new ParameterData(); + simpleData.setName("姓名" + i); + list.add(simpleData); + } + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/repetition/RepetitionData.java b/src/test/java/com/alibaba/easyexcel/test/core/repetition/RepetitionData.java new file mode 100644 index 0000000..0a7378f --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/repetition/RepetitionData.java @@ -0,0 +1,14 @@ +package com.alibaba.easyexcel.test.core.repetition; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class RepetitionData { + @ExcelProperty("字符串") + private String string; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/repetition/RepetitionDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/repetition/RepetitionDataListener.java new file mode 100644 index 0000000..ff0a332 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/repetition/RepetitionDataListener.java @@ -0,0 +1,34 @@ +package com.alibaba.easyexcel.test.core.repetition; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.core.simple.SimpleDataListener; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class RepetitionDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleDataListener.class); + List list = new ArrayList(); + + @Override + public void invoke(RepetitionData data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 2); + Assert.assertEquals(list.get(0).getString(), "字符串0"); + Assert.assertEquals(list.get(1).getString(), "字符串0"); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/repetition/RepetitionDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/repetition/RepetitionDataTest.java new file mode 100644 index 0000000..5005764 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/repetition/RepetitionDataTest.java @@ -0,0 +1,86 @@ +package com.alibaba.easyexcel.test.core.repetition; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.WriteTable; + +/** + * + * @author Jiaju Zhuang + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class RepetitionDataTest { + + private static File file07; + private static File file03; + private static File fileTable07; + private static File fileTable03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("repetition07.xlsx"); + file03 = TestFileUtil.createNewFile("repetition03.xls"); + fileTable07 = TestFileUtil.createNewFile("repetitionTable07.xlsx"); + fileTable03 = TestFileUtil.createNewFile("repetitionTable03.xls"); + } + + @Test + public void T01ReadAndWrite07() { + readAndWrite(file07); + } + + @Test + public void T02ReadAndWrite03() { + readAndWrite(file03); + } + + private void readAndWrite(File file) { + ExcelWriter excelWriter = EasyExcel.write(file, RepetitionData.class).build(); + WriteSheet writeSheet = EasyExcel.writerSheet(0).build(); + excelWriter.write(data(), writeSheet).write(data(), writeSheet).finish(); + ExcelReader excelReader = EasyExcel.read(file, RepetitionData.class, new RepetitionDataListener()).build(); + ReadSheet readSheet = EasyExcel.readSheet(0).build(); + excelReader.read(readSheet).finish(); + } + + @Test + public void T03ReadAndWriteTable07() { + readAndWriteTable(fileTable07); + } + + @Test + public void T04ReadAndWriteTable03() { + readAndWriteTable(fileTable03); + } + + private void readAndWriteTable(File file) { + ExcelWriter excelWriter = EasyExcel.write(file, RepetitionData.class).build(); + WriteSheet writeSheet = EasyExcel.writerSheet(0).build(); + WriteTable writeTable = EasyExcel.writerTable(0).relativeHeadRowIndex(0).build(); + excelWriter.write(data(), writeSheet, writeTable).write(data(), writeSheet, writeTable).finish(); + ExcelReader excelReader = EasyExcel.read(file, RepetitionData.class, new RepetitionDataListener()).build(); + ReadSheet readSheet = EasyExcel.readSheet(0).headRowNumber(2).build(); + excelReader.read(readSheet).finish(); + } + + private List data() { + List list = new ArrayList(); + RepetitionData data = new RepetitionData(); + data.setString("字符串0"); + list.add(data); + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/simple/SimpleData.java b/src/test/java/com/alibaba/easyexcel/test/core/simple/SimpleData.java new file mode 100644 index 0000000..6c541a2 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/simple/SimpleData.java @@ -0,0 +1,14 @@ +package com.alibaba.easyexcel.test.core.simple; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class SimpleData { + @ExcelProperty("姓名") + private String name; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/simple/SimpleDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/simple/SimpleDataListener.java new file mode 100644 index 0000000..757cb07 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/simple/SimpleDataListener.java @@ -0,0 +1,35 @@ +package com.alibaba.easyexcel.test.core.simple; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class SimpleDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleDataListener.class); + List list = new ArrayList(); + + @Override + public void invoke(SimpleData data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 10); + Assert.assertEquals(list.get(0).getName(), "姓名0"); + Assert.assertEquals((int)(context.readSheetHolder().getSheetNo()), 0); + Assert.assertEquals( + context.readSheetHolder().getExcelReadHeadProperty().getHeadMap().get(0).getHeadNameList().get(0), "姓名"); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/simple/SimpleDataSheetNameListener.java b/src/test/java/com/alibaba/easyexcel/test/core/simple/SimpleDataSheetNameListener.java new file mode 100644 index 0000000..72c4c15 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/simple/SimpleDataSheetNameListener.java @@ -0,0 +1,32 @@ +package com.alibaba.easyexcel.test.core.simple; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class SimpleDataSheetNameListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleDataSheetNameListener.class); + List list = new ArrayList(); + + @Override + public void invoke(SimpleData data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 1); + Assert.assertEquals(list.get(0).getName(), "张三"); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/simple/SimpleDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/simple/SimpleDataTest.java new file mode 100644 index 0000000..fee56e5 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/simple/SimpleDataTest.java @@ -0,0 +1,80 @@ +package com.alibaba.easyexcel.test.core.simple; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; + +/** + * + * @author Jiaju Zhuang + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class SimpleDataTest { + + private static File file07; + private static File file03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("simple07.xlsx"); + file03 = TestFileUtil.createNewFile("simple03.xls"); + } + + @Test + public void T01ReadAndWrite07() { + readAndWrite(file07); + } + + @Test + public void T02ReadAndWrite03() { + readAndWrite(file03); + } + + private void readAndWrite(File file) { + EasyExcel.write(file, SimpleData.class).sheet().doWrite(data()); + EasyExcel.read(file, SimpleData.class, new SimpleDataListener()).sheet().doRead(); + } + + @Test + public void T03SynchronousRead07() { + synchronousRead(file07); + } + + @Test + public void T04SynchronousRead03() { + synchronousRead(file03); + } + + @Test + public void T05SheetNameRead07() { + EasyExcel.read(TestFileUtil.readFile("simple" + File.separator + "simple07.xlsx"), SimpleData.class, + new SimpleDataSheetNameListener()).sheet("simple").doRead(); + } + + private void synchronousRead(File file) { + // Synchronous read file + List list = EasyExcel.read(file).head(SimpleData.class).sheet().doReadSync(); + Assert.assertEquals(list.size(), 10); + Assert.assertTrue(list.get(0) instanceof SimpleData); + Assert.assertEquals(((SimpleData)list.get(0)).getName(), "姓名0"); + } + + private List data() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + SimpleData simpleData = new SimpleData(); + simpleData.setName("姓名" + i); + list.add(simpleData); + } + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/style/StyleData.java b/src/test/java/com/alibaba/easyexcel/test/core/style/StyleData.java new file mode 100644 index 0000000..f7094eb --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/style/StyleData.java @@ -0,0 +1,16 @@ +package com.alibaba.easyexcel.test.core.style; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class StyleData { + @ExcelProperty("字符串") + private String string; + @ExcelProperty("字符串1") + private String string1; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/style/StyleDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/style/StyleDataListener.java new file mode 100644 index 0000000..9246a10 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/style/StyleDataListener.java @@ -0,0 +1,34 @@ +package com.alibaba.easyexcel.test.core.style; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.core.simple.SimpleDataListener; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class StyleDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleDataListener.class); + List list = new ArrayList(); + + @Override + public void invoke(StyleData data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 2); + Assert.assertEquals(list.get(0).getString(), "字符串0"); + Assert.assertEquals(list.get(1).getString(), "字符串1"); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/style/StyleDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/style/StyleDataTest.java new file mode 100644 index 0000000..d52aee7 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/style/StyleDataTest.java @@ -0,0 +1,169 @@ +package com.alibaba.easyexcel.test.core.style; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.VerticalAlignment; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.merge.LoopMergeStrategy; +import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import com.alibaba.excel.write.style.AbstractVerticalCellStyleStrategy; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; +import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy; +import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy; + +/** + * + * @author Jiaju Zhuang + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class StyleDataTest { + + private static File file07; + private static File file03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("style07.xlsx"); + file03 = TestFileUtil.createNewFile("style03.xls"); + } + + @Test + public void T01ReadAndWrite07() { + readAndWrite(file07); + } + + @Test + public void T02ReadAndWrite03() { + readAndWrite(file03); + } + + @Test + public void T03AbstractVerticalCellStyleStrategy() { + AbstractVerticalCellStyleStrategy verticalCellStyleStrategy = new AbstractVerticalCellStyleStrategy() { + @Override + protected WriteCellStyle headCellStyle(Head head) { + WriteCellStyle writeCellStyle = new WriteCellStyle(); + writeCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); + writeCellStyle.setDataFormat((short)0); + writeCellStyle.setHidden(false); + writeCellStyle.setLocked(true); + writeCellStyle.setQuotePrefix(true); + writeCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); + writeCellStyle.setWrapped(true); + writeCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); + writeCellStyle.setRotation((short)0); + writeCellStyle.setIndent((short)10); + writeCellStyle.setBorderLeft(BorderStyle.THIN); + writeCellStyle.setBorderRight(BorderStyle.THIN); + writeCellStyle.setBorderTop(BorderStyle.THIN); + writeCellStyle.setBorderBottom(BorderStyle.THIN); + writeCellStyle.setLeftBorderColor(IndexedColors.RED.getIndex()); + writeCellStyle.setRightBorderColor(IndexedColors.RED.getIndex()); + writeCellStyle.setTopBorderColor(IndexedColors.RED.getIndex()); + writeCellStyle.setBottomBorderColor(IndexedColors.RED.getIndex()); + writeCellStyle.setFillBackgroundColor(IndexedColors.RED.getIndex()); + writeCellStyle.setShrinkToFit(Boolean.TRUE); + + if (head.getColumnIndex() == 0) { + writeCellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex()); + WriteFont writeFont = new WriteFont(); + writeFont.setItalic(true); + writeFont.setStrikeout(true); + writeFont.setTypeOffset(Font.SS_NONE); + writeFont.setUnderline(Font.U_DOUBLE); + writeFont.setBold(true); + writeFont.setCharset((int)Font.DEFAULT_CHARSET); + } else { + writeCellStyle.setFillForegroundColor(IndexedColors.BLUE.getIndex()); + } + return writeCellStyle; + } + + @Override + protected WriteCellStyle contentCellStyle(Head head) { + WriteCellStyle writeCellStyle = new WriteCellStyle(); + writeCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); + if (head.getColumnIndex() == 0) { + writeCellStyle.setFillForegroundColor(IndexedColors.DARK_GREEN.getIndex()); + } else { + writeCellStyle.setFillForegroundColor(IndexedColors.PINK.getIndex()); + } + return writeCellStyle; + } + }; + EasyExcel.write(file07, StyleData.class).registerWriteHandler(verticalCellStyleStrategy).sheet() + .doWrite(data()); + } + + @Test + public void T04LoopMergeStrategy() { + EasyExcel.write(file07, StyleData.class).sheet().registerWriteHandler(new LoopMergeStrategy(2, 1)) + .doWrite(data10()); + } + + private void readAndWrite(File file) { + SimpleColumnWidthStyleStrategy simpleColumnWidthStyleStrategy = new SimpleColumnWidthStyleStrategy(50); + SimpleRowHeightStyleStrategy simpleRowHeightStyleStrategy = + new SimpleRowHeightStyleStrategy((short)40, (short)50); + + WriteCellStyle headWriteCellStyle = new WriteCellStyle(); + headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex()); + WriteFont headWriteFont = new WriteFont(); + headWriteFont.setFontHeightInPoints((short)20); + headWriteCellStyle.setWriteFont(headWriteFont); + WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); + contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); + contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex()); + WriteFont contentWriteFont = new WriteFont(); + contentWriteFont.setFontHeightInPoints((short)20); + headWriteCellStyle.setWriteFont(contentWriteFont); + HorizontalCellStyleStrategy horizontalCellStyleStrategy = + new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle); + + OnceAbsoluteMergeStrategy onceAbsoluteMergeStrategy = new OnceAbsoluteMergeStrategy(2, 2, 0, 1); + EasyExcel.write(file, StyleData.class).registerWriteHandler(simpleColumnWidthStyleStrategy) + .registerWriteHandler(simpleRowHeightStyleStrategy).registerWriteHandler(horizontalCellStyleStrategy) + .registerWriteHandler(onceAbsoluteMergeStrategy).sheet().doWrite(data()); + EasyExcel.read(file, StyleData.class, new StyleDataListener()).sheet().doRead(); + } + + private List data() { + List list = new ArrayList(); + StyleData data = new StyleData(); + data.setString("字符串0"); + data.setString1("字符串01"); + StyleData data1 = new StyleData(); + data1.setString("字符串1"); + data1.setString1("字符串11"); + list.add(data); + list.add(data1); + return list; + } + + private List data10() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + StyleData data = new StyleData(); + data.setString("字符串0"); + data.setString1("字符串01"); + list.add(data); + } + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/template/TemplateData.java b/src/test/java/com/alibaba/easyexcel/test/core/template/TemplateData.java new file mode 100644 index 0000000..31778a2 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/template/TemplateData.java @@ -0,0 +1,16 @@ +package com.alibaba.easyexcel.test.core.template; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class TemplateData { + @ExcelProperty("字符串0") + private String string0; + @ExcelProperty("字符串1") + private String string1; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/template/TemplateDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/template/TemplateDataListener.java new file mode 100644 index 0000000..0286e2e --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/template/TemplateDataListener.java @@ -0,0 +1,34 @@ +package com.alibaba.easyexcel.test.core.template; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.core.simple.SimpleDataListener; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class TemplateDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleDataListener.class); + List list = new ArrayList(); + + @Override + public void invoke(TemplateData data, AnalysisContext context) { + list.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + Assert.assertEquals(list.size(), 2); + Assert.assertEquals(list.get(0).getString0(), "字符串0"); + Assert.assertEquals(list.get(1).getString0(), "字符串1"); + LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/template/TemplateDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/template/TemplateDataTest.java new file mode 100644 index 0000000..369bc8b --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/template/TemplateDataTest.java @@ -0,0 +1,67 @@ +package com.alibaba.easyexcel.test.core.template; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; + +/** + * + * @author Jiaju Zhuang + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TemplateDataTest { + + private static File file07; + private static File file03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.createNewFile("template07.xlsx"); + file03 = TestFileUtil.createNewFile("template03.xls"); + } + + @Test + public void T01ReadAndWrite07() { + readAndWrite07(file07); + } + + @Test + public void T02ReadAndWrite03() { + readAndWrite03(file03); + } + + private void readAndWrite07(File file) { + EasyExcel.write(file, TemplateData.class) + .withTemplate(TestFileUtil.readFile("template" + File.separator + "template07.xlsx")).sheet() + .doWrite(data()); + EasyExcel.read(file, TemplateData.class, new TemplateDataListener()).headRowNumber(3).sheet().doRead(); + } + + private void readAndWrite03(File file) { + EasyExcel.write(file, TemplateData.class) + .withTemplate(TestFileUtil.readFile("template" + File.separator + "template03.xls")).sheet() + .doWrite(data()); + EasyExcel.read(file, TemplateData.class, new TemplateDataListener()).headRowNumber(3).sheet().doRead(); + } + + private List data() { + List list = new ArrayList(); + TemplateData data = new TemplateData(); + data.setString0("字符串0"); + data.setString1("字符串01"); + TemplateData data1 = new TemplateData(); + data1.setString0("字符串1"); + data1.setString1("字符串11"); + list.add(data); + list.add(data1); + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/ConverterData.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/ConverterData.java new file mode 100644 index 0000000..bc27e1f --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/ConverterData.java @@ -0,0 +1,31 @@ +package com.alibaba.easyexcel.test.demo.read; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.DateTimeFormat; +import com.alibaba.excel.annotation.format.NumberFormat; + +import lombok.Data; + +/** + * 基础数据类.这里的排序和excel里面的排序一致 + * + * @author Jiaju Zhuang + **/ +@Data +public class ConverterData { + /** + * 我自定义 转换器,不管数据库传过来什么 。我给他加上“自定义:” + */ + @ExcelProperty(converter = CustomStringStringConverter.class) + private String string; + /** + * 这里用string 去接日期才能格式化。我想接收年月日格式 + */ + @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒") + private String date; + /** + * 我想接收百分比的数字 + */ + @NumberFormat("#.##%") + private String doubleData; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/ConverterDataListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/ConverterDataListener.java new file mode 100644 index 0000000..d343964 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/ConverterDataListener.java @@ -0,0 +1,49 @@ +package com.alibaba.easyexcel.test.demo.read; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * 模板的读取类 + * + * @author Jiaju Zhuang + */ +public class ConverterDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(ConverterDataListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static final int BATCH_COUNT = 5; + List list = new ArrayList(); + + @Override + public void invoke(ConverterData data, AnalysisContext context) { + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + list.add(data); + if (list.size() >= BATCH_COUNT) { + saveData(); + list.clear(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + saveData(); + LOGGER.info("所有数据解析完成!"); + } + + /** + * 加上存储数据库 + */ + private void saveData() { + LOGGER.info("{}条数据,开始存储数据库!", list.size()); + LOGGER.info("存储数据库成功!"); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/CustomStringStringConverter.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/CustomStringStringConverter.java new file mode 100644 index 0000000..5201e75 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/CustomStringStringConverter.java @@ -0,0 +1,59 @@ +package com.alibaba.easyexcel.test.demo.read; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * String and string converter + * + * @author Jiaju Zhuang + */ +public class CustomStringStringConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return String.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + /** + * 这里读的时候会调用 + * + * @param cellData + * NotNull + * @param contentProperty + * Nullable + * @param globalConfiguration + * NotNull + * @return + */ + @Override + public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return "自定义:" + cellData.getStringValue(); + } + + /** + * 这里是写的时候会调用 不用管 + * + * @param value + * NotNull + * @param contentProperty + * Nullable + * @param globalConfiguration + * NotNull + * @return + */ + @Override + public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData(value); + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoData.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoData.java new file mode 100644 index 0000000..a7a7519 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoData.java @@ -0,0 +1,17 @@ +package com.alibaba.easyexcel.test.demo.read; + +import java.util.Date; + +import lombok.Data; + +/** + * 基础数据类.这里的排序和excel里面的排序一致 + * + * @author Jiaju Zhuang + **/ +@Data +public class DemoData { + private String string; + private Date date; + private Double doubleData; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoDataListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoDataListener.java new file mode 100644 index 0000000..bf4dd63 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoDataListener.java @@ -0,0 +1,49 @@ +package com.alibaba.easyexcel.test.demo.read; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * 模板的读取类 + * + * @author Jiaju Zhuang + */ +public class DemoDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static final int BATCH_COUNT = 5; + List list = new ArrayList(); + + @Override + public void invoke(DemoData data, AnalysisContext context) { + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + list.add(data); + if (list.size() >= BATCH_COUNT) { + saveData(); + list.clear(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + saveData(); + LOGGER.info("所有数据解析完成!"); + } + + /** + * 加上存储数据库 + */ + private void saveData() { + LOGGER.info("{}条数据,开始存储数据库!", list.size()); + LOGGER.info("存储数据库成功!"); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/IndexOrNameData.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/IndexOrNameData.java new file mode 100644 index 0000000..1521b8c --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/IndexOrNameData.java @@ -0,0 +1,28 @@ +package com.alibaba.easyexcel.test.demo.read; + +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * 基础数据类 + * + * @author Jiaju Zhuang + **/ +@Data +public class IndexOrNameData { + /** + * 强制读取第三个 这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配 + */ + @ExcelProperty(index = 2) + private Double doubleData; + /** + * 用名字去匹配,这里需要注意,如果名字重复,会导致只有一个字段读取到数据 + */ + @ExcelProperty("字符串标题") + private String string; + @ExcelProperty("日期标题") + private Date date; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/IndexOrNameDataListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/IndexOrNameDataListener.java new file mode 100644 index 0000000..6c13d68 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/IndexOrNameDataListener.java @@ -0,0 +1,49 @@ +package com.alibaba.easyexcel.test.demo.read; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * 模板的读取类 + * + * @author Jiaju Zhuang + */ +public class IndexOrNameDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(IndexOrNameDataListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static final int BATCH_COUNT = 5; + List list = new ArrayList(); + + @Override + public void invoke(IndexOrNameData data, AnalysisContext context) { + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + list.add(data); + if (list.size() >= BATCH_COUNT) { + saveData(); + list.clear(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + saveData(); + LOGGER.info("所有数据解析完成!"); + } + + /** + * 加上存储数据库 + */ + private void saveData() { + LOGGER.info("{}条数据,开始存储数据库!", list.size()); + LOGGER.info("存储数据库成功!"); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java new file mode 100644 index 0000000..90524d3 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java @@ -0,0 +1,159 @@ +package com.alibaba.easyexcel.test.demo.read; + +import java.io.File; +import java.util.List; +import java.util.Map; + +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelReader; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.DateTimeFormat; +import com.alibaba.excel.annotation.format.NumberFormat; +import com.alibaba.excel.converters.DefaultConverterLoader; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.fastjson.JSON; + +/** + * 读的常见写法 + * + * @author Jiaju Zhuang + */ +@Ignore +public class ReadTest { + private static final Logger LOGGER = LoggerFactory.getLogger(ReadTest.class); + + /** + * 最简单的读 + *

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

+ * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} + *

+ * 3. 直接读即可 + */ + @Test + public void simpleRead() { + // 写法1: + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭 + EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead(); + + // 写法2: + fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build(); + ReadSheet readSheet = EasyExcel.readSheet(0).build(); + excelReader.read(readSheet); + // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的 + excelReader.finish(); + } + + /** + * 指定列的下标或者列名 + * + *

+ * 1. 创建excel对应的实体对象,并使用{@link ExcelProperty}注解. 参照{@link IndexOrNameData} + *

+ * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link IndexOrNameDataListener} + *

+ * 3. 直接读即可 + */ + @Test + public void indexOrNameRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + // 这里默认读取第一个sheet + EasyExcel.read(fileName, IndexOrNameData.class, new IndexOrNameDataListener()).sheet().doRead(); + } + + /** + * 读多个sheet,这里注意一个sheet不能读取多次,多次读取需要重新读取文件 + *

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

+ * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} + *

+ * 3. 直接读即可 + */ + @Test + public void repeatedRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build(); + ReadSheet readSheet1 = EasyExcel.readSheet(0).build(); + ReadSheet readSheet2 = EasyExcel.readSheet(1).build(); + excelReader.read(readSheet1); + excelReader.read(readSheet2); + // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的 + excelReader.finish(); + } + + /** + * 日期、数字或者自定义格式转换 + *

+ * 默认读的转换器{@link DefaultConverterLoader#loadDefaultReadConverter()} + *

+ * 1. 创建excel对应的实体对象 参照{@link ConverterData}.里面可以使用注解{@link DateTimeFormat}、{@link NumberFormat}或者自定义注解 + *

+ * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link ConverterDataListener} + *

+ * 3. 直接读即可 + */ + @Test + public void converterRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + // 这里 需要指定读用哪个class去读,然后读取第一个sheet 然后千万别忘记 finish + EasyExcel.read(fileName, ConverterData.class, new ConverterDataListener()) + // 这里注意 我们也可以registerConverter来指定自定义转换器, 但是这个转换变成全局了, 所有java为string,excel为string的都会用这个转换器。 + // 如果就想单个字段使用请使用@ExcelProperty 指定converter + // .registerConverter(new CustomStringStringConverter()) + // 读取sheet + .sheet().doRead(); + } + + /** + * 多行头 + * + *

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

+ * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} + *

+ * 3. 设置headRowNumber参数,然后读。 这里要注意headRowNumber如果不指定, 会根据你传入的class的{@link ExcelProperty#value()}里面的表头的数量来决定行数, + * 如果不传入class则默认为1.当然你指定了headRowNumber不管是否传入class都是以你传入的为准。 + */ + @Test + public void complexHeaderRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + // 这里 需要指定读用哪个class去读,然后读取第一个sheet 然后千万别忘记 finish + EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet() + // 这里可以设置1,因为头就是一行。如果多行头,可以设置其他值。不传入也可以,因为默认会根据DemoData 来解析,他没有指定头,也就是默认1行 + .headRowNumber(1).doRead(); + } + + /** + * 同步的返回,不推荐使用,如果数据量大会把数据放到内存里面 + */ + @Test + public void synchronousRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + // 这里 需要指定读用哪个class去读,然后读取第一个sheet 同步读取会自动finish + List list = EasyExcel.read(fileName).head(DemoData.class).sheet().doReadSync(); + for (Object obj : list) { + DemoData data = (DemoData)obj; + LOGGER.info("读取到数据:{}", JSON.toJSONString(data)); + } + + // 这里 也可以不指定class,返回一个list,然后读取第一个sheet 同步读取会自动finish + list = EasyExcel.read(fileName).sheet().doReadSync(); + for (Object obj : list) { + // 返回每条数据的键值对 表示所在的列 和所在列的值 + Map data = (Map)obj; + LOGGER.info("读取到数据:{}", JSON.toJSONString(data)); + } + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/web/DownloadData.java b/src/test/java/com/alibaba/easyexcel/test/demo/web/DownloadData.java new file mode 100644 index 0000000..4fa3a78 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/web/DownloadData.java @@ -0,0 +1,22 @@ +package com.alibaba.easyexcel.test.demo.web; + +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * 基础数据类 + * + * @author Jiaju Zhuang + **/ +@Data +public class DownloadData { + @ExcelProperty("字符串标题") + private String string; + @ExcelProperty("日期标题") + private Date date; + @ExcelProperty("数字标题") + private Double doubleData; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/web/EasyexcelApplication.java b/src/test/java/com/alibaba/easyexcel/test/demo/web/EasyexcelApplication.java new file mode 100644 index 0000000..d12cf85 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/web/EasyexcelApplication.java @@ -0,0 +1,12 @@ +package com.alibaba.easyexcel.test.demo.web; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class EasyexcelApplication { + + public static void main(String[] args) { + SpringApplication.run(EasyexcelApplication.class, args); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/web/UploadData.java b/src/test/java/com/alibaba/easyexcel/test/demo/web/UploadData.java new file mode 100644 index 0000000..80a0e65 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/web/UploadData.java @@ -0,0 +1,17 @@ +package com.alibaba.easyexcel.test.demo.web; + +import java.util.Date; + +import lombok.Data; + +/** + * 基础数据类 + * + * @author Jiaju Zhuang + **/ +@Data +public class UploadData { + private String string; + private Date date; + private Double doubleData; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/web/UploadDataListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/web/UploadDataListener.java new file mode 100644 index 0000000..7475ced --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/web/UploadDataListener.java @@ -0,0 +1,49 @@ +package com.alibaba.easyexcel.test.demo.web; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; + +/** + * 模板的读取类 + * + * @author Jiaju Zhuang + */ +public class UploadDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(UploadDataListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static final int BATCH_COUNT = 5; + List list = new ArrayList(); + + @Override + public void invoke(UploadData data, AnalysisContext context) { + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + list.add(data); + if (list.size() >= BATCH_COUNT) { + saveData(); + list.clear(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + saveData(); + LOGGER.info("所有数据解析完成!"); + } + + /** + * 加上存储数据库 + */ + private void saveData() { + LOGGER.info("{}条数据,开始存储数据库!", list.size()); + LOGGER.info("存储数据库成功!"); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java new file mode 100644 index 0000000..d96f89b --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java @@ -0,0 +1,69 @@ +package com.alibaba.easyexcel.test.demo.web; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.multipart.MultipartFile; + +import com.alibaba.excel.EasyExcel; + +/** + * web读写案例 + * + * @author Jiaju Zhuang + **/ +@Controller +public class WebTest { + /** + * 文件下载 + *

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

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

+ * 3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大 + */ + @GetMapping("download") + public void download(HttpServletResponse response) throws IOException { + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + response.setHeader("Content-disposition", "attachment;filename=demo.xlsx"); + EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data()); + } + + /** + * 文件上传 + *

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

+ * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener} + *

+ * 3. 直接读即可 + */ + @PostMapping("upload") + @ResponseBody + public String upload(MultipartFile file) throws IOException { + EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener()).sheet().doRead(); + return "success"; + } + + private List data() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + DownloadData data = new DownloadData(); + data.setString("字符串" + 0); + data.setDate(new Date()); + data.setDoubleData(0.56); + list.add(data); + } + return list; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/ComplexHeadData.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/ComplexHeadData.java new file mode 100644 index 0000000..44ce5cc --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/ComplexHeadData.java @@ -0,0 +1,22 @@ +package com.alibaba.easyexcel.test.demo.write; + +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * 复杂头数据.这里最终效果是第一行就一个主标题,第二行分类 + * + * @author Jiaju Zhuang + **/ +@Data +public class ComplexHeadData { + @ExcelProperty({"主标题", "字符串标题"}) + private String string; + @ExcelProperty({"主标题", "日期标题"}) + private Date date; + @ExcelProperty({"主标题", "数字标题"}) + private Double doubleData; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/ConverterData.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/ConverterData.java new file mode 100644 index 0000000..864cfcb --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/ConverterData.java @@ -0,0 +1,35 @@ +package com.alibaba.easyexcel.test.demo.write; + +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.DateTimeFormat; +import com.alibaba.excel.annotation.format.NumberFormat; + +import lombok.Data; + +/** + * 基础数据类.这里的排序和excel里面的排序一致 + * + * @author Jiaju Zhuang + **/ +@Data +public class ConverterData { + /** + * 我想所有的 字符串起前面加上"自定义:"三个字 + */ + @ExcelProperty(value = "字符串标题", converter = CustomStringStringConverter.class) + private String string; + /** + * 我想写到excel 用年月日的格式 + */ + @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒") + @ExcelProperty("日期标题") + private Date date; + /** + * 我想写到excel 用百分比表示 + */ + @NumberFormat("#.##%") + @ExcelProperty(value = "数字标题") + private Double doubleData; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java new file mode 100644 index 0000000..bff544a --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java @@ -0,0 +1,45 @@ +package com.alibaba.easyexcel.test.demo.write; + +import org.apache.poi.common.usermodel.HyperlinkType; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CreationHelper; +import org.apache.poi.ss.usermodel.Hyperlink; +import org.apache.poi.ss.usermodel.Row; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; + +/** + * 自定义拦截器。对第一行第一列的头超链接到:https://github.com/alibaba/easyexcel + * + * @author Jiaju Zhuang + */ +public class CustomCellWriteHandler implements CellWriteHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(CustomCellWriteHandler.class); + + @Override + public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Head head, int relativeRowIndex, boolean isHead) { + + } + + @Override + public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, + Cell cell, Head head, int relativeRowIndex, boolean isHead) { + // 这里可以对cell进行任何操作 + LOGGER.info("第{}行,第{}列写入完成。", cell.getRowIndex(), cell.getColumnIndex()); + if (isHead && cell.getColumnIndex() == 0) { + CreationHelper createHelper = writeSheetHolder.getSheet().getWorkbook().getCreationHelper(); + Hyperlink hyperlink = createHelper.createHyperlink(HyperlinkType.URL); + hyperlink.setAddress("https://github.com/alibaba/easyexcel"); + cell.setHyperlink(hyperlink); + } + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomSheetWriteHandler.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomSheetWriteHandler.java new file mode 100644 index 0000000..fe29045 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomSheetWriteHandler.java @@ -0,0 +1,39 @@ +package com.alibaba.easyexcel.test.demo.write; + +import org.apache.poi.ss.usermodel.DataValidation; +import org.apache.poi.ss.usermodel.DataValidationConstraint; +import org.apache.poi.ss.usermodel.DataValidationHelper; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; + +/** + * 自定义拦截器.对第一列第一行和第二行的数据新增下拉框,显示 测试1 测试2 + * + * @author Jiaju Zhuang + */ +public class CustomSheetWriteHandler implements SheetWriteHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(CustomSheetWriteHandler.class); + + @Override + public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + + } + + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + LOGGER.info("第{}个Sheet写入成功。", writeSheetHolder.getSheetNo()); + + // 区间设置 第一列第一行和第二行的数据。由于第一行是头,所以第一、二行的数据实际上是第二三行 + CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 2, 0, 0); + DataValidationHelper helper = writeSheetHolder.getSheet().getDataValidationHelper(); + DataValidationConstraint constraint = helper.createExplicitListConstraint(new String[] {"测试1", "测试2"}); + DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList); + writeSheetHolder.getSheet().addValidationData(dataValidation); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomStringStringConverter.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomStringStringConverter.java new file mode 100644 index 0000000..45ebc8c --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomStringStringConverter.java @@ -0,0 +1,59 @@ +package com.alibaba.easyexcel.test.demo.write; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +/** + * String and string converter + * + * @author Jiaju Zhuang + */ +public class CustomStringStringConverter implements Converter { + @Override + public Class supportJavaTypeKey() { + return String.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + /** + * 这里是读的时候会调用 不用管 + * + * @param cellData + * NotNull + * @param contentProperty + * Nullable + * @param globalConfiguration + * NotNull + * @return + */ + @Override + public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return cellData.getStringValue(); + } + + /** + * 这里是写的时候会调用 不用管 + * + * @param value + * NotNull + * @param contentProperty + * Nullable + * @param globalConfiguration + * NotNull + * @return + */ + @Override + public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) { + return new CellData("自定义:" + value); + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/DemoData.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/DemoData.java new file mode 100644 index 0000000..b65fbf0 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/DemoData.java @@ -0,0 +1,22 @@ +package com.alibaba.easyexcel.test.demo.write; + +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * 基础数据类 + * + * @author Jiaju Zhuang + **/ +@Data +public class DemoData { + @ExcelProperty("字符串标题") + private String string; + @ExcelProperty("日期标题") + private Date date; + @ExcelProperty("数字标题") + private Double doubleData; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/ImageData.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/ImageData.java new file mode 100644 index 0000000..951026c --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/ImageData.java @@ -0,0 +1,30 @@ +package com.alibaba.easyexcel.test.demo.write; + +import java.io.File; +import java.io.InputStream; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.ContentRowHeight; +import com.alibaba.excel.converters.string.StringImageConverter; + +import lombok.Data; + +/** + * 图片导出类 + * + * @author Jiaju Zhuang + */ +@Data +@ContentRowHeight(100) +@ColumnWidth(100 / 8) +public class ImageData { + private File file; + private InputStream inputStream; + /** + * 如果string类型 必须指定转换器,string默认转换成string + */ + @ExcelProperty(converter = StringImageConverter.class) + private String string; + private byte[] byteArray; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/IndexData.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/IndexData.java new file mode 100644 index 0000000..81c2d4e --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/IndexData.java @@ -0,0 +1,25 @@ +package com.alibaba.easyexcel.test.demo.write; + +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * 基础数据类 + * + * @author Jiaju Zhuang + **/ +@Data +public class IndexData { + @ExcelProperty(value = "字符串标题", index = 0) + private String string; + @ExcelProperty(value = "日期标题", index = 1) + private Date date; + /** + * 这里设置3 会导致第二列空的 + */ + @ExcelProperty(value = "数字标题", index = 3) + private Double doubleData; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/LongestMatchColumnWidthData.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/LongestMatchColumnWidthData.java new file mode 100644 index 0000000..69ad51d --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/LongestMatchColumnWidthData.java @@ -0,0 +1,22 @@ +package com.alibaba.easyexcel.test.demo.write; + +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelProperty; + +import lombok.Data; + +/** + * 基础数据类 + * + * @author Jiaju Zhuang + **/ +@Data +public class LongestMatchColumnWidthData { + @ExcelProperty("字符串标题") + private String string; + @ExcelProperty("日期标题很长日期标题很长日期标题很长很长") + private Date date; + @ExcelProperty("数字") + private Double doubleData; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/WidthAndHeightData.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/WidthAndHeightData.java new file mode 100644 index 0000000..42a7f88 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/WidthAndHeightData.java @@ -0,0 +1,32 @@ +package com.alibaba.easyexcel.test.demo.write; + +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.ContentRowHeight; +import com.alibaba.excel.annotation.write.style.HeadRowHeight; + +import lombok.Data; + +/** + * 基础数据类 + * + * @author Jiaju Zhuang + **/ +@Data +@ContentRowHeight(10) +@HeadRowHeight(20) +@ColumnWidth(25) +public class WidthAndHeightData { + @ExcelProperty("字符串标题") + private String string; + @ExcelProperty("日期标题") + private Date date; + /** + * 宽度为50 + */ + @ColumnWidth(50) + @ExcelProperty("数字标题") + private Double doubleData; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java new file mode 100644 index 0000000..e6bc998 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java @@ -0,0 +1,386 @@ +package com.alibaba.easyexcel.test.demo.write; + +import java.io.File; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.xssf.streaming.SXSSFSheet; +import org.junit.Ignore; +import org.junit.Test; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.DateTimeFormat; +import com.alibaba.excel.annotation.format.NumberFormat; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.ContentRowHeight; +import com.alibaba.excel.annotation.write.style.HeadRowHeight; +import com.alibaba.excel.util.FileUtils; +import com.alibaba.excel.write.merge.LoopMergeStrategy; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.WriteTable; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; + +/** + * 写的常见写法 + * + * @author Jiaju Zhuang + */ +@Ignore +public class WriteTest { + /** + * 最简单的写 + *

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

+ * 2. 直接写即可 + */ + @Test + public void simpleWrite() { + // 写法1 + String fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 如果这里想使用03 则 传入excelType参数即可 + EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data()); + + // 写法2 + fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读 + ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); + WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); + excelWriter.write(data(), writeSheet); + /// 千万别忘记finish 会帮忙关闭流 + excelWriter.finish(); + } + + /** + * 指定写入的列 + *

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

+ * 2. 使用{@link ExcelProperty}注解指定写入的列 + *

+ * 3. 直接写即可 + */ + @Test + public void indexWrite() { + String fileName = TestFileUtil.getPath() + "indexWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, IndexData.class).sheet("模板").doWrite(data()); + } + + /** + * 复杂头写入 + *

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

+ * 2. 使用{@link ExcelProperty}注解指定复杂的头 + *

+ * 3. 直接写即可 + */ + @Test + public void complexHeadWrite() { + String fileName = TestFileUtil.getPath() + "complexHeadWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, ComplexHeadData.class).sheet("模板").doWrite(data()); + } + + /** + * 重复多次写入 + *

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

+ * 2. 使用{@link ExcelProperty}注解指定复杂的头 + *

+ * 3. 直接调用二次写入即可 + */ + @Test + public void repeatedWrite() { + String fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读 + ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); + WriteSheet writeSheet = EasyExcel.writerSheet("模板").build(); + // 第一次写入会创建头 + excelWriter.write(data(), writeSheet); + // 第二次写入会在上一次写入的最后一行后面写入 + excelWriter.write(data(), writeSheet); + /// 千万别忘记finish 会帮忙关闭流 + excelWriter.finish(); + } + + /** + * 日期、数字或者自定义格式转换 + *

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

+ * 2. 使用{@link ExcelProperty}配合使用注解{@link DateTimeFormat}、{@link NumberFormat}或者自定义注解 + *

+ * 3. 直接写即可 + */ + @Test + public void converterWrite() { + String fileName = TestFileUtil.getPath() + "converterWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, ConverterData.class).sheet("模板").doWrite(data()); + } + + /** + * 图片导出 + *

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

+ * 2. 直接写即可 + */ + @Test + public void imageWrite() throws Exception { + String fileName = TestFileUtil.getPath() + "imageWrite" + System.currentTimeMillis() + ".xlsx"; + // 如果使用流 记得关闭 + InputStream inputStream = null; + try { + List list = new ArrayList(); + ImageData imageData = new ImageData(); + list.add(imageData); + String imagePath = TestFileUtil.getPath() + "converter" + File.separator + "img.jpg"; + // 放入四种类型的图片 实际使用只要选一种即可 + imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath))); + imageData.setFile(new File(imagePath)); + imageData.setString(imagePath); + inputStream = FileUtils.openInputStream(new File(imagePath)); + imageData.setInputStream(inputStream); + EasyExcel.write(fileName, ImageData.class).sheet().doWrite(list); + } finally { + if (inputStream != null) { + inputStream.close(); + } + } + } + + /** + * 根据模板写入 + *

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

+ * 2. 使用{@link ExcelProperty}注解指定写入的列 + *

+ * 3. 使用withTemplate 读取模板 + *

+ * 4. 直接写即可 + */ + @Test + public void templateWrite() { + String templateFileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + String fileName = TestFileUtil.getPath() + "templateWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, DemoData.class).withTemplate(templateFileName).sheet().doWrite(data()); + } + + /** + * 列宽、行高 + *

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

+ * 2. 使用注解{@link ColumnWidth}、{@link HeadRowHeight}、{@link ContentRowHeight}指定宽度或高度 + *

+ * 3. 直接写即可 + */ + @Test + public void widthAndHeightWrite() { + String fileName = TestFileUtil.getPath() + "widthAndHeightWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, WidthAndHeightData.class).sheet("模板").doWrite(data()); + } + + /** + * 自定义样式 + *

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

+ * 2. 创建一个style策略 并注册 + *

+ * 3. 直接写即可 + */ + @Test + public void styleWrite() { + String fileName = TestFileUtil.getPath() + "styleWrite" + System.currentTimeMillis() + ".xlsx"; + // 头的策略 + WriteCellStyle headWriteCellStyle = new WriteCellStyle(); + // 背景设置为红色 + headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex()); + WriteFont headWriteFont = new WriteFont(); + headWriteFont.setFontHeightInPoints((short)20); + headWriteCellStyle.setWriteFont(headWriteFont); + // 内容的策略 + WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); + // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定 + contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); + // 背景绿色 + contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex()); + WriteFont contentWriteFont = new WriteFont(); + // 字体大小 + contentWriteFont.setFontHeightInPoints((short)20); + contentWriteCellStyle.setWriteFont(contentWriteFont); + // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现 + HorizontalCellStyleStrategy horizontalCellStyleStrategy = + new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle); + + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, DemoData.class).registerWriteHandler(horizontalCellStyleStrategy).sheet("模板") + .doWrite(data()); + } + + /** + * 合并单元格 + *

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

+ * 2. 创建一个merge策略 并注册 + *

+ * 3. 直接写即可 + */ + @Test + public void mergeWrite() { + String fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx"; + // 每隔2行会合并 把eachColumn 设置成 3 也就是我们数据的长度,所以就第一列会合并。当然其他合并策略也可以自己写 + LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0); + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, DemoData.class).registerWriteHandler(loopMergeStrategy).sheet("模板").doWrite(data()); + } + + /** + * 使用table去写入 + *

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

+ * 2. 然后写入table即可 + */ + @Test + public void tableWrite() { + String fileName = TestFileUtil.getPath() + "tableWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里直接写多个table的案例了,如果只有一个 也可以直一行代码搞定,参照其他案例 + // 这里 需要指定写用哪个class去读 + ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build(); + // 把sheet设置为不需要头 不然会输出sheet的头 这样看起来第一个table 就有2个头了 + WriteSheet writeSheet = EasyExcel.writerSheet("模板").needHead(Boolean.FALSE).build(); + // 这里必须指定需要头,table 会继承sheet的配置,sheet配置了不需要,table 默认也是不需要 + WriteTable writeTable0 = EasyExcel.writerTable(0).needHead(Boolean.TRUE).build(); + WriteTable writeTable1 = EasyExcel.writerTable(1).needHead(Boolean.TRUE).build(); + // 第一次写入会创建头 + excelWriter.write(data(), writeSheet, writeTable0); + // 第二次写如也会创建头,然后在第一次的后面写入数据 + excelWriter.write(data(), writeSheet, writeTable1); + /// 千万别忘记finish 会帮忙关闭流 + excelWriter.finish(); + } + + /** + * 动态头,实时生成头写入 + *

+ * 思路是这样子的,先创建List头格式的sheet仅仅写入头,然后通过table 不写入头的方式 去写入数据 + * + *

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

+ * 2. 然后写入table即可 + */ + @Test + public void dynamicHeadWrite() { + String fileName = TestFileUtil.getPath() + "dynamicHeadWrite" + System.currentTimeMillis() + ".xlsx"; + // write的时候 不传入 class 在table的时候传入 + EasyExcel.write(fileName) + // 这里放入动态头 + .head(head()).sheet("模板") + // table的时候 传入class 并且设置needHead =false + .table().head(DemoData.class).needHead(Boolean.FALSE).doWrite(data()); + } + + /** + * 自动列宽(不太精确) + *

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

+ * poi 自带{@link SXSSFSheet#autoSizeColumn(int)} 对中文支持也不太好。目前没找到很好的算法。 有的话可以推荐下。 + * + *

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

+ * 2. 注册策略{@link LongestMatchColumnWidthStyleStrategy} + *

+ * 3. 直接写即可 + */ + @Test + public void longestMatchColumnWidthWrite() { + String fileName = + TestFileUtil.getPath() + "longestMatchColumnWidthWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, LongestMatchColumnWidthData.class) + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("模板").doWrite(dataLong()); + } + + /** + * 下拉,超链接等自定义拦截器(上面几点都不符合但是要对单元格进行操作的参照这个) + *

+ * demo这里实现2点。1. 对第一行第一列的头超链接到:https://github.com/alibaba/easyexcel 2. 对第一列第一行和第二行的数据新增下拉框,显示 测试1 测试2 + *

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

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

+ * 2. 直接写即可 + */ + @Test + public void customHandlerWrite() { + String fileName = TestFileUtil.getPath() + "customHandlerWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, DemoData.class).registerWriteHandler(new CustomSheetWriteHandler()) + .registerWriteHandler(new CustomCellWriteHandler()).sheet("模板").doWrite(data()); + } + + private List dataLong() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + LongestMatchColumnWidthData data = new LongestMatchColumnWidthData(); + data.setString("测试很长的字符串测试很长的字符串测试很长的字符串" + i); + data.setDate(new Date()); + data.setDoubleData(1000000000000.0); + list.add(data); + } + return list; + } + + private List> head() { + List> list = new ArrayList>(); + List head0 = new ArrayList(); + head0.add("字符串" + System.currentTimeMillis()); + List head1 = new ArrayList(); + head1.add("数字" + System.currentTimeMillis()); + List head2 = new ArrayList(); + head2.add("日期" + System.currentTimeMillis()); + list.add(head0); + list.add(head1); + list.add(head2); + return list; + } + + private List data() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + DemoData data = new DemoData(); + data.setString("字符串" + i); + data.setDate(new Date()); + data.setDoubleData(0.56); + list.add(data); + } + return list; + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/listen/AfterWriteHandlerImpl.java b/src/test/java/com/alibaba/easyexcel/test/listen/AfterWriteHandlerImpl.java deleted file mode 100644 index fd7c38f..0000000 --- a/src/test/java/com/alibaba/easyexcel/test/listen/AfterWriteHandlerImpl.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.alibaba.easyexcel.test.listen; - -import com.alibaba.excel.event.WriteHandler; -import org.apache.poi.ss.usermodel.*; -import org.apache.poi.xssf.usermodel.XSSFClientAnchor; -import org.apache.poi.xssf.usermodel.XSSFRichTextString; - -public class AfterWriteHandlerImpl implements WriteHandler { - - // - CellStyle cellStyle; - - @Override - public void sheet(int sheetNo, Sheet sheet) { - Workbook workbook = sheet.getWorkbook(); - //要锁定单元格需先为此表单设置保护密码,设置之后此表单默认为所有单元格锁定,可使用setLocked(false)为指定单元格设置不锁定。 - //设置表单保护密码 - sheet.protectSheet("your password"); - //创建样式 - cellStyle = workbook.createCellStyle(); - //设置是否锁 - cellStyle.setLocked(false); - - } - - @Override - public void row(int rowNum, Row row) { - Workbook workbook = row.getSheet().getWorkbook(); - //设置行高 - row.setHeight((short)20); - } - - @Override - public void cell(int cellNum, Cell cell) { - Workbook workbook = cell.getSheet().getWorkbook(); - Sheet currentSheet = cell.getSheet(); - if (cellNum == 4 && cell.getRowIndex() == 30) { - //设置样式 - //注意:样式最好采用公用样式,样式在创建sheet后创建,如果有多个样式也需要在创建sheet时候创建后面直接使用,不要每个Cell Create 一个样式,不然会导致报错 The maximum number - // of Cell Styles was exceeded. - cell.setCellStyle(cellStyle); - - - - //设置备注 - Drawing draw = currentSheet.createDrawingPatriarch(); - Comment comment = draw.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, 4, 25, 9, 30)); - XSSFRichTextString rtf = new XSSFRichTextString("添加批注内容收到货死的死哦多胡搜idsad是否会杜甫的范德萨发!1111"); - Font commentFormatter = workbook.createFont(); - commentFormatter.setFontName("宋体"); - //设置字体大小 - commentFormatter.setFontHeightInPoints((short)9); - rtf.applyFont(commentFormatter); - comment.setString(rtf); - comment.setAuthor("ceshi"); - cell.setCellComment(comment); - } - } -} diff --git a/src/test/java/com/alibaba/easyexcel/test/listen/ExcelListener.java b/src/test/java/com/alibaba/easyexcel/test/listen/ExcelListener.java deleted file mode 100644 index 0f17a39..0000000 --- a/src/test/java/com/alibaba/easyexcel/test/listen/ExcelListener.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.alibaba.easyexcel.test.listen; - -import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.event.AnalysisEventListener; - -import java.util.ArrayList; -import java.util.List; - -public class ExcelListener extends AnalysisEventListener { - - - private List data = new ArrayList(); - - @Override - public void invoke(Object object, AnalysisContext context) { - System.out.println(context.getCurrentSheet()); - data.add(object); - if(data.size()>=100){ - doSomething(); - data = new ArrayList(); - } - } - - @Override - public void doAfterAllAnalysed(AnalysisContext context) { - doSomething(); - } - public void doSomething(){ - for (Object o:data) { - System.out.println(o); - } - } -} diff --git a/src/test/java/com/alibaba/easyexcel/test/model/BaseReadModel.java b/src/test/java/com/alibaba/easyexcel/test/model/BaseReadModel.java deleted file mode 100644 index be65aa7..0000000 --- a/src/test/java/com/alibaba/easyexcel/test/model/BaseReadModel.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.alibaba.easyexcel.test.model; - -import com.alibaba.excel.annotation.ExcelProperty; -import com.alibaba.excel.metadata.BaseRowModel; - -public class BaseReadModel extends BaseRowModel { - @ExcelProperty(index = 0) - protected String str; - - @ExcelProperty(index = 1) - protected Float ff; - public String getStr() { - return str; - } - - - public void setStr(String str) { - this.str = str; - } - - public Float getFf() { - return ff; - } - - public void setFf(Float ff) { - this.ff = ff; - } -} diff --git a/src/test/java/com/alibaba/easyexcel/test/model/BaseWriteModel.java b/src/test/java/com/alibaba/easyexcel/test/model/BaseWriteModel.java deleted file mode 100644 index 8688216..0000000 --- a/src/test/java/com/alibaba/easyexcel/test/model/BaseWriteModel.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.alibaba.easyexcel.test.model; - -import com.alibaba.excel.annotation.ExcelProperty; -import com.alibaba.excel.metadata.BaseRowModel; - -public class BaseWriteModel extends BaseRowModel { - @ExcelProperty(value = {"表头1","表头1","表头31"},index = 0) - protected String p1; - - @ExcelProperty(value = {"表头1","表头1","表头32"},index = 1) - protected String p2; - - public String getP1() { - return p1; - } - - public void setP1(String p1) { - this.p1 = p1; - } - - public String getP2() { - return p2; - } - - public void setP2(String p2) { - this.p2 = p2; - } -} diff --git a/src/test/java/com/alibaba/easyexcel/test/model/ReadModel.java b/src/test/java/com/alibaba/easyexcel/test/model/ReadModel.java deleted file mode 100644 index fe90171..0000000 --- a/src/test/java/com/alibaba/easyexcel/test/model/ReadModel.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.alibaba.easyexcel.test.model; - -import com.alibaba.excel.annotation.ExcelProperty; - -import java.math.BigDecimal; -import java.util.Date; - -public class ReadModel extends BaseReadModel { - - @ExcelProperty(index = 2) - private Integer mm; - - @ExcelProperty(index = 3) - private BigDecimal money; - - @ExcelProperty(index = 4) - private Long times; - - @ExcelProperty(index = 5) - private Double activityCode; - - @ExcelProperty(index = 6,format = "yyyy-MM-dd") - private Date date; - - @ExcelProperty(index = 7) - private String lx; - - @ExcelProperty(index = 8) - private String name; - - @ExcelProperty(index = 18) - private String kk; - - - public Integer getMm() { - return mm; - } - - public void setMm(Integer mm) { - this.mm = mm; - } - - public BigDecimal getMoney() { - return money; - } - - public void setMoney(BigDecimal money) { - this.money = money; - } - - public Long getTimes() { - return times; - } - - public void setTimes(Long times) { - this.times = times; - } - - public Double getActivityCode() { - return activityCode; - } - - public void setActivityCode(Double activityCode) { - this.activityCode = activityCode; - } - - public Date getDate() { - return date; - } - - public void setDate(Date date) { - this.date = date; - } - - public String getLx() { - return lx; - } - - public void setLx(String lx) { - this.lx = lx; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getKk() { - return kk; - } - - public void setKk(String kk) { - this.kk = kk; - } - - @Override - public String toString() { - return "JavaModel{" + - "str='" + str + '\'' + - ", ff=" + ff + - ", mm=" + mm + - ", money=" + money + - ", times=" + times + - ", activityCode=" + activityCode + - ", date=" + date + - ", lx='" + lx + '\'' + - ", name='" + name + '\'' + - ", kk='" + kk + '\'' + - '}'; - } -} diff --git a/src/test/java/com/alibaba/easyexcel/test/model/ReadModel2.java b/src/test/java/com/alibaba/easyexcel/test/model/ReadModel2.java deleted file mode 100644 index a64f701..0000000 --- a/src/test/java/com/alibaba/easyexcel/test/model/ReadModel2.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.alibaba.easyexcel.test.model; - -import com.alibaba.excel.annotation.ExcelProperty; -import com.alibaba.excel.metadata.BaseRowModel; - -import java.math.BigDecimal; -import java.util.Date; - -public class ReadModel2 extends BaseRowModel { - @ExcelProperty(index = 0) - private String str; - - @ExcelProperty(index = 1) - private Float ff; - - @ExcelProperty(index = 2) - private Integer mm; - - @ExcelProperty(index = 3) - private BigDecimal money; - - @ExcelProperty(index = 4) - private Long times; - - @ExcelProperty(index = 5) - private Double activityCode; - - @ExcelProperty(index = 6,format = "yyyy-MM-dd") - private Date date; - - @ExcelProperty(index = 7) - private String lx; - - @ExcelProperty(index = 8) - private String name; - - @ExcelProperty(index = 18) - private String kk; - - public String getStr() { - return str; - } - - - public void setStr(String str) { - this.str = str; - } - - public Float getFf() { - return ff; - } - - public void setFf(Float ff) { - this.ff = ff; - } - - public Integer getMm() { - return mm; - } - - public void setMm(Integer mm) { - this.mm = mm; - } - - public BigDecimal getMoney() { - return money; - } - - public void setMoney(BigDecimal money) { - this.money = money; - } - - public Long getTimes() { - return times; - } - - public void setTimes(Long times) { - this.times = times; - } - - public Double getActivityCode() { - return activityCode; - } - - public void setActivityCode(Double activityCode) { - this.activityCode = activityCode; - } - - public Date getDate() { - return date; - } - - public void setDate(Date date) { - this.date = date; - } - - public String getLx() { - return lx; - } - - public void setLx(String lx) { - this.lx = lx; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getKk() { - return kk; - } - - public void setKk(String kk) { - this.kk = kk; - } - - @Override - public String toString() { - return "JavaModel2{" + - "str='" + str + '\'' + - ", ff=" + ff + - ", mm=" + mm + - ", money=" + money + - ", times=" + times + - ", activityCode=" + activityCode + - ", date=" + date + - ", lx='" + lx + '\'' + - ", name='" + name + '\'' + - ", kk='" + kk + '\'' + - '}'; - } -} diff --git a/src/test/java/com/alibaba/easyexcel/test/model/WriteModel.java b/src/test/java/com/alibaba/easyexcel/test/model/WriteModel.java deleted file mode 100644 index acb17c1..0000000 --- a/src/test/java/com/alibaba/easyexcel/test/model/WriteModel.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.alibaba.easyexcel.test.model; - -import com.alibaba.excel.annotation.ExcelProperty; -import com.alibaba.excel.metadata.BaseRowModel; - -import java.math.BigDecimal; -import java.util.Date; - -public class WriteModel extends BaseWriteModel { - - - - @ExcelProperty(value = {"表头3","表头3","表头3"},index = 2) - private int p3; - - @ExcelProperty(value = {"表头1","表头4","表头4"},index = 3) - private long p4; - - @ExcelProperty(value = {"表头5","表头51","表头52"},index = 4) - private String p5; - - @ExcelProperty(value = {"表头6","表头61","表头611"},index = 5) - private float p6; - - @ExcelProperty(value = {"表头6","表头61","表头612"},index = 6) - private BigDecimal p7; - - @ExcelProperty(value = {"表头6","表头62","表头621"},index = 7) - private Date p8; - - @ExcelProperty(value = {"表头6","表头62","表头622"},index = 8) - private String p9; - - @ExcelProperty(value = {"表头6","表头62","表头622"},index = 9) - private double p10; - - public String getP1() { - return p1; - } - - public void setP1(String p1) { - this.p1 = p1; - } - - public String getP2() { - return p2; - } - - public void setP2(String p2) { - this.p2 = p2; - } - - public int getP3() { - return p3; - } - - public void setP3(int p3) { - this.p3 = p3; - } - - public long getP4() { - return p4; - } - - public void setP4(long p4) { - this.p4 = p4; - } - - public String getP5() { - return p5; - } - - public void setP5(String p5) { - this.p5 = p5; - } - - public float getP6() { - return p6; - } - - public void setP6(float p6) { - this.p6 = p6; - } - - public BigDecimal getP7() { - return p7; - } - - public void setP7(BigDecimal p7) { - this.p7 = p7; - } - - public Date getP8() { - return p8; - } - - public void setP8(Date p8) { - this.p8 = p8; - } - - public String getP9() { - return p9; - } - - public void setP9(String p9) { - this.p9 = p9; - } - - public double getP10() { - return p10; - } - - public void setP10(double p10) { - this.p10 = p10; - } - - @Override - public String toString() { - return "JavaModel1{" + - "p1='" + p1 + '\'' + - ", p2='" + p2 + '\'' + - ", p3=" + p3 + - ", p4=" + p4 + - ", p5='" + p5 + '\'' + - ", p6=" + p6 + - ", p7=" + p7 + - ", p8=" + p8 + - ", p9='" + p9 + '\'' + - ", p10=" + p10 + - '}'; - } -} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/LockTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/LockTest.java new file mode 100644 index 0000000..733f1a2 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/LockTest.java @@ -0,0 +1,38 @@ +package com.alibaba.easyexcel.test.temp; + +import java.io.File; +import java.io.FileInputStream; +import java.util.List; + +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.fastjson.JSON; + +/** + * 临时测试 + * + * @author Jiaju Zhuang + **/ +@Ignore +public class LockTest { + private static final Logger LOGGER = LoggerFactory.getLogger(LockTest.class); + + @Test + public void test() throws Exception { + + List list = + EasyExcel.read(new FileInputStream("D:\\test\\t222.xlsx")).sheet().headRowNumber(0).doReadSync(); + for (Object data : list) { + LOGGER.info("返回数据:{}", JSON.toJSONString(data)); + } + list = EasyExcel.read(new File("D:\\test\\t222.xlsx")).sheet().headRowNumber(0).doReadSync(); + for (Object data : list) { + LOGGER.info("返回数据:{}", JSON.toJSONString(data)); + } + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/StyleData.java b/src/test/java/com/alibaba/easyexcel/test/temp/StyleData.java new file mode 100644 index 0000000..8921492 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/StyleData.java @@ -0,0 +1,20 @@ +package com.alibaba.easyexcel.test.temp; + +import java.util.List; + +import lombok.Data; + +/** + * + * @author Jiaju Zhuang + **/ +@Data +public class StyleData { + private byte[] byteValue; + private Byte[] byteValue2; + private byte byteValue1; + private Byte byteValue4; + private byte byteValue3; + private String[] ss; + private List s1s; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/StyleTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/StyleTest.java new file mode 100644 index 0000000..ece50bd --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/StyleTest.java @@ -0,0 +1,198 @@ +package com.alibaba.easyexcel.test.temp; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.util.Date; +import java.util.List; + +import org.apache.poi.hssf.usermodel.HSSFDateUtil; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.poifs.crypt.Decryptor; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.ss.usermodel.BuiltinFormats; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.ExcelStyleDateFormatter; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.fastjson.JSON; + +/** + * 临时测试 + * + * @author Jiaju Zhuang + **/ +@Ignore +public class StyleTest { + private static final Logger LOGGER = LoggerFactory.getLogger(StyleTest.class); + + @Test + public void test() { + List list = EasyExcel.read("D:\\test\\styleTest.xls").sheet().headRowNumber(0).doReadSync(); + for (Object data : list) { + LOGGER.info("返回数据:{}", JSON.toJSONString(data)); + } + } + + @Test + public void poi() throws Exception { + InputStream is = new FileInputStream("D:\\test\\styleTest.xls"); + HSSFWorkbook hssfWorkbook = new HSSFWorkbook(is); + HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(0); + HSSFRow hssfRow = hssfSheet.getRow(0); + System.out.println(hssfRow.getCell(0).getCellStyle().getDataFormatString()); + DataFormatter formatter = new DataFormatter(); + System.out.println(hssfRow.getCell(0).getNumericCellValue()); + System.out.println(hssfRow.getCell(1).getNumericCellValue()); + System.out.println(hssfRow.getCell(2).getNumericCellValue()); + System.out.println(hssfRow.getCell(0).getCellStyle().getDataFormatString()); + System.out.println(hssfRow.getCell(1).getCellStyle().getDataFormatString()); + System.out.println(hssfRow.getCell(2).getCellStyle().getDataFormatString()); + + } + + @Test + public void poi07() throws Exception { + InputStream is = new FileInputStream("D:\\test\\styleTest.xlsx"); + Workbook workbook = WorkbookFactory.create(is); // 这种方式 Excel 2003/2007/2010 都是可以处理的 + Sheet sheet = workbook.getSheetAt(0); + Row hssfRow = sheet.getRow(0); + System.out.println(hssfRow.getCell(0).getCellStyle().getDataFormatString()); + DataFormatter formatter = new DataFormatter(); + System.out.println(hssfRow.getCell(0).getNumericCellValue()); + System.out.println(hssfRow.getCell(1).getNumericCellValue()); + System.out.println(hssfRow.getCell(2).getNumericCellValue()); + System.out.println(hssfRow.getCell(0).getCellStyle().getDataFormat()); + System.out.println(hssfRow.getCell(1).getCellStyle().getDataFormat()); + System.out.println(hssfRow.getCell(2).getCellStyle().getDataFormat()); + System.out.println(hssfRow.getCell(3).getCellStyle().getDataFormat()); + System.out.println(hssfRow.getCell(0).getCellStyle().getDataFormatString()); + System.out.println(hssfRow.getCell(1).getCellStyle().getDataFormatString()); + System.out.println(hssfRow.getCell(2).getCellStyle().getDataFormatString()); + System.out.println(hssfRow.getCell(3).getCellStyle().getDataFormatString()); + isDate(hssfRow.getCell(0)); + isDate(hssfRow.getCell(1)); + isDate(hssfRow.getCell(2)); + isDate(hssfRow.getCell(3)); + + } + + @Test + public void poi0701() throws Exception { + InputStream is = new FileInputStream("D:\\test\\f1.xlsx"); + Workbook workbook = WorkbookFactory.create(is); + Sheet sheet = workbook.getSheetAt(0); + print(sheet.getRow(0).getCell(0)); + print(sheet.getRow(1).getCell(0)); + print(sheet.getRow(2).getCell(0)); + print(sheet.getRow(3).getCell(0)); + } + + @Test + public void poi0702() throws Exception { + Workbook workbook = WorkbookFactory.create(new FileInputStream("D:\\test\\t2.xlsx")); + workbook = WorkbookFactory.create(new File("D:\\test\\t2.xlsx")); + Sheet sheet = workbook.getSheetAt(0); + Row row = sheet.getRow(0); + System.out.println(row.getCell(0).getNumericCellValue()); + } + + @Test + public void poi0703() throws Exception { + try { + POIFSFileSystem poifsFileSystem = new POIFSFileSystem(new FileInputStream("D:\\test\\t2.xlsx")); + System.out.println(poifsFileSystem.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)); + } catch (Exception e) { + e.printStackTrace(); + } + + try { + POIFSFileSystem poifsFileSystem = new POIFSFileSystem(new File("D:\\test\\t2.xlsx")); + System.out.println(poifsFileSystem.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)); + } catch (Exception e) { + e.printStackTrace(); + } + try { + POIFSFileSystem poifsFileSystem = new POIFSFileSystem(new FileInputStream("D:\\test\\t222.xlsx")); + System.out.println(poifsFileSystem.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)); + } catch (Exception e) { + e.printStackTrace(); + } + try { + POIFSFileSystem poifsFileSystem = new POIFSFileSystem(new File("D:\\test\\t222.xlsx")); + System.out.println(poifsFileSystem.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void print(Cell cell) { + System.out.println( + DateUtil.isADateFormat(cell.getCellStyle().getDataFormat(), cell.getCellStyle().getDataFormatString())); + System.out.println(cell.getCellStyle().getDataFormat()); + System.out.println(cell.getCellStyle().getDataFormatString()); + DataFormatter f = new DataFormatter(); + System.out.println(f.formatCellValue(cell)); + if (cell.getCellStyle().getDataFormatString() != null) { + + } + ExcelStyleDateFormatter ff = new ExcelStyleDateFormatter(cell.getCellStyle().getDataFormatString()); + + } + + @Test + public void testFormatter() throws Exception { + ExcelStyleDateFormatter ff = new ExcelStyleDateFormatter("yyyy年m月d日"); + + System.out.println(ff.format(new Date())); + } + + @Test + public void testFormatter2() throws Exception { + StyleData styleData = new StyleData(); + Field field = styleData.getClass().getDeclaredField("byteValue"); + LOGGER.info("filed:{}", field.getType().getName()); + field = styleData.getClass().getDeclaredField("byteValue2"); + LOGGER.info("filed:{}", field.getType().getName()); + field = styleData.getClass().getDeclaredField("byteValue4"); + LOGGER.info("filed:{}", field.getType()); + field = styleData.getClass().getDeclaredField("byteValue3"); + LOGGER.info("filed:{}", field.getType()); + } + + @Test + public void testFormatter3() throws Exception { + LOGGER.info("filed:{}", Byte.class == Byte.class); + } + + private void isDate(Cell cell) { + System.out.println( + DateUtil.isADateFormat(cell.getCellStyle().getDataFormat(), cell.getCellStyle().getDataFormatString())); + System.out.println(HSSFDateUtil.isCellDateFormatted(cell)); + DataFormatter f = new DataFormatter(); + System.out.println(f.formatCellValue(cell)); + + } + + @Test + public void testBuiltinFormats() throws Exception { + System.out.println(BuiltinFormats.getBuiltinFormat(48)); + System.out.println(BuiltinFormats.getBuiltinFormat(57)); + System.out.println(BuiltinFormats.getBuiltinFormat(28)); + + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/Xls03Test.java b/src/test/java/com/alibaba/easyexcel/test/temp/Xls03Test.java new file mode 100644 index 0000000..c4331b1 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/Xls03Test.java @@ -0,0 +1,30 @@ +package com.alibaba.easyexcel.test.temp; + +import java.util.List; + +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.EasyExcel; +import com.alibaba.fastjson.JSON; + +/** + * 临时测试 + * + * @author Jiaju Zhuang + **/ +@Ignore +public class Xls03Test { + private static final Logger LOGGER = LoggerFactory.getLogger(Xls03Test.class); + + @Test + public void test() { + List list = EasyExcel.read("D:\\test\\8.xls").sheet().doReadSync(); + for (Object data : list) { + LOGGER.info("返回数据:{}", JSON.toJSONString(data)); + } + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiFormatTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiFormatTest.java new file mode 100644 index 0000000..99885fa --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiFormatTest.java @@ -0,0 +1,53 @@ +package com.alibaba.easyexcel.test.temp.poi; + +import java.io.File; +import java.io.IOException; + +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.xssf.streaming.SXSSFRow; +import org.apache.poi.xssf.streaming.SXSSFSheet; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.util.TestFileUtil; + +/** + * 测试poi + * + * @author Jiaju Zhuang + **/ +@Ignore +public class PoiFormatTest { + private static final Logger LOGGER = LoggerFactory.getLogger(PoiFormatTest.class); + + @Test + public void lastRowNum() throws IOException { + String file = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + SXSSFWorkbook xssfWorkbook = new SXSSFWorkbook(new XSSFWorkbook(file)); + SXSSFSheet xssfSheet = xssfWorkbook.getSheetAt(0); + LOGGER.info("一共行数:{}", xssfSheet.getLastRowNum()); + SXSSFRow row = xssfSheet.getRow(0); + LOGGER.info("第一行数据:{}", row); + xssfSheet.createRow(20); + LOGGER.info("一共行数:{}", xssfSheet.getLastRowNum()); + } + + @Test + public void lastRowNumXSSF() throws IOException { + String file = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + XSSFWorkbook xssfWorkbook = new XSSFWorkbook(file); + LOGGER.info("一共:{}个sheet", xssfWorkbook.getNumberOfSheets()); + XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(0); + LOGGER.info("一共行数:{}", xssfSheet.getLastRowNum()); + XSSFRow row = xssfSheet.getRow(0); + LOGGER.info("第一行数据:{}", row); + xssfSheet.createRow(20); + LOGGER.info("一共行数:{}", xssfSheet.getLastRowNum()); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiTest.java new file mode 100644 index 0000000..ea6dba1 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiTest.java @@ -0,0 +1,52 @@ +package com.alibaba.easyexcel.test.temp.poi; + +import java.io.File; +import java.io.IOException; + +import org.apache.poi.xssf.streaming.SXSSFRow; +import org.apache.poi.xssf.streaming.SXSSFSheet; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.util.TestFileUtil; + +/** + * 测试poi + * + * @author Jiaju Zhuang + **/ +@Ignore +public class PoiTest { + private static final Logger LOGGER = LoggerFactory.getLogger(PoiTest.class); + + @Test + public void lastRowNum() throws IOException { + String file = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + SXSSFWorkbook xssfWorkbook = new SXSSFWorkbook(new XSSFWorkbook(file)); + SXSSFSheet xssfSheet = xssfWorkbook.getSheetAt(0); + LOGGER.info("一共行数:{}", xssfSheet.getLastRowNum()); + SXSSFRow row = xssfSheet.getRow(0); + LOGGER.info("第一行数据:{}", row); + xssfSheet.createRow(20); + LOGGER.info("一共行数:{}", xssfSheet.getLastRowNum()); + } + + @Test + public void lastRowNumXSSF() throws IOException { + String file = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + XSSFWorkbook xssfWorkbook = new XSSFWorkbook(file); + LOGGER.info("一共:{}个sheet", xssfWorkbook.getNumberOfSheets()); + XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(0); + LOGGER.info("一共行数:{}", xssfSheet.getLastRowNum()); + XSSFRow row = xssfSheet.getRow(0); + LOGGER.info("第一行数据:{}", row); + xssfSheet.createRow(20); + LOGGER.info("一共行数:{}", xssfSheet.getLastRowNum()); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/util/DataUtil.java b/src/test/java/com/alibaba/easyexcel/test/util/DataUtil.java deleted file mode 100644 index 505dab5..0000000 --- a/src/test/java/com/alibaba/easyexcel/test/util/DataUtil.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.alibaba.easyexcel.test.util; - -import com.alibaba.easyexcel.test.model.WriteModel; -import com.alibaba.excel.metadata.Font; -import com.alibaba.excel.metadata.TableStyle; -import org.apache.poi.ss.usermodel.IndexedColors; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -public class DataUtil { - - - public static List> createTestListObject() { - List> object = new ArrayList>(); - for (int i = 0; i < 1000; i++) { - List da = new ArrayList(); - da.add("字符串"+i); - da.add(Long.valueOf(187837834l+i)); - da.add(Integer.valueOf(2233+i)); - da.add(Double.valueOf(2233.00+i)); - da.add(Float.valueOf(2233.0f+i)); - da.add(new Date()); - da.add(new BigDecimal("3434343433554545"+i)); - da.add(Short.valueOf((short)i)); - object.add(da); - } - return object; - } - - public static List> createTestListStringHead(){ - //写sheet3 模型上没有注解,表头数据动态传入 - List> head = new ArrayList>(); - List headCoulumn1 = new ArrayList(); - List headCoulumn2 = new ArrayList(); - List headCoulumn3 = new ArrayList(); - List headCoulumn4 = new ArrayList(); - List headCoulumn5 = new ArrayList(); - - headCoulumn1.add("第一列");headCoulumn1.add("第一列");headCoulumn1.add("第一列"); - headCoulumn2.add("第一列");headCoulumn2.add("第一列");headCoulumn2.add("第一列"); - - headCoulumn3.add("第二列");headCoulumn3.add("第二列");headCoulumn3.add("第二列"); - headCoulumn4.add("第三列");headCoulumn4.add("第三列2");headCoulumn4.add("第三列2"); - headCoulumn5.add("第一列");headCoulumn5.add("第3列");headCoulumn5.add("第4列"); - - head.add(headCoulumn1); - head.add(headCoulumn2); - head.add(headCoulumn3); - head.add(headCoulumn4); - head.add(headCoulumn5); - return head; - } - - public static List createTestListJavaMode(){ - List model1s = new ArrayList(); - for (int i = 0; i <10000 ; i++) { - WriteModel model1 = new WriteModel(); - model1.setP1("第一列,第行"); - model1.setP2("121212jjj"); - model1.setP3(33+i); - model1.setP4(44); - model1.setP5("555"); - model1.setP6(666.2f); - model1.setP7(new BigDecimal("454545656343434"+i)); - model1.setP8(new Date()); - model1.setP9("llll9999>&&&&&6666^^^^"); - model1.setP10(1111.77+i); - model1s.add(model1); - } - return model1s; - } - - public static TableStyle createTableStyle() { - TableStyle tableStyle = new TableStyle(); - Font headFont = new Font(); - headFont.setBold(true); - headFont.setFontHeightInPoints((short)22); - headFont.setFontName("楷体"); - tableStyle.setTableHeadFont(headFont); - tableStyle.setTableHeadBackGroundColor(IndexedColors.BLUE); - - Font contentFont = new Font(); - contentFont.setBold(true); - contentFont.setFontHeightInPoints((short)22); - contentFont.setFontName("黑体"); - tableStyle.setTableContentFont(contentFont); - tableStyle.setTableContentBackGroundColor(IndexedColors.GREEN); - return tableStyle; - } -} diff --git a/src/test/java/com/alibaba/easyexcel/test/util/FileUtil.java b/src/test/java/com/alibaba/easyexcel/test/util/FileUtil.java deleted file mode 100644 index 60cea7a..0000000 --- a/src/test/java/com/alibaba/easyexcel/test/util/FileUtil.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.alibaba.easyexcel.test.util; - -import java.io.InputStream; - -public class FileUtil { - - public static InputStream getResourcesFileInputStream(String fileName) { - return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); - } -} diff --git a/src/test/java/com/alibaba/easyexcel/test/util/TestFileUtil.java b/src/test/java/com/alibaba/easyexcel/test/util/TestFileUtil.java new file mode 100644 index 0000000..2031e70 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/util/TestFileUtil.java @@ -0,0 +1,32 @@ +package com.alibaba.easyexcel.test.util; + +import java.io.File; +import java.io.InputStream; + +public class TestFileUtil { + + public static InputStream getResourcesFileInputStream(String fileName) { + return Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName); + } + + public static String getPath() { + return TestFileUtil.class.getResource("/").getPath(); + } + + public static File createNewFile(String pathName) { + File file = new File(getPath() + pathName); + if (file.exists()) { + file.delete(); + } else { + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + } + return file; + } + + public static File readFile(String pathName) { + return new File(getPath() + pathName); + } + +} diff --git a/src/test/resources/2003.xls b/src/test/resources/2003.xls deleted file mode 100644 index 3c2fa34..0000000 Binary files a/src/test/resources/2003.xls and /dev/null differ diff --git a/src/test/resources/2007.xlsx b/src/test/resources/2007.xlsx deleted file mode 100644 index 1c17101..0000000 Binary files a/src/test/resources/2007.xlsx and /dev/null differ diff --git a/src/test/resources/converter/converter03.xls b/src/test/resources/converter/converter03.xls new file mode 100644 index 0000000..3373d81 Binary files /dev/null and b/src/test/resources/converter/converter03.xls differ diff --git a/src/test/resources/converter/converter07.xlsx b/src/test/resources/converter/converter07.xlsx new file mode 100644 index 0000000..92b93e2 Binary files /dev/null and b/src/test/resources/converter/converter07.xlsx differ diff --git a/src/test/resources/converter/img.jpg b/src/test/resources/converter/img.jpg new file mode 100644 index 0000000..953f39f Binary files /dev/null and b/src/test/resources/converter/img.jpg differ diff --git a/src/test/resources/demo/demo.xlsx b/src/test/resources/demo/demo.xlsx new file mode 100644 index 0000000..303733c Binary files /dev/null and b/src/test/resources/demo/demo.xlsx differ diff --git a/src/test/resources/large/large07.xlsx b/src/test/resources/large/large07.xlsx new file mode 100644 index 0000000..a317e71 Binary files /dev/null and b/src/test/resources/large/large07.xlsx differ diff --git a/src/test/resources/logback.xml b/src/test/resources/logback.xml new file mode 100644 index 0000000..602049a --- /dev/null +++ b/src/test/resources/logback.xml @@ -0,0 +1,13 @@ + + + + + + ${LOG_PATTERN} + + + + + + diff --git a/src/test/resources/simple/simple07.xlsx b/src/test/resources/simple/simple07.xlsx new file mode 100644 index 0000000..3d25fcd Binary files /dev/null and b/src/test/resources/simple/simple07.xlsx differ diff --git a/src/test/resources/temp.xlsx b/src/test/resources/temp.xlsx deleted file mode 100644 index 2149a23..0000000 Binary files a/src/test/resources/temp.xlsx and /dev/null differ diff --git a/src/test/resources/template/template03.xls b/src/test/resources/template/template03.xls new file mode 100644 index 0000000..7c17eee Binary files /dev/null and b/src/test/resources/template/template03.xls differ diff --git a/src/test/resources/template/template07.xlsx b/src/test/resources/template/template07.xlsx new file mode 100644 index 0000000..a046fbc Binary files /dev/null and b/src/test/resources/template/template07.xlsx differ diff --git a/style/STYLE.md b/style/STYLE.md new file mode 100644 index 0000000..cc75b44 --- /dev/null +++ b/style/STYLE.md @@ -0,0 +1,29 @@ +## 统一代码风格 +如果要编辑本项目,一定要统一代码风格 +### 统一方案 +本工程代码遵守阿里巴巴[p3c](https://github.com/alibaba/p3c)规范,在代码开发前建议: +* 安装阿里巴巴规约插件,用于提早发现不规范代码,具体安装方法参照:[p3c](https://github.com/alibaba/p3c),里面有eclipse,idea的安装方法 +* 安装codeStyle插件,用于格式化代码的时候符合代码规范,安装方法见:[安装codeStyle插件](#codeStyleInstall) +* checkStyle校验,这个不用安装,`mvn`在编译的时候自己会调用,写在`pom.xml`里,用`maven-pmd-plugin`调用`pmd-p3c`规范校验 + +如果工作中遇到代码格式化问题,经常导致git冲突,也可以采用上面的方案 +### codeStyle插件安装 +这里注意下,不管eclipse或者idea,都需要导入eclipse文件夹下面的配置 +#### eclipse +* 依次点击:`Window->Preferences->Java->Code Style->Formatter->Import` +* 选择`style/eclipse/codestyle.xml`文件 确定 +* 默认在`Active profile`中选择新导入的`P3C-CodeStyle`,如未选择,请手动选择 +* 点击`Apply`完成配置 +![step](../img/style/eclipse/step.jpg) +#### idea +* 依次点击进入插件界面:`File->Settings->Plugins`,搜索 eclipse code formatter,如已有插件则不需安装,如没有,点击Search in repositories自动搜索线上插件。 +![step1](../img/style/idea/step1.png) +* 导入`style/eclipse/codestyle.xml` 这里记住用的也是eclipse里面的 点击OK +![step1](../img/style/idea/step2.png) +* 依次点击进入插件界面:`File->Settings->Editor->Code Style->Java->Import Scheme->Intellij IDEA code style XML`,导入`style/idea/codestyle.xml` 这里用的是idea的配置文件 +![step1](../img/style/idea/step3.png) +* 完成 + +### 附 +#### windows系统,代码规范校验提示乱码 +这个是因为cmd默认gbk,cmd输入:`CHCP 65001` 在运行mvn 提示就是不会乱码了 \ No newline at end of file diff --git a/style/codestyle/eclipse/codestyle.xml b/style/codestyle/eclipse/codestyle.xml new file mode 100644 index 0000000..42b3055 --- /dev/null +++ b/style/codestyle/eclipse/codestyle.xml @@ -0,0 +1,603 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/style/codestyle/idea/codestyle.xml b/style/codestyle/idea/codestyle.xml new file mode 100644 index 0000000..9815956 --- /dev/null +++ b/style/codestyle/idea/codestyle.xml @@ -0,0 +1,27 @@ + + \ No newline at end of file diff --git a/update.md b/update.md index 1414957..12a2f85 100644 --- a/update.md +++ b/update.md @@ -1,39 +1,28 @@ -# 1.0.1 - -完善测试用例,防止歧义,模型字段映射不上时候有抛异常,改为提醒。 - -# 1.0.2 - -修复拿到一行数据后,存到list中,但最后处理时候变为空的bug。 - -# 1.0.3 - -修复无@ExcelProperty标注的多余字段时候报错。 - -# 1.0.4 - -修复日期类型转换时候数字问题。基础模型支持字段类型int,long,double,boolean,date,string - -# 1.0.5 - -优化类型转换的性能。 - -# 1.0.6 - -增加@ExcelColumnNum,修复字符串前后空白,增加过滤功能。 -# 1.0.8 - -如果整行excel数据全部为空,则不解析返回。完善多sheet的解析。 - -# 1.0.9 - -修复excel超过16列被覆盖的问题,修复数据只有一行时候无法透传的bug。 - - -# 1.2.1 - -修复POI在大并发情况下创建临时目录失败的bug - +# 2.0.0 +* 优化读写逻辑 +* 优化读写对外接口 +* 加入转换器,方便格式转换 +* 极大优化读大文件的内存和效率 +* sheetNo 改成0开始 +* 读支持指定列名 +* 升级poi 到4.0.1 # 1.2.4 - 修复read()方法存在的bug +# 1.2.1 +修复POI在大并发情况下创建临时目录失败的bug +# 1.0.9 +修复excel超过16列被覆盖的问题,修复数据只有一行时候无法透传的bug。 +# 1.0.8 +如果整行excel数据全部为空,则不解析返回。完善多sheet的解析。 +# 1.0.6 +增加@ExcelColumnNum,修复字符串前后空白,增加过滤功能。 +# 1.0.5 +优化类型转换的性能。 +# 1.0.4 +修复日期类型转换时候数字问题。基础模型支持字段类型int,long,double,boolean,date,string +# 1.0.3 +修复无@ExcelProperty标注的多余字段时候报错。 +# 1.0.2 +修复拿到一行数据后,存到list中,但最后处理时候变为空的bug。 +# 1.0.1 +完善测试用例,防止歧义,模型字段映射不上时候有抛异常,改为提醒。 \ No newline at end of file