当前位置:网站首页>POI和EasyExcel讲解
POI和EasyExcel讲解
2022-04-23 22:02:00 【.G( );】
全文内容来自官方文档和相关视频的讲解,本作者用做笔记!
POI和EasyExcel讲解
常用场景:
- 将用户信息导出为Excel表格(导出xls数据…)
- 将Excel表中的信息录入到网站数据库(习题上传…公司找老师填写题目到excel再上传网站,网站会利用相关POI将数据回填到数据库,这样大大减轻网站录入量。)
开发中经常会设计到excel的处理,如导出Excel,导入Excel到数据库中!
操作Excel目前流行的就是Apache POI 和 阿里巴巴 EasyExcel!
Apache POI
Apache POI 官网:
Apache POI 官网:https://poi.apache.org/
Apache POI 是Apache软件基金会的开放源码函数库,用Java编写的免费开源的跨平台的 Java API。Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写,意为“简洁版的模糊实现”。
基本功能:
HSSF - 提供读写Microsoft Excel XLS格式档案的功能。
XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。
HWPF - 提供读写Microsoft Word DOC格式档案的功能。
HSLF - 提供读写Microsoft PowerPoint格式档案的功能。
HDGF - 提供读Microsoft Visio格式档案的功能。
HPBF - 提供读Microsoft Publisher格式档案的功能。
HSMF - 提供读Microsoft Outlook格式档案的功能。
Excel 版本区别:03版和07版
03版本 2003版本.xls
:行数只有65535行,多了放不了。
07版本 2007版本.xlsx
:无限制
POI-Excel 写
创建普通Maven项目:
Java版本:1.8
创建完项目,导入依赖 pom.xml:
<!--导入依赖-->
<dependencies>
<!-- excel2003版本 xls -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.9</version>
</dependency>
<!-- excel 2007版本 xlsx -->
<dependency>-->
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.9</version>
</dependency>
<!-- 日期格式化工具 -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.1</version>
</dependency>
<!-- test 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
Java编程,万物皆对象:
excel 表中的各个对象: 工作簿、工作表、行、列、单元格
实现类,写入
先创建工作簿,后创建工作表,再有行和列,最后组成了数据:
public class ExcelWriteTest {
//03版本实现类
String PATH = "/Users/**/Documents/IdeaProjects/guo_poi/src/main/resources/data/" ;//设置固定文件路径
@Test //创建03版本
public void testWrite03() throws Exception{
// 1.创建一个工作簿
Workbook workbook = new HSSFWorkbook(); //对象存在差别 HSSF
// 2.创建一个工作表
Sheet sheet = workbook.createSheet("guo1"); //sheet 名字为:guo1
// 3.创建一个行 (1,1)
Row row11 = sheet.createRow(0); //第一行
// 4. 创建一个单元格
Cell cell11 = row11.createCell(0); //第一行,第一列的格子(0,0)
cell11.setCellValue("今日人数"); //设置值
//(1,2)
Row row12 = sheet.createRow(1);
Cell cell12 = row12.createCell(0);
cell12.setCellValue(666);
// 第二行
Row row2 = sheet.createRow(1);
Cell cell21 = row2.createCell(0);
cell21.setCellValue("统计时间");
// (2,2)
Cell cell22 = row2.createCell(1);
String time = new DateTime().toString("yyyy-mm-dd HH:mm:ss");
cell22.setCellValue(time);
//生成一张表(IO流) 03版本 就是使用xls结尾!
FileOutputStream fileOutputStream = new FileOutputStream(PATH + "03版本统计表.xls");
//输出
workbook.write(fileOutputStream);
//关闭流
fileOutputStream.close();
System.out.println("03版本统计表.xls 生成完毕!");
}
}
public class ExcelWriteTest {
//07版本实现类 和03版本写在同一个类下
//设置固定文件路径,与03相同
String PATH = "/Users/**/Documents/IdeaProjects/guo_poi/src/main/resources/data/" ;
@Test //创建07版本
public void testWrite07() throws Exception{
// 1.创建一个工作簿
Workbook workbook = new XSSFWorkbook(); //对象存在差别 XSSF
// 2.创建一个工作表
Sheet sheet = workbook.createSheet("guo2"); //sheet 名字为:guo1
// 3.创建一个行 (1,1)
Row row11 = sheet.createRow(0); //第一行
// 4. 创建一个单元格
Cell cell11 = row11.createCell(0); //第一行,第一列的格子(0,0)
cell11.setCellValue("今日人数"); //设置值
//(1,2)
Row row12 = sheet.createRow(1);
Cell cell12 = row12.createCell(0);
cell12.setCellValue(666);
// 第二行
Row row2 = sheet.createRow(1);
Cell cell21 = row2.createCell(0);
cell21.setCellValue("统计时间");
// (2,2)
Cell cell22 = row2.createCell(1);
String time = new DateTime().toString("yyyy-mm-dd HH:mm:ss");
cell22.setCellValue(time);
//生成一张表(IO流) 03版本 就是使用xlsx结尾! //这里存在差别
FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07版本统计表.xlsx");
//输出
workbook.write(fileOutputStream);
//关闭流
fileOutputStream.close();
System.out.println("07版本统计表.xlsx 生成完毕!")
}
}
03与07差别只有文件后缀不同!
数据批量写入:大文件写入HSSF (03版)
缺点:最多只能处理65536行,否则会抛出异常
java.lang.11legalArgumentException : Invalid row number (65536) outside allowable range (0..65535)
优点:过程中写入缓存,不操作磁盘,最后一次性写入磁盘,速度快。
//设置固定文件路径,与03相同
String PATH = "/Users/**/Documents/IdeaProjects/guo_poi/src/main/resources/data/" ;
@Test //03大量数据
public void testWrite03BigData() throws IOException {
//时间差 begin 和 end 的差值
long begin = System.currentTimeMillis();
// 创建工作簿
Workbook workbook = new HSSFWorkbook(); //03版本对象 HSSF
// 创建工作表
Sheet sheet = workbook.createSheet();
// 写入数据
for( int rowNum = 0; rowNum < 65536; rowNum++){
//65537会报错
Row row = sheet.createRow(rowNum); // 行
for (int cellNum = 0; cellNum <10; cellNum++){
//这里设置了10列
Cell cell = row.createCell(cellNum); // 列
cell.setCellValue(cellNum); //循环65536行,每一行都是10列的数据
}
}
//运行完毕,输出文件流
System.out.println("over");
FileOutputStream outputStream = new FileOutputStream(PATH + "testWrite03BigDATA.xls" );
workbook.write(outputStream); //写入
// 关闭流
outputStream.close();
//时间差
long end = System.currentTimeMillis();
//计算时间差,强制转换double,按秒来
System.out.println((double)(end - begin)/1000);
}
大文件写入HSSF (07版)
缺点: 写数据时速度非常慢,非常耗内存,可能会发生内存溢出,如100万条。
优点,可以写入较大的数据量,如20万条数据。
//设置固定文件路径,与03相同
String PATH = "/Users/**/Documents/IdeaProjects/guo_poi/src/main/resources/data/" ;
@Test //07大数据读取 耗时较长
public void testWrite07BigData() throws IOException {
//时间差 begin 和 end 的差值
long begin = System.currentTimeMillis();
// 创建工作簿
Workbook workbook = new XSSFWorkbook(); //07版本对象 XSSF
// 创建工作表
Sheet sheet = workbook.createSheet();
// 写入数据
for( int rowNum = 0; rowNum < 1000000; rowNum++){
Row row = sheet.createRow(rowNum); // 行
for (int cellNum = 0; cellNum <10; cellNum++){
//这里设置了10列
Cell cell = row.createCell(cellNum); // 列
cell.setCellValue(cellNum); //循环65536行,每一行都是10列的数据
}
}
//运行完毕,输出文件流
System.out.println("over");
FileOutputStream outputStream = new FileOutputStream(PATH + "testWrite07BigDATA.xlsx" );
workbook.write(outputStream); //写入
// 关闭流
outputStream.close();
//时间差
long end = System.currentTimeMillis();
//计算时间差,强制转换double,按秒来
System.out.println((double)(end - begin)/1000);
}
大文件写SXSSF (比07版,速度更快)
优点:可以写非常大的数据量,如100万条甚至更多条,写数据速度快,占用更少的内存。
注意:过程中会产生临时文件,需要清理临时文件
原理:默认由100条记录保存在内存中,如果超出这数量,则最前面的数据最前面的数据被写入临时文件,如果想自定义内存中的数据的数量,可以使用new SXSSFWorkbook(数量)
SXSSFWorkbook 来至官方的解释,实现“BigGridDemo“策略的流式XSSFWorkbook版本,这允许写入非常大的文件而不会耗尽内存,因为任何时候只有可配置的行部分被保存在内存中。
请注意,仍然可能会消耗大量内存,这些内存基于您正在使用的功能,例如合并区域,注释,仍然只能存储在内存中,因此如果广泛使用,可能需要大量内存。
//设置固定文件路径,与03相同
String PATH = "/Users/**/Documents/IdeaProjects/guo_poi/src/main/resources/data/" ;
@Test //07大数据读取 耗时短
public void testWrite07BigDataS() throws IOException{
//时间差 begin 和 end 的差值
long begin = System.currentTimeMillis();
// 创建工作簿
Workbook workbook = new SXSSFWorkbook(); //07版本对象 XSSF
// 创建工作表
Sheet sheet = workbook.createSheet();
// 写入数据
for( int rowNum = 0; rowNum < 100000; rowNum++){
Row row = sheet.createRow(rowNum); // 行
for (int cellNum = 0; cellNum <10; cellNum++){
//这里设置了10列
Cell cell = row.createCell(cellNum); // 列
cell.setCellValue(cellNum); //循环65536行,每一行都是10列的数据
}
}
//运行完毕,输出文件流
System.out.println("over");
FileOutputStream outputStream = new FileOutputStream(PATH + "testWrite07BigDATAS.xlsx" );
workbook.write(outputStream); //写入
// 关闭流
outputStream.close();
//清除临时文件!
((SXSSFWorkbook)workbook).dispose();
//时间差
long end = System.currentTimeMillis();
//计算时间差,强制转换double,按秒来
System.out.println((double)(end - begin)/1000);
}
POI-Excel 读
// workbook 代表工作簿,使用excel能操作的功能,workbook都可以操作
workbook.createCellStyle();//创建样式
workbook.createName();//创建名称
workbook.findFont();//找内容
workbook.getAllPictures();//得到一些图片
workbook.isHidden();//隐藏
workbook.removeName();//移除名字
//sheet 代表表中的设置 使用excel表能操作的功能,sheet都可以操作
sheet.createRow();//创建行
sheet.autoSizeColumn();//列的大小
sheet.getColumnWidth();//列的宽度
sheet.getDefaultRowHeightInPoints();//行间距
03版本,读数据:
@Test。 //03版本读数据
public void testRead03() throws Exception{
//获取文件流
FileInputStream inputStream = new FileInputStream(PATH +"guo_poi03版本统计表.xls");
// 1.创建一个工作簿 使用excel能操作的功能,workbook都可以操作
Workbook workbook = new HSSFWorkbook(inputStream); // 流获取到工作簿
// 2.得到表 表中的设置
Sheet sheet = workbook.getSheetAt(0); //拿去 get方法
// 3.得到行
Row row = sheet.getRow(0); //得到第一行
// 4.得到列
Cell cell = row.getCell(0); //得到第一列
//读取值时需要类型判断!
// 获得字符串
System.out.println(cell.getStringCellValue()); //字符串类型
//cell.getNumericCellValue()获取数字
// 关闭流
inputStream.close();
}
07版本,读数据:
@Test //07版本读数据
public void testRead07() throws Exception{
//获取文件流
FileInputStream inputStream = new FileInputStream(PATH +"guo_poi07版本统计表.xlsx");
// 1.创建一个工作簿 使用excel能操作的功能,workbook都可以操作
Workbook workbook = new XSSFWorkbook(inputStream); // 流获取到工作簿
// 2.得到表 表中的设置
Sheet sheet = workbook.getSheetAt(0); //拿去 get方法
// 3.得到行
Row row = sheet.getRow(0); //得到第一行
// 4.得到列
Cell cell = row.getCell(0); //得到第一列
//读取值时需要类型判断!
// 获得字符串
System.out.println(cell.getNumericCellValue()); //获取数字
// 关闭流
inputStream.close();
}
注意获取值的类型;
读取不同数据类型:(最麻烦)注意类型转换
@Test //测试类型
public void testCellType() throws Exception{
//获取文件流
FileInputStream inputStream = new FileInputStream(PATH +"会员消费商品明细表.xls");
// 创建一个工作簿 使用excel能操作的这边都可以操作
Workbook workbook = new HSSFWorkbook(inputStream); //03版本
//获取表
Sheet sheet = workbook.getSheetAt(0);
//获取标题内容
Row rowTitle = sheet.getRow(0); //最上面一行
if(rowTitle != null){
//一定要掌握 拿到所有的列
int cellCount = rowTitle.getPhysicalNumberOfCells(); // 获取所有列数据,总数 比如:13个列
for (int cellNum = 0; cellNum < cellCount;cellNum++){
Cell cell = rowTitle.getCell(cellNum);
if (cell != null){
CellType cellType = cell.getCellType(); //取出数据的类型
String cellValue = cell.getStringCellValue(); //获取数据 该数据是string 字符串类型
System.out.print(cellValue + "|"); //把数据打印出来,输出时不换行
}
}
System.out.println();
}
//获取表中的内容
int rowCount = sheet.getPhysicalNumberOfRows(); //获取所有的行 getPhysicalNumberOfCells()获取所有列
for( int rowNum = 1;rowNum< rowCount;rowNum++){
Row rowData = sheet.getRow(rowNum);
if(rowData != null){
//判空
//读取列
int cellCoumt = rowTitle.getPhysicalNumberOfCells();
for (int cellNum = 0;cellNum < cellCoumt ; cellNum++){
System.out.print("["+(rowNum+1)+"-"+(rowNum+1)+"]");
Cell cell = rowData.getCell(cellNum);
// 匹配列的数据类型
if(cell != null){
CellType cellType = cell.getCellType();
String cellValue = "";
switch(cellType){
case STRING: //字符串类型
System.out.print("[String]");
cellValue = cell.getStringCellValue();
break;
case BOOLEAN: //布尔类型
System.out.print("[BOOLEAN]");
cellValue = String.valueOf(cell.getBooleanCellValue());
break;
case BLANK: //空
System.out.print("[BLANK]");
break;
case _NONE:
System.out.print("[NONE]");
break;
case NUMERIC: //数字(日期、普通数字)
System.out.print("[NUMERIC]");
if(DateUtil.isCellInternalDateFormatted(cell)) {
//日期
System.out.print("[日期]");
Date date = cell.getDateCellValue();
cellValue = new DateTime(date).toString("yyyy-MM-dd");
}else{
//不是日期格式,防止数字过长!
System.out.print("[转换为字符串输出]");
cellValue = cell.toString();
}
break;
case ERROR: //错误
System.out.print("【数据类型错误】");
break;
}
System.out.println(cellValue);
}
}
}
}
inputStream.close(); //关闭流
}
@Test //测试类型 提取成工具类
public void testCellType(FileInputStream inputStream) throws Exception{
// 创建一个工作簿 使用excel能操作的这边都可以操作
Workbook workbook = new HSSFWorkbook(inputStream); //03版本
//获取表
Sheet sheet = workbook.getSheetAt(0);
//获取标题内容
Row rowTitle = sheet.getRow(0); //最上面一行
if(rowTitle != null){
//一定要掌握 拿到所有的列
int cellCount = rowTitle.getPhysicalNumberOfCells(); // 获取所有列数据,总数 比如:13个列
for (int cellNum = 0; cellNum < cellCount;cellNum++){
Cell cell = rowTitle.getCell(cellNum);
if (cell != null){
CellType cellType = cell.getCellType(); //取出数据的类型
String cellValue = cell.getStringCellValue(); //获取数据 该数据是string 字符串类型
System.out.print(cellValue + "|"); //把数据打印出来,输出时不换行
}
}
System.out.println();
}
//获取表中的内容
int rowCount = sheet.getPhysicalNumberOfRows(); //获取所有的行 getPhysicalNumberOfCells()获取所有列
for( int rowNum = 1;rowNum< rowCount;rowNum++){
Row rowData = sheet.getRow(rowNum);
if(rowData != null){
//判空
//读取列
int cellCoumt = rowTitle.getPhysicalNumberOfCells();
for (int cellNum = 0;cellNum < cellCoumt ; cellNum++){
System.out.print("["+(rowNum+1)+"-"+(rowNum+1)+"]");
Cell cell = rowData.getCell(cellNum);
// 匹配列的数据类型
if(cell != null){
CellType cellType = cell.getCellType();
String cellValue = "";
switch(cellType){
case STRING: //字符串类型
System.out.print("[String]");
cellValue = cell.getStringCellValue();
break;
case BOOLEAN: //布尔类型
System.out.print("[BOOLEAN]");
cellValue = String.valueOf(cell.getBooleanCellValue());
break;
case BLANK: //空
System.out.print("[BLANK]");
break;
case _NONE:
System.out.print("[NONE]");
break;
case NUMERIC: //数字(日期、普通数字)
System.out.print("[NUMERIC]");
if(DateUtil.isCellInternalDateFormatted(cell)) {
//日期
System.out.print("[日期]");
Date date = cell.getDateCellValue();
cellValue = new DateTime(date).toString("yyyy-MM-dd");
}else{
//不是日期格式,防止数字过长!
System.out.print("[转换为字符串输出]");
cellValue = cell.toString();
}
break;
case ERROR: //错误
System.out.print("【数据类型错误】");
break;
}
System.out.println(cellValue);
}
}
}
}
inputStream.close(); //关闭流
}
读取并计算公式:
表格样式:
@Test //公式
public void testFormula() throws Exception{
//获取文件流
FileInputStream inputStream = new FileInputStream(PATH +"公式.xls");
// 创建一个工作簿 使用excel能操作的这边都可以操作
Workbook workbook = new HSSFWorkbook(inputStream); //03版本
//获取表
Sheet sheet = workbook.getSheetAt(0);
//获取第五行
Row row = sheet.getRow(4);
//获取第一列
Cell cell = row.getCell(0);
//拿到计算公式 eval函数 通过它来计算
FormulaEvaluator formulaEvaluator = new HSSFFormulaEvaluator((HSSFWorkbook)workbook);
//输出单元格内容
CellType cellType = cell.getCellType();
switch (cellType){
case FORMULA: //公式类型 需要和公式类型匹配,如果不匹配不会进入方法的
String formula = cell.getCellFormula();
System.out.println(formula);
//计算
CellValue evaluate = formulaEvaluator.evaluate(cell); // 用evaluate(cell)方法计算
String cellValue = evaluate.formatAsString();//计算结果,列的值,格式化成字符串来输出
System.out.println(cellValue); //输出结果
break;
}
}
EasyExcel
EasyExcel:快速、简洁、解决大文件内存溢出的java处理Excel工具
POI一般底层仍会使用,弊端就是当数据量大的时候会报OOM异常,相比较POI相对简单一些!
EasyExcel :
EasyExcel官方地址:https://github.com/alibaba/easyexcel
官方简介:
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便
GitHub EasyExcel :
官方文档:
官方文档:https://www.yuque.com/easyexcel/doc/easyexcel
EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存存储著称。
EasyExcel 能大大减少占用内存的主要原因是在解析Excel是没有将数据一次性全部加载到内存中,而且是从磁盘上一行行读取数据,逐个解析。
内存问题:POI = 100w先加载到内存中(十分耗内存)再一次性写入文件中,当内存不够时可能会报OOM。而EasyExcel在写入文件中是通过磁盘一行一行读取的。
下图是EasyExcel和POI在解析Excel时的对比图。
pom.xml 依赖
<!-- 导入easyexcel依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>
<!-- 可能需要导入的其他依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
实体类:EasyExcel会根据实体类自动生成表
package easy;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.util.Date;
@Data
public class DemoData {
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题")
private Date date;
@ExcelProperty("数字标题")
private Double doubleData;
/** * 忽略这个字段 */
@ExcelIgnore
private String ignore;
}
实现类:写数据
package easy;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.util.ListUtils;
import org.junit.Test;
import java.util.Date;
import java.util.List;
public class TestExcel {
String PATH = "/Users/**/Documents/IdeaProjects/guo_poi/src/main/resources/" ;//设置固定文件路径
//自动生成10个随机数,再把随机数放入list
private List<DemoData> data() {
//实体类加载过来
List<DemoData> list = ListUtils.newArrayList();
for (int i = 0; i < 10; i++) {
DemoData data = new DemoData();
//设初值,返回到list中
data.setString("字符串" + i);
data.setDate(new Date());
data.setDoubleData(0.56);
list.add(data);
}
return list;
}
//根据list 写入excel
/** * 最简单的写 * <p> * 1. 创建excel对应的实体对象 参照{@link DemoData} * <p> * 2. 直接写即可 */
@Test
public void simpleWrite() {
// 注意 simpleWrite在数据量不大的情况下可以使用(5000以内,具体也要看实际情况),数据量大参照 重复多次写入
// 最简单写法 JDK8+ 其余写法官方文档上都有
String fileName = PATH + "dataEasyTest.xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
// write.(fileName,格式类) 格式类会根据注释自动生成表的属性
// sheet("表名") 生成表的方法
//dowrite.(数据) 写入数据 从前端或者数据库读取的数据
EasyExcel.write(fileName, DemoData.class) //filename 数据流,DemoData.class 对应实体 标题生成
.sheet("模板") //生成一个sheet为模版的表
.doWrite(data());//dowrite(数据)
//data() 这里就是写了一个简单的生成随机数,真实情况是从前端返过来或数据库中读取出来的一个list,绑定mapper就行
}
}
成功运行:可以看到生成了dataEasyExcel.xlsx
生成的数据
实现类:读数据
//只写了方法,该方法也放在TestExcel中
/** * 最简单的读 * <p> * 1. 创建excel对应的实体对象 参照{@link DemoData} * <p> * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} * <p> * 3. 直接读即可 */
@Test
public void simpleRead() {
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
// 最简单写法 JDK8+ 其余写法官方文档上都有
String fileName = PATH + "dataEasyExcel.xlsx";
// 这里 需要指定读哪个文件,用哪个class按格式输出,通过DemoDataListener监视器去判断逻辑然后读取第一个sheet 文件流会自动关闭
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
}
持久层:DAO
package easy;
import java.util.List;
/** * 假设这个是你的DAO存储。当然还要这个类让spring管理,当然你不用需要存储,也不需要这个类。 **/
public class DemoDAO {
public void save(List<DemoData> list) {
//持久化操作,保存数据库!
// 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入
}
}
DemoDataListener:
package easy;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener extends AnalysisEventListener<DemoData> {
private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);
/** * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收 */
private static final int BATCH_COUNT = 5;
private List<DemoData> list = new ArrayList<DemoData>();
//sprin 需要注入时使用
/** * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。 */
private DemoDAO demoDAO;
public DemoDataListener() {
// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
demoDAO = new DemoDAO();
}
/** * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来 * * @param demoDAO */
public DemoDataListener(DemoDAO demoDAO) {
this.demoDAO = demoDAO;
}
//读取数据时会执行 invoke 方法
// 读入
// DemoData 类型
// AnalysisContext 分析器 用来分析上下文
/** * 这个每一条数据解析都会来调用 invoke 方法 * * @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()} * @param context */
@Override
public void invoke(DemoData data, AnalysisContext context) {
//fastjson 导入Maven依赖
System.out.println(JSON.toJSONString(data)); //读取到的每一条数据都会变成 JSON字符串
list.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData(); //保存数据库 这里是空的
// 存储完成清理 list
list.clear();
}
}
/** * 所有数据解析完成了 都会来调用 * * @param context */
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
log.info("所有数据解析完成!");
}
/** * 加上存储数据库 */
private void saveData() {
log.info("{}条数据,开始存储数据库!", list.size());
demoDAO.save(list);
log.info("存储数据库成功!");
}
}
固定套路:
1. 写入,固定类格式的进行写入!
2. 读取,根据监听器设置的规则进行读取!
一切代码都在官方文档
版权声明
本文为[.G( );]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_45048331/article/details/124355610
边栏推荐
- Database Experiment 7 stored procedure experiment
- Pycharm download and installation
- C # problem of updating data: dynamic SQL generation is not supported for multiple base tables
- Colon function and explicit keyword in constructor
- Ribbon停止维护
- OpenFeign之响应处理
- QT QML component library records owned by QML except basic components
- [※ leetcode refers to offer 46. Translate numbers into strings (medium)]
- Database experiment I database definition and data import
- Detailed explanation of basic assembly instructions of x86 architecture
猜你喜欢
Plato Farm元宇宙IEO上线四大,链上交易颇高
Oracle ora-01033: Oracle initialization or shutdown in progressprocess solution
consul client客户端开发
openfeign集成Hystrix的备选方案处理
CVPR2022 | 基于知识蒸馏的高效预训练
1. Finishing huazi Mianjing -- 1
Online Excel to CSV tool
MVC three-tier architecture (illustration)
NVM introduction, NVM download, installation and use (node version management)
OpenFeign组件的简介和使用
随机推荐
Pyuninstaller package exe cannot find the source code when running, function error oserror: could not get source code
Opencv application -- jigsaw puzzle
OpenFeign调用详细日志展示
Subcontracting of wechat applet based on uni app
在线Excel转CSV工具
Error message: b04access.00f eve'. Read of address 000001B4
Automatic heap dump using MBean
Database Experiment 5 Security Language Experiment
[※ leetcode refers to offer 46. Translate numbers into strings (medium)]
服务间通信方式
A series of problems of C DataGridView binding list
OpenFeign 组件说明
JUnit unit test ---- a good tool for testing a single method
2022-04-24日报:在生物科学领域应用深度学习的当前进展和开放挑战
OpenFeign的参数传递之数组和集合类型
MySQL 回表
Colon function and explicit keyword in constructor
JS to get the browser and screen height
The DNN of OpenCV is used to read onnx as the prediction end to realize classification
SSH in win10