前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Word 模板动态数据合成

Word 模板动态数据合成

作者头像
前Thoughtworks-杨焱
发布2022-02-19 10:30:59
7890
发布2022-02-19 10:30:59
举报
文章被收录于专栏:杨焱的专栏

发表于2018-06-052019-01-01 作者 wind

代码语言:javascript
复制
/*
 * Copyright (c) 2017 西安才多信息技术有限责任公司。
 * 项目名称:dev
 * 文件名称:DocxTemplateUtils.java
 * 日期:17-10-11 下午2:18
 * 作者:yangyan
 *
 */

package com.deyatong.common.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * WORD DOCX 文件变量替换输出工具类
 */
public class DocxTemplateUtils {

    Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 变量替换符号的正则,用来找到 ${xxx} 这样的内容,并实现替换
     */
    Pattern compile = Pattern.compile("(\\$\\{([^\\}]*)\\})");
    private final Map<String, ?> params;  //数据填充对象
    InputStream is;    //读入模板文件的流
    XWPFDocument doc;  //内存中构建的文档对象

    /**
     * 使用文件路径和变量集合创建
     *
     * @param templateDocxFile
     * @param params
     */
    public DocxTemplateUtils(String templateDocxFile, Map<String, ?> params) {
        this.params = params;
        try {
            is = new FileInputStream(templateDocxFile);
            doc = new XWPFDocument(is);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 使用文件和和变量集合创建
     *
     * @param templateDocxFile
     * @param params
     */
    public DocxTemplateUtils(File templateDocxFile, Map<String, ?> params) {
        this.params = params;
        try {
            is = new FileInputStream(templateDocxFile);
            doc = new XWPFDocument(is);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 使用模板读入的流和变量集合创建
     *
     * @param templateDocxFileInputStream
     * @param params
     */
    public DocxTemplateUtils(InputStream templateDocxFileInputStream, Map<String, ?> params) {
        this.params = params;
        try {
            is = templateDocxFileInputStream;
            doc = new XWPFDocument(is);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 此类为poi操作word模板的工具类
     **/
    public XWPFDocument getDoc() {
        return doc;
    }

    /**
     * 替换所有段落中的变量
     */
    public void replaceInPara() {
        Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
        XWPFParagraph para;
        while (iterator.hasNext()) {
            para = iterator.next();
            this.replaceInPara(para);
        }
    }

    /**
     * 替换传入段落里面的变量
     *
     * @param para 要替换的段落
     */
    private void replaceInPara(XWPFParagraph para) {
        String paragraphText = para.getParagraphText();
        int start = paragraphText.indexOf("${");
        int end = paragraphText.indexOf("}");
        if (start == -1 && end == -1) { //段落中没有变量直接跳过
            logger.warn("没开始,没结束,直接跳过:" + paragraphText);
            return;
        }
        boolean isStart = false;
        boolean isEnd = false;
        StringBuilder varName = null;
        List<XWPFRun> runs;
        Matcher matcher;
        runs = para.getRuns(); //不同的文字片段可能有不同的样式
        logger.info("整段:" + paragraphText);

//        for (int i = 0; i < runs.size(); i++) {
//            XWPFRun run = runs.get(i);
//            String runText = run.toString().trim();
//            System.out.println(runText);
//        }

        for (int i = 0; i < runs.size(); i++) {
            XWPFRun run = runs.get(i);
            String runText = run.toString().trim();
            logger.debug(">>>处理文字片段:" + runText);
            String tail = "";
            if (runText.trim().length() == 0) {
                continue;
            }
            if (varName == null) {
                varName = new StringBuilder();
            }
            int s = runText.indexOf("${");
            if (s > -1) { //有开始
                int n = runText.indexOf("}", s);
                if (n != -1) { //有结束
                    varName.append(runText.substring(s, n + 1));
                    isEnd = true;
                    if (runText.indexOf("${", n) != -1) { //一行内是否有第二个变量开启
                        isStart = true;
                    }
                    tail = runText.substring(n + 1);
                } else { //没结束
                    isStart = true;
                    isEnd = false;
                    varName.append(runText.substring(s));
                    run.setText("", 0);
                }
            } else { //没开始
                if (isStart) { //之前开始了
                    int n = runText.indexOf("}");
                    if (n == -1) { //没结束
                        varName.append(runText);
                        run.setText("", 0);
                    } else { //结束
                        isStart = false;
                        varName.append(runText.substring(0, n + 1));
                        if (runText.indexOf("${", n) != -1) { //一行内是否有第二个变量开启
                            isStart = true;
                            tail = runText.substring(n + 1);
                        }
                        isEnd = true;
                    }
                }
            }
            if (isEnd) {
                String s1 = varName.toString();
                logger.warn("拼接结果:" + s1);
                Object o = params.get(s1);
                String value = o == null ? "" : o.toString();
                run.setText(value + tail, 0);
                varName = null;
                isEnd = false;
            }
//            if (s == -1) { //如果没有开始标记后面的就不用执行了
//                break;
//            }
            //文字替换处理
            matcher = compile.matcher(runText);
            while (matcher.find()) {
                String group = matcher.group(1);
                logger.debug("----找到变量:" + group + String.format(",文字片段内位置:(%s-%s)", matcher.start(), matcher.end()));
                Object o = params.get(group);
                String replacement = "";
                if (o != null) {
                    if (o instanceof List) {
                        //替换的内容
                        logger.debug("----变量替换成为:" + StringUtils.join(o));
                        run.setText("", 0);
                        List list = (List) o;
                        for (Object o1 : list) {
                            run.addCarriageReturn();
                            run.setText(o1.toString());
                        }
                        break;
                    } else {
                        replacement = o.toString();
                        //替换的内容
                        runText = matcher.replaceFirst(replacement);
                        logger.debug("----变量替换成为:" + replacement);
                        run.setText(runText, 0);
                        logger.debug(">>>片段替换成为:" + runText);
                    }
                }
            }
        }
    }


    /**
     * 替换表格里面的变量
     */
    public void replaceInTable() {
        Iterator<XWPFTable> iterator = doc.getTablesIterator();
        XWPFTable table;
        List<XWPFTableRow> rows;
        List<XWPFTableCell> cells;
        List<XWPFParagraph> paras;
        while (iterator.hasNext()) {
            table = iterator.next();
            rows = table.getRows();
            for (XWPFTableRow row : rows) {
                cells = row.getTableCells();
                for (XWPFTableCell cell : cells) {
                    paras = cell.getParagraphs();
                    for (XWPFParagraph para : paras) {
                        this.replaceInPara(para);
                    }
                }
            }
        }
    }

    /**
     * 关闭输入流
     */
    public void closeInputStream() {
        if (is != null) {
            try {
                is.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭输出流
     *
     * @param os
     */
    public void closeOutputStream(OutputStream os) {
        if (os != null) {
            try {
                os.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void addTablesRows(List<List<String>> data, int tableIndex, int rowIndex) {
        List<XWPFTable> list = doc.getTables();
        System.out.println("----" + list.size());
        XWPFTable xt = list.get(tableIndex);
        if (rowIndex < 0 || (rowIndex + 1) > xt.getNumberOfRows()) {
            rowIndex = xt.getNumberOfRows() - 1;
        }
        XWPFTableRow row1 = xt.getRow(rowIndex + 1);
        if (row1 == null) {
            row1 = xt.createRow();
            addTablesRows(data, tableIndex, rowIndex);
            return;
        }
        for (int i = 0; i < data.size(); i++) {
            XWPFTableRow row2 = xt.getRow(rowIndex + i);
            if (row2 == null) {
                row2 = xt.createRow();
            }
            List<XWPFTableCell> cells = row2.getTableCells();
            List<String> clist = data.get(i);
            for (int k = 0; k < clist.size(); k++) {
                XWPFTableCell cell = row2.getCell(k);
                cell.setText(clist.get(k));
            }
        }
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-06-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档