当前位置: 首页 > news >正文

EasyExcel-最简单的读写excel工具类

前言:
easyExcel 的官网文档给的示例非常全,可以参考https://easyexcel.opensource.alibaba.com/docs/current/quickstart/read
在此我贴出自己的工具类,可以直接用

导包

		<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.0</version></dependency>

读excel

1:最简单读-使用demo对象

创建对象bean

package com.wkl.testdemo.excel;import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;/*** @author wangkanglu* @version 1.0* @description* @date 2023-12-08 17:28*/
@Data
public class DemoBean {/*** 用名字去匹配,这里需要注意,如果名字重复,会导致只有一个字段读取到数据*/@ExcelProperty("姓名")private String name;/*** 强制读取第二个 这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配*/@ExcelProperty(index = 1)private String sex;
}

创建读取器

package com.wkl.testdemo.excel;import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.util.ListUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;import java.util.List;/*** @author wangkanglu* @version 1.0* @description* @date 2023-12-08 17:27*/
@Data
public class DemoListener extends AnalysisEventListener<DemoBean> {/*** 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收*/private static final int BATCH_COUNT = 100;/*** 缓存的数据*/private List<DemoBean> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);/*** 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。*/private DemoBean demoDAO;public DemoListener() {// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数demoDAO = new DemoBean();}@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {if (exception instanceof ExcelDataConvertException) {Integer columnIndex = ((ExcelDataConvertException) exception).getColumnIndex() + 1;Integer rowIndex = ((ExcelDataConvertException) exception).getRowIndex() + 1;String message = "第" + rowIndex + "行,第" + columnIndex + "列,数据格式有误,请核实";System.out.println("导入数据转换出现错误: " + message);} else if (exception instanceof RuntimeException) {System.out.println("导入错误:" + exception);if (exception.getMessage().contains("列与模板上顺序不符,请勿修改表头模板")) {throw new RuntimeException(exception.getMessage());}}}@Overridepublic void invoke(DemoBean data, AnalysisContext analysisContext) {System.out.println("解析到一条数据:{}"+data);cachedDataList.add(data);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (cachedDataList.size() >= BATCH_COUNT) {saveData();// 存储完成清理 listcachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);}}@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {// 这里也要保存数据,确保最后遗留的数据也存储到数据库saveData();System.out.println("解析完了");}/*** 加上存储数据库*/private void saveData() {System.out.println("{}条数据,开始存储数据库!"+ cachedDataList.size());
//        demoDAO.save(cachedDataList);System.out.println("存储数据库成功!");}}

测试程序

package com.wkl.testdemo.excel;import com.alibaba.excel.EasyExcel;import java.util.List;/*** @author wangkanglu* @version 1.0* @description* @date 2023-12-08 17:45*/
public class SimpleTest {public static void main(String[] args) {String path = "C:\\Users\\Desktop\\demo.xlsx";DemoListener listener = new DemoListener();EasyExcel.read(path,DemoBean.class,listener).sheet().doRead();List<DemoBean> cachedDataList = listener.getCachedDataList();System.out.println("end----");}
}

2:读取多个sheet

 public static void main(String[] args) {String path = "C:\\Users\\wenge\\Desktop\\demo.xlsx";DemoListener listener = new DemoListener();//生成读取对象ExcelReader excelReader = EasyExcel.read(path).build();//生成一个sheetReadSheet build = EasyExcel.readSheet(0).head(DemoBean.class).registerReadListener(listener).build();//读取多个sheetExcelReader read = excelReader.read(Arrays.asList(build));List<DemoBean> cachedDataList = listener.getCachedDataList();System.out.println("end----");

3:复杂头的读取

如果遇到这样的excel
在这里插入图片描述

创建对象bean

package com.wkl.testdemo.excel;import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;/*** @author wangkanglu* @version 1.0* @description* @date 2023-12-08 17:28*/
@Data
public class DemoBeanheads {/*** 用名字去匹配,这里需要注意,如果名字重复,会导致只有一个字段读取到数据*/@ExcelProperty({"大学","姓名"})private String name;/*** 强制读取第二个 这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配*/@ExcelProperty({"大学","性别"})private String sex;
}

读取器不变

测试程序

public static void main(String[] args) {String path = "C:\\Users\\Desktop\\demo.xlsx";DemoHeadListener listener = new DemoHeadListener();//生成读取对象ExcelReader excelReader = EasyExcel.read(path).build();//生成一个sheetReadSheet build = EasyExcel.readSheet(0).head(DemoBeanheads.class).registerReadListener(listener).headRowNumber(2).build();//读取多个sheetExcelReader read = excelReader.read(Arrays.asList(build));List<DemoBeanheads> cachedDataList = listener.getCachedDataList();System.out.println("end----");}

4:不创建对象的对

读取器

package com.wkl.testdemo.excel;import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;@Slf4j
public class NoHeadMapListener extends AnalysisEventListener<Map<Integer, String>> {private List<Map<Integer, String>> list = new ArrayList<>();private static final SimpleDateFormat sdfFormat = new SimpleDateFormat("yyyy-MM-dd");//表头private List<String> headList = Arrays.asList("姓名","性别");@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {if (headMap==null){throw new RuntimeException("文件表头为空,请勿上传非法excel文件,请先下载对应的导入模板文件" );}if (headMap.size()!=headList.size()){throw new RuntimeException("文件表头列与模板不符,请勿上传非法excel文件,请先下载对应的导入模板文件" );}for (int i = 0; i < headList.size(); i++) {String tableHead = headMap.get(i);String head = headList.get(i);if (!head.equals(tableHead)) {throw new RuntimeException("表头中'" + tableHead + "'列与模板上顺序不符,请勿修改模板表头");}}}@Overridepublic void invoke(Map<Integer, String> integerStringMap, AnalysisContext analysisContext) {
//        log.info("解析到一条数据:{}", JSON.toJSONString(integerStringMap));List<String> picList = new ArrayList<>();if (!ObjectUtils.isEmpty(integerStringMap)) {list.add(integerStringMap);}}@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {log.info("所有数据解析完成!");}@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {if (exception instanceof ExcelDataConvertException) {Integer columnIndex = ((ExcelDataConvertException) exception).getColumnIndex() + 1;Integer rowIndex = ((ExcelDataConvertException) exception).getRowIndex() + 1;String message = "第" + rowIndex + "行,第" + columnIndex + "列,数据格式有误,请核实";log.error("导入数据转换出现错误: " + message);} else if (exception instanceof RuntimeException) {log.error("导入错误:" + exception);if (exception.getMessage().contains("列与模板上顺序不符,请勿修改表头模板")) {throw new RuntimeException(exception.getMessage());}}}public List<String> getHeadList() {return headList;}public void setHeadList(List<String> headList) {this.headList = headList;}public List<Map<Integer, String>> getList() {return list;}}

测试程序-读取本地本间

 public static void main(String[] args) {String path = "C:\\Users\\Desktop\\demo.xlsx";NoHeadMapListener listener = new NoHeadMapListener();EasyExcel.read(path, listener).sheet().doRead();List<String> headList = listener.getHeadList();List<Map<Integer, String>> list = listener.getList();System.out.println("end");}

测试程序-读取网络文件

 public static void main(MultipartFile file) {NoHeadMapListener listener = new NoHeadMapListener();InputStream inputStream = null;try {inputStream = file.getInputStream();} catch (IOException e) {throw new RuntimeException(e);}EasyExcel.read(inputStream, listener).sheet().doRead();List<Map<Integer, String>> list = listener.getList();System.out.println("end");}

读取后的得到的数据列表:
在这里插入图片描述

写excel

1:最简单的写

创建对象

@Getter
@Setter
@EqualsAndHashCode
public class DemoData {@ExcelProperty("字符串标题")private String string;@ExcelProperty("日期标题")private Date date;@ExcelProperty("数字标题")private Double doubleData;/*** 忽略这个字段*/@ExcelIgnoreprivate String ignore;
}

测试程序

List<DemoData> data = new ArrayList();
fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭// 如果这里想使用03 则 传入excelType参数即可EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data);

测试程序-导出指定列

List<DemoData> data = new ArrayList();
fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";// 根据用户传入字段 假设我们要忽略 name列Set<String> excludeColumnFiledNames = new HashSet<String>();excludeColumnFiledNames.add("name");// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭EasyExcel.write(fileName, DemoData.class).excludeColumnFiledNames(excludeColumnFiledNames).sheet("模板").doWrite(data);// 根据用户传入字段 假设我们只要导出 name列Set<String> includeColumnFiledNames = new HashSet<String>();includeColumnFiledNames.add("name");// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭EasyExcel.write(fileName, DemoData.class).includeColumnFiledNames(includeColumnFiledNames).sheet("模板").doWrite(data);

2:数据写到不同的sheet

fileName = TestFileUtil.getPath() + "repeatedWrite" + System.currentTimeMillis() + ".xlsx";// 这里 指定文件try (ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build()) {// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面for (int i = 0; i < 5; i++) {// 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).build();// 分页去数据库查询数据 这里可以去数据库查询每一页的数据List<DemoData> data = data();excelWriter.write(data, writeSheet);}}

3:动态表头写入web

private List<List<String>> head() {List<List<String>> list = new ArrayList<List<String>>();List<String> head0 = new ArrayList<String>();head0.add("字符串" + System.currentTimeMillis());List<String> head1 = new ArrayList<String>();head1.add("数字" + System.currentTimeMillis());List<String> head2 = new ArrayList<String>();head2.add("日期" + System.currentTimeMillis());list.add(head0);list.add(head1);list.add(head2);return list;}private List<DemoData> data() {List<DemoData> list = ListUtils.newArrayList();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;}@GetMapping("download")public void download(HttpServletResponse response) throws IOException {// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postmanresponse.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");EasyExcel.write(response.getOutputStream()).sheet("模板").head(head).doWrite(data());}

相关文章:

  • 【Vue】日常错误总结(持续更新)
  • acwing算法提高之动态规划--状态机模型
  • Python接口自动化 —— Json 数据处理实战(详解)
  • 2019年第八届数学建模国际赛小美赛C题预测通过拥堵路段所需的时间解题全过程文档及程序
  • JAVA的关键字、标识符和命名规范
  • 【计算机网络】UDP报文详解
  • WPF使用WebBrowser报脚本错误问题处理
  • Linux 常用命令----mktemp 命令
  • 使用Postman如何在接口测试前将请求的参数进行自定义处理
  • 企业IT安全:内部威胁检测和缓解
  • 租一台服务器多少钱决定服务器的价格因素有哪些
  • ubuntu下搜索文件的几种方法
  • Unity2023.3(Unity6)版本开始将可以发布WebGPU
  • Unity检测AssetBundle是否循环依赖
  • LVS 负载均衡群集 NAT
  • 【Redis学习笔记】2018-06-28 redis命令源码学习1
  • 77. Combinations
  • bearychat的java client
  • CSS实用技巧干货
  • ECMAScript6(0):ES6简明参考手册
  • express + mock 让前后台并行开发
  • Hexo+码云+git快速搭建免费的静态Blog
  • Java的Interrupt与线程中断
  • 表单中readonly的input等标签,禁止光标进入(focus)的几种方式
  • 大数据与云计算学习:数据分析(二)
  • 翻译--Thinking in React
  • 给初学者:JavaScript 中数组操作注意点
  • 好的网址,关于.net 4.0 ,vs 2010
  • 让你的分享飞起来——极光推出社会化分享组件
  • 异常机制详解
  • 用element的upload组件实现多图片上传和压缩
  • 优化 Vue 项目编译文件大小
  • k8s使用glusterfs实现动态持久化存储
  • #FPGA(基础知识)
  • #Linux(帮助手册)
  • #stm32驱动外设模块总结w5500模块
  • (16)Reactor的测试——响应式Spring的道法术器
  • (31)对象的克隆
  • (6)设计一个TimeMap
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (力扣)1314.矩阵区域和
  • (算法)前K大的和
  • (万字长文)Spring的核心知识尽揽其中
  • (转载)Linux 多线程条件变量同步
  • (转载)Linux网络编程入门
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • .describe() python_Python-Win32com-Excel
  • .form文件_一篇文章学会文件上传
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .net 按比例显示图片的缩略图
  • .NET 将多个程序集合并成单一程序集的 4+3 种方法
  • .NET/C# 项目如何优雅地设置条件编译符号?
  • .NET实现之(自动更新)
  • .net网站发布-允许更新此预编译站点