天天看点

Java word aspose(2.2 读取表格中的文本与图片)

作者:EYE33

1.读取word中表格的介绍

这个功能 应该是需要导入word时最常用的功能了

可能有些需求 就是要求系统导入word文档 把一些个人或者项目上的资料转存到数据库 以便在系统上查阅 搜索相关信息

在前1篇文章导入纯文本中 我们看到导入时 是可以指定读取的节点类型的 文本的节点类型就是NodeType.PARAGRAPH

现在我们需要导入读取表格数据 那就要用到表格所需的节点类型

NodeType.TABLE -> 表格

NodeType.ROW -> 表格行

NodeType.CELL -> 表格行中的单元格

2. 准备需要读取的表格(纯文本)

Java word aspose(2.2 读取表格中的文本与图片)

3. 发起请求(纯文本)

Java word aspose(2.2 读取表格中的文本与图片)

4. 读取表格数据(纯文本)

按表格索引读取表格中的内容 适用于读取多个表格的数据

当然 如果表格只有1个 而且内容简单 没有子表 也可以直接按NodeType.ROW类型读取表格行 这种本文不再赘述

/**
     * 按表格索引读取表格中的内容 <br/>
     * 适用于文档中存在多个表格的读取 每个表格读取时单独写逻辑
     * @param wordFile
     * @return
     */
    @SneakyThrows
    @PostMapping("readTableTxtByIndex")
    public Ret readTableTxtByIndex(MultipartFile wordFile){
        try(InputStream inputStream = wordFile.getInputStream()){
            Document doc = new Document(inputStream);
            //获取所有的表格
            NodeCollection tableNodes = doc.getChildNodes(NodeType.TABLE, true);
            int tableCount = tableNodes.getCount();
            log.info("表格数量:{}", tableCount);
            for (int i = 0; i < tableCount; i++) {
                Table table = (Table)tableNodes.get(i);
                //按表格索引 单独写逻辑进行数据的读取 本示例中就1个表格 因此就放1个逻辑进行解析了
                if(0 == i){
                    //获取表格中的所有行节点
                    RowCollection rows = table.getRows();
                    int rowCount = rows.getCount();
                    log.info("共有表格行:{}",rowCount);
                    //获取每一行的单元格节点
                    for (int j = 0; j < rowCount; j++) {
                        Row row = rows.get(j);
                        CellCollection cells = row.getCells();
                        int cellsCount = cells.getCount();
                        log.info("第{}行有{}个单元格{}",j,cellsCount);
                        for (int k = 0; k < cellsCount; k++) {
                            Cell cell = cells.get(k);
                            String cellText = cell.getText();
                            log.info("第{}行 第{}个单元格的文本:{}",j,k,cellText);
                        }
                    }
                }
            }
            //本方法是为了演示逐行逐个单元格读取的效果 故采用了fori循环 看起来索引比较多
            //实际使用时 可以使用iter循环 直接获取集合内对象
        }
        return Ret.success();
    }           

控制台输出

2022-11-25 11:33:09.996  INFO ReadWordHandler      : 表格数量:1
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 共有表格行:14
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第0行有3个单元格{}
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第0行 第0个单元格的文本:姓名
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第0行 第1个单元格的文本:光头强
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第0行 第2个单元格的文本:
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第1行有3个单元格{}
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第1行 第0个单元格的文本:身份证号
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第1行 第1个单元格的文本:123
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第1行 第2个单元格的文本:
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第2行有3个单元格{}
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第2行 第0个单元格的文本:联系电话
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第2行 第1个单元格的文本:666
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第2行 第2个单元格的文本:
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第3行有4个单元格{}
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第3行 第0个单元格的文本:住址
2022-11-25 11:33:09.997  INFO ReadWordHandler      : 第3行 第1个单元格的文本:帝国大厦
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第3行 第2个单元格的文本:学历
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第3行 第3个单元格的文本:翰林
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第4行有1个单元格{}
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第4行 第0个单元格的文本:教育经历
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第5行有4个单元格{}
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第5行 第0个单元格的文本:开始时间
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第5行 第1个单元格的文本:结束时间
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第5行 第2个单元格的文本:学校
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第5行 第3个单元格的文本:专业
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第6行有4个单元格{}
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第6行 第0个单元格的文本:2018-09
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第6行 第1个单元格的文本:2021-07
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第6行 第2个单元格的文本:高中
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第6行 第3个单元格的文本:
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第7行有4个单元格{}
2022-11-25 11:33:09.998  INFO ReadWordHandler      : 第7行 第0个单元格的文本:2021-09
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第7行 第1个单元格的文本:至今
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第7行 第2个单元格的文本:大学
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第7行 第3个单元格的文本:四库全书
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第8行有4个单元格{}
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第8行 第0个单元格的文本:
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第8行 第1个单元格的文本:
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第8行 第2个单元格的文本:
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第8行 第3个单元格的文本:
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第9行有1个单元格{}
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第9行 第0个单元格的文本:获得证书
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第10行有2个单元格{}
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第10行 第0个单元格的文本:获得时间
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第10行 第1个单元格的文本:证书名称
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第11行有2个单元格{}
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第11行 第0个单元格的文本:2022-11-01
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第11行 第1个单元格的文本:CET-6级
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第12行有2个单元格{}
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第12行 第0个单元格的文本:2022-12-01
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第12行 第1个单元格的文本:PMP
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第13行有2个单元格{}
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第13行 第0个单元格的文本:
2022-11-25 11:33:09.999  INFO ReadWordHandler      : 第13行 第1个单元格的文本:
           

还是因为粘贴问题 不能看到有些行的文字后面分页符 实际上打印出来的数据

Java word aspose(2.2 读取表格中的文本与图片)

这里 我们可以在读取单元格文本时 增加处理方法

/**
     * 获取单元格的文本并移除"\f"分页符
     * @param cell 单元格对象
     * @return
     */
    private String getText(Cell cell){
        String text = cell.getText();
        return StrUtil.isBlank(text) ? "" : text.trim().replace("\f","");
    }

/**
     * 按表格索引读取表格中的内容 <br/>
     * 适用于文档中存在多个表格的读取 每个表格读取时单独写逻辑
     * @param wordFile
     * @return
     */
    @SneakyThrows
    @PostMapping("readTableTxtByIndex")
    public Ret readTableTxtByIndex(MultipartFile wordFile){
        try(InputStream inputStream = wordFile.getInputStream()){
            Document doc = new Document(inputStream);
            //获取所有的表格
            NodeCollection tableNodes = doc.getChildNodes(NodeType.TABLE, true);
            int tableCount = tableNodes.getCount();
            log.info("表格数量:{}", tableCount);
            for (int i = 0; i < tableCount; i++) {
                Table table = (Table)tableNodes.get(i);
                //按表格索引 单独写逻辑进行数据的读取 本示例中就1个表格 因此就放1个逻辑进行解析了
                if(0 == i){
                    //获取表格中的所有行节点
                    RowCollection rows = table.getRows();
                    int rowCount = rows.getCount();
                    log.info("共有表格行:{}",rowCount);
                    //获取每一行的单元格节点
                    for (int j = 0; j < rowCount; j++) {
                        Row row = rows.get(j);
                        CellCollection cells = row.getCells();
                        int cellsCount = cells.getCount();
                        log.info("第{}行有{}个单元格{}",j,cellsCount);
                        for (int k = 0; k < cellsCount; k++) {
                            Cell cell = cells.get(k);
                            log.info("第{}行 第{}个单元格的文本:{}",j,k,this.getText(cell));
                        }
                    }
                }
            }
            //本方法是为了演示逐行逐个单元格读取的效果 故采用了fori循环 看起来索引比较多
            //实际使用时 可以使用iter循环 直接获取集合内对象
        }
        return Ret.success();
    }
           
Java word aspose(2.2 读取表格中的文本与图片)

这样读取的数据 就没有换页符了

观察比对读取结果与表格内容的对应关系

Java word aspose(2.2 读取表格中的文本与图片)

通过观察 我们可以看到 读取结果准确无误

5.准备需要读取的表格(文本+图片)

Java word aspose(2.2 读取表格中的文本与图片)

6.发起请求(文本+图片)

Java word aspose(2.2 读取表格中的文本与图片)

7.读取表格数据(文本+图片)

@SneakyThrows
    @PostMapping("readTable")
    public Ret readTable(MultipartFile wordFile){
        try(InputStream inputStream = wordFile.getInputStream()){
            Document doc = new Document(inputStream);
            //获取所有的表格
            NodeCollection tableNodes = doc.getChildNodes(NodeType.TABLE, true);
            int tableCount = tableNodes.getCount();
            log.info("表格数量:{}", tableCount);
            for (int i = 0; i < tableCount; i++) {
                Table table = (Table)tableNodes.get(i);
                //按表格索引 单独写逻辑进行数据的读取 本示例中就1个表格 因此就放1个逻辑进行解析了
                if(0 == i){
                    //获取表格中的所有行节点
                    RowCollection rows = table.getRows();
                    int rowCount = rows.getCount();
                    log.info("共有表格行:{}",rowCount);
                    //获取每一行的单元格节点
                    for (int j = 0; j < rowCount; j++) {
                        Row row = rows.get(j);
                        CellCollection cells = row.getCells();
                        int cellsCount = cells.getCount();
                        log.info("第{}行有{}个单元格{}",j,cellsCount);
                        for (int k = 0; k < cellsCount; k++) {
                            Cell cell = cells.get(k);
                            NodeCollection shapeNodes = cell.getChildNodes(NodeType.SHAPE, true);
                            if(shapeNodes.getCount() < 1){//文本
                                log.info("第{}行 第{}个单元格的文本:{}",j,k, AsposeTool.getText(cell));
                            }else{//图片
                                for (Object childNode : shapeNodes) {
                                    Shape shape = (Shape)childNode;
                                    byte[] imageBytes = shape.getImageData().getImageBytes();
                                    FileUtil.writeBytes(imageBytes,"C:/Users/Administrator/Desktop/aspose/" + RandomUtil.randomString(3) + ".jpg");
                                }
                            }

                        }
                    }
                }
            }
            //本方法是为了演示逐行逐个单元格读取的效果 故采用了fori循环 看起来索引比较多
            //实际使用时 可以使用iter循环 直接获取集合内对象
        }
        return Ret.success();
    }           

控制台输出

2022-11-25 16:49:55.732  INFO ReadWordHandler      : 表格数量:1
2022-11-25 16:49:55.732  INFO ReadWordHandler      : 共有表格行:14
2022-11-25 16:49:55.732  INFO ReadWordHandler      : 第0行有3个单元格{}
2022-11-25 16:49:55.732  INFO ReadWordHandler      : 第0行 第0个单元格的文本:姓名
2022-11-25 16:49:55.732  INFO ReadWordHandler      : 第0行 第1个单元格的文本:光头强
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第1行有3个单元格{}
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第1行 第0个单元格的文本:身份证号
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第1行 第1个单元格的文本:123
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第1行 第2个单元格的文本:
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第2行有3个单元格{}
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第2行 第0个单元格的文本:联系电话
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第2行 第1个单元格的文本:666
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第2行 第2个单元格的文本:
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第3行有4个单元格{}
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第3行 第0个单元格的文本:住址
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第3行 第1个单元格的文本:帝国大厦
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第3行 第2个单元格的文本:学历
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第3行 第3个单元格的文本:翰林
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第4行有1个单元格{}
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第4行 第0个单元格的文本:教育经历
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第5行有4个单元格{}
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第5行 第0个单元格的文本:开始时间
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第5行 第1个单元格的文本:结束时间
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第5行 第2个单元格的文本:学校
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第5行 第3个单元格的文本:专业
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第6行有4个单元格{}
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第6行 第0个单元格的文本:2018-09
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第6行 第1个单元格的文本:2021-07
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第6行 第2个单元格的文本:高中
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第6行 第3个单元格的文本:
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第7行有4个单元格{}
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第7行 第0个单元格的文本:2021-09
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第7行 第1个单元格的文本:至今
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第7行 第2个单元格的文本:大学
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第7行 第3个单元格的文本:四库全书
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第8行有4个单元格{}
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第8行 第0个单元格的文本:
2022-11-25 16:49:55.743  INFO ReadWordHandler      : 第8行 第1个单元格的文本:
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第8行 第2个单元格的文本:
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第8行 第3个单元格的文本:
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第9行有1个单元格{}
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第9行 第0个单元格的文本:获得证书
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第10行有2个单元格{}
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第10行 第0个单元格的文本:获得时间
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第10行 第1个单元格的文本:证书名称
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第11行有2个单元格{}
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第11行 第0个单元格的文本:2022-11-01
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第11行 第1个单元格的文本:CET-6级
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第12行有2个单元格{}
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第12行 第0个单元格的文本:2022-12-01
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第12行 第1个单元格的文本:PMP
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第13行有2个单元格{}
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第13行 第0个单元格的文本:
2022-11-25 16:49:55.744  INFO ReadWordHandler      : 第13行 第1个单元格的文本:
           

图片输出

Java word aspose(2.2 读取表格中的文本与图片)

8 如何将读取的文本转化为我们所需的数据对象

在这份word中

教育经历 和获得证书 这2项 数据是动态的 也就是说他们的内容行数量不固定 需要一套识别逻辑

其他数据都是有固定的位置的

  • 如果根据行列索引来取数 那么就很麻烦要一一对应 而且一旦增加删除行 按行列索引取数据就乱了 需要重新设定索引值
  • 如果根据左侧单元格标题 来取右侧字段值 那么就会有可能因为其他单元格的值 使用了目标单元格的标题名 而导致数据读取错位 而且 一旦标题名改了 也需要重新设定目标标题名
  • 比对这2种读取 都不是很方便 没办法 两权相害取其轻 以数据的准确性为第一目标 因此针对固定位置的数据读取 采用行列坐标来确定

最终 取数转换为对象的逻辑 可以归纳如下

1.针对表格中左侧单元格为字段名 右侧单元格为字段值 的类型:按照单元格值所在的行列索引取值

2.针对动态行数据的 类似子表格 这个子表 带有1个大标题行 1个小标题行 若干数据行 的类型:按照

a.根据大标题行的下一行的小标题的列索引 确定各字段数据所在列索引

b.根据小标题的行索引之后的数据行 根据列索引转换为对应字段的数据值

c.直到下一行的单元格数量 与 小标题行的单元格数量不一致 终止子表的数据读取

9 读取表格文本与图片的方法封装

package com.example.support.entity;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.StrUtil;
import com.aspose.words.*;
import com.example.support.tool.AsposeTool;
import lombok.Getter;

import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author LWB
 * @Description aspose读取表格数据的策略
 */
public class AsposeReadStrategy {

    private Table table;

    /**
     * 字段值所在的行列坐标与字段名的读取映射
     * map的key 为表格中的需要读取数据的行列索引 行索引|列索引 例: 行索引0 列索引0 则坐标为 "0|0"
     * map的value 为对象的属性
     *  */
    private Map<String,String> coordKeyMap = new HashMap<>();
    
    /**
     * 存储 左侧单元格为字段名 右侧单元格为字段值 的数据map
     * 如果需要获取map 直接调用getDataMap
     * map的key 为对象的属性
     * map的value 为对象的属性值 可能为图片因此用Object
     */
    @Getter
    private Map<String,Object> dataMap = new HashMap<>();

    /**
     * 子表的读取映射
     * map的key 为表格中的大标题
     * map的value 存储的是小标题对应的属性名集合 顺序依次已word中的对应
     */
    private Map<String, List<String>> subTableTitleKeyMap = new HashMap<>();

    /**
     * 存储 子表的数据map
     * map的key 为表格中的大标题
     * map的value 为 map集合 key-对象的属性名 value-对象的属性值(因为要考虑兼容图片数据的读取,因此value类型为object)
     */
    @Getter
    private Map<String,List<Map<String,Object>>> subTableDataMap = new HashMap<>();


    /**
     * 设置坐标对应的属性名
     * @param rowIndex 行索引 从0开始
     * @param colIndex 列索引 从0开始
     * @param key 属性名
     * @return
     */
    public AsposeReadStrategy setCoordProperty(int rowIndex, int colIndex, String key){
        String coord = StrFormatter.format("{}|{}",rowIndex,colIndex);
        this.coordKeyMap.put(coord,key);
        return this;
    }

    /**
     * 设置子表的标题名与小标题的属性名
     * @param subTableTitle 子表的标题名
     * @param subTitleKeys 子表的小标题的属性名 注意顺序要与word中的一致
     * @return
     */
    public AsposeReadStrategy setTableProperty(String subTableTitle, String... subTitleKeys){
        this.subTableTitleKeyMap.put(subTableTitle, ListUtil.of(subTitleKeys));
        return this;
    }

    /**
     * 数据表的读取策略构造器
     * @param table aspose数据表对象 必传
     */
    public AsposeReadStrategy(Table table) {
        Assert.notNull(table);
        this.table = table;
    }

    /**
     * 解析表格数据到对应的属性名
     */
    public AsposeReadStrategy parse(){
        /**
         * 表格行列坐标 对应的数据 按逐行解析时的顺序排序
         * key:行索引|列索引 例: 行索引0 列索引0 则坐标为 "0|0"
         * value:单元格数据 2种类型 string-文本 byte[]-图片字节数组
         */
        Map<String,Object> rowDataMap = new LinkedHashMap<>();
        RowCollection rows = table.getRows();
        int rowCount = rows.getCount();
        //读取所有表格行
        for (int i = 0; i < rowCount; i++) {
            int rowIndex = i;
            Row row = rows.get(i);
            CellCollection cells = row.getCells();
            int cellCount = cells.getCount();
            for (int j = 0; j < cellCount; j++) {
                int cellIndex = j;
                String coord = StrFormatter.format("{}|{}",rowIndex,cellIndex);
                Cell cell = cells.get(j);
                //检测单元格种的图片数量
                NodeCollection shapeNodes = cell.getChildNodes(NodeType.SHAPE, true);
                if(shapeNodes.getCount() > 0){//图片
                    rowDataMap.put(coord, AsposeTool.getImg(cell));
                }else{//文本
                    rowDataMap.put(coord, AsposeTool.getText(cell));
                }
            }
        }

        //遍历读取到的单元格数据 层层筛选所需的数据存储到对应容器
        Set<String> coordSet = rowDataMap.keySet();
        rowDataMap.forEach((coord,value) -> {
            //解析左右对应单元格数据
            if(null != coordKeyMap && coordKeyMap.containsKey(coord)){
                String key = coordKeyMap.get(coord);
                dataMap.put(key,value);
            }
            //解析子表数据 先确定单元格值为字符串 再匹配大标题
            if(null != subTableTitleKeyMap && (value instanceof String) && subTableTitleKeyMap.containsKey((String)value)){
                String bigTitle = (String) value;
                List<String> subTitleKeyList = subTableTitleKeyMap.get(bigTitle);
                /** 存放小标题的列索引和属性名映射 */
                Map<String,String> subTitleIndexKeyMap = new HashMap<>();
                for (int i = 0; i < subTitleKeyList.size(); i++) {
                    subTitleIndexKeyMap.put(String.valueOf(i),subTitleKeyList.get(i));
                }
                int bigTitleRowIndex = Integer.valueOf(StrUtil.subBefore(coord,"|",false));
                int subTitleSize = subTitleKeyList.size();//小标题行的单元格数量
                //捕捉到大标题后 取出下一行小标题之后的数据
                int nextRowIndexStart = bigTitleRowIndex + 1;//小标题的行索引
                //直到下一行的单元格数量 与 小标题行的单元格数量不一致 或者 没有下一行时 终止子表的数据读取
                //存储子表的数据
                List<Map<String,Object>> subTableDataList = new ArrayList<>();
                while (true){
                    nextRowIndexStart ++;
                    String curRowCoordHead = nextRowIndexStart + "|";
                    List<String> curRowCoordList = coordSet.parallelStream().filter(a -> a.startsWith(curRowCoordHead)).collect(Collectors.toList());
                    int curRowCellCount = curRowCoordList.size();
                    if(curRowCellCount != subTitleSize || curRowCellCount < 1) break;

                    Map<String,Object> dataMap = new HashMap<>();
                    for (String curCoord : curRowCoordList) {
                        String colIndex = StrUtil.subAfter(curCoord, "|",false);
                        String key = subTitleIndexKeyMap.get(colIndex);
                        dataMap.put(key,rowDataMap.get(curCoord));
                    }
                    subTableDataList.add(dataMap);
                }
                subTableDataMap.put(bigTitle,subTableDataList);
            }
        });

        return this;
    }


    /**
     * 获取解析后的对象
     * @param clz 需要将dataMap映射为的对象类
     * @param <T>
     * @return
     */
    public <T> T getDataBean(Class<T> clz){
        return BeanUtil.toBean(this.dataMap, clz);
    }



}

           

10. 测试读取

读取的文档

Java word aspose(2.2 读取表格中的文本与图片)

发起请求

Java word aspose(2.2 读取表格中的文本与图片)

读取方法

@SneakyThrows
    @PostMapping("readTableFinal")
    public Ret readTableFinal(MultipartFile wordFile){
        try(InputStream inputStream = wordFile.getInputStream()){
            Document doc = new Document(inputStream);
            //获取所有的表格
            NodeCollection tableNodes = doc.getChildNodes(NodeType.TABLE, true);
            int tableCount = tableNodes.getCount();
            for (int i = 0; i < tableCount; i++) {
                if(0 == i){
                    Table table = (Table)tableNodes.get(i);
                    AsposeReadStrategy readStrategy = new AsposeReadStrategy(table);
                    readStrategy.setCoordProperty(0,1,"name")
                            .setCoordProperty(0,2,"photos")
                            .setCoordProperty(1,1,"idNo")
                            .setCoordProperty(2,1,"tel")
                            .setCoordProperty(3,1,"addr")
                            .setCoordProperty(3,3,"topEdu")
                            .setTableProperty("教育经历","startTime","endTime","school","major")
                            .setTableProperty("获得证书","gainTime","certificateName")
                            .parse();
                    Map<String, Object> dataMap = readStrategy.getDataMap();
                    PersonInfo dataBean = readStrategy.getDataBean(PersonInfo.class);
                    Map<String, List<Map<String, Object>>> subTableDataMap = readStrategy.getSubTableDataMap();
                    //演示map转为对象 subTableDataMap中的数据 也可以通过以下方法转换为所需对象
                    PersonInfo personInfo = BeanUtil.toBean(dataMap, PersonInfo.class);

                    //观察照片的提取结果
                    List<byte[]> photos = personInfo.getPhotos();
                    for (byte[] photoBytes : photos) {
                        FileUtil.writeBytes(photoBytes,RandomUtil.randomString(3)+".jpg");
                    }

                    int j = 0;
                }
            }
        }
        return Ret.success();
    }
           
package com.example.support.entity;

import lombok.Data;

import java.util.List;

/**
 * @author LWB
 * @Description
 */
@Data
public class PersonInfo {
    private String name;
    private List<byte[]> photos;
    private String idNo;
    private String tel;
    private String addr;
    private String topEdu;
}
           

读取结果

在int j = 0 处打断电观察数据读取解析的结果

Java word aspose(2.2 读取表格中的文本与图片)
Java word aspose(2.2 读取表格中的文本与图片)
Java word aspose(2.2 读取表格中的文本与图片)

ok 至此 读取word的功能 基本可以满足大多数需求了