Java转换Excel文件为MarkDown格式

一、程序功能说明

支持上传xls、xlsx格式文档,转换为MarkDown格式文本返回

二、程序依赖包

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>5.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.xmlbeans</groupId>
            <artifactId>xmlbeans</artifactId>
            <version>5.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>4.4</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.16</version>
        </dependency>

三、接口入口方法controller层代码

    /**
     * Excel文件转markdown格式文本
     * @param file
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/excelFileToMDtext", method = RequestMethod.POST, produces = "application/json; text/plain; */*")
    public String excelFileToMDtext(@RequestParam("file") MultipartFile file) throws IOException {
        log.info("收到excel2md请求:file={}", file.getOriginalFilename());
        String result = ExcelToMarkdownConverter.convertExcelToMD(file);
        log.info("完成excel2md请求:file={}", result);
        return result;
    }

四、转换工具类ExcelToMarkdownConverter.java

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.OfficeXmlFileException;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * Excel 转 Markdown 表格转换器
 * 将上传的 Excel 文件(.xls 或 .xlsx)转换为 Markdown 格式的表格字符串
 */
public class ExcelToMarkdownConverter {

    /**
     * 将 MultipartFile 格式的 Excel 文件转换为 Markdown 表格字符串
     *
     * @param multipartFile 上传的 Excel 文件
     * @return 转换后的 Markdown 字符串
     * @throws IOException 文件读取异常
     */
    public static String convertExcelToMD(MultipartFile multipartFile) throws IOException {
        // 创建临时文件,用于保存上传的 Excel 文件
        // 文件名前缀为 "temp",后缀使用原始文件名以保留扩展名
        File tempFile = File.createTempFile("temp", multipartFile.getOriginalFilename());
        // 标记临时文件在 JVM 退出时自动删除
        tempFile.deleteOnExit();

        // 将 MultipartFile 内容写入临时文件
        multipartFile.transferTo(tempFile);

        // 根据文件路径创建 Workbook 实例(兼容 .xls 和 .xlsx)
        Workbook workbook = getWorkbookByFilePath(tempFile.getAbsolutePath());
        // 获取第一个工作表
        Sheet sheet = workbook.getSheetAt(0);

        // 使用 StringBuilder 构建 Markdown 字符串
        StringBuilder mdBuilder = new StringBuilder();
        // 添加标题:## 工作表名称
        mdBuilder.append("## ").append(sheet.getSheetName()).append("\n");

        // 获取表头行(第一行)
        Row headerRow = sheet.getRow(0);
        if (headerRow == null) {
            throw new IllegalArgumentException("Excel 文件中没有表头(第一行为空)");
        }

        // 构建表头 Markdown 行
        mdBuilder.append("| ");
        for (int j = 0; j < headerRow.getLastCellNum(); j++) {
            Cell cell = headerRow.getCell(j);
            mdBuilder.append(getCellValue(cell)).append(" | ");
        }
        mdBuilder.append("\n");

        // 添加 Markdown 表格分隔行:|---|---|...
        mdBuilder.append("|");
        for (int i = 0; i < headerRow.getLastCellNum(); i++) {
            mdBuilder.append("---|");
        }
        mdBuilder.append("\n");

        // 遍历数据行(从第二行开始)
        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row == null) continue; // 跳过空行

            // 特殊处理最后一行:如果整行为空(值为 "NaN"),则跳过不输出
            if (i == sheet.getLastRowNum()) {
                boolean isBlankRow = true;
                for (int j = 0; j < row.getLastCellNum(); j++) {
                    Cell cell = row.getCell(j);
                    if (!"NaN".equals(getCellValue(cell))) {
                        isBlankRow = false;
                        break;
                    }
                }
                if (isBlankRow) {
                    break; // 跳出循环,不处理该空行
                }
            }

            // 开始构建数据行
            mdBuilder.append("| ");
            for (int j = 0; j < row.getLastCellNum(); j++) {
                Cell cell = row.getCell(j);
                mdBuilder.append(getCellValue(cell)).append(" | ");
            }
            mdBuilder.append("\n");
        }

        // 关闭 Workbook 资源(建议使用 try-with-resources,此处依赖外部调用者管理)
        workbook.close();

        return mdBuilder.toString();
    }

    /**
     * 获取单元格的字符串值,处理各种数据类型和特殊字符
     * 支持公式、数值、字符串、错误类型等
     *
     * @param cell Excel 单元格
     * @return 单元格的格式化字符串值,若为空则返回 "NaN"
     */
    private static String getCellValue(Cell cell) {
        if (cell == null) {
            return "NaN";
        }

        DataFormatter formatter = new DataFormatter();
        String value;

        // 处理公式单元格
        if (cell.getCellType() == CellType.FORMULA) {
            CellType formulaResultType = cell.getCachedFormulaResultType();

            switch (formulaResultType) {
                case STRING:
                    value = cell.getStringCellValue();
                    break;
                case NUMERIC:
                    double numericValue = cell.getNumericCellValue();
                    value = String.valueOf(numericValue);
                    break;
                case BOOLEAN:
                    value = String.valueOf(cell.getBooleanCellValue());
                    break;
                case ERROR:
                    value = ""; // 公式错误时返回空字符串
                    break;
                default:
                    value = formatter.formatCellValue(cell);
                    break;
            }
        } else {
            // 非公式单元格,直接格式化
            value = formatter.formatCellValue(cell);
        }

        // 特殊处理数值类型:若为整数,则去除小数点(如 123.0 -> 123)
        if (cell.getCellType() == CellType.NUMERIC && !DateUtil.isCellDateFormatted(cell)) {
            double num = cell.getNumericCellValue();
            if (num == (long) num) {
                value = String.valueOf((long) num);
            }
        }

        // 转义 Markdown 特殊字符
        value = value.replace("|", "\\|")   // 转义竖线,防止破坏表格结构
                   .replace("\n", " ")     // 换行符替换为空格
                   .trim();                // 去除首尾空格

        // 若处理后为空字符串,返回 "NaN" 表示空值
        if (value.isEmpty()) {
            return "NaN";
        }

        return value;
    }

    /**
     * 根据文件路径创建 Workbook 实例,兼容 .xls 和 .xlsx 格式
     * 支持文件后缀与实际内容不一致的情况(如 .xls 文件实际为 .xlsx 格式)
     *
     * @param excelFilePath Excel 文件路径
     * @return Workbook 实例
     * @throws RuntimeException 包装的 IO 异常或文件格式异常
     */
    public static Workbook getWorkbookByFilePath(String excelFilePath) {
        boolean forceOpenXlsx = false; // 标记是否需要强制以 XSSF 方式打开
        Workbook workbook = null;

        try (FileInputStream inputStream = new FileInputStream(excelFilePath)) {
            if (excelFilePath.toLowerCase().endsWith(".xlsx")) {
                workbook = new XSSFWorkbook(inputStream); // 读取 .xlsx 文件
            } else if (excelFilePath.toLowerCase().endsWith(".xls")) {
                workbook = new HSSFWorkbook(inputStream); // 读取 .xls 文件
            } else {
                throw new IllegalArgumentException("不支持的文件格式: " + excelFilePath);
            }
        } catch (IOException e) {
            // 文件读取失败
            throw new RuntimeException("IO 错误: 无法读取文件 " + excelFilePath, e);
        } catch (OfficeXmlFileException e) {
            // 文件后缀为 .xls,但内容实际是 .xlsx 格式,需尝试用 XSSF 打开
            forceOpenXlsx = true;
        }

        // 如果检测到 OfficeXmlFileException,尝试以 .xlsx 方式强制打开
        if (forceOpenXlsx) {
            try (FileInputStream inputStream = new FileInputStream(excelFilePath)) {
                workbook = new XSSFWorkbook(inputStream); // 强制使用 XSSF 解析
            } catch (IOException e) {
                throw new RuntimeException("IO 错误: 无法以 .xlsx 格式读取文件 " + excelFilePath, e);
            }
        }
        return workbook;
    }
}

<think>嗯,用户想了解如何将Excel文件转换Markdown格式,特别是在Java环境下。首先,我需要确认用户的具体需求。他们可能需要处理表格数据,将Excel中的表格转换成适合文档或网页展示的Markdown表格。常见的应用场景可能包括生成文档、报告,或者在静态网站中展示数据。 接下来,我得考虑Java中处理Excel的常用库。Apache POI是一个广泛使用的库,支持读写Excel文件。所以,用户需要先引入POI的依赖,比如Maven或Gradle配置。然后,读取Excel文件的工作簿,处理每个工作表,以及每个行和单元格的数据。 用户可能不太清楚Markdown表格的语法规则,需要明确如何将Excel的单元格内容转换为用竖线分隔的文本,并处理表头和分隔行。比如,表头下方需要用三个连字符和竖线来分隔表头和内容行。 另外,需要考虑Excel中可能存在的合并单元格、特殊字符(如竖线本身)等问题。这些情况需要特殊处理,比如义竖线字符,或者拆分合并的单元格以适应Markdown的表格结构。 用户可能还需要处理不同格式的数据,比如数字、日期,这些在转换时是否需要特殊处理?或者是否保留原始的字符串形式?这也是需要考虑的地方。 然后,代码的结构大致分为读取Excel文件,遍历每个Sheet和Row,提取单元格数据,拼接成Markdown表格的字符串,最后写入到文件或输出。这里可能需要处理空单元格,避免数组越界,以及处理不同行之间列数不一致的情况,比如用空字符串填充。 最后,测试和验证转换后的Markdown是否正确显示,是否有对齐问题,或者是否需要调整列宽等。用户可能还需要自定义样式,比如对齐方式,但Markdown本身支持有限,可能需要通过HTML或其他扩展来实现,但基本转换可能不需要这些。 总结步骤:添加依赖、读取Excel、处理数据、生成Markdown表格、处理异常和边缘情况。同时,可能需要给出示例代码,帮助用户快速上手,并提醒他们注意依赖版本和可能的异常处理,比如文件不存在或格式错误。</think>在Java中将Excel转换Markdown表格的实现步骤如下(示例使用Apache POI库): 1. **添加依赖** ```xml <dependency> <groupId>org.apache.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.3</version> </dependency> <dependency> <groupId>org.apache.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.3</version> </dependency> ``` 2. **核心代码示例** ```java import org.apache.poi.ss.usermodel.*; import java.io.FileInputStream; import java.io.BufferedWriter; import java.io.FileWriter; public class ExcelToMarkdown { public static void convert(String excelPath, String mdPath) throws Exception { try (FileInputStream fis = new FileInputStream(excelPath); Workbook workbook = WorkbookFactory.create(fis); BufferedWriter writer = new BufferedWriter(new FileWriter(mdPath))) { Sheet sheet = workbook.getSheetAt(0); // 取第一个工作表 boolean isFirstRow = true; for (Row row : sheet) { StringBuilder mdRow = new StringBuilder("|"); // 处理表头分隔符 if (isFirstRow) { StringBuilder headerSeparator = new StringBuilder("|"); for (Cell cell : row) { headerSeparator.append("---|"); } writer.write(mdRow.toString() + "\n"); writer.write(headerSeparator.toString() + "\n"); isFirstRow = false; continue; } // 处理数据行 for (Cell cell : row) { String cellValue = getCellValueAsString(cell); mdRow.append(cellValue).append("|"); } writer.write(mdRow.toString() + "\n"); } } } private static String getCellValueAsString(Cell cell) { if (cell == null) return ""; switch (cell.getCellType()) { case STRING: return cell.getStringCellValue(); case NUMERIC: return String.valueOf(cell.getNumericCellValue()); case BOOLEAN: return String.valueOf(cell.getBooleanCellValue()); default: return ""; } } } ``` 3. **使用注意事项** - 表格转换规则: $$ \text{Excel列数} \rightarrow \text{Markdown表格列数} $$ $$ \text{空单元格} \rightarrow \text{空字符串} $$ - 需要处理特殊字符: - 竖线`|`需义为`\|` - 换行符转换为`<br>` - 支持最大列宽:建议不超过150字符 4. **扩展优化方向** - 增加对齐方式控制: ```java // 在表头分隔符中设置对齐 headerSeparator.append(":---|"); // 左对齐 headerSeparator.append(":---:|"); // 居中对齐 headerSeparator.append("---:|"); // 右对齐 ``` - 支持合并单元格处理 - 添加CSV文件转换支持 - 实现HTML表格的双向转换 完整实现建议结合具体需求选择以下方案: 1. 轻量级转换:直接使用POI+字符串拼接 2. 复杂需求:结合OpenXML SDK处理样式 3. 服务化方案:集成Spring Boot提供REST API 是否需要进一步说明某个具体功能的实现细节?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nbman2013

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值