Excel操作-Apache-POI
一、场景需求
将一些数据库信息导出为Excel表格
将Excel表格数据导入数据库
大量的数据的导入导出操作
解决方案
常用的解决方案:Apache POI与阿里巴巴easyExcel
Apache-POI介绍
Apache-POI是基于office open XML标准(OOXML)和Microsoft和OLE2复合文档格式(OLE2)处理各种格式的开源项目,简而言之,您可以使用java读写MS excel文件,可以使用java读写MS word 和MS powerPoint文件
模块
HSSF: 提供读写Microsoft Excel XLS格式(2003)档案的功能
XSSF: 提供读写Microsoft Excel OOXML XLSX(2007+)格式档案的功能
SXSSF: 提供低内存占用量读写Microsoft Excel OOXML XLSX格式档案的功能
HWPF: 提供读写Microsoft Word DOC97(2003)格式档案的功能
XWPF: 提供读写Microsoft Word Doc2003格式(2007+)档案的功能
HSLF/XSLF: 提供读写Misrosoft powerPoint格式档案的功能
HDGF/XDGF: 提供读Miscrosoft Visio格式档案的功能
HSMF: 提供Misrosoft outlook格式档案的功能
POI存在的问题
java解析、生成EExcel比较有名的框架有POI、JXL。但是他们都存在一个严重的问题,就是非常耗内存,也就是数量量比较大的时候可能会出现OOM(内存溢出)的问题,但是POI有一套SAX模式可以一定程度上解决一些内存溢出的问题,但是依旧没有完全解决内存消耗过大的问题
Excel表格03和07版本区别
POI可以支持不同版本的Excel表格的操作,那么现在大提升的就是03版本和07+版本,那么这两个表格有什么区别如下:
03版本:最多行数支持65536,并且后缀为.xls
07+版本:理论上是没有限制的,但是实际支持的行数为:1048576,并且后缀名为xlsx
POI操作Excel
首先第一件事情,我们需要创建项目导入对应的maven,这里我们需要演示03版本和07+版本,所以两个依赖都导入
接下来我们完成通过POI写入Excel表格数据的操作,那么我们首先要知道写一个表格需要的步骤
创建工作簿:Workbook
创建工作表:sheet
创建行:Row
创建列(单元格):Cell
具体数据写入
03版本测试
package ExcelTest;
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 java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @ClaseName: ExcelWrite03$
* @Description:
* @Author: wuhs
* @Date: 2022/12/12$ 13:49$
* @param: $
* @return: $
*/
public class ExcelWrite03 {
public static void main(String[] args) {
// 03版本的写入
// 创建工作簿
Workbook workbook = new HSSFWorkbook();
// 创建工作表
Sheet sheet = workbook.createSheet("03版本写入测试");
// 创建行(第一行)
Row row = sheet.createRow(0);
// 创建单元格
Cell cell11 = row.createCell(0);
// 写入数据
cell11.setCellValue("商品ID");
// 写入数据(1,2)
Cell cell = row.createCell(1);
cell.setCellValue("商品名称");
// 第二行
Row row1 = sheet.createRow(1);//创建行
Cell cell21 = row1.createCell(0);//创建单元格
cell21.setCellValue(1);
Cell cell22 = row1.createCell(1);
cell22.setCellValue("电脑");
// 生成一张表-IO流
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream("./03版本写入测试.xls");
workbook.write(fileOutputStream);
try {
// 关闭流
fileOutputStream.close();
System.out.println("表格生成完毕");
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果
07版本测试
package ExcelTest;
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.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @ClaseName: ExcelWrite03$
* @Description:
* @Author: wuhs
* @Date: 2022/12/12$ 13:49$
* @param: $
* @return: $
*/
public class ExcelWrite07 {
public static void main(String[] args) {
// 03版本的写入
// 创建工作簿
Workbook workbook = new XSSFWorkbook();
// 创建工作表
Sheet sheet = workbook.createSheet("07版本写入测试");
// 创建行(第一行)
Row row = sheet.createRow(0);
// 创建单元格
Cell cell11 = row.createCell(0);
// 写入数据
cell11.setCellValue("商品ID");
// 写入数据(1,2)
Cell cell = row.createCell(1);
cell.setCellValue("商品名称");
// 第二行
Row row1 = sheet.createRow(1);//创建行
Cell cell21 = row1.createCell(0);//创建单元格
cell21.setCellValue(1);
Cell cell22 = row1.createCell(1);
cell22.setCellValue("电脑");
// 生成一张表-IO流
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream("./07版本写入测试.xlsx");
workbook.write(fileOutputStream);
try {
// 关闭流
fileOutputStream.close();
System.out.println("表格生成完毕");
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果
批量数据写入
那么不管使用03还是07+版本,那么在实际开发中都会碰到批量写入数据的操作,尤其是数据量比较多的时候,那么03版本和07+版本是处理的方式是不同的:
03版本HSSF:
最多支持65536行数据的写入,超出会抛异常
操作方式为,先将所有的数据放入到缓存中,最后一次性写入磁盘,写入速度快
07版本XSSF:
数据写入速度比较慢,因为XSSF是获取全部行的数据,因此会消耗大量的内存,数据量庞大的时候有可能会发现内存溢出
可以写入较大的数据,比如10W+数据
具体测试
03版本HSSF
package ExcelTest;
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 java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @ClaseName: WriteBatchDate03$
* @Description:
* @Author: wuhs
* @Date: 2022/12/12$ 14:48$
* @param: $
* @return: $
*/
public class WriteBatchDate03 {//03版本批量写入
public static void main(String[] args) {
// 开始时间
long start = System.currentTimeMillis();
// 创建工作簿
Workbook workbook = new HSSFWorkbook();
// 创建表
Sheet sheet = workbook.createSheet("03版本批量写入");
// 创建数据
for (int rowNum = 0; rowNum < 65536; rowNum++) {//行
Row row = sheet.createRow(rowNum);
for (int cellNum = 0; cellNum < 20; cellNum++) {//列
Cell cell = row.createCell(cellNum);
cell.setCellValue(cellNum + 1);
}
}
try {
FileOutputStream fileOutputStream = new FileOutputStream("./WriteBatchDate03.xls");
try {
workbook.write(fileOutputStream);
fileOutputStream.close();
System.out.println("表格生成完毕!!!!");
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 结束时间
long end = System.currentTimeMillis();
System.out.println("执行时间:"+(end-start)/1000+"s");
}
}
07版本HSSF
package ExcelTest;
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.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @ClaseName: WriteBatchDate03$
* @Description:
* @Author: wuhs
* @Date: 2022/12/12$ 14:48$
* @param: $
* @return: $
*/
public class WriteBatchDate07 {//07版本批量写入
public static void main(String[] args) {
// 开始时间
long start = System.currentTimeMillis();
// 创建工作簿
Workbook workbook = new XSSFWorkbook();
// 创建表
Sheet sheet = workbook.createSheet("07版本批量写入");
// 创建数据
for (int rowNum = 0; rowNum < 65537; rowNum++) {//行
Row row = sheet.createRow(rowNum);
for (int cellNum = 0; cellNum < 20; cellNum++) {//列
Cell cell = row.createCell(cellNum);
cell.setCellValue(cellNum + 1);
}
}
try {
FileOutputStream fileOutputStream = new FileOutputStream("./WriteBatchDate07.xlsx");
try {
workbook.write(fileOutputStream);
fileOutputStream.close();
System.out.println("表格生成完毕!!!!");
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 结束时间
long end = System.currentTimeMillis();
System.out.println("执行时间:"+(end-start)/1000+"s");
}
}
大数据量写入
大数据写SXSSF
为了解决大数据量写入的问题,所以官方提供了SXSSF来解决大文件写入问题,所以它可以写入非常大量的数据,比如上百万条的数据,并且写入速度更快,占用内存更少
官方文档翻译:SXSSF在兼容XSSF的同时,能够应对大数据量和内存空间有限的情况,SXSSF每次获取的行数是在一个数值范围内,这个范围称为“滑动窗口”,在这个窗口内的数据均存在于内存中,超过这个窗口大小时,数据会被写入磁盘,由此控制内存使用,相比较而言,XSSF则每次获取全部行
窗口默认大小为100(可以自定义),如果行数为101行,那么此时超过了窗口限制,索引值最小的行会被“刷入”磁盘,需要注意,SXSSF会自动分配临时文件,这些临时文件需要我们手动清除,清除的方式是使用dispose()方法;
自定义的方式:SXSSFWorkBook wb = new SXSSFWorkbook(自定义窗口大小)
package ExcelTest;
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.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @ClaseName: WriteBigDate$
* @Description:
* @Author: wuhs
* @Date: 2022/12/12$ 15:15$
* @param: $
* @return: $
*/
public class WriteBigDate {
public static void main(String[] args) {
// 开始时间
long start = System.currentTimeMillis();
// 创建工作簿
Workbook workbook = new SXSSFWorkbook();
// 创建表
Sheet sheet = workbook.createSheet("07版本大数量写入");
// 创建数据
for (int rowNum = 0; rowNum < 100000; rowNum++) {//行
Row row = sheet.createRow(rowNum);
for (int cellNum = 0; cellNum < 20; cellNum++) {//列
Cell cell = row.createCell(cellNum);
cell.setCellValue(cellNum + 1);
}
}
try {
FileOutputStream fileOutputStream = new FileOutputStream("./WriteBigDate07.xlsx");
try {
workbook.write(fileOutputStream);
fileOutputStream.close();
System.out.println("表格生成完毕!!!!");
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 结束时间
long end = System.currentTimeMillis();
System.out.println("执行时间:"+(end-start)/1000+"s");
}
}
POI操作--读取Excel
其实读取用到的对象和写入的对象是一样的:
工作簿:WorkBoot(所有的Excel工作簿的操作都是通过此类型进行设置)
03 HSSF
07 XSSF
数据行:Sheet(所有关于数据表的操作都是通过sheet都可以进行设置)
行:ROW
单元格:Cell
具体读取步骤
利用文件流来读取
获取工作簿
获取表
获取行
获取单元格
读取数据
那么这里我们还是针对03和07版本的读取进行测试
03版本读取
package ExcelTest;
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 java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* @ClaseName: ReadExcel03$
* @Description:
* @Author: wuhs
* @Date: 2022/12/12$ 15:25$
* @param: $
* @return: $
*/
public class ReadExcel03 {
public static void main(String[] args) {
try {
// 通过文件流读取
FileInputStream inputStream = new FileInputStream("./03版本写入测试.xls");
// 读取工作簿
Workbook workbook = new HSSFWorkbook(inputStream);
// 获取表(通过下标方式来进行读取或者可以采用表名进行读取)
Sheet sheet = workbook.getSheetAt(0);
// 获取行(采用下标方式获取)
Row row = sheet.getRow(0);
// 获取单元格(采用下标方式获取)
Cell cell = row.getCell(0);
// 读取数据
String stringCellValue = cell.getStringCellValue();
System.out.println(stringCellValue);
inputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
07版本读取
package ExcelTest;
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.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* @ClaseName: ReadExcel03$
* @Description:
* @Author: wuhs
* @Date: 2022/12/12$ 15:25$
* @param: $
* @return: $
*/
public class ReadExcel07 {
public static void main(String[] args) {
try {
// 通过文件流读取
FileInputStream inputStream = new FileInputStream("./07版本写入测试.xlsx");
// 读取工作簿
Workbook workbook = new XSSFWorkbook(inputStream);
// 获取表(通过下标方式来进行读取或者可以采用表名进行读取)
Sheet sheet = workbook.getSheetAt(0);
// 获取行(采用下标方式获取)
Row row = sheet.getRow(0);
// 获取单元格(采用下标方式获取)
Cell cell = row.getCell(0);
// 读取数据
String stringCellValue = cell.getStringCellValue();
System.out.println(stringCellValue);
inputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
批量读取
在我们实际的开发过程中,经常会遇到不同类型的数据,这也是我们工作中最麻烦的操作,首先我们假设有一张表:商品表.xls,具体数据如下:
那么我们想要读取这张表,需要首先读取标题部分,然后在读取具体的数据部分,这两不一定要分开的
读取标题部分
package ExcelTest;
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 java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* @ClaseName: ReadExcel03$
* @Description:
* @Author: wuhs
* @Date: 2022/12/12$ 15:25$
* @param: $
* @return: $
*/
public class ReadExcelCellType {
public static void main(String[] args) {
try {
// 通过文件流读取
FileInputStream inputStream = new FileInputStream("./商品表.xls");
// 读取工作簿
Workbook workbook = new HSSFWorkbook(inputStream);
// 获取表(通过下标方式来进行读取或者可以采用表名进行读取)
Sheet sheet = workbook.getSheetAt(0);
// 获取表中的第一行数据
Row titleRow = sheet.getRow(0);
if (titleRow!=null){
// 获取标题单元格的数量,用于表里获取所有单元格
int cellNum = titleRow.getPhysicalNumberOfCells();
System.out.println(cellNum);
for (int i = 0; i // 获取所有单元格 Cell cell = titleRow.getCell(i); if (cell!=null){ // 获取单元格的数据 String stringCellValue = cell.getStringCellValue(); System.out.print(stringCellValue+"\t"); } } } inputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } .getCellType()的几种类型值 CELL_TYPE_NUMERIC数值型CELL_TYPE_STRING字符串型CELL_TYPE_FORMULA公式型CELL_TYPE_BLANK空值CELL_TYPE_BOOLEAN布尔型CELL_TYPE_ERROR错误 读取数据部分 package ExcelTest; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; /** * @ClaseName: ReadExcel03$ * @Description: * @Author: wuhs * @Date: 2022/12/12$ 15:25$ * @param: $ * @return: $ */ public class ReadExcelCellType { public static void main(String[] args) throws IOException { // 通过文件流读取 FileInputStream inputStream = new FileInputStream("./商品表.xls"); // 读取工作簿 Workbook workbook = new HSSFWorkbook(inputStream); // 获取表(通过下标方式来进行读取或者可以采用表名进行读取) Sheet sheet = workbook.getSheetAt(0); //获取标题以下的具体内容 //获取一共有多少行数据 int rowNum = sheet.getPhysicalNumberOfRows(); // 跳过第一行标题数据获取以下具体内容 for (int i = 1; i < rowNum; i++) { Row row = sheet.getRow(i); if (row != null) { // 获取每一行里面有多少单元格 int NumberOfCells = row.getPhysicalNumberOfCells(); for (int j = 0; j < NumberOfCells; j++) { Cell cell = row.getCell(j); if (cell != null) { // 获取所有读取数据的类型 CellType cellType = cell.getCellType(); // 根据不同的数据类型来读取数据 String cellVal = ""; switch (cellType) { case STRING://字符串 cellVal = cell.getStringCellValue(); break; case NUMERIC://数值类型--日期也会当做数值类型 // 判断是否为日期 if (DateUtil.isCellDateFormatted(cell)) { Date date = cell.getDateCellValue(); cellVal = new SimpleDateFormat("yyyy-MM-dd").format(date); } else { cellVal = cell.toString(); } break; } System.out.print(cellVal + "\t"); } } System.out.println(); } } inputStream.close(); } } 完整代码 package ExcelTest; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; /** * @ClaseName: ReadExcel03$ * @Description: * @Author: wuhs * @Date: 2022/12/12$ 15:25$ * @param: $ * @return: $ */ public class ReadExcelCellType { public static void main(String[] args) throws IOException { // 通过文件流读取 FileInputStream inputStream = new FileInputStream("./商品表.xls"); // 读取工作簿 Workbook workbook = new HSSFWorkbook(inputStream); // 获取表(通过下标方式来进行读取或者可以采用表名进行读取) Sheet sheet = workbook.getSheetAt(0); // 获取表中的第一行数据 Row titleRow = sheet.getRow(0); if (titleRow != null) { // 获取标题单元格的数量,用于表里获取所有单元格 int cellNum = titleRow.getPhysicalNumberOfCells(); for (int i = 0; i < cellNum; i++) { // 获取所有单元格 Cell cell = titleRow.getCell(i); if (cell != null) { // 获取单元格的数据 String stringCellValue = cell.getStringCellValue(); System.out.print(stringCellValue + "\t"); } } } System.out.println(); //获取标题以下的具体内容 //获取一共有多少行数据 int rowNum = sheet.getPhysicalNumberOfRows(); // 跳过第一行标题数据获取以下具体内容 for (int i = 1; i < rowNum; i++) { Row row = sheet.getRow(i); if (row != null) { // 获取每一行里面有多少单元格 int NumberOfCells = row.getPhysicalNumberOfCells(); for (int j = 0; j < NumberOfCells; j++) { Cell cell = row.getCell(j); if (cell != null) { // 获取所有读取数据的类型 CellType cellType = cell.getCellType(); // 根据不同的数据类型来读取数据 String cellVal = ""; switch (cellType) { case STRING://字符串 cellVal = cell.getStringCellValue(); break; case NUMERIC://数值类型--日期也会当做数值类型 // 判断是否为日期 if (DateUtil.isCellDateFormatted(cell)) { Date date = cell.getDateCellValue(); cellVal = new SimpleDateFormat("yyyy-MM-dd").format(date); } else { cellVal = cell.toString(); } break; } System.out.print(cellVal + "\t"); } } System.out.println(); } } inputStream.close(); } } 测试结果 ExcelUtil封装 在我们给用户的excel文件的模板中隐藏一行“实体类名”,以便我们在读取文件的时候获取,并作为key值存储 封装的工具类需求:用户只需要传入Workbook对象(匹配版本),文件输入流,对应实体的class。就可以得到接卸表哥以后的结果 ,同时通过传入的实体类类型集合的方式返回 package Util; import org.apache.poi.ss.usermodel.*; import java.io.FileInputStream; import java.lang.reflect.Field; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.*; /** * @ClaseName: ExcelUtil$ * @Description:用户只需要传入Workbook对象(匹配版本),文件输入流,对应实体的class。就可以得到接卸表哥以后的结果 ,同时通过传入的实体类类型集合的方式返回* * * @Author: wuhs * @Date: 2022/12/12$ 16:34$ * @param: $ * @return: $ */ public class ExcelUtil { public static // 给用户返回的实体类集合 List // 在工作簿中获取工作表 Sheet sheet = workbook.getSheetAt(0); // 获取工作表中的行数(第一行是标题、第二行是对应的实体) int NumberOfRows = sheet.getPhysicalNumberOfRows(); // 获取第一行数据(隐藏行) Row row = sheet.getRow(1); // 遍历第一行数据就是当前实体类对应的所有属性,同时要把这些数据放入到Map中的key List for (Cell cell : row ) { if (cell != null) { // 获取单元格中的数据 String value = cell.getStringCellValue(); key.add(value); } } for (int i = 2; i < NumberOfRows; i++) { // 获取属性名以下的数据 row = sheet.getRow(i); if (row != null) { // 计数器j用于映射数据使用 int j = 0; // 用于保存每条数据的Map,并且在Map中建立对应的数据的映射关系 Map for (Cell cell : row) { if (cell != null) { // 把所有的单元格格式设置为String String celVale = getCelVale(cell); if (celVale != null && !celVale.equals("")) { excelMap.put(key.get(j), celVale); j++; } } } System.out.println(); // 创建对应实体类类型,并且把读取到的数据转换成实体类对象 T t = mapToEntity(excelMap,T); result.add(t); } } inputStream.close(); return result; } public static NumberFormat nf = NumberFormat.getInstance(); static { nf.setGroupingUsed(false); } public static String getCelVale(Cell cell) { CellType cellType = cell.getCellType(); String valueCel = ""; switch (cellType) { case STRING://字符串 valueCel = cell.getStringCellValue(); break; case NUMERIC://数值类型--日期也会当做数值类型 // 判断是否为日期 if (DateUtil.isCellDateFormatted(cell)) { Date date = cell.getDateCellValue(); valueCel = new SimpleDateFormat("yyyy-MM-dd").format(date); } else { valueCel = nf.format(cell.getNumericCellValue()); } break; case BLANK://空字符串 break; case BOOLEAN://布尔类型 valueCel = String.valueOf(cell.getBooleanCellValue()); break; case ERROR: break; } System.out.print(valueCel + "\t"); return valueCel; } private static T t = null; t = entity.newInstance();//基于反射拿到实体类属性 for (Field field : entity.getDeclaredFields()) { if (map.containsKey(field.getName())) {//属性的名称map中是否包含 boolean flag = field.isAccessible(); // 值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。 // 值为 false 则指示反射的对象应该实施 Java 语言访问检查。 field.setAccessible(true); // 根据key拿到value值 String mapValue = map.get(field.getName()); // 获取实体类属性的类型 String type = field.getGenericType().toString(); System.out.println("type------------"+type); //重新制定对应的属性的值 if (mapValue != null) { if (type.equals("class java.lang.String")) { // Field.set()向对象的这个Field属性设置新值value field.set(t, mapValue); } else if (type.equals("double")) { field.set(t, Double.parseDouble(String.valueOf(mapValue))); } else if (type.equals("int")) { field.set(t, Integer.parseInt(String.valueOf(mapValue))); } else if (type.equals("class java.util.Date")) { Date date = new SimpleDateFormat("yyyy-MM-dd").parse(mapValue); field.set(t, date); } } field.setAccessible(flag); } } return t; } } 测试: package ExcelTest; import Util.ExcelUtil; import entity.Product; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Workbook; import java.io.FileInputStream; import java.util.List; /** * @ClaseName: UtilTest$ * @Description: * @Author: wuhs * @Date: 2022/12/12$ 16:50$ * @param: $ * @return: $ */ public class UtilTest { public static void main(String[] args)throws Exception { FileInputStream fileInputStream = new FileInputStream("./商品表.xls"); Workbook workbook = new HSSFWorkbook(fileInputStream); List System.out.println(products); } } 结果: Excel中的公式---POI读取公式 excel表中会有一些公式(求和、求差等),所以如果我们想要获取公式的内容,那么我们需要在读取的时候用到POI提供的一些公式对象,当然如果是想直接读取数值的话,可以直接通过数据类型来读取 package ExcelTest; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.FileInputStream; /** * @ClaseName: GetFormula$ * @Description: * @Author: wuhs * @Date: 2022/12/12$ 18:40$ * @param: $ * @return: $ */ public class GetFormula { public static void main(String[] args) throws Exception { // 通过文件流读取excel工作簿 FileInputStream fileInputStream = new FileInputStream("./读取公式.xlsx"); // 获取工作簿 Workbook workbook = new XSSFWorkbook(fileInputStream); // 获取表(通过下标的方式来获取) Sheet sheet = workbook.getSheetAt(0); // 获取行和单元格(带公式) Row row = sheet.getRow(2); Cell cell = row.getCell(0); 也可以直接读取数值 // System.out.println(cell.getNumericCellValue()); FormulaEvaluator formulaEvaluator = new XSSFFormulaEvaluator((XSSFWorkbook) workbook); // 获取单元格的内容 CellType cellType = cell.getCellType(); switch (cellType){ case FORMULA://公式 // 获取公式 String formula = cell.getCellFormula(); System.out.println(formula); CellValue value = formulaEvaluator.evaluate(cell); String val = value.formatAsString(); System.out.println(val); break; } fileInputStream.close(); } } 执行结果 Excel操作-EasyExcel EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目,在尽可能节约内存的情况下支持读写百M的Excel。具有快速、简单避免OOM的java处理的Excel工具 具体操作: 注意:这个工具的操作都是依赖于实体类,所以我们需要建立一个实体类 package entity; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; import java.util.Date; /** * @ClaseName: Product$ * @Description: * @Author: wuhs * @Date: 2022/12/12$ 16:57$ * @param: $ * @return: $ */ @Data @NoArgsConstructor @AllArgsConstructor @ToString public class Product { private int id; private String name; private double price; private int count; private Date createTime; } 写入操作: 直接参照官方文档即可,里面写的很详细;https://easyexcel.opensource.alibaba.com/ 好文推荐
发表评论