Apache POI 解析复杂的excel表格

这篇具有很好参考价值的文章主要介绍了Apache POI 解析复杂的excel表格。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一:场景说明

       最近接到一个需求,让我解析Excel表。这要是简单常规的Excel表,那我还能摸一摸鱼给他整出来,主要是给我的Excel表长得跟下图中的Excel表一样复杂难搞,这可把我难倒了。于是开启了我的百度之旅,有可能是我不会百度或者理解能力太差,反正就是我的问题。愣是找不到一篇文章能让我这种智力不足的人弄明白该如何去解析这种复杂的Excel表格。于是我决定按照自己的思维去解析这种复杂的Excel表格,希望能得到小伙伴们的认可。

图片来源:https://blog.csdn.net/weixin_42803027/article/details/110189928

Apache POI 解析复杂的excel表格

二:Apache POI常用类

​        Java中有很多框架可以去解析Excel文件,这里我使用到POI去解析Excel文件。由于前辈们已经给出了很多很好的使用说明了,这里我就直接粘几篇我看到觉得很好的POI使用详解文章。(Apache POI使用详解_vbirdbest的博客-CSDN博客、POI核心类 - POI教程 (yiibai.com))

  • HSSF - 提供读写Microsoft Excel XLS格式档案的功能。

  • XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。

  • HWPF - 提供读写Microsoft Word DOC97格式档案的功能。

  • XWPF - 提供读写Microsoft Word DOC2003格式档案的功能。

  • HSLF - 提供读写Microsoft PowerPoint格式档案的功能。

  • HDGF - 提供读Microsoft Visio格式档案的功能。

  • HPBF - 提供读Microsoft Publisher格式档案的功能。

  • HSMF - 提供读Microsoft Outlook格式档案的功能。

  • 在开发中我们经常使用HSSF用来操作Excel处理表格数据,对于其它的不经常使用。

       这里我使用到是XSSF接口,毕竟除了能解析xlsx格式的Excel以外,也可以兼容解析xls格式的Excel。详细的使用可以常考上面的两篇文章,第一篇是讲HSSF的用法,第二篇是讲XSSF的用法。两者的用法非常相似,建议两篇文章结合使用。为了消除接下来的代码阅读障碍,这里将简单讲解一下案例中使用到的方法。

// 创建一个关联输入流的工作簿
Workbook workbook = WorkbookFactory.create(file.getInputStream());
// 根据工作表下标获取指定工作表
Sheet sheet = workbook.getSheetAt(sheetIndex);
// 获取工作表中的行,此处为第一行
Row row = sheet.getRow(0);
// 获取工作表中第一行的第一列单元格
Cell cell = row.getCell(0);
// 获取单元格的属性值,由于cell有相应的单元格类型以及对应的值也有其数据类型,所以获取值的路途可能比较麻烦点。这里简单获取它的值一下,接下来会有一个专门的函数去获取它的值。
cell.getStringCellValue();

// 获取sheet工作表中所有的合并单元格的个数
int sheetMergerCount = sheet.getNumMergedRegions();
// 根据下标获取工作表中指定的合并单元格
CellRangeAddress cra = sheet.getMergedRegion(i);

Excel中的工作簿、工作表、行、单元格中的关系:

一个Excel文件对应于一个workbook(XSSFWorkbook),
一个workbook可以有多个sheet(XSSFSheet)组成,
一个sheet是由多个row(XSSFRow)组成,
一个row是由多个cell(XSSFCell)组成

为了加深对Excel的了解,这里将结合图片详细讲解一下。

Apache POI 解析复杂的excel表格

三:案例分析

1、思路说明
  1. 在真正读取复杂Excel表格前,需要解析一下这个Excel表格的模板,也就是这个复杂Excel表格没有输入值的状态,如上图所示。
  2. 在解析这个Excel表格模板时,我们需要去一行一行的遍历每一个单元格,判断它的值是否为null。为null则说明该单元格是用来存储数据的,此时我们需要记录下它的位置(行号以及列号)。若该单元格为合并单元格时,只需记录其第一行、第一列对应的单元格的位置即可。若不为null,则说明其只是一个数据标识,如:姓名、性别等这类数据标识,并不需要记录相应位置。
  3. 这里可能会有些疑问,POI会不会识别到黑框框表单之外的单元格。需要说明的是,excel表格设计好了是不会识别黑框框外的单元格的。
  4. 重点:由于复杂表格是合并单元格和普通单元格混杂一起的,而遍历单元格的时候,会把合并单元格当成普通单元格去遍历。所以我们需要根据行号和列号去判断当前的单元格是否包含在合并单元格中,若是在合并单元格中,需要判断一下是否为该合并单元格的第一行、第一列。若为该合并单元格的第一行、第一列就去读数据,否则根据该合并单元格的最后一列下标去到当前行的下一个单元格。普通单元格直接读取判断其值即可。
  5. 解析完Excel模板后,就会得到一组用于数据存储的单元格的位置,这时我们只需根据这些位置去上传的Excel表中取值即可。
  6. 需要注意的是,我们是从左到右、从上到下的去存储数据存储单元格的位置,所以我们在定义数据类属性的时候也需要根据这个顺序来,否则在通过反射机制自动装配数据类对象属性时会出现顺序错误。(对于自动装配数据类对象属性不熟悉的小伙伴可以参考:Java通过反射机制获取数据类对象的属性及方法)
2、重要代码展示
1、获取cell单元格中的数据
/**
 * 获取cell单元格中的值
 * @param cell
 * @return
 */
private Object getValue(Cell cell) {
    Object value = null;
    if (cell == null) {
        return null;
    } else if (cell.getCellType().equals(CellType.FORMULA)) {   // 单元格的数据属于公式类
        switch (cell.getCachedFormulaResultType()) {
            case STRING:
                // 字符串类型
                value = cell.getStringCellValue();
                break;
            case NUMERIC:
                // double类型
                value = cell.getNumericCellValue();
                break;
            case BOOLEAN:
                // boolean类型
                value = cell.getBooleanCellValue();
                break;
            default:
                // 字符串类型
                value = cell.getCellFormula();
        }
    } else if (cell.getCellType().equals(CellType.NUMERIC)) {   // 单元格的数据属于数字类
        if (DateUtil.isCellDateFormatted(cell)) {
            value = cell.getDateCellValue();
        } else {
            value = new BigDecimal(cell.toString());
        }
    } else {
        value = StringUtils.isBlank(cell.toString()) ? null : cell.toString();
    }
    return value;
}
2、通过行号和列号判断当前单元格是否属于合并单元格(MergedRegion类存储的是合并单元格的起始行号、结束行号、起始列号、结束列号)
/**
 * 判断cellRow行、cellCol列对应的单元格是否为合并单元格
 * @param sheet	工作表
 * @param cellRow	cell对应的行号
 * @param cellCol	cell对应的列号
 * @return
 */
private MergedRegion getMergerCellRegionRow(Sheet sheet, int cellRow, int cellCol) {
    // 获取sheet工作表中所有的合并单元格的个数
    int sheetMergerCount = sheet.getNumMergedRegions();
    for (int i = 0; i < sheetMergerCount; i++) {
        // 获取指定合并单元格
        CellRangeAddress cra = sheet.getMergedRegion(i);
        int firstRow = cra.getFirstRow(); // 合并单元格CELL起始行
        int firstCol = cra.getFirstColumn(); // 合并单元格CELL起始列
        int lastRow = cra.getLastRow(); // 合并单元格CELL结束行
        int lastCol = cra.getLastColumn(); // 合并单元格CELL结束列
        // 判断cellRow行、cellCol列对应的单元格是否在该合并单元格的范围中
        if (cellRow >= firstRow && cellRow <= lastRow) {
            if (cellCol >= firstCol && cellCol <= lastCol) {
                return new MergedRegion(firstRow, lastRow, firstCol, lastCol);
            }
        }
    }
    return null;
}
3、解析复杂Excel模板(TargetRegion存储的是数据存储单元格的行号和列号,targetRegions是TargetRegion类的List集合,用来存储所有的数据存储单元格的位置)
// 解析复杂excel表,并将目标值的位置存储起来
private void readExcelMixMergedRegion(Sheet sheet) {
    System.out.println("======= 解析Excel文件start =======");
    // 获取工作表中的行数
    int numberOfRows = sheet.getPhysicalNumberOfRows();
    for (int i = 0; i < numberOfRows; i++) {
        Row row = sheet.getRow(i);
        // 遍历每行的列(即遍历所有单元格)
        for (int j = 0; j < row.getPhysicalNumberOfCells(); j++) {
            System.out.printf("(%d-%d)", i, j);
            int rowIndex = i, columnIndex = j;
            // 判断行号为i,列号为j的单元格是否为合并单元格,不为合并单元格返回null,若为合并单元格返回MergedRegion对象
            MergedRegion mergedRegion = getMergerCellRegionRow(sheet, i, j);
            Cell cell = null;
            if (mergedRegion != null) { // 若为合并单元格,需要进行进一步处理
                // 若当前的行号和列号是合并单元格的第一行、第一列,就获取单元格(合并单元格只有其第一行、第一列的位置有值)
                if (i == mergedRegion.getFirstRow() && j == mergedRegion.getFirstColumn()) {
                    cell = row.getCell(j);  // 获取单元格
                    j = mergedRegion.getLastColumn();  // 将列下标移到当前行的下一个单元格列下标,减少不必要的扫描
                }else{  // 若为合并单元格的非第一行,则直接将列下标移到当前行的下一个单元格列下标,并进行接下来的扫描
                    j = mergedRegion.getLastColumn();   //
                    continue;
                }
            } else {    // 若不为合并单元格,直接获取单元格
                cell = row.getCell(j);
            }
            Object val = getValue(cell);    // 获取单元格的值
            if (val==null) {    // 若单元格的值为null,说明该单元格为目标单元格,需要存储它的位置
                TargetRegion targetRegion = new TargetRegion(rowIndex, columnIndex);
                targetRegions.add(targetRegion);
            }
            System.out.println(val==null?null:val.toString());
        }
    }
    System.out.println("======= 解析Excel文件end =======");
}
4、根据数据存储单元格的位置去获取相关数据
/**
 * 根据存储的目标值位置去获取相应的value值
 * @param sheet
 * @param paramsValueList   存储目标值容器
 */
private void getTargetCellsValue(Sheet sheet,List<Object> paramsValueList) {
    System.out.println("======= 读取目标值start =======");
    targetRegions.forEach(item -> {
        int row = item.getRow();
        int column = item.getColumn();
        System.out.print("("+row+","+column+") ");
        Object val = getValue(sheet.getRow(row).getCell(column));
        paramsValueList.add(val);
        System.out.println(val==null?null:val.toString());
    });
    System.out.println("======= 读取目标值end =======");
}
3、成果展示

待解析模板:

Apache POI 解析复杂的excel表格

解析成果:
Apache POI 解析复杂的excel表格

四:项目示例代码

项目中包含测试文件,以及刘姥姥都说看得懂的代码注解,可以放心食用。下载项目配置好环境后只需运行测试案例(FileTest)即可。

示例代码只需5积分,绝对的良心之作,还在等什么,冲冲冲!

https://download.csdn.net/download/Mr_Hugo/86036793文章来源地址https://www.toymoban.com/news/detail-443836.html

到了这里,关于Apache POI 解析复杂的excel表格的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java Poi导出Excel表格详解

    一、导出下面的表格 二、流程详解         1、导出excel需要先将数据准备好         2、创建工作傅对象SXSSFWorkbook         3、使用工作傅对象创建sheet对象(工作页)         4、使用sheet对象创建行对象row(行对象)         5、使用row对象创建cell对象(单元格

    2024年02月10日
    浏览(52)
  • Apache POI 导出Excel报表

    大家好我是苏麟 , 今天聊聊Apache POI . 介绍 Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是,我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。 一般情况下,POI 都是用于操作 Excel 文件。 官网 : Apache POI - the Java API for Microsoft Do

    2024年01月17日
    浏览(44)
  • Apache POI Excel的读写

    Apache POI是用Java编写的免费开源的跨平台的Java API,Apache POI提供API给Java程 序对Microsoft Office格式档案读和写的功能,其中使用最多的就是使用POI操作Excel文 件。 jxl:专门操作Excel maven坐标: POI结构: 2.1   从 Excel 文件读取数据 使用POI可以从一个已经存在的Excel文件中读取数据

    2024年03月12日
    浏览(48)
  • Apache POI操作Excel文件

            Apache POI是用Java编写的免费开源的跨平台的Java API,Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能,其中使用最多的就是使用 POI操作Excel文件 。 POI结构: 我们使用:XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能 POI操作Excel表格封装了几个核心

    2024年02月10日
    浏览(67)
  • Apache POI 以及 导出Excel表

    Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是,我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。 一般情况下,POI 都是用于操作 Excel 文件。 导依赖 将数据写入Excel文件 读取Excel文件数据 学习

    2024年02月11日
    浏览(39)
  • Apache POI 操作Excel常用方法

    一、Java使用Apache POI导出excel 二、Apache POI 操作Excel常用方法 三、Apache poi 拆分单元格并赋值 四、使用easypoi模板方法导出excel 五、Apache poi给excel单元格添加下拉框或数据验证 POI提供了HSSF、XSSF以及SXSSF三种方式操作Excel。 HSSF:Excel97-2003版本,扩展名为.xls。一个sheet最大行数6

    2024年02月09日
    浏览(54)
  • Apache-POI读写excel文件

    ApachePOI是用Java编写的免费开源的跨平台的JavaAPI,ApachePOI提供API给Java程序对MicrosoftOffice格式档案读和写的功能,其中使用最多的就是使用POI操作Excel文件。 依赖导入: 针对不同的文档形式来操作的时候会提供相应的一些类 HSSF - 提供读写Microsoft Excel XLS格式档案的功能 XSSF -

    2024年02月05日
    浏览(38)
  • 基于Apache POI-操作Excel数据-读写

    实现: 读(获取) 写(导入) 2.1 介绍 Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是,我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。 一般情况下,POI 都是用于操作 Excel 文件。 Apache POI 的应用场景: 银行网银系统导出交

    2024年01月16日
    浏览(39)
  • Apache POI | Java操作Excel文件

    目录 1、介绍 2、代码示例 2.1、将数据写入Excel文件 2.2、读取Excel文件中的数据 🍃作者介绍:双非本科大三网络工程专业在读,阿里云专家博主,专注于Java领域学习,擅长web应用开发、数据结构和算法,初步涉猎Python人工智能开发和前端开发。 🦅主页:@逐梦苍穹 📕您的一

    2024年02月20日
    浏览(57)
  • Apache Poi 实现Excel多级联动下拉框

    由于最近做的功能,需要将接口返回的数据列表,输出到excel中,以供后续导入,且网上现有的封装,使用起来都较为麻烦,故参考已有做法封装了工具类。 使用apache poi实现excel联动下拉框思路 创建隐藏单元格,存储下拉数据 创建名称管理器 使用indirect表达式进行联动 添加

    2024年02月11日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包