使用poi通过word模板导出数据

  • 引入Apache POI依赖
  • 制作word模板
  • 加载word模板,读取word模板的内容,替换占位符内容
  • 将修改后文档另存为

一、基础示例

1. 引入依赖

在POM文件中引入相关依赖

复制代码
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.2.3</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.3</version>
</dependency>

2. 制作模板

新建一个word文档,需要动态替换的位置使用占位符,后面匹配到该占位符将数据填充到该位置即可。对于动态表格(项次条数不确定),在表格的第一行使用占位符 ${dynamicTable} 标记,表明该表格是动态表格,后面循环创建行并插入数据。

3. 读取模板

  1. 通过 XWPFDocument 加载模板文件

    // 读取文件
    InputStream is = new FileInputStream("这里填模板位置/inFile.docx");
    XWPFDocument doc = new XWPFDocument(is);

  2. 替换文本内容

遍历段落替换占位符

复制代码
for (XWPFParagraph paragraph : doc.getParagraphs()) {
    String text = paragraph.getText();
    if (text != null && text.contains("${name}")) {
        text = text.replace("${name}", "张三");
        paragraph.getRuns().get(0).setText(text, 0);
    }
}
  1. 处理表格

定位表格并填充数据:

复制代码
XWPFTable table = doc.getTables().get(0);
// 示例:替换表格第一行第一列的内容
table.getRow(0).getCell(0).setText("数据1");

4. 导出文件

将修改后的文档写入新文件:

复制代码
FileOutputStream out = new FileOutputStream("输入文件的位置/outFile.docx");
doc.write(out);
out.close();
doc.close();

二、案例

同时导出四个文件,有些文件既有普通固定表格,又有动态表格,又有文本。

从数据库查询数据,将每个字段数据通过key-value的形式存储在map集合中。动态数据存储在一个map中,静态数据存储在一个map中。

导出方法处理动态表格、段落、静态表格

复制代码
// 模板位置
        String[] templatePathArr =  {"d:/excel/模板1.docx",
                "d:/excel/模板2.docx",
                "d:/excel/模板3.docx",
                "d:/excel/模板4.docx"};
        // 输出位置
        String[] outFilePathArr =  {"d:/tmp/" + projectName +"-文档1.docx",
                "d:/tmp/" + projectName + "-文档2.报告.docx",
                "d:/tmp/" + projectName + "-文档3.docx",
                "d:/tmp/" + projectName + "-文档4.docx"};

for (int i = 0; i < templatePathArr.length; i++) {

            // 读取Word模板
            XWPFDocument doc = new XWPFDocument(new FileInputStream(templatePathArr[i]));

            // 处理动态表格(移除标识行)
            for (XWPFTable table : doc.getTables()) {
                if (table.getRows().size() > 0) {
                    String firstCellText = table.getRow(0).getCell(0).getText();
                    if (firstCellText != null && firstCellText.contains("${dynamicTable}")) {
                        // 处理这个动态表格
                        processDynamicTable(table, dynamicData);
                    }
                }
            }

            // 替换所有固定占位符
            for (XWPFParagraph p : doc.getParagraphs()) {
                replaceText(p, data);
            }

            // 处理静态表格
            for (XWPFTable table : doc.getTables()) {
                for (XWPFTableRow row : table.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells()) {
                        for (XWPFParagraph p : cell.getParagraphs()) {
                            replaceText(p, data);
                        }
                    }
                }
            }

            // 4. 保存到新文件
            FileOutputStream out = new FileOutputStream(new File(outFilePathArr[i]));
            doc.write(out);
            doc.close();
            out.close();
        }

处理文本和固定表格方法

复制代码
  // 处理段落和固定表格并替换占位符
    private static void replaceText(XWPFParagraph p, Map<String, String> data) {
        // 获取整个段落的文本
        String text = p.getText();

        if (text != null && text.contains("${")) {
            // 替换所有占位符
            for (String key : data.keySet()) {
                text = text.replace("${" + key + "}", data.get(key));
            }

            // 关键:清空原有内容再设置新内容
            for (XWPFRun run : p.getRuns()) {
                run.setText("", 0);
            }

            if (!p.getRuns().isEmpty()) {
                p.getRuns().get(0).setText(text);
            }
        }
    }

处理动态表格方法

复制代码
// 填充动态表格
    private void processDynamicTable(XWPFTable table, Map<String, Object> dynamicData) {
        // 1. 移除标识行(第一行:${dynamicTable})
        table.removeRow(0);

        // 2. 移除占位符示例行
        if (table.getRows().size() > 1) {
            table.removeRow(1);
        }

        // 3. 处理表格
        List<Object[]> tableData = new ArrayList<>();
        String header = table.getRow(0).getCell(1).getText().trim();  // 获取表格第1行的第2列标题
        int cellNum = table.getRow(0).getTableCells().size();  // 获取表格有多少列

        if (header.contains("投资项目应用")) {
            // 项目资金预算表
            List<PatentEconomicItem> economicList = (List<PatentEconomicItem>) dynamicData.get("economicList");
            // 转成数组
            for (PatentEconomicItem patentEconomicItem : economicList) {
                Object[] row = {
                        patentEconomicItem.getProjectApplicantion(),
                        patentEconomicItem.getCost(),
                        patentEconomicItem.getOrigin()
                };
                tableData.add(row);
            }
        } else if (header.contains("姓名")) {
            // 主要人员参与表
            List<PatentPeopleItem> peopleList = (List<PatentPeopleItem>) dynamicData.get("peopleList");
            // 转成数组
            for (PatentPeopleItem patentPeopleItem : peopleList) {
                Object[] row = {
                        patentPeopleItem.getName(),
                        patentPeopleItem.getQualification(),
                        patentPeopleItem.getRank(),
                        patentPeopleItem.getProjectTask()
                };
                tableData.add(row);
            }
        } else if (header.contains("项次")) {
            //自检表
            List<PatentCheckList> checkList = (List<PatentCheckList>) dynamicData.get("checkList");
            // 转成数组
            for (PatentCheckList item : checkList) {
                Object[] row = {
                        item.getItemNum(),
                        item.getResult(),
                        item.getRemark()
                };
                tableData.add(row);
            }
        }

        // 填充动态表格数据
        for (int i = 0; i < tableData.size(); i++) {
            XWPFTableRow newRow = table.createRow();
             // 第一列是序号,自动生成
            newRow.getCell(0).setText(String.valueOf(i + 1));
            // 填充其他列
            for (int j = 1; j < cellNum; j++) {
                newRow.getCell(j).setText(tableData.get(i)[j - 1].toString());
            }
        }

    }

前端创建a标签下载

相关推荐
洛卡卡了3 小时前
活动玩法越堆越乱,我重构了一套事件驱动的活动系统
后端·面试·架构
柯杰3 小时前
DNS劫持防护:从被动监测到主动防御
后端·dns
墨守城规3 小时前
CompletableFuture 使用与分析
后端
爱叫啥叫啥4 小时前
你都知道哪些嵌入式中的常用关键字
后端
a程序小傲4 小时前
淘宝Java面试被问:Atomic原子类的实现原理
java·开发语言·后端·面试
expect7g4 小时前
Paimon源码解读 -- Compaction-9.SortMergeReaderWithLoserTree
大数据·后端·flink
程序员爱钓鱼4 小时前
BlackHole 2ch:macOS无杂音录屏与系统音频采集完整技术指南
前端·后端·设计模式
与遨游于天地4 小时前
接口与实现分离:从 SPI 到 OSGi、SOFAArk的模块化演进
开发语言·后端·架构
ss2734 小时前
springboot二手车交易系统
java·spring boot·后端