初识EasyExcel
Apache POI
Apache POI是Apache软件基金会的开源函式库,提供跨平台的Java API实现Microsoft Office格式档案读写。但是存在如下一些问题:
- 学习使用成本较高
对POI有过深入了解的应该知道POI有SAX模式(Dom解析模式)。但SAX模式相对比较复杂,excel有03(xls文件)和07(xlsx文件)两种版本,两个版本数据存储方式截然不同,sax解析方式也各不一样。
POI的SAX模式的API可以一定程度的解决一些内存溢出的问题,但是POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大,一个3M的excel用POI的SAX解析,依然需要100M左右内存。
- POI的内存消耗较大
大部分使用POI都是使用它的userModel模式。userModel的好处是上手容易、使用简单,然而userModel模式最大的问题是在于非常大的内存消耗,一个几兆的文件解析要用掉几百兆的内存。现在很多应用采用这种模式,之所以还正常在跑一定是并发不大,并发上来后一定会OOM或者频繁的full gc。
总体来说,简单写法重度依赖内存,复杂写法学习成本高。
EasyExcel
重写了POI对07版excel的解析。
easyexcel重写了POI对07版excel的解析,可以把内存消耗从100M左右降低到10M以内,并且再大的excel不会出现内存溢出,03版仍依赖POI的SAX模式。
下图为64M内存1分钟内读取75M(46万行25列)的excel(当然还有急速模式能更快,但是内存占用会在100M多一点)。
在上层做了模型转换的封装,让使用者更加简单方便。
特点
- 在数据模式层面进行了封装,使用简单;
- 重写了07版本的excel的解析代码,降低内存消耗,能有效避免OOM;
- 只能操作excel;
- 不能读取图片。
快速入门
简单读
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qrxqrx</groupId>
<artifactId>easyexcel</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>
</project>
log4j.properties
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct message to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=d:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=debug, stdout
Student
package com.qrxqrx.easyexcel.domain;
import lombok.Data;
import java.util.Date;
@Data
public class Student {
private String name;
private String gender;
private Date birthday;
private String id;
}
StudentListener
package com.qrxqrx.easyexcel.listener;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.qrxqrx.easyexcel.domain.Student;
//读取文档的监听器类
public class StudentListener extends AnalysisEventListener<Student> {
// 每读一行内容,都会调用一次该对象的invoke方法,在invoke方法中可以操作使用读取到的数据
// 参数student:每次读取到的数据封装到的对象
@Override
public void invoke(Student student, AnalysisContext analysisContext) {
System.out.println(student);
}
// 读取完整个文档之后调用的方法
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
ExcelTest
package com.qrxqrx.easyexcel;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import com.qrxqrx.easyexcel.domain.Student;
import com.qrxqrx.easyexcel.listener.StudentListener;
import org.junit.Test;
public class ExcelTest {
/*
* 工作簿:一个excel文件就是一个工作簿
* 工作表:一个工作簿中可以有多个工作表(sheet)
* */
@Test
public void test01() {
// 获得工作簿对象
//输入参数:要读的文件的路径、文件中每一行数据要存储到的实体的类型的class、
// 读监听器(每读一行内容,都会调用一次该对象的invoke方法,在invoke方法中可以操作使用读取到的数据)
ExcelReaderBuilder readWorkBook = EasyExcel.read("data.xlsx", Student.class, new StudentListener());
// 获得工作表对象
ExcelReaderSheetBuilder sheet = readWorkBook.sheet();
// 读取工作表中内容
sheet.doRead();
}
}
data.xlsx:
简单写
Student
package com.qrxqrx.easyexcel.domain;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import lombok.Data;
import java.util.Date;
@Data
// @ContentRowHeight() // 内容行高
public class Student {
@ColumnWidth(20)
@ExcelProperty(value = "学生姓名", index = 1)
private String name;
@ExcelProperty(value = "学生性别", index = 3)
private String gender;
@ColumnWidth(20)
@ExcelProperty(value = "学生生日", index = 2)
private Date birthday;
@ExcelProperty(value = "ID", index = 4)
private String id;
}
ExcelTest
package com.qrxqrx.easyexcel;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.qrxqrx.easyexcel.domain.Student;
import com.qrxqrx.easyexcel.listener.StudentListener;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Date;
public class ExcelTest {
/*
* 工作簿:一个excel文件就是一个工作簿
* 工作表:一个工作簿中可以有多个工作表(sheet)
* */
@Test
public void test01() {
// 获得工作簿对象
//输入参数:要读的文件的路径、文件中每一行数据要存储到的实体的类型的class、
// 读监听器(每读一行内容,都会调用一次该对象的invoke方法,在invoke方法中可以操作使用读取到的数据)
ExcelReaderBuilder readWorkBook = EasyExcel.read("data.xlsx", Student.class, new StudentListener());
// 获得工作表对象
ExcelReaderSheetBuilder sheet = readWorkBook.sheet();
// 读取工作表中内容
sheet.doRead();
}
@Test
public void test02() {
// 工作簿对象
ExcelWriterBuilder writeWorkBook = EasyExcel.write("data-w.xlsx", Student.class);
// 工作表对象
ExcelWriterSheetBuilder sheet = writeWorkBook.sheet();
ArrayList<Student> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Student student = new Student();
student.setName("qrx"+i);
student.setGender("男");
student.setBirthday(new Date());
list.add(student);
}
sheet.doWrite(list);
}
}
data-w.xlsx:
常用API及注释
常用类
- EasyExcel入口类,用于构建各种对象,开始各种操作;
- ExcelReaderBuilder构建出一个ReadWorkbook对象,即一个工作簿对象,对应的是一个Excel文件;
- ExcelWriterBuilder构建出一个WriteWorkbook对象,即一个工作簿对象,对应的是一个Excel文件;
- ExcelReaderSheetBuilder构建出一个ReadSheet对象,即一个工作表对象,对应的Excel中的每个sheet,一个工作簿可以有多个工作表;
- ExcelWriterSheetBuilder构建出一个WriteSheet对象,即一个工作表对象,对应的Excel中的每个sheet,一个工作簿可以有多个工作表;
- ReadListener在每一行读取完毕后都会调用ReadListener来处理数据,可以把调用service的代码写在其invoke方法内部;
- WriteHandler在每一个操作包括创建单元格、创建表格等都会调用WriteHandler来处理数据,对使用者透明不可见;
- 所有配置都是继承的,Workbook的配置会被Sheet继承。所以在用EasyExcel设置参数的时候,在sheet()方法之前作用域是整个workbook的所有sheet,之后针对单个sheet。
读取时的注解
@ExcelProperty
使用位置:标准作用在成员变量上。
可选属性:
属性名 | 含义 | 说明 |
---|---|---|
index | 对应excel表中的列数 | 默认-1,建议从0开始 |
value | 对应excel表中的列头 | |
converter | 成员变量转换器 | 自定义转换器需要实现Converter接口 |
使用效果:index属性可以指定当前字段对应excel中的哪一列,可以根据列名value去匹配,也可以不写。如果不使用@ExcelProperties注解,成员变量从上到下的顺序,对应表格中从左到右的顺序。
使用建议:要么全部不写,要么全部用index,要么全部用value去匹配,尽量不要三个混着用。
@ExcelIgnore
标注在成员变量上,默认所有字段都会和excel去匹配,加了这个注解会忽略该字段
@DateTimeFormat
标注在成员变量上,日期转换,代码中用String类型的成员变量去接收excel中日期格式的数据会调用这个注解。里面的value参照java.text.SimpleDateFormat。
@DateTimeFormat("yyyy-MM-dd")
private Date birthday;
@NumberFormat
标注在成员变量上,数字转换,代码中用String类型的成员变量去接收excel数字格式的数据会调用这个注解,里面的value参照java.text.DecimalFormat。
ExcelIngoreUnannotated
标注在类上。
不标注该注解时,默认类中所有成员变量都会参与读写,无论是否在成员变量上加了@ExcelProperty的注解。
标注该注解后,类中的成员变量如果没有标注@ExcelProperty注解将不会参与读写。
读取时的通用参数
ReadWorkbook,ReadSheet都会有的参数,如果为空,默认使用上级。
- converter转换器,默认加载了很多转换器,也可以自定义。
- readListener监听器,在读取数据的过程中会不断的调用监听器。
- headRowNumber指定需要读表格的列头行数。默认有一行头,也就是认为第二行开始起为数据。
- head与clazz二选一。读取文件头对应的列表,会根据列表匹配数据。建议使用class,就是文件中每一行数据对应的代码中的实体类型。
- clazz与head二选一,读取文件的头对应的class,也可以使用注解。如果两个都不指定,则会读取全部数据。
- autoTrim字符串、表头等数据自动trim。
- password读的时候是否需要使用密码。
ReadWorkbook(工作簿对象)参数
- excelType当前excel的类型,读取时会自动判断,无需设置。
- inputStream与file二选一,建议使用file。
- file与inputStream二选一,读取文件的文件。
- autoCloseStream自动关闭流。
- readCache默认小于5M用内存,超过5M会使用EhCache,不建议使用这个参数。
- useDefaultListener默认会加入ModelBuildEventListener来转换成传入class的对象,设置成false后将不会协助转换对象,自定义的监听器会接收到Map<Integer,CellData>对象,如果还想继续监听到class对象,请调用readListener方法,加入自己定义的beforeListener、ModelBuildEventListener、自定义的afterListener即可。
ReadSheet(工作表对象)参数
- sheetNo需要读取Sheet的编号,建议使用这个指定读取哪个Sheet
- sheetName根据名字去匹配Sheet,excel2003不支持根据名字去匹配
写入时的注解
@ExcelProperty
使用位置:标准作用在成员变量上
可选属性:
属性名 | 含义 | 说明 |
---|---|---|
index | 对应excel表中的列数 | 默认-1,指定时建议从0开始 |
value | 对应excel表中的列头 | |
converter | 成员变量转换器 | 自定义转换器需要实现Converter接口 |
使用效果:index指定写到第几列,如果不指定则根据成员变量位置排序;value指定写入的列头,如果不指定则使用成员变量的名字作为列头;如果要设置复杂的头,可以为value指定多个值。
其他注释
基本和读取时一致:
- @ContentRowHeight标注在类上或属性上,指定内容行高
- @HeadRowHeight标注在类上或属性上,指定列头行高
- @ColumnWidth标注在类上或属性上,指定列宽
- @ExcelIgnore默认所有字段都会写入excel,这个注解会忽略这个字段
- @DateTimeFormat日期转换,将Date写到excel会调用这个注释,里面的value参照java.text.SimpleDateFormat。
- NumberFormat数字转换,用Number写excel会调用这个注解,里面的value参照java.text.DecimalFormat。
- ExcelIgnoreUnannotated默认不加ExcelProperty的注解都会参与读写,加了不会参与。
写入时通用参数
writeworkbook、writesheet都会有的参数,如果为空,默认使用上级。
- converter转换器,默认加载了很多转换器,也可以自定义。
- writeHandler写的处理器。可以实现workbookwriteHandler,SheetWriteHandler,RowWriteHandler,CellWriteHandler,在写入excel的不同阶段会调用,对使用者透明不可见。
- relativeHeadRowIndex距离多少行后开始。也就是开头空几行
- needHead是否导出头
- head与clazz二选一。写入文件的头列表,建议使用class。
- clazz与head二选一。写入文件的头对应的class,也可以使用注解。
- autoTrim字符串、表头等数据自动trim
WriteWorkBook(工作簿对象)参数
- excelType当前excel的类型,默认为xlsx
- outputStream与file二选一,写入文件的流
- file与outputStream二选一,写入的文件
- templateInputStream模板的文件流
- templateFile模板文件
- autoCloseStream自动关闭流
- password写的时候是否需要使用密码
- useDefaultStyle写的时候是否是使用默认头
WriteSheet(工作表对象)参数
- sheetNo需要写入的编号,默认0
- sheetName需要写的Sheet名称,默认同sheetNo
文件上传和下载
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qrxqrx</groupId>
<artifactId>easyexcel</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
</project>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 配置spring的监听器,默认只加载WEB-INF目录下的applicationContext.xml配置文件 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 设置配置文件的路径 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml</param-value>
</context-param>
<!-- 解决中文乱码的过滤器 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置前端控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 加载springmvc.xml配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!-- 启动服务器,创建该servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.qrxqrx.easyexcel.web.controller"/>
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver"/>
</beans>
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.qrxqrx.easyexcel">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
log4j.properties
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct message to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=d:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=debug, stdout
Student
package com.qrxqrx.easyexcel.domain;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import lombok.Data;
import java.util.Date;
@Data
// @ContentRowHeight() // 内容行高
public class Student {
@ColumnWidth(20)
@ExcelProperty(value = "学生姓名", index = 1)
private String name;
@ExcelProperty(value = "学生性别", index = 3)
private String gender;
@ColumnWidth(20)
@ExcelProperty(value = "学生生日", index = 2)
private Date birthday;
@ExcelProperty(value = "ID", index = 4)
private String id;
}
StudentService
package com.qrxqrx.easyexcel.service;
import com.qrxqrx.easyexcel.domain.Student;
import java.util.List;
public interface StudentService {
void readExcel(List<Student> students);
}
StudentServiceImpl
package com.qrxqrx.easyexcel.service.impl;
import com.qrxqrx.easyexcel.domain.Student;
import com.qrxqrx.easyexcel.service.StudentService;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class StudentServiceImpl implements StudentService {
@Override
public void readExcel(List<Student> students) {
for (Student student : students) {
System.out.println(student);
}
}
}
WebStudentListener
package com.qrxqrx.easyexcel.web.listener;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.qrxqrx.easyexcel.domain.Student;
import com.qrxqrx.easyexcel.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
@Component
@Scope("prototype")
public class WebStudentListener extends AnalysisEventListener<Student> {
@Autowired
StudentService studentService;
ArrayList<Student> students = new ArrayList<>();
@Override
public void invoke(Student student, AnalysisContext analysisContext) {
students.add(student);
if (students.size() % 5 == 0) {
studentService.readExcel(students);
students.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
}
}
StudentController
package com.qrxqrx.easyexcel.web.controller;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.qrxqrx.easyexcel.domain.Student;
import com.qrxqrx.easyexcel.service.StudentService;
import com.qrxqrx.easyexcel.web.listener.WebStudentListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
@Controller
@RequestMapping("student")
public class StudentController {
@Autowired
WebStudentListener webStudentListener;
// 上传
@RequestMapping("read")
@ResponseBody
public String readExcel(MultipartFile uploadExcel) {
try {
// 工作簿
ExcelReaderBuilder readWorkBook = EasyExcel.read(uploadExcel.getInputStream(), Student.class, webStudentListener);
// 工作表
readWorkBook.sheet().doRead();
return "success";
} catch (IOException e) {
e.printStackTrace();
return "fail";
}
}
// 下载
@RequestMapping("write")
@ResponseBody
public void writeExcel(HttpServletResponse httpServletResponse) throws IOException {
httpServletResponse.setContentType("application/vnd.ms-excel");
httpServletResponse.setCharacterEncoding("utf-8");
String filename = URLEncoder.encode("data2", "UTF-8");
httpServletResponse.setHeader("Content-Disposition","attachment; filename*=UTF-8''"+filename+".xlsx");
ServletOutputStream outputStream = httpServletResponse.getOutputStream();
ExcelWriterBuilder writeWorkBook = EasyExcel.write(outputStream, Student.class);
ExcelWriterSheetBuilder sheet = writeWorkBook.sheet();
ArrayList<Student> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Student student = new Student();
student.setName("qrx"+i);
student.setGender("男");
student.setBirthday(new Date());
list.add(student);
}
sheet.doWrite(list);
}
}
填充
填充一组数据
准备模板
excel表格中用{}来包裹要填充的变量,如果单元格文本中本来就有{、}左右大括号,需要在括号前面使用斜杠转义\{、\}。
代码中被填充数据的实体对象的成员变量名或被填充map集合的key需要和excel中被{}包裹的变量名称一致。
FillData
package com.qrxqrx.easyexcel.domain;
import lombok.Data;
@Data
public class FillData {
private String name;
private int age;
}
ExcelTest
@Test
public void test03() {
String template = "fill-data-template01.xlsx";
ExcelWriterBuilder writeWorkBook = EasyExcel.write("data-fill01.xlsx", FillData.class).withTemplate(template);
ExcelWriterSheetBuilder sheet = writeWorkBook.sheet();
// 准备数据
FillData fillData = new FillData();
fillData.setName("qrx");
fillData.setAge(25);
// 准备map数据
HashMap<String, String> map = new HashMap<>();
map.put("name","qrxqrx");
map.put("age","19");
// sheet.doFill(fillData);
sheet.doFill(map);
}
填充多组数据
@Test
public void test04() {
String template = "fill-data-template02.xlsx";
ExcelWriterBuilder writeWorkBook = EasyExcel.write("data-fill02.xlsx", FillData.class).withTemplate(template);
ExcelWriterSheetBuilder sheet = writeWorkBook.sheet();
// 准备数据
List<FillData> list = new ArrayList<>();
for (int i = 0;i < 9;i++) {
FillData fillData = new FillData();
fillData.setName("abc"+i);
fillData.setAge(i+10);
list.add(fillData);
}
sheet.doFill(list);
}
组合填充
@Test
public void test05() {
String template = "fill-data-template03.xlsx";
ExcelWriter build = EasyExcel.write("data-fill03.xlsx", FillData.class).withTemplate(template).build();
WriteSheet sheet = EasyExcel.writerSheet().build();
// 组合数据填充,因为多组填充的数据量不确定,需要在多组填充完之后另起一行
FillConfig config = FillConfig.builder().forceNewRow(true).build();
// 准备数据
List<FillData> list = new ArrayList<>();
for (int i = 0;i < 9;i++) {
FillData fillData = new FillData();
fillData.setName("abc"+i);
fillData.setAge(i+10);
list.add(fillData);
}
HashMap<String, String> map = new HashMap<>();
map.put("date",new Date().toString());
map.put("total","1w");
build.fill(list, config, sheet);
build.fill(map, sheet);
build.finish();
}
水平填充
@Test
public void test06() {
String template = "fill-data-template04.xlsx";
ExcelWriter build = EasyExcel.write("data-fill04.xlsx", FillData.class).withTemplate(template).build();
WriteSheet sheet = EasyExcel.writerSheet().build();
FillConfig config = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
// 准备数据
List<FillData> list = new ArrayList<>();
for (int i = 0;i < 9;i++) {
FillData fillData = new FillData();
fillData.setName("abc"+i);
fillData.setAge(i+10);
list.add(fillData);
}
build.fill(list, config, sheet);
build.finish();
}