Java中的Excel操作工具类

123 阅读3分钟

1. 背景

在实际的业务开发中,我们经常会遇到需要导入和导出Excel文件的需求。例如,HR部门可能需要从系统中导出员工信息,或者销售团队需要上传每月的销售数据。虽然市面上有很多功能强大的Excel处理工具,但有时候,我们只需要一个简单、轻量级的工具来完成基本的导入和导出操作。

因此,我创建了一个简单的ExcelUtil工具类,使用了EasyExcel库来简化和优化Excel操作。

2. 什么时候需要这个工具类?

当你需要进行以下操作时,可以考虑使用这个工具类:

  • 创建一个带有指定表头的Excel文件。
  • 从Excel文件中读取数据,并按照给定的表头进行映射。
  • 将数据写入到一个已经存在的Excel文件中。

3. 如何使用?

创建Excel文件

Map<String, Object> headers = new HashMap<>();
headers.put("Name", null);
headers.put("Age", null);
OutputStream os = new FileOutputStream("path_to_file.xlsx");
ExcelUtil.createExcelWithHeaders(os, headers);

从Excel文件中读取数据

Map<String, Integer> headers = new HashMap<>();
headers.put("Name", 0);
headers.put("Age", 1);
InputStream is = new FileInputStream("path_to_file.xlsx");
ExcelUtil.readExcelWithHeaders(is, headers, rowMap -> {
    System.out.println(rowMap);
});

将数据写入Excel文件

Map<String, Object> headers = new HashMap<>();
headers.put("Name", null);
headers.put("Age", null);
List<Map<String, Object>> data = new ArrayList<>();
// ... 填充数据 ...
OutputStream os = new FileOutputStream("path_to_file.xlsx");
ExcelUtil.writeDataToExcel(os, headers, data);

4. 代码附录


import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import com.alibaba.excel.EasyExcel;

/**
 * @author aihe.ah
 * @time 2023/10/12
 * 功能说明:
 */
public class ExcelUtil {

    /**
     * 根据给定的表头创建一个Excel文件。
     *
     * @param os      输出流
     * @param headers 表头
     * @return 返回输出流
     */
    public static OutputStream createExcelWithHeaders(OutputStream os, Map<String, Object> headers) {
        if (os == null || headers == null || headers.isEmpty()) {
            throw new IllegalArgumentException("参数不能为空");
        }

        List<List<String>> headerList = headers.keySet().stream()
            .map(Collections::singletonList)
            .collect(Collectors.toList());

        // 注意:此处的OutputStream不会被关闭
        EasyExcel.write(os).head(headerList).sheet("Sheet1").doWrite(Collections.emptyList());

        return os;
    }

    /**
     * 根据给定的表头读取Excel文件。
     *
     * @param is        输入流
     * @param headers   表头
     * @param processor 数据处理函数
     */
    public static void readExcelWithHeaders(InputStream is, Map<String, Integer> headers,
        Consumer<Map<String, Object>> processor) {
        if (is == null || headers == null || headers.isEmpty() || processor == null) {
            throw new IllegalArgumentException("参数不能为空");
        }

        EasyExcel.read(is, new com.alibaba.excel.event.AnalysisEventListener<Map<Integer, String>>() {
            @Override
            public void invoke(Map<Integer, String> data, com.alibaba.excel.context.AnalysisContext context) {
                Map<String, Object> rowMap = headers.entrySet().stream()
                    .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> data.getOrDefault(entry.getValue(), null)
                    ));
                processor.accept(rowMap);
            }

            @Override
            public void doAfterAllAnalysed(com.alibaba.excel.context.AnalysisContext context) {}

        }).sheet().doRead();
    }

    /**
     * 将数据写入Excel文件。
     *
     * @param os      输出流
     * @param headers 表头
     * @param data    要写入的数据
     */
    public static void writeDataToExcel(OutputStream os, Map<String, Object> headers, List<Map<String, Object>> data) {
        if (os == null || headers == null || headers.isEmpty() || data == null || data.isEmpty()) {
            throw new IllegalArgumentException("参数不能为空");
        }

        List<List<String>> headerList = headers.keySet().stream()
            .map(Collections::singletonList)
            .collect(Collectors.toList());

        List<List<Object>> dataList = data.stream()
            .map(rowMap -> headers.keySet().stream()
                .map(rowMap::get)
                .collect(Collectors.toList()))
            .collect(Collectors.toList());

        EasyExcel.write(os).head(headerList).sheet("Sheet1").doWrite(dataList);
    }
}

第二版

public class ExcelUtil {

    /**
     * 根据给定的表头创建一个Excel文件。
     *
     * @param headers
     * @return
     */
    public static byte[] createExcelWithHeaders(Map<String, Object> headers) {
        if (headers == null || headers.isEmpty()) {
            throw new IllegalArgumentException("参数不能为空");
        }

        ByteArrayOutputStream os = new ByteArrayOutputStream();

        List<List<String>> headerList = headers.keySet().stream()
            .map(Collections::singletonList)
            .collect(Collectors.toList());

        // 注意:此处的OutputStream不会被关闭
        EasyExcel.write(os)
            .head(headerList)
            .sheet("Sheet1")
            .registerWriteHandler(new SimpleColumnWidthStyleStrategy(TafpCommonSwitch.excelColumnWidth))
 //            .registerWriteHandler(new CommentWriteHandler(headers))
            .doWrite(Collections.emptyList());

        return os.toByteArray();
    }

    public static void readExcelWithHeaders(InputStream is,
        Consumer<Map<String, Object>> processor) {
        if (is == null || processor == null) {
            throw new IllegalArgumentException("参数不能为空");
        }

        EasyExcel.read(is, new AnalysisEventListener<Map<Integer, String>>() {
            Map<Integer, String> headerMap = new HashMap<>();

            @Override
            public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
                // 将表头的映射存储起来
                headerMap = headMap;
            }

            @Override
            public void invoke(Map<Integer, String> data, AnalysisContext context) {
                Map<String, Object> rowMap = new HashMap<>();
                for (Map.Entry<Integer, String> headerEntry : headerMap.entrySet()) {
                    Integer columnIndex = headerEntry.getKey();
                    String key = headerEntry.getValue();
                    Object value = data.get(columnIndex);
                    rowMap.put(key, value);
                }
                processor.accept(rowMap);
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {}
        }).sheet().doRead();
    }

    /**
     * 使用EasyExcel将数据写入Excel。
     *
     * @param os      输出流,用于写入Excel数据。
     * @param headers 表头和对应的宽度。
     * @param data    数据列表,每个Map代表一行数据,key为表头,value为单元格的值。
     */
    public static void writeDataToExcel(OutputStream os, Map<String, Object> headers, List<Map<String, Object>> data) {
        if (os == null || headers == null || headers.isEmpty() || data == null || data.isEmpty()) {
            throw new IllegalArgumentException("参数不能为空");
        }

        List<List<String>> headerList = headers.keySet().stream()
            .map(Collections::singletonList)
            .collect(Collectors.toList());

        List<List<Object>> dataList = data.stream()
            .map(rowMap -> headers.keySet().stream()
                .map(rowMap::get)
                .collect(Collectors.toList()))
            .collect(Collectors.toList());

        // 创建Excel写入器
        ExcelWriter excelWriter = EasyExcel.write(os).build();

        // 创建Sheet并设置表头宽度
        WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1")
            .head(headerList)
            .registerWriteHandler(new SimpleColumnWidthStyleStrategy(TafpCommonSwitch.excelColumnWidth))
            .build();

        // 写入数据
        excelWriter.write(dataList, writeSheet);

        // 关闭Excel写入器
        excelWriter.finish();
    }
}