使用POI读取Excel文件

article/2025/10/21 4:19:55

使用POI读取Excel文件

一、前言

用户可以通过上传excel文件,后端通过读取excel文件的内容并将内容写入数据库中以便更好的使用。

本文档使用的excel的工具类既可以读取有合并单元格的文件也可以读取没有合并单元格的文件,并且读取到单元格的数据进行了一些处理。

二、导入依赖

<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.1.0</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.1.0</version>
</dependency>

三、Excel表格信息

有合并单元格的文件

在这里插入图片描述

没有合并单元格的文件

在这里插入图片描述

四、读取Excel文件的自定义工具类

package com.example.util;import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.stereotype.Component;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;/*** 读取Excel工具类*/
@Slf4j
@Component
public class ExcelUtils {/*** 1、将单元格的内容转换为字符串** @param cell 单元格* @return 返回转换后的字符串*/private static String convertCellValueToString(Cell cell) {//1.1、判断单元格的数据是否为空if (cell == null) {return null;}//1.2、设置单元格数据的初始值String cellValue = null;//1.3、获取单元格数据的类型switch (cell.getCellType()) {case NUMERIC://1.3.1、获取到单元格数据的格式short dataFormat = cell.getCellStyle().getDataFormat();if (DateUtil.isCellDateFormatted(cell)) {SimpleDateFormat sdf = null;//1.3.1.1、处理日期格式,根据不同日期长度去判断switch (dataFormat) {case 14:sdf = new SimpleDateFormat("yyyy/MM/dd");break;case 21:sdf = new SimpleDateFormat("HH:mm:ss");break;case 22:sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");break;}//1.3.1.2、处理时间格式Date date = cell.getDateCellValue();assert sdf != null;cellValue = sdf.format(date);} else if (dataFormat == 0) {//1.3.2、处理普通数字格式DecimalFormat format = new DecimalFormat("0");double numericCellValue = cell.getNumericCellValue();cellValue = format.format(numericCellValue);}break;case STRING://处理字符串类型cellValue = cell.getStringCellValue();break;case BOOLEAN://处理布尔类型boolean booleanCellValue = cell.getBooleanCellValue();cellValue = Boolean.toString(booleanCellValue);break;case FORMULA://处理函数类型cellValue = cell.getCellFormula();break;case ERROR:byte errorCellValue = cell.getErrorCellValue();cellValue = Byte.toString(errorCellValue);break;default:break;}return cellValue;}/*** 2、处理合并单元格里面的数据** @param sheet 工作薄* @return 返回合并单元格后里面的数据*/public static List<CellRangeAddress> getCombineCell(Sheet sheet) {List<CellRangeAddress> list = new ArrayList<CellRangeAddress>();//2.1、获得一个 sheet 中合并单元格的数量int sheetMergerCount = sheet.getNumMergedRegions();//2.2、遍历合并单元格for (int i = 0; i < sheetMergerCount; i++) {//2.2.1、获得合并单元格加入list中CellRangeAddress rangeAddress = sheet.getMergedRegion(i);list.add(rangeAddress);}return list;}/*** 3、判断单元格是否为合并单元格** @param listCombineCell 存放合并单元格的list* @param cell            需要判断的单元格* @param sheet           sheet*/public static String isCombineCell(List<CellRangeAddress> listCombineCell, Cell cell, Sheet sheet) {//3.1、设置第一个单元格和最后一个单元格的值int firstColumn = 0;int lastColumn = 0;//3.2、设置第一个单元格和最后一个行的值int firstRow = 0;int lastRow = 0;//3.3、初始化单元格值String cellValue = null;for (CellRangeAddress rangeAddress : listCombineCell) {//3.3.1、获得合并单元格的起始行, 结束行, 起始列, 结束列firstColumn = rangeAddress.getFirstColumn();lastColumn = rangeAddress.getLastColumn();firstRow = rangeAddress.getFirstRow();lastRow = rangeAddress.getLastRow();//3.3.2、判断是不是合并单元格if (cell.getRowIndex() >= firstRow && cell.getRowIndex() <= lastRow) {if (cell.getColumnIndex() >= firstColumn && cell.getColumnIndex() <= lastColumn) {//3.3.2.1、获取行数据Row fRow = sheet.getRow(firstRow);//3.3.2.2、获取单元格数据Cell fCell = fRow.getCell(firstColumn);//3.3.2.3、对有合并单元格的数据进行格式处理cellValue = convertCellValueToString(fCell);break;}} else {//3.3.3、对没有合并单元格的数据进行格式处理cellValue = convertCellValueToString(cell);}}//3.4、返回处理后的单元格数据return cellValue;}/*** 4、判断sheet页中是否有合并单元格** @param sheet sheet* @return 返回值*/private static boolean hasMerged(Sheet sheet) {int numMergedRegions = sheet.getNumMergedRegions();if (numMergedRegions > 0) {return true;} else {return false;}}/*** 5、读取excel文件内容** @param inputStream 输入流* @return 返回值*/public static List<Object[]> importExcel(InputStream inputStream) {//5.1、定义一个集合用来存储Object数据List<Object[]> list = new ArrayList<>();try {//5.2、创建工作薄Workbook workbook = WorkbookFactory.create(inputStream);//5.3、获取工作薄里面sheet的个数int sheetNum = workbook.getNumberOfSheets();//5.4、遍历每一个sheetfor (int i = 0; i < sheetNum; i++) {Sheet sheet = workbook.getSheetAt(i);//5.4.1、获取sheet中有数据的行数int rows = sheet.getPhysicalNumberOfRows();for (int j = 0; j < rows; j++) {//5.4.1.1、过滤掉文件的表头(视文件表头情况而定)if (i == 1 || j == 0) {continue;}//5.4.1.2、获取每一行的数据Row row = sheet.getRow(j);if (row == null) {System.out.println("row is null");} else {//5.4.1.3、得到每一行中有效单元格的数据int cells = row.getPhysicalNumberOfCells();//5.4.1.4、定义一个Object数组用来存储读取单元格的数据Object[] objects = new Object[cells];//5.4.1.5、初始化对象数组的下标int index = 0;//5.4.1.6、遍历每一个有效的单元格数据for (int k = 0; k < cells; k++) {//5.4.1.6.1、获取每一个单元格的数据Cell cell = row.getCell(k);//5.4.1.6.2、判断当前sheet页是否合并有单元格boolean b = hasMerged(sheet);if (b) {//5.4.1.6.2.1、判断当前单元格是不是合并单元格,如果是则输出合并单元格的数据,不是则直接输出List<CellRangeAddress> listCombineCell = getCombineCell(sheet);String combineCell = isCombineCell(listCombineCell, cell, sheet);//5.4.1.6.2.1.2、对单元格的数据进行处理objects[index] = combineCell;} else {String cellValueToString = convertCellValueToString(cell);objects[index] = cellValueToString;}//5.4.1.6.3、下标累加index++;}//5.4.1.7、将对象数组里面的数据添加到list集合中去list.add(objects);}}}log.info("导入文件解析成功!");} catch (Exception e) {log.info("导入文件解析失败!");e.printStackTrace();return null;};//5.5、返回List集合return list;}
}

五、测试

public static void main(String[] args) throws FileNotFoundException {File file = new File("F:\\有合并单元格.xlsx");InputStream inputStream = new FileInputStream(file);List<Object[]> objects = ExcelUtils.importExcel(inputStream);assert objects != null;for (Object[] object : objects) {System.out.println(object[0] + "\t" + object[1] + "\t" + object[2]);}
}

http://chatgpt.dhexx.cn/article/DgWqoB9i.shtml

相关文章

POI读写Excel的基本使用

一、Excel导入导出的应用场景 1、数据导入&#xff1a;减轻录入工作量 2、数据导出&#xff1a;统计信息归档 3、数据传输&#xff1a;异构系统之间数据传输 二、POI简介&#xff08;Apache POI&#xff09; 1、什么是POI Apache POI是Apache软件基金会的开放源码函式库&…

C# 加载DotNetBar组件

C#作为前端的开发软件&#xff0c;使用的人很多&#xff0c;但是原生的C#界面较为简陋&#xff0c;已经不能满足公司级的开发工作了&#xff0c;今天这篇博客的主要内容是讲一下怎么在C#端使用一个可以提升界面美感的第三方控件&#xff0c;DotNetBar 首先去官网下载最新的DotN…

DevComponents.DotNetBar2 美化包使用以及验证教程

使用这个美化包是在别人项目上看到的&#xff0c;遇到一些懵逼问题&#xff0c;不断总结&#xff0c;所以写一下教程 DotNetBar 美化包控件不可编辑问题&#xff1a; 如图&#xff1a; 解决办法&#xff1a; 安装DotNetBar 这个软件&#xff08;有试用版&#xff09;&#xff…

winform DevComponents.DotNetBar2 添加到工具栏方法

当C#项目引入皮肤组件&#xff0c;或其他组件是&#xff0c;发现工具框里面没有引用的组件怎么办&#xff1f; 1.组件的引用 我是把下载好的*.dll组件&#xff0c;复制到项目的\bin\Debug\路径下&#xff0c;然后在项目处右键-->添加引用&#xff0c;这样组件就引入项目了…

DotNetBar控件的多文档界面的实现

DotNetBar是一个不错的DotNET控件套装&#xff0c;原来是一个DLL文件&#xff0c;能够做出很漂亮的界面效果&#xff0c;记得在8.0以前的版本&#xff0c;好像实现多文档界面稍显得麻烦一些&#xff0c;我的Winform框架、WCF框架虽然也提供了这样多文档的界面&#xff0c;不过都…

C#之DotNetBar2使用方法 - itemPanel1

用itemPanel做个按钮菜单&#xff0c;模拟用来操控开关按钮 对象buttonItem1的属性&#xff08;itempanel可以添加的子控件列表对象&#xff0c;根据需要选择&#xff0c;这里用到的Button&#xff09; 可以用控件自带的样式&#xff0c;也可以用代码控制&#xff0c;也可以预先…

winfrom DotNetBar sideNav控件使用问题

sideNav初始UI 在最开始的界面&#xff0c;不知道设置了什么东西&#xff0c;然后没有那个东西 最后又新建了个项目&#xff0c;一个一个对比参数。还是没找到&#xff01;倒是发现几个其他的参数属性 在这里记录下 这是分别对应的是对sideNav的sideNavPanel的折叠 最大化 隐藏…

界面控件DotNetBar for WinForms使用教程:highlight组件使用教程

DotNetBar for WinForms是一个拥有89个组件的用户界面控件套包&#xff0c;用户可以使用Visual Studio 2005-2015轻松地创建专业的用户界面。十多年来DotNetBar帮助开发人员轻松地创建易用的专业Windows Forms (WinForms) 用户界面。DotNetBar是全世界第一个引入全功能Office 2…

C#之DotNetBar2使用方法 - superTabControl1

C#版本&#xff1a;DevComponents.DotNetBar2 14.1.0 &#xff08;可以搜下各种版本&#xff09; 常用的控件使用属性&#xff0c;方法&#xff1b; 1&#xff09;superTabControl1 关闭和菜单设置方法 visibletrue/false closebox :关闭当前选中的TAB menubox:切换tab的菜…

DevComponents.DotNetBar2之SuperTabControl使用技巧

关于类似SuperTabControl的使用如何动态调整其TAB标签的顺序问题&#xff0c;搜了全网也没有找到类似答案&#xff0c;都提到tab键的顺序或者是通过控件界面进行调整其顺序&#xff0c;都不是想要的结果&#xff0c;有个网友问的类似问题但是没有一个答案可用。经过反复测试总结…

界面控件DotNetBar for WinForms使用教程:LayoutControl详解(二)

DotNetBar for WinForms是一个拥有89个组件的用户界面控件套包&#xff0c;用户可以使用Visual Studio 2005-2015轻松地创建专业的用户界面。十多年来DotNetBar帮助开发人员轻松地创建易用的专业Windows Forms (WinForms) 用户界面。 点击下载DotNetBar for WinForms最新试用版…

DotNetBar布局(一)

相信大家搞.NET桌面程序开发都会用到一些界面布局的组件&#xff0c;常用的由DotNetBar和devexpress。今天主要将DotNetBar在项目中布局简单介绍一下&#xff0c;个人感觉这个控件还是有很多bug的&#xff0c;不知道什么时候就出现莫名奇妙的排版问题错误。比如突然在设计视图D…

dotnetbar-SuperTabControl禁止调整顺序

superTabCtl.ReorderTabsEnabled false; 禁止调整TAB顺序 superTabCtl.CloseButtonOnTabsAlwaysDisplayedfalse; 禁止x关闭按钮一直在TAB上显示 superTabCtl.CloseButtonOnTabsVisibletrue/false;关闭按钮是否可见 注意&#xff1a; superTabitem.CloseButtonVisibletru…

Visual Studio 2019 中使用 DotNetBar

1、下载并安装DotNetBarSetupTrial 2、在新建项目或者现有项目中进行引用&#xff0c;找到DotNetBar安装路径中需要用到的dll引用&#xff0c;引用路径正确是关键 3、在工具箱中添加选项卡&#xff0c;加载需要用到的控件 先在工具箱空白处添加选项卡&#xff0c;方便管理&am…

DotNetBar for WinForms使用教程:图表控件用户指南(一)

DotNetBar for WinForms是一个拥有89个组件的用户界面控件套包&#xff0c;用户可以使用Visual Studio 2005-2015轻松地创建专业的用户界面。十多年来DotNetBar帮助开发人员轻松地创建易用的专业Windows Forms (WinForms) 用户界面。DotNetBar是全世界第一个引入全功能Office 2…

c# 使用dotnetbar 控件绘制曲线图形

废话不说,直接上过程 加载dotnetbar库后,将chartcontrol控件拖动到界面上,选择line polt 增加一个按钮,绘制曲线功能 private void buttonX26_Click(object sender, EventArgs e) { CreateChartSeries1(); } public void CreateChart…

经典:DotNetBar Suite UI 7.9 for WPF Crack

创建专业的 WPF 应用程序 DotNetBar Suite for WPF 是超过 38 个本机 Windows Presentation Foundation 控件的工具箱&#xff0c;用于创建专业的 WPF 应用程序。 Office 2016 类样式添加到功能区、日程安排和其他控件... 我们痴迷于控制性能和像素级细节。我们很自豪地说&…

DotNetBar SuperGridControl控件

1.添加表头 sgc.PrimaryGrid.SelectionGranularity SelectionGranularity.Row;//点击选中一行DevComponents.DotNetBar.SuperGrid.GridColumn gc null;gc new DevComponents.DotNetBar.SuperGrid.GridColumn("ID");sgc.PrimaryGrid.Columns.Add(gc);gc new DevCo…

DotNetBar第三方控件详解

DotNetBar是一款性价比很强的界面控件&#xff0c;带有56个Windows Form 控件的工具箱&#xff0c;使开发人员可以轻而易举地创建出专业美观的Windows Form应用程序用户界面&#xff0c;控件全部采用C#编写&#xff0c;引入了全部Office 2007 style Ribbon控件、Office 2003 of…

C#界面控件DotNetBar使用详解

一般来说&#xff0c;运用传统的界面控件元素&#xff0c;合理设计布局&#xff0c;能够设计出比较中规中矩的标准界面&#xff1b;利用一些换肤的控件或者部分界面组件&#xff0c;能够设计出相对好看一些的界面效果&#xff0c;如以前很盛行的ActiveSkin、IrisSkin和DotNetSk…