title: 9 easyexcel author: glls date: '2023-3-29'
EasyExcel
1.easyexcel介绍
EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。 github地址:GitHub - alibaba/easyexcel: 快速、简洁、解决大文件内存溢出的java处理Excel工具
2.快速入门
2.1 创建maven 工程
2.2 添加依赖
<?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.glls</groupId> <artifactId>easyexcel</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </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>
2.3 单实体导入
2.3.1创建实体类
package com.glls.easyexcel.pojo; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.ColumnWidth; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; /** * @ClassName : Student * @Description : 实体类中定义属性的顺序 和 excel 中的 列顺序 有对应关系 */ @Data @AllArgsConstructor @NoArgsConstructor public class Student { private String id; private String name; private String sex; private Date birthday; }
2.3.2 准备一个 excel 文件
2.3.3 测试读数据
//简单读 excel 数据 @Test public void test01(){ //获得一个工作簿对象 .xls //param1 文件路径 //param2 文件中每行数据y要存储的实体类类型 //param3 监听器 每读取一行数据 都会调用监听器的 invoke 方法 ,在invoke 方法中可以获取读取到的数据 ExcelReaderBuilder excelReaderBuilder = EasyExcel.read("f://测试easyexcel.xlsx", Student.class, new StudentReadListener()); //获得一个工作表对象 sheet ExcelReaderSheetBuilder sheet = excelReaderBuilder.sheet(); // 读取工作表中的内容 sheet.doRead(); }
package com.glls.easyexcel.listener; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.glls.easyexcel.pojo.Student; /** * @ClassName : StudentListener * @Description : */ public class StudentReadListener extends AnalysisEventListener<Student> { //每读取一行数据 会调用一次这个方法 @Override public void invoke(Student student, AnalysisContext analysisContext) { System.out.println(student); } //全部读取完之后 会调用该方法 @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { System.out.println("读取完毕"); } }
2.4 添加日志的配置文件 log4j.properties
log4j.rootLogger=debug, Console #file Console log4j.appender.Console=org.apache.log4j.ConsoleAppender #log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.Console.layout=org.apache.log4j.PatternLayout log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n #log4j.appender.file.File=e:/my.log #log4j.appender.file.Append=true #log4j.appender.file.layout=org.apache.log4j.PatternLayout #log4j.appender.file.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n log4j.logger.org.apache.ibatis=info
测试结果
2.5 写数据到excel 中
//简单写 写数据到 excel 中 @Test public void test02(){ //工作簿对象 ExcelWriterBuilder writerBuilder = EasyExcel.write("f://测试easyexcel-write.xlsx", Student.class); //工作表对象 ExcelWriterSheetBuilder sheet = writerBuilder.sheet(); //写 List<Student> students = Arrays.asList(new Student("1","zs","男",new Date()), new Student("2","ls","女",new Date())); sheet.doWrite(students); }
2.6 常用注解
@ExcelProperty 作用在成员变量 属性 value 指定列头名 默认列头是属性名 index 指定属性在 excel 中的第几列 默认 按照属性顺序 converter 成员变量转换器 自定义转换器需要实现Converter 接口 建议 index 和 value 要对应着使用 @ColumnWidth value 指定 列宽 @ExcelIgnore 忽略某个属性 不把某一个属性写入excel @DateTimeFormat("yyyy-MM-dd") 日期格式化 @ContentRowHeight 内容行高 只能作用于类 @HeadRowHeight 列头行高 只能作用于类
2.7 常用API
EasyExcel 入口类 用于构建各种对象 开始各种操作 ExcelReaderBuilder 构建出一个 ReadWorkbook 对象 是其属性 即一个工作簿对象 对应一个 excel 文件 ExcelWriterBuilder 构建出一个 WriteWorkbook 对象 是其属性 即一个工作簿对象 对应一个 excel 文件 ExcelReaderSheetBuilder 构建一个 ReadSheet 对象 即一个工作表对象 对应excel 中的 sheet 页 ,一个工作簿可以有多个sheet ExcelWriterSheetBuilder 构建一个 WriteSheet 对象 即一个工作表对象 对应excel 中的 sheet 页 ,一个工作簿可以有多个sheet ReadListener 在每一行读取完毕后 都会调用 ReadListener 来处理数据,我们可以把调用service 的代码 写在invoke 中 WriteHandler 在每一个操作 包括创建单元格 创建表格 都会调用WriteHandler 来处理数据,对使用者透明不可见 所有的配置都是继承的,WorkBook 的配置会被sheet 继承,所以在EasyExcel 设置参数的时候 在EasyExcel . sheet()方法之前作用域是整个workbook的所有sheet,之后针对单个sheet
3.文件上传下载
3.1 上传文件
从 一个excel 文件中读取数据到数据库中
准备工作 搭建一个 ssm环境,或者 springmvc 的环境,咱们借助 springmvc 的 文件上传来做
添加依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.1.6</version> </dependency> <!--文件上传--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency>
配置springmvc文件
记得配置multipartResolver 这个 bean
准备监听器
package com.qf.ssm.listener; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.qf.ssm.pojo.Student; import com.qf.ssm.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; /** * @ClassName : WebStudentListener * @Author : glls * @Date: 2021/8/23 16:04 * @Description : */ @Component @Scope("prototype") // 注意 这里要设置成多例模式 public class WebStudentListener extends AnalysisEventListener<Student> { @Autowired StudentService studentService; @Override public void invoke(Student data, AnalysisContext context) { System.out.println(data); studentService.addStudent(data); } @Override public void doAfterAllAnalysed(AnalysisContext context) { } }
controller
@Autowired WebStudentListener webStudentListener; @Autowired private StudentService studentService; @RequestMapping("/read") @ResponseBody public String readExcel(MultipartFile file){ try { ExcelReaderBuilder read = EasyExcel.read(file.getInputStream(), Student.class, webStudentListener); ExcelReaderSheetBuilder sheet = read.sheet(); sheet.doRead(); } catch (IOException e) { e.printStackTrace(); } return "success"; }
3.2 下载文件
把数据库中的数据下载到excel 中
controller
@RequestMapping("/write") @ResponseBody public void writeExcel(HttpServletResponse response) throws IOException { response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); //防止中文乱码 String filename = URLEncoder.encode("测试文件名", "utf-8"); response.setHeader("Content-Disposition","attachment;filename="+filename+".xlsx"); ServletOutputStream outputStream = response.getOutputStream(); ExcelWriterBuilder write = EasyExcel.write(outputStream,Student.class); ExcelWriterSheetBuilder sheet = write.sheet(); //准备列表数据 PageInfo<Student> pageData = studentService.getPageData(1, new Student()); sheet.doWrite(pageData.getList()); }
4.填充
Easyexcel 支持调整行高 列宽 背景色 字体大小等设置,但是 通过代码来控制比较麻烦,所以 不建议使用,但是 可以使用模板填充的方式 ,向预设样式的表格中直接写入数据,写入数据后 会保持原有样式
4.1 准备模板
Excel表格中用{}来包裹要填充的变量,如果单元格中本来就有 { } 左右大括号,需要在括号前面使用 \ 转义字符,
\{ \}
代码中被填充数据的实体对象的成员变量名 或 被填充map 集合的 key 需要和excel 中 被{} 包裹的变量名称一致。
4.2 封装数据
编写封装填充数据的类 或者 选择使用 map
@Test public void test03(){ String template = "f://template1.xlsx"; ExcelWriterBuilder write = EasyExcel.write("f://测试填充单一模板数据.xlsx", FillData.class); write.withTemplate(template); ExcelWriterSheetBuilder sheet = write.sheet(); //准备实体类数据 FillData fillData = new FillData(); fillData.setName("zs"); fillData.setAge(22); //准备map 数据 HashMap<String, String> map = new HashMap<>(); map.put("name","ls"); map.put("age","21"); //sheet.doFill(fillData); sheet.doFill(map); }
4.3 多组数据填充
和之前模板 不一样的地方 就是 多了个 .
代码
@Test public void test04(){ String template = "f://template2.xlsx"; ExcelWriterBuilder write = EasyExcel.write("f://测试填充多条数据模板.xlsx", FillData.class); write.withTemplate(template); ExcelWriterSheetBuilder sheet = write.sheet(); List<FillData> fillData = Arrays.asList(new FillData("zs", 5), new FillData("ls", 6),new FillData("ww",7)); sheet.doFill(fillData); }
4.4 组合数据填充
模板
代码
@Test public void test05(){ //使用模板 组合填充 有多行 有单行 String template = "f://template3.xlsx"; ExcelWriter workBook = EasyExcel.write("f://测试填充组合数据模板.xlsx", FillData.class).withTemplate(template).build(); WriteSheet writeSheet = EasyExcel.writerSheet().build(); FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build(); List<FillData> fillData = Arrays.asList(new FillData("zs", 5), new FillData("ls", 6),new FillData("ww",7)); //填充并换行 workBook.fill(fillData,fillConfig,writeSheet); //填充多行数据 //准备单行数据 HashMap<String, String> map = new HashMap<>(); map.put("date","1999-11-11"); map.put("total","111"); workBook.fill(map,writeSheet); // 填充单行数据 //关闭流 workBook.finish(); }
4.5 水平填充
模板
@Test public void test06(){ //使用模板 水平填充 String template = "f://template4.xlsx"; ExcelWriter workBook = EasyExcel.write("f://测试水平填充数据模板.xlsx", FillData.class).withTemplate(template).build(); WriteSheet writeSheet = EasyExcel.writerSheet().build(); FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build(); List<FillData> fillData = Arrays.asList(new FillData("zs", 5), new FillData("ls", 6),new FillData("ww",7)); //填充并换行 workBook.fill(fillData,fillConfig,writeSheet); //填充多行数据 //关闭流 workBook.finish(); }