基于Apache POI生成Word文档

531 阅读1分钟

前言

在工作中,很多客户会要求我们每天在微信或者邮箱给他们定时发送格式固定的报告,方便客户实时掌握数据异常的情况,下面是通过Apache POI生成Word文档,如果有需要可以参考一下。

话不多说,先看实现的效果

这是模版 image.png 这是替换后的效果 image.png

1、先引入依赖

<!-- 文档模板导出平台 --> 
<dependency> 
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.3.1</version> 
</dependency>

2、下面2个类,看需要添加

CountrySectionTablePolicyStartOne(从文档表格第一行开始插入数据)

import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.policy.DynamicTableRenderPolicy;
import com.deepoove.poi.policy.MiniTableRenderPolicy;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import java.util.List;


public class CountrySectionTablePolicyStartOne extends DynamicTableRenderPolicy {
    int laborsStartRow = 1;

    public XWPFTableRow newRowFromSourceRow(XWPFTable table, XWPFTableRow sourceRow, int rowIndex, RowRenderData rowData) {
        //在表格指定位置新增一行
        XWPFTableRow targetRow = table.insertNewTableRow(rowIndex);
        //复制行属性
        targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());
        List<XWPFTableCell> cellList = sourceRow.getTableCells();
        if (null == cellList) {
            return null;
        }
        //复制列及其属性和内容
        XWPFTableCell targetCell = null;
        for (XWPFTableCell sourceCell : cellList) {
            targetCell = targetRow.addNewTableCell();
            //列属性
            targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());
            //段落属性
            if (sourceCell.getParagraphs() != null && sourceCell.getParagraphs().size() > 0) {
                targetCell.getParagraphs().get(0).getCTP().setPPr(sourceCell.getParagraphs().get(0).getCTP().getPPr());
                if (sourceCell.getParagraphs().get(0).getRuns() != null && sourceCell.getParagraphs().get(0).getRuns().size() > 0) {
                    XWPFRun cellR = targetCell.getParagraphs().get(0).createRun();
                    //cellR.setText(sourceCell.getText());
                    cellR.setBold(sourceCell.getParagraphs().get(0).getRuns().get(0).isBold());
                }
            }
        }
        MiniTableRenderPolicy.renderRow(table, laborsStartRow, rowData);
        return targetRow;
    }

    @Override
    public void render(XWPFTable table, Object data) {
        System.out.println("start render xwPFTable");
        List<RowRenderData> labors = (List<RowRenderData>) data;
        XWPFTableRow sourceRow = table.getRow(laborsStartRow);
        for (int i = 0; i < labors.size(); i++) {
            newRowFromSourceRow(table, sourceRow, 1, labors.get(i));
        }
        table.removeRow(table.getNumberOfRows() - 1);
    }
}

CountrySectionTablePolicyStartTwo(从文档表格第二行开始插入数据)

import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.policy.DynamicTableRenderPolicy;
import com.deepoove.poi.policy.MiniTableRenderPolicy;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import java.util.List;

public class CountrySectionTablePolicyStartTwo extends DynamicTableRenderPolicy {
    int laborsStartRow = 2;

    public XWPFTableRow newRowFromSourceRow(XWPFTable table, XWPFTableRow sourceRow, int rowIndex, RowRenderData rowData) {
        //在表格指定位置新增一行
        XWPFTableRow targetRow = table.insertNewTableRow(rowIndex);
        //复制行属性
        targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());
        List<XWPFTableCell> cellList = sourceRow.getTableCells();
        if (null == cellList) {
            return null;
        }
        //复制列及其属性和内容
        XWPFTableCell targetCell = null;
        for (XWPFTableCell sourceCell : cellList) {
            targetCell = targetRow.addNewTableCell();
            //列属性
            targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());
            //段落属性
            if (sourceCell.getParagraphs() != null && sourceCell.getParagraphs().size() > 0) {
                targetCell.getParagraphs().get(0).getCTP().setPPr(sourceCell.getParagraphs().get(0).getCTP().getPPr());
                if (sourceCell.getParagraphs().get(0).getRuns() != null && sourceCell.getParagraphs().get(0).getRuns().size() > 0) {
                    XWPFRun cellR = targetCell.getParagraphs().get(0).createRun();
                    cellR.setBold(sourceCell.getParagraphs().get(0).getRuns().get(0).isBold());
                }
            }
        }
        MiniTableRenderPolicy.renderRow(table, laborsStartRow, rowData);
        return targetRow;
    }

    @Override
    public void render(XWPFTable table, Object data) {
        System.out.println("start render xwPFTable");
        List<RowRenderData> labors = (List<RowRenderData>) data;
        XWPFTableRow sourceRow = table.getRow(laborsStartRow);
        for (int i = 0; i < labors.size(); i++) {
            newRowFromSourceRow(table, sourceRow, 2, labors.get(i));
        }
        table.removeRow(table.getNumberOfRows() - 1);
    }
}

3、在 resources 目录下添加模版配置(模版内容自己定义)

image.png 这是我的模版 image.png

4、添加Word工具类

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.data.TextRenderData;
import com.deepoove.poi.data.style.Style;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.*;

/**
 * Word工具类
 */
public class WordUtil {
    public void run() {
        // 定义用户的名称和年龄
        List<Map<String, Object>> data = new ArrayList<>();
        Map<String, Object> map1 = new HashMap<>();
        map1.put("mc","张三");
        map1.put("age","88");
        data.add(map1);
        Map<String, Object> map2 = new HashMap<>();
        map2.put("mc","李四");
        map2.put("age","89");
        data.add(map2);

        // 获取当天的日期
        LocalDate today = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
        // 获取今天的日期字符串
        String date = today.format(formatter);
        // 获取年份
        int year = today.getYear();
        // 获取星期几
        DayOfWeek dayOfWeek = today.getDayOfWeek();
        // 创建一个中文语言环境
        Locale locale = Locale.CHINESE;
        // 获取星期几的本地化显示名称
        String chineseDayOfWeek = dayOfWeek.getDisplayName(TextStyle.FULL_STANDALONE, locale);
        String rq = date + " " + chineseDayOfWeek;

        /**
         * 有些表格表头有两行
         * CountrySectionTablePolicyStartOne 从第一行开始插入数据
         * CountrySectionTablePolicyStartTwo 从第二行开始插入数据
         */
        Configure.ConfigureBuilder builder = Configure.newBuilder()
                .customPolicy("data1", new CountrySectionTablePolicyStartOne())
                .customPolicy("data2", new CountrySectionTablePolicyStartTwo());

        // 将模版文档里需要替换的占位符数据存到一个Map里面
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("year", year);
        dataMap.put("rq", rq);
        dataMap.put("date", date);
        dataMap.put("data1", getDataTable(data));
        dataMap.put("data2", getDataTable(data));

        String path = "D:\filestorage\platform\FBBG\BG\测试文档" + "_" + date + ".docx";

        //模板路径
        InputStream templateStream = WordUtil.class.getResourceAsStream("/data/测试报告.docx");
        File filename = new File(path);
        XWPFTemplate template = XWPFTemplate.compile(templateStream, builder.build())
                .render(dataMap);
        FileOutputStream out;
        try {
            out = new FileOutputStream(filename);
            template.write(out);
            out.flush();
            out.close();
            template.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 渲染word里面的表格
     * @param data
     * @return
     */
    private List<RowRenderData> getDataTable(List<Map<String, Object>> data) {
        //有多少条数据就有多少行
        List<RowRenderData> rows = new ArrayList<>();
        for (Map<String, Object> map : data) {
            RowRenderData row = new RowRenderData();
            List<TextRenderData> cellDatas = new ArrayList<>();
            Style style = new Style();
            style.setFontSize(9);
            //定义表格头部字段名
            cellDatas.add(new TextRenderData(String.valueOf(map.get("mc")), style));
            cellDatas.add(new TextRenderData(String.valueOf(map.get("age")), style));
            row.setRowData(cellDatas);
            rows.add(row);
        }
        Collections.reverse(rows);
        return rows;
    }
}

5、测试成功! image.png