Excel 导入

简介

背景

在数据处理和分析的过程中,读取和解析 Excel 文件是常见的需求。Java 开发中,有许多库可以帮助我们实现这一需求。本文将介绍如何使用 Alibaba 的 EasyExcel 库读取 Excel 文件,并将内容转换为自定义的数据结构。

我们将通过一个具体的例子,演示如何读取 Excel 文件中的数据,并将其转换为 TableInput 对象。

依赖项

首先,需要在项目中引入 api-tableEasyExcel 的依赖项:

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>easyexcel</artifactId>
  <version>2.2.10</version>
</dependency>
<dependency>
  <groupId>com.litongjava</groupId>
  <artifactId>api-table</artifactId>
  <version>${api-table.version}</version>
</dependency>

需要注意的是,EasyExcel 会引入 Apache POI 的依赖,这可能会增加项目的打包体积。

异步导入

示例

以下是一个完整的代码示例,演示如何读取 Excel 文件并处理其内容:

import java.io.ByteArrayInputStream;
import java.net.URL;
import java.util.Map;
import java.util.Map.Entry;

import org.junit.Test;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.litongjava.table.model.TableInput;
import com.litongjava.tio.utils.hutool.FileUtil;
import com.litongjava.tio.utils.hutool.ResourceUtil;
import com.litongjava.tio.utils.json.FastJson2Utils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ReadExcelTest {

  @Test
  public void readExcel() {
    // 获取 Excel 文件的 URL
    URL resource = ResourceUtil.getResource("tio_boot_admin_system_article-2024_7_10 12_29_08.xlsx");
    // 读取 Excel 文件的字节内容
    byte[] bytes = FileUtil.readUrlAsBytes(resource);

    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);

    // 定义 Excel 解析监听器
    AnalysisEventListener<Map<Integer, Object>> readListener = new AnalysisEventListener<Map<Integer, Object>>() {
      private Map<Integer, String> headMap = null;

      @Override
      public void doAfterAllAnalysed(AnalysisContext context) {
        // 全部解析完成后的处理
      }

      @Override
      public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        // 处理表头数据
        String json = FastJson2Utils.toJson(headMap);
        log.info("json:{}", json);
        this.headMap = headMap;
      }

      @Override
      public void invoke(Map<Integer, Object> data, AnalysisContext context) {
        // 处理每一行数据
        String json = FastJson2Utils.toJson(data);
        log.info("json:{}", json);

        TableInput ti = TableInput.create();
        for (Entry<Integer, Object> e : data.entrySet()) {
          String keyName = headMap.get(e.getKey());
          Object value = e.getValue();
          ti.set(keyName, value);
        }

        json = FastJson2Utils.toJson(ti);
        log.info("json:{}", json);
      }
    };

    // 构建 Excel 读取器
    ExcelReaderBuilder readBuilder = EasyExcel.read(byteArrayInputStream, readListener);
    readBuilder.doReadAll();
  }
}

表头数据示例

invokeHeadMap 方法中,解析并打印了表头数据,示例如下:

{
  "0": "id",
  "1": "orders",
  "2": "title",
  "3": "content",
  "4": "category_id",
  "5": "summary",
  "6": "locale",
  "7": "status",
  "8": "files",
  "9": "remark",
  "10": "creator",
  "11": "create_time",
  "12": "updater",
  "13": "update_time",
  "14": "deleted",
  "15": "tenant_id"
}

行数据示例

invoke 方法中,处理并打印了每一行数据,示例如下:

{
  "1": "1",
  "2": "测试展示youtube视频",
  "3": "",
  "4": "400537606909092000",
  "6": "zh_cn",
  "7": "1",
  "8": "[{\"uid\":\"1720576961389\",\"size\":3103640,\"name\":\"image.png\",\"id\":\"400560112936251392\",\"type\":\"image/png\",\"url\":\"https://sejie.s3.us-west-1.amazonaws.com/default/400560065427369984.png\",\"status\":\"done\"}]"
}

TableInput 数据示例

最终转换后的 TableInput 对象数据如下:然后您可以使用 ApiTable 的 Save 方法将 TableInput 存入数据库中。

{
  "title": "测试展示youtube视频",
  "locale": "zh_cn",
  "content": "",
  "category_id": "400537606909092000",
  "files": "[{\"uid\":\"1720576961389\",\"size\":3103640,\"name\":\"image.png\",\"id\":\"400560112936251392\",\"type\":\"image/png\",\"url\":\"https://sejie.s3.us-west-1.amazonaws.com/default/400560065427369984.png\",\"status\":\"done\"}]",
  "orders": "1",
  "status": "1"
}

通过上述代码和示例,您可以了解到如何使用 EasyExcel 读取 Excel 文件,并将其内容转换为自定义的数据结构 TableInput。这种方式可以方便地进行数据处理和分析,适用于各种应用场景。

同步导入

使用 doReadAllSync 方法同步导入

import java.io.ByteArrayInputStream;
import java.net.URL;
import java.util.List;
import java.util.Map;

import org.junit.Test;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.litongjava.tio.utils.hutool.FileUtil;
import com.litongjava.tio.utils.hutool.ResourceUtil;
import com.litongjava.tio.utils.json.JsonUtils;

public class ReadExcelDoReadAllSyncTest {

  @Test
  public void doReadAllSync() {
    // 获取 Excel 文件的 URL
    URL resource = ResourceUtil.getResource("tio_boot_admin_system_article-2024_7_10 12_29_08.xlsx");
    // 读取 Excel 文件的字节内容
    byte[] bytes = FileUtil.readUrlAsBytes(resource);

    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);

    // 构建 Excel 读取器
    ExcelReaderBuilder readBuilder = EasyExcel.read(byteArrayInputStream);
    // 同步读取数据
    List<Map<String, Object>> tableInputList = readBuilder.doReadAllSync();

    System.out.println(tableInputList.size());
    System.out.println(JsonUtils.toJson(tableInputList));
  }
}

注意:使用 doReadAllSync 导入后返回的 List<Map> 中的 map 的键是 0,1,2,3,4 的形式,您需要在使用前对其进行处理。

{ "0": "400637631022534660", "1": "1", "2": "其他数据" }

使用自定义 Excel 解析监听器读取数据

package com.sejie.service;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.junit.Test;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.litongjava.tio.utils.hutool.FileUtil;
import com.litongjava.tio.utils.hutool.ResourceUtil;
import com.litongjava.tio.utils.json.JsonUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ReadExcelSyncTest {

  @Test
  public void readExcelSync() {
    // 获取 Excel 文件的 URL
    URL resource = ResourceUtil.getResource("tio_boot_admin_system_article-2024_7_10 12_29_08.xlsx");
    // 读取 Excel 文件的字节内容
    byte[] bytes = FileUtil.readUrlAsBytes(resource);

    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);

    // 读取数据
    List<Map<String, Object>> tableInputList = doReadAllSync(byteArrayInputStream);

    System.out.println(tableInputList.size());
    System.out.println(JsonUtils.toJson(tableInputList));
  }

  private List<Map<String, Object>> doReadAllSync(InputStream inputStream) {
    // 存放

解析后的所有数据
    List<Map<String, Object>> tableInputList = new ArrayList<>();

    // 定义 Excel 解析监听器
    AnalysisEventListener<Map<Integer, Object>> readListener = new AnalysisEventListener<Map<Integer, Object>>() {
      private Map<Integer, String> headMap = null;

      @Override
      public void doAfterAllAnalysed(AnalysisContext context) {
        // 全部解析完成后的处理
        log.info("所有数据解析完成,总共 {} 行数据", tableInputList.size());
      }

      @Override
      public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        // 处理表头数据
        this.headMap = headMap;
      }

      @Override
      public void invoke(Map<Integer, Object> data, AnalysisContext context) {
        // 处理每一行数据并转换为 TableInput 对象
        Map<String, Object> map = new HashMap<>();
        for (Entry<Integer, Object> e : data.entrySet()) {
          map.put(headMap.get(e.getKey()), e.getValue());
        }
        tableInputList.add(map);
      }
    };

    // 构建 Excel 读取器
    ExcelReaderBuilder readBuilder = EasyExcel.read(inputStream, readListener);
    readBuilder.doReadAll();
    return tableInputList;
  }
}

通过上述代码示例,您可以了解如何使用自定义的 Excel 解析监听器同步读取 Excel 数据,并将其转换为所需的格式。这个方法适用于对数据有特殊处理需求的场景。