本文最后更新于:May 13, 2023 pm
Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java对Microsoft Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写,意为“简洁版的模糊实现”。
目录 今天偶然看见一篇博文,写的是关于SpringBoot实现Excel导入导出。因为自己不会,然后就专门花了点时间学了一下。
1.POI 1.0 导入环境依赖 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <dependencies > <dependency > <groupId > org.apache.poi</groupId > <artifactId > poi</artifactId > <version > 3.15-beta2</version > </dependency > <dependency > <groupId > org.apache.poi</groupId > <artifactId > poi-ooxml</artifactId > <version > 3.15-beta2</version > </dependency > <dependency > <groupId > joda-time</groupId > <artifactId > joda-time</artifactId > <version > 2.10.12</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > <scope > test</scope > </dependency > <dependency > <groupId > org.junit.jupiter</groupId > <artifactId > junit-jupiter</artifactId > <version > RELEASE</version > <scope > compile</scope > </dependency > </dependencies >
1.1 POI常用的包
HSSF - 提供读写Microsoft Excel XLS格式档案的功能。(03版的Excel以.xls结尾)
XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。(07版的Excel以.xlsx结尾)
HWPF - 提供读写Microsoft Word DOC格式档案的功能。
HSLF - 提供读写Microsoft PowerPoint格式档案的功能。
HDGF - 提供读Microsoft Visio格式档案的功能。
HPBF - 提供读Microsoft Publisher格式档案的功能。
HSMF - 提供读Microsoft Outlook格式档案的功能。
1.1.1 常用类和方法 1.2 POI实现写入Excel 首先需要明白下面这张图。
其中哪儿是工作簿、哪儿是工作表。应该不会有人看不懂。
Excel03版、和Excel07版的区别是:03版最多有65536条数据,而07版无限制。
实现步骤
先建工作簿。
通过工作簿,再建工作表。
通过工作表,建行。
通过行,建单元格(列)。
给单元格赋值。
通过流的方式生成表并输出。
关闭流。
1.2.1 Excel03版 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 package com.tothefor;import org.apache.poi.hssf.usermodel.HSSFWorkbook;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.joda.time.DateTime;import org.junit.jupiter.api.Test;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.util.Date;public class ExcelWriteTest { String PATH = "/Users/dragonone/IdeaProjects/JAVAStudy/poi" ; @SuppressWarnings("all") @Test public void excelWrite03 () throws Exception { Workbook workbook = new HSSFWorkbook(); Sheet sheet = workbook.createSheet("tothefor" ); Row row1 = sheet.createRow(0 ); Cell cell11 = row1.createCell(0 ); cell11.setCellValue("第一行第一列的单元格" ); Cell cell12 = row1.createCell(1 ); cell12.setCellValue("6666666" ); Row row2 = sheet.createRow(1 ); Cell cell21 = row2.createCell(0 ); cell21.setCellValue("第二行第一列的单元格" ); Cell cell22 = row2.createCell(1 ); cell22.setCellValue(777777777 ); Row row3 = sheet.createRow(2 ); Cell cell31 = row3.createCell(0 ); cell31.setCellValue(new DateTime().toString("yyyy-MM-dd HH:mm:ss" )); FileOutputStream fileOutputStream = new FileOutputStream(PATH + "excel03.xls" ); workbook.write(fileOutputStream); fileOutputStream.close(); System.out.println("文件输出成功!" ); } }
在相应的位置即可找到Excel文件。
1.2.2 Excel07版 其实和03版几乎一模一样,只是改一个对象而已。
Workbook workbook = new HSSFWorkbook(); Workbook workbook = new XSSFWorkbook();
就只需要改这一点即可,当然了,输出的格式也得从.xls改为.xlsx。
1.2.3 报错问题 在写完代码后,运行时,报了一下错误。这里也记录一下。
java: 错误: 不支持发行版本 5
首先要确保你的JDK没问题。然后看下面的图中是否对。(我在测试时用的是JDK8,所有的都是设置为了8) File -> settings-> Build,Execution,Deployment -> Compiler -> Java Compiler
1.2.4 批量写入 直接套上双重for即可。一个for控制行,一个for控制列。不演示了。 另外,用03版的速度比较快,但数据有限制。 用07版的数据无限制,但速度慢。则需要进行优化。这时,就需要使用07版加强版。
Workbook workbook = new SXSSFWorkbook(); Workbook workbook = new SXSSFWorkbook(10000 );
依旧其他的都不变,只是变对象。优势在与可以写入非常大的数据量,且速度也快。但需要注意的是:过程中会产生临时文件,需要清除临时文件。默认由100条记录被保存在内存中,如果超过这数量,则最前面的数据被写入临时文件。当然,也可以自定义内存中的数据的数量。而且在关闭流后面还需要写清除临时文件的代码:
fileOutputStream.close(); ((SXSSFWorkbook) workbook).dispose();
1.3 POI实现读入Excel 实现读入和写入其实是差不多的,步骤都是一样的,只不过是方法不同而已。具体的步骤可见读入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package com.tothefor;import org.apache.poi.hssf.usermodel.HSSFWorkbook;import org.apache.poi.sl.draw.geom.Path;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.xssf.usermodel.XSSFWorkbook;import org.junit.jupiter.api.Test;import java.io.FileInputStream;import java.io.FileNotFoundException;public class ExcelReadTest { String PATH = "/Users/dragonone/IdeaProjects/JAVAStudy/poi" ; @Test public void read03T () throws Exception { FileInputStream fileInputStream = new FileInputStream(PATH + "excel003.xlsx" ); Workbook workbook = new XSSFWorkbook(fileInputStream); Sheet sheet = workbook.getSheetAt(0 ); Row row = sheet.getRow(0 ); Cell cell = row.getCell(0 ); System.out.println(cell.getStringCellValue()); Cell cell1 = row.getCell(1 ); System.out.println(cell1.getNumericCellValue()); fileInputStream.close(); } }
1.3.1 读取不同的数据类型(重点) 首先,看一个小例子,用来获取一张表的首行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package com.tothefor;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.xssf.usermodel.XSSFWorkbook;import org.junit.jupiter.api.Test;import java.io.FileInputStream;public class getExcelType { String PATH = "/Users/dragonone/IdeaProjects/JAVAStudy/poi" ; @SuppressWarnings("all") @Test public void test () throws Exception { FileInputStream fileInputStream = new FileInputStream(PATH + "excel003.xlsx" ); Workbook workbook = new XSSFWorkbook(fileInputStream); Sheet sheet = workbook.getSheetAt(0 ); Row row = sheet.getRow(0 ); if (row!=null ){ int cnt = row.getPhysicalNumberOfCells(); for (int i = 0 ; i < cnt; i++) { Cell cell = row.getCell(i); if (cell!=null ){ String value = cell.getStringCellValue(); System.out.print(value + " | " ); } } System.out.println(); } } }
前面只是获取了第一行的数据。下面就直接进行获取表的全部数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 package com.tothefor;import org.apache.poi.hssf.usermodel.HSSFCell;import org.apache.poi.hssf.usermodel.HSSFDateUtil;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.xssf.usermodel.XSSFWorkbook;import org.joda.time.DateTime;import org.junit.jupiter.api.Test;import java.io.FileInputStream;import java.util.Date;public class getExcelType { String PATH = "/Users/dragonone/IdeaProjects/JAVAStudy/poi" ; @SuppressWarnings("all") @Test public void test () throws Exception { FileInputStream fileInputStream = new FileInputStream(PATH + "excel003.xlsx" ); Workbook workbook = new XSSFWorkbook(fileInputStream); Sheet sheet = workbook.getSheetAt(0 ); int rowCount = sheet.getPhysicalNumberOfRows(); for (int i = 0 ; i < rowCount; i++) { Row row = sheet.getRow(i); if (row!=null ){ int cloCount = row.getPhysicalNumberOfCells(); for (int j = 0 ; j < cloCount; j++) { Cell cell = row.getCell(j); if (cell!=null ){ int typeCount = cell.getCellType(); switch (typeCount){ case HSSFCell.CELL_TYPE_STRING:{ String s = cell.getStringCellValue(); System.out.print(s+" | " ); break ; } case HSSFCell.CELL_TYPE_BLANK:{ System.out.print(" " ); break ; } case HSSFCell.CELL_TYPE_BOOLEAN:{ String s = String.valueOf(cell.getBooleanCellValue()); System.out.print(s+" | " ); break ; } case HSSFCell.CELL_TYPE_NUMERIC:{ if (HSSFDateUtil.isCellDateFormatted(cell)){ Date date = cell.getDateCellValue(); System.out.print(new DateTime(date).toString("yyyy-MM-dd" ) + " | " ); }else { cell.setCellType(HSSFCell.CELL_TYPE_STRING); System.out.print(cell.getStringCellValue() + " | " ); } break ; } } } } System.out.println(); } } } }
至此,基本的算过完了。其中还有一个是获取计算公式的,这里就没写了,感兴趣的可以自行了解。
2.EasyExcel 2.0新手教程 没看视频,单纯看着阿里巴巴的easyexcel官方文档照着写的一个入门案例。不想说了,中途报过n多错,而且用代码操作写出的Excel中的日期类型不知道为什么是#号,而不显示正常。但鼠标放在上面点击后在上面栏中看到的又是正常的。不知道为什么,也没解决。帖下代码吧。防止后面连这个都跑不出来。 这里附上官方文档链接: GIthub:https://github.com/alibaba/easyexcel https://www.yuque.com/easyexcel/doc/easyexcel
2.0.0 导入依赖 直接复制的阿里巴巴的官方pom.xml中的部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 <?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.tothefor</groupId > <artifactId > poi</artifactId > <version > 1.0-SNAPSHOT</version > <build > <plugins > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-compiler-plugin</artifactId > <configuration > <source > 7</source > <target > 7</target > </configuration > </plugin > </plugins > </build > <dependencies > <dependency > <groupId > org.apache.poi</groupId > <artifactId > poi</artifactId > <version > 4.1.2</version > </dependency > <dependency > <groupId > org.apache.poi</groupId > <artifactId > poi-ooxml</artifactId > <version > 4.1.2</version > </dependency > <dependency > <groupId > org.apache.poi</groupId > <artifactId > poi-ooxml-schemas</artifactId > <version > 4.1.2</version > </dependency > <dependency > <groupId > org.apache.commons</groupId > <artifactId > commons-csv</artifactId > <version > 1.8</version > </dependency > <dependency > <groupId > cglib</groupId > <artifactId > cglib</artifactId > <version > 3.3.0</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-api</artifactId > <version > 1.7.32</version > </dependency > <dependency > <groupId > org.ehcache</groupId > <artifactId > ehcache</artifactId > <version > 3.8.1</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.20</version > <scope > provided</scope > </dependency > <dependency > <groupId > ch.qos.logback</groupId > <artifactId > logback-classic</artifactId > <version > 1.2.5</version > <scope > test</scope > </dependency > <dependency > <groupId > com.alibaba</groupId > <artifactId > fastjson</artifactId > <version > 1.2.78</version > <scope > test</scope > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot</artifactId > <version > 2.5.4</version > <scope > test</scope > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > <version > 2.5.4</version > <scope > test</scope > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.13.2</version > <scope > test</scope > </dependency > <dependency > <groupId > com.alibaba</groupId > <artifactId > easyexcel</artifactId > <version > 3.0.0-beta3</version > </dependency > <dependency > <groupId > org.junit.jupiter</groupId > <artifactId > junit-jupiter</artifactId > <version > RELEASE</version > <scope > compile</scope > </dependency > <dependency > <groupId > com.alibaba</groupId > <artifactId > fastjson</artifactId > <version > 1.2.78</version > <scope > compile</scope > </dependency > </dependencies > <distributionManagement > <snapshotRepository > <id > ossrh</id > <url > https://oss.sonatype.org/content/repositories/snapshots</url > </snapshotRepository > <repository > <id > ossrh</id > <url > https://oss.sonatype.org/service/local/staging/deploy/maven2/</url > </repository > </distributionManagement > </project >
2.0.1 写操作 DemoData.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.tothefor.easyexcel;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; }
eeTest.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package com.tothefor.easyexcel;import com.alibaba.excel.EasyExcel;import org.junit.jupiter.api.Test;import java.util.ArrayList;import java.util.Date;import java.util.List;public class eeTest { private List<DemoData> data () { List<DemoData> list = new ArrayList<DemoData>(); 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; } @Test public void simpleWrite () { String PATH = "/Users/dragonone/IdeaProjects/JAVAStudy/poi" ; String fileName = PATH+"pp.xlsx" ; EasyExcel.write(fileName, DemoData.class).sheet("模板" ).doWrite(data()); } }
2.0.2 读操作 DemoData.java
package com.tothefor.eeRead;import lombok.Data;import java.util.Date;@Data public class DemoData { private String string; private Date date; private Double doubleData; }
DemoDAO.java
package com.tothefor.eeRead;import java.util.List;public class DemoDAO { public void save (List<DemoData> list) { } }
DemoDataListener.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 package com.tothefor.eeRead;import com.alibaba.excel.context.AnalysisContext;import com.alibaba.excel.event.AnalysisEventListener;import com.alibaba.fastjson.JSON;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.ArrayList;import java.util.List;public class DemoDataListener extends AnalysisEventListener <DemoData > { private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class); private static final int BATCH_COUNT = 3000 ; private List<DemoData> list = new ArrayList<>(BATCH_COUNT); private DemoDAO demoDAO; public DemoDataListener () { demoDAO = new DemoDAO(); } public DemoDataListener (DemoDAO demoDAO) { this .demoDAO = demoDAO; } @Override public void invoke (DemoData data, AnalysisContext context) { System.out.println(JSON.toJSONString(data)); list.add(data); if (list.size() >= BATCH_COUNT) { saveData(); list = new ArrayList<>(BATCH_COUNT); } } @Override public void doAfterAllAnalysed (AnalysisContext context) { saveData(); LOGGER.info("所有数据解析完成!" ); } private void saveData () { LOGGER.info("{}条数据,开始存储数据库!" , list.size()); demoDAO.save(list); LOGGER.info("存储数据库成功!" ); } }
eeTest.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.tothefor.eeRead;import com.alibaba.excel.EasyExcel;import org.junit.jupiter.api.Test;public class eeTest { @Test public void simpleRead () { String PATH = "/Users/dragonone/IdeaProjects/JAVAStudy/poi" ; String fileName = PATH+"pp.xlsx" ; EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead(); } }
后面的其他用法有机会再补吧。