精华内容
下载资源
问答
  • 在我们编辑word时经常会出现一些空白,为了保证word文档...方式如下:方法:按Delete在Word中遇到空白时,第应该尝试的就是Delete键,一般来说Delete键就能解决空白的问题。方法二:删除分页符如果使用De...

    在我们编辑word时经常会出现一些空白页,为了保证word文档的美观度,我们往往会去删除这些空白页,那么横向空白页如何删除呢,就让小编来告诉你吧。

    其实横版空白页的删除方式和纵向的一致,或者也可以在页面设置中将横版设置为纵向的进行删除。方式如下:

    方法一:按Delete

    在Word中遇到空白页时,第一应该尝试的就是Delete键,一般来说Delete键就能解决空白页的问题。

    77efb6c7f19c54af99e063ba003b13f9.png

    方法二:删除分页符

    如果使用Delete删不掉空白页,那很可能是因为这一页是用分页符分出来的,这种情况按按一次删除键是不够的,多按几次就能够删掉。

    3d01d159184713219540795a7009a497.png

    当然,如果分页符很多,那就可以采用编辑-替换-高级-特殊字符-人工分页符-全部替换就可以了。

    e4b5c6987329567e42f0d99afb7e3641.png

    4b655038c33cd2941f22f6c35bdb2fbd.png

    3c318a3ef52e66cac3be7fd46ff90181.png

    方法三:缩小行距

    如果还是删不掉空白页,则是因为行距引起的,可能是因为上一页插入的图标过大或者使用了特殊格式的字体。

    首先在多的那个空白页上按鼠标右键,选择“段落”。在弹出的窗口中,选择行距固定值,然后设置值选择1磅。都设置好后,点击确定按钮保存设置。这时候就会发现多出的空格被删掉,相对应的空白页也没有了。

    a74d8159473702c3e0f41ac7e0754fb1.png

    展开全文
  • 由于POI本身在处理docx文档上不完善,...这里,分享个Demo项目,动态生成文档,并巧妙删除空白。代码中含docx4j的可去除,其分页效果差,至于使用BlockPage对象需导个Plutext-Enterprise的包,网上压根找不到。
  • 使用java Apache poi 根据word模板生成word报表

    万次阅读 多人点赞 2018-03-24 16:19:37
    使用java Apache poi 根据word模板生成word报表 使用poi读取word模板,替换word中的{text}标签,并根据自定义标签循环生成表格或表格中的行。 代码示例下载:...

    使用java Apache poi 根据word模板生成word报表

    使用poi读取word模板,替换word中的{text}标签,并根据自定义标签循环生成表格或表格中的行。
    代码示例下载:https://download.csdn.net/download/u012775558/10306308
    注意,仅支持docx格式的word文件,大概是word2010及以后版本,doc格式不支持。

    word模板需要有固定的格式

    这是表格内部循环生成行的例子。
    注意:
    1.表格第一行通过合并单元格的方式,设置为只有两个单元格,第一个单元格填写foreachTableRow标签,第二个单元格填写要替换的数据List名称,本例中是table1或table2,注意名称要和你后台wordDataMap中存入的key值相同。
    2.表格第二行是表头。
    3.表格第三行需要通过合并单元格的方式,设置为只有一个单元格,填写上foreachRows标签,代表从这一行以下开始循环替换。
    4.表格第四行是要替换的数据,在map中的key值。

    你也可以给行加上序号,但是不能直接输入序号,而是通过word的插入编号的功能插入编号,生成的表格才会有编号。

    可以给表格加上表头和表尾数据,只需要把数据放入parametersMap(存储报表中不循环的数据)中即可。

    这是循环生成表格的例子。
    注意:
    1.表格第一行通过合并单元格的方式,设置为只有两个单元格,第一个单元格填写foreachTable标签,第二个单元格填写要替换的数据List名称,本例中是table1。
    2.表格其他部分只需要将要替换的数据用标签替换即可。

    效果图如下:
    - 模板文件
    这里写图片描述
    这里写图片描述

    这里写图片描述

    • 生成文件

    这里写图片描述

    这里写图片描述

    这里写图片描述


    使用maven搭建项目,引入poi相关jar包。

    <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>3.13</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>3.13</version>
            </dependency>

    代码如下

    • 工具类 WordTemplate

    /**
     * @Title: WordTemplate2.java
     * @Package: com.highdata.templateTools
     * @Description: TODO
     * @author: Juveniless
     * @date: 2017年11月27日 下午3:23:13
     */
    package com.hidata.tool;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    import org.apache.poi.xwpf.usermodel.BodyElementType;
    import org.apache.poi.xwpf.usermodel.IBodyElement;
    import org.apache.poi.xwpf.usermodel.PositionInParagraph;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.apache.poi.xwpf.usermodel.XWPFParagraph;
    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;
    
    /**
     *
     * 对docx文件中的文本及表格中的内容进行替换 --模板仅支持对 {key} 标签的替换
     *
     * @ClassName: WordTemplate
     * @Description: TODO(!!!使用word2013 docx文件)
     * @author Juveniless
     * @date: 2017年11月27日 下午3:25:56
     * <br>(1)word模板注意页边距的问题,存在问题:比如页边距默认为3cm,画表格时,仍然可以通过
     * 拖拽,把表格边框拖动到看起来就像页边距只有1cm的样子,但是实际上此时页边距还是3cm,生成的
     * word报表的页边距还是会按照3cm来生成。解决办法,在word文件里,设置好页边距,如果需要表格
     * 两边页边距很窄,需要在word里设置页边距窄一点,而不是直接拖动表格边框来实现。
     *
     */
    
    public class WordTemplate {
    
        private XWPFDocument document;
    
        public XWPFDocument getDocument() {
            return document;
        }
    
        public void setDocument(XWPFDocument document) {
            this.document = document;
        }
    
        /**
         * 初始化模板内容
         *
         * @author Juveniless
         * @date 2017年11月27日 下午3:59:22
         * @param inputStream
         *            模板的读取流(docx文件)
         * @throws IOException
         *
         */
        public WordTemplate(InputStream inputStream) throws IOException {
            document = new XWPFDocument(inputStream);
        }
    
        /**
         * 将处理后的内容写入到输出流中
         *
         * @param outputStream
         * @throws IOException
         */
        public void write(OutputStream outputStream) throws IOException {
            document.write(outputStream);
        }
    
    
    
    
    
        /**
         * 根据dataMap对word文件中的标签进行替换; <br><br>
         * !!!!***需要注意dataMap的数据格式***!!!! <br><br>
         * 对于需要替换的普通标签数据标签(不需要循环)-----必须在dataMap中存储一个key为parametersMap的map,
         * 来存储这些不需要循环生成的数据,比如:表头信息,日期,制表人等。 <br><br>
         * 对于需要循环生成的表格数据------key自定义,value为 --ArrayList&lt;Map&lt;String, String>>
         * @author Juveniless
         * @date 2017年11月27日 下午3:29:27
         * @param dataMap
         *
         */
        public void replaceDocument(Map<String, Object> dataMap) {
    
            if (!dataMap.containsKey("parametersMap")) {
                System.out.println("数据源错误--数据源(parametersMap)缺失");
                return;
            }
            @SuppressWarnings("unchecked")
            Map<String, Object> parametersMap = (Map<String, Object>) dataMap
                    .get("parametersMap");
    
            List<IBodyElement> bodyElements = document.getBodyElements();// 所有对象(段落+表格)
            int templateBodySize = bodyElements.size();// 标记模板文件(段落+表格)总个数
    
            int curT = 0;// 当前操作表格对象的索引
            int curP = 0;// 当前操作段落对象的索引
            for (int a = 0; a < templateBodySize; a++) {
                IBodyElement body = bodyElements.get(a);
                if (BodyElementType.TABLE.equals(body.getElementType())) {// 处理表格
                    XWPFTable table = body.getBody().getTableArray(curT);
    
                    List<XWPFTable> tables = body.getBody().getTables();
                    table = tables.get(curT);
                    if (table != null) {
    
                        // 处理表格
                        List<XWPFTableCell> tableCells = table.getRows().get(0).getTableCells();// 获取到模板表格第一行,用来判断表格类型
                        String tableText = table.getText();// 表格中的所有文本
    
                        if (tableText.indexOf("##{foreach") > -1) {
                            // 查找到##{foreach标签,该表格需要处理循环
                            if (tableCells.size() != 2
                                    || tableCells.get(0).getText().indexOf("##{foreach") < 0
                                    || tableCells.get(0).getText().trim().length() == 0) {
                                System.out
                                        .println("文档中第"
                                                + (curT + 1)
                                                + "个表格模板错误,模板表格第一行需要设置2个单元格,"
                                                + "第一个单元格存储表格类型(##{foreachTable}## 或者 ##{foreachTableRow}##),第二个单元格定义数据源。");
                                return;
                            }
    
                            String tableType = tableCells.get(0).getText();
                            String dataSource = tableCells.get(1).getText();
                            System.out.println("读取到数据源:"+dataSource);
                            if (!dataMap.containsKey(dataSource)) {
                                System.out.println("文档中第" + (curT + 1) + "个表格模板数据源缺失");
                                return;
                            }
                            @SuppressWarnings("unchecked")
                            List<Map<String, Object>> tableDataList = (List<Map<String, Object>>) dataMap
                                    .get(dataSource);
                            if ("##{foreachTable}##".equals(tableType)) {
                                // System.out.println("循环生成表格");
                                addTableInDocFooter(table, tableDataList, parametersMap, 1);
    
                            } else if ("##{foreachTableRow}##".equals(tableType)) {
                                // System.out.println("循环生成表格内部的行");
                                addTableInDocFooter(table, tableDataList, parametersMap, 2);
                            }
    
                        } else if (tableText.indexOf("{") > -1) {
                            // 没有查找到##{foreach标签,查找到了普通替换数据的{}标签,该表格只需要简单替换
                            addTableInDocFooter(table, null, parametersMap, 3);
                        } else {
                            // 没有查找到任何标签,该表格是一个静态表格,仅需要复制一个即可。
                            addTableInDocFooter(table, null, null, 0);
                        }
                        curT++;
    
                    }
                } else if (BodyElementType.PARAGRAPH.equals(body.getElementType())) {// 处理段落
                    // System.out.println("获取到段落");
                    XWPFParagraph ph = body.getBody().getParagraphArray(curP);
                    if (ph != null) {
                        // htmlText = htmlText+readParagraphX(ph);
                        addParagraphInDocFooter(ph, null, parametersMap, 0);
    
                        curP++;
                    }
                }
    
            }
            // 处理完毕模板,删除文本中的模板内容
            for (int a = 0; a < templateBodySize; a++) {
                document.removeBodyElement(0);
            }
    
        }
    
    
    
    
    
    
    
    
        /**
         * 根据 模板表格 和 数据list 在word文档末尾生成表格
         * @author Juveniless
         * @date 2017年12月6日 上午10:12:05
         * @param templateTable 模板表格
         * @param list   循环数据集
         * @param parametersMap  不循环数据集
         * @param flag   (0为静态表格,1为表格整体循环,2为表格内部行循环,3为表格不循环仅简单替换标签即可)
         *
         */
        public void addTableInDocFooter(XWPFTable templateTable, List<Map<String, Object>> list,
                Map<String, Object> parametersMap, int flag) {
    
            if (flag == 1) {// 表格整体循环
                for (Map<String, Object> map : list) {
                    List<XWPFTableRow> templateTableRows = templateTable.getRows();// 获取模板表格所有行
                    XWPFTable newCreateTable = document.createTable();// 创建新表格,默认一行一列
                    for (int i = 1; i < templateTableRows.size(); i++) {
                        XWPFTableRow newCreateRow = newCreateTable.createRow();
                        CopyTableRow(newCreateRow, templateTableRows.get(i));// 复制模板行文本和样式到新行
                    }
                    newCreateTable.removeRow(0);// 移除多出来的第一行
                    document.createParagraph();// 添加回车换行
                    replaceTable(newCreateTable, map);//替换标签
                }
    
            } else if (flag == 2) {// 表格表格内部行循环
                XWPFTable newCreateTable = document.createTable();// 创建新表格,默认一行一列
                List<XWPFTableRow> TempTableRows = templateTable.getRows();// 获取模板表格所有行
                int tagRowsIndex = 0;// 标签行indexs
                for (int i = 0, size = TempTableRows.size(); i < size; i++) {
                    String rowText = TempTableRows.get(i).getCell(0).getText();// 获取到表格行的第一个单元格
                    if (rowText.indexOf("##{foreachRows}##") > -1) {
                        tagRowsIndex = i;
                        break;
                    }
                }
    
                /* 复制模板行和标签行之前的行 */
                for (int i = 1; i < tagRowsIndex; i++) {
                    XWPFTableRow newCreateRow = newCreateTable.createRow();
                    CopyTableRow(newCreateRow, TempTableRows.get(i));// 复制行
                    replaceTableRow(newCreateRow, parametersMap);// 处理不循环标签的替换
                }
    
                /* 循环生成模板行 */
                XWPFTableRow tempRow = TempTableRows.get(tagRowsIndex + 1);// 获取到模板行
                for (int i = 0; i < list.size(); i++) {
                    XWPFTableRow newCreateRow = newCreateTable.createRow();
                    CopyTableRow(newCreateRow, tempRow);// 复制模板行
                    replaceTableRow(newCreateRow, list.get(i));// 处理标签替换
                }
    
                /* 复制模板行和标签行之后的行 */
                for (int i = tagRowsIndex + 2; i < TempTableRows.size(); i++) {
                    XWPFTableRow newCreateRow = newCreateTable.createRow();
                    CopyTableRow(newCreateRow, TempTableRows.get(i));// 复制行
                    replaceTableRow(newCreateRow, parametersMap);// 处理不循环标签的替换
                }
                newCreateTable.removeRow(0);// 移除多出来的第一行
                document.createParagraph();// 添加回车换行
    
            } else if (flag == 3) {
                //表格不循环仅简单替换标签
                List<XWPFTableRow> templateTableRows = templateTable.getRows();// 获取模板表格所有行
                XWPFTable newCreateTable = document.createTable();// 创建新表格,默认一行一列
                for (int i = 0; i < templateTableRows.size(); i++) {
                    XWPFTableRow newCreateRow = newCreateTable.createRow();
                    CopyTableRow(newCreateRow, templateTableRows.get(i));// 复制模板行文本和样式到新行
                }
                newCreateTable.removeRow(0);// 移除多出来的第一行
                document.createParagraph();// 添加回车换行
                replaceTable(newCreateTable, parametersMap);
    
            } else if (flag == 0) {
                List<XWPFTableRow> templateTableRows = templateTable.getRows();// 获取模板表格所有行
                XWPFTable newCreateTable = document.createTable();// 创建新表格,默认一行一列
                for (int i = 0; i < templateTableRows.size(); i++) {
                    XWPFTableRow newCreateRow = newCreateTable.createRow();
                    CopyTableRow(newCreateRow, templateTableRows.get(i));// 复制模板行文本和样式到新行
                }
                newCreateTable.removeRow(0);// 移除多出来的第一行
                document.createParagraph();// 添加回车换行
            }
    
        }
    
    
    
    
    
    
        /**
         * 根据 模板段落 和 数据 在文档末尾生成段落
         *
         * @author Juveniless
         * @date 2017年11月27日 上午11:49:42
         * @param templateParagraph
         *            模板段落
         * @param list
         *            循环数据集
         * @param parametersMap
         *            不循环数据集
         * @param flag
         *            (0为不循环替换,1为循环替换)
         *
         */
        public void addParagraphInDocFooter(XWPFParagraph templateParagraph,
                List<Map<String, String>> list, Map<String, Object> parametersMap, int flag) {
    
            if (flag == 0) {
                XWPFParagraph createParagraph = document.createParagraph();
                // 设置段落样式
                createParagraph.getCTP().setPPr(templateParagraph.getCTP().getPPr());
                // 移除原始内容
                for (int pos = 0; pos < createParagraph.getRuns().size(); pos++) {
                    createParagraph.removeRun(pos);
                }
                // 添加Run标签
                for (XWPFRun s : templateParagraph.getRuns()) {
                    XWPFRun targetrun = createParagraph.createRun();
                    CopyRun(targetrun, s);
                }
    
                replaceParagraph(createParagraph, parametersMap);
    
            } else if (flag == 1) {
                // 暂无实现
            }
    
        }
    
    
    
    
        /**
         * 根据map替换段落元素内的{**}标签
         * @author Juveniless
         * @date 2017年12月4日 下午3:09:00
         * @param xWPFParagraph
         * @param parametersMap
         *
         */
        public void replaceParagraph(XWPFParagraph xWPFParagraph, Map<String, Object> parametersMap) {
            List<XWPFRun> runs = xWPFParagraph.getRuns();
            String xWPFParagraphText = xWPFParagraph.getText();
            String regEx = "\\{.+?\\}";
            Pattern pattern = Pattern.compile(regEx);
            Matcher matcher = pattern.matcher(xWPFParagraphText);//正则匹配字符串{****}
    
            if (matcher.find()) {
                // 查找到有标签才执行替换
                int beginRunIndex = xWPFParagraph.searchText("{", new PositionInParagraph()).getBeginRun();// 标签开始run位置
                int endRunIndex = xWPFParagraph.searchText("}", new PositionInParagraph()).getEndRun();// 结束标签
                StringBuffer key = new StringBuffer();
    
                if (beginRunIndex == endRunIndex) {
                    // {**}在一个run标签内
                    XWPFRun beginRun = runs.get(beginRunIndex);
                    String beginRunText = beginRun.text();
    
                    int beginIndex = beginRunText.indexOf("{");
                    int endIndex = beginRunText.indexOf("}");
                    int length = beginRunText.length();
    
                    if (beginIndex == 0 && endIndex == length - 1) {
                        // 该run标签只有{**}
                        XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex);
                        insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr());
                        // 设置文本
                        key.append(beginRunText.substring(1, endIndex));
                        insertNewRun.setText(getValueBykey(key.toString(),parametersMap));
                        xWPFParagraph.removeRun(beginRunIndex + 1);
                    } else {
                        // 该run标签为**{**}** 或者 **{**} 或者{**}**,替换key后,还需要加上原始key前后的文本
                        XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex);
                        insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr());
                        // 设置文本
                        key.append(beginRunText.substring(beginRunText.indexOf("{")+1, beginRunText.indexOf("}")));
                        String textString=beginRunText.substring(0, beginIndex) + getValueBykey(key.toString(),parametersMap)
                                + beginRunText.substring(endIndex + 1);
                        insertNewRun.setText(textString);
                        xWPFParagraph.removeRun(beginRunIndex + 1);
                    }
    
                }else {
                    // {**}被分成多个run
    
                    //先处理起始run标签,取得第一个{key}值
                    XWPFRun beginRun = runs.get(beginRunIndex);
                    String beginRunText = beginRun.text();
                    int beginIndex = beginRunText.indexOf("{");
                    if (beginRunText.length()>1  ) {
                        key.append(beginRunText.substring(beginIndex+1));
                    }
                    ArrayList<Integer> removeRunList = new ArrayList<>();//需要移除的run
                    //处理中间的run
                    for (int i = beginRunIndex + 1; i < endRunIndex; i++) {
                        XWPFRun run = runs.get(i);
                        String runText = run.text();
                        key.append(runText);
                        removeRunList.add(i);
                    }
    
                    // 获取endRun中的key值
                    XWPFRun endRun = runs.get(endRunIndex);
                    String endRunText = endRun.text();
                    int endIndex = endRunText.indexOf("}");
                    //run中**}或者**}**
                    if (endRunText.length()>1 && endIndex!=0) {
                        key.append(endRunText.substring(0,endIndex));
                    }
    
    
    
                    //*******************************************************************
                    //取得key值后替换标签
    
                    //先处理开始标签
                    if (beginRunText.length()==2 ) {
                        // run标签内文本{
                        XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex);
                        insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr());
                        // 设置文本
                        insertNewRun.setText(getValueBykey(key.toString(),parametersMap));
                        xWPFParagraph.removeRun(beginRunIndex + 1);//移除原始的run
                    }else {
                        // 该run标签为**{**或者 {** ,替换key后,还需要加上原始key前的文本
                        XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex);
                        insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr());
                        // 设置文本
                        String textString=beginRunText.substring(0,beginRunText.indexOf("{"))+getValueBykey(key.toString(),parametersMap);
                        insertNewRun.setText(textString);
                        xWPFParagraph.removeRun(beginRunIndex + 1);//移除原始的run
                    }
    
                    //处理结束标签
                    if (endRunText.length()==1 ) {
                        // run标签内文本只有}
                        XWPFRun insertNewRun = xWPFParagraph.insertNewRun(endRunIndex);
                        insertNewRun.getCTR().setRPr(endRun.getCTR().getRPr());
                        // 设置文本
                        insertNewRun.setText("");
                        xWPFParagraph.removeRun(endRunIndex + 1);//移除原始的run
    
                    }else {
                        // 该run标签为**}**或者 }** 或者**},替换key后,还需要加上原始key后的文本
                        XWPFRun insertNewRun = xWPFParagraph.insertNewRun(endRunIndex);
                        insertNewRun.getCTR().setRPr(endRun.getCTR().getRPr());
                        // 设置文本
                        String textString=endRunText.substring(endRunText.indexOf("}")+1);
                        insertNewRun.setText(textString);
                        xWPFParagraph.removeRun(endRunIndex + 1);//移除原始的run
                    }
    
                    //处理中间的run标签
                    for (int i = 0; i < removeRunList.size(); i++) {
                        XWPFRun xWPFRun = runs.get(removeRunList.get(i));//原始run
                        XWPFRun insertNewRun = xWPFParagraph.insertNewRun(removeRunList.get(i));
                        insertNewRun.getCTR().setRPr(xWPFRun.getCTR().getRPr());
                        insertNewRun.setText("");
                        xWPFParagraph.removeRun(removeRunList.get(i) + 1);//移除原始的run
                    }
    
                }// 处理${**}被分成多个run
    
                replaceParagraph( xWPFParagraph, parametersMap);
    
            }//if 有标签
    
        }
    
    
    
    
    
    
    
    
        /**
         * 复制表格行XWPFTableRow格式
         *
         * @param target
         *            待修改格式的XWPFTableRow
         * @param source
         *            模板XWPFTableRow
         */
        private void CopyTableRow(XWPFTableRow target, XWPFTableRow source) {
    
            int tempRowCellsize = source.getTableCells().size();// 模板行的列数
            for (int i = 0; i < tempRowCellsize - 1; i++) {
                target.addNewTableCell();// 为新添加的行添加与模板表格对应行行相同个数的单元格
            }
            // 复制样式
            target.getCtRow().setTrPr(source.getCtRow().getTrPr());
            // 复制单元格
            for (int i = 0; i < target.getTableCells().size(); i++) {
                copyTableCell(target.getCell(i), source.getCell(i));
            }
        }
    
    
    
    
    
        /**
         * 复制单元格XWPFTableCell格式
         *
         * @author Juveniless
         * @date 2017年11月27日 下午3:41:02
         * @param newTableCell
         *            新创建的的单元格
         * @param templateTableCell
         *            模板单元格
         *
         */
        private void copyTableCell(XWPFTableCell newTableCell, XWPFTableCell templateTableCell) {
            // 列属性
            newTableCell.getCTTc().setTcPr(templateTableCell.getCTTc().getTcPr());
            // 删除目标 targetCell 所有文本段落
            for (int pos = 0; pos < newTableCell.getParagraphs().size(); pos++) {
                newTableCell.removeParagraph(pos);
            }
            // 添加新文本段落
            for (XWPFParagraph sp : templateTableCell.getParagraphs()) {
                XWPFParagraph targetP = newTableCell.addParagraph();
                copyParagraph(targetP, sp);
            }
        }
    
        /**
         * 复制文本段落XWPFParagraph格式
         *
         * @author Juveniless
         * @date 2017年11月27日 下午3:43:08
         * @param newParagraph
         *            新创建的的段落
         * @param templateParagraph
         *            模板段落
         *
         */
        private void copyParagraph(XWPFParagraph newParagraph, XWPFParagraph templateParagraph) {
            // 设置段落样式
            newParagraph.getCTP().setPPr(templateParagraph.getCTP().getPPr());
            // 添加Run标签
            for (int pos = 0; pos < newParagraph.getRuns().size(); pos++) {
                newParagraph.removeRun(pos);
    
            }
            for (XWPFRun s : templateParagraph.getRuns()) {
                XWPFRun targetrun = newParagraph.createRun();
                CopyRun(targetrun, s);
            }
    
        }
    
        /**
         * 复制文本节点run
         * @author Juveniless
         * @date 2017年11月27日 下午3:47:17
         * @param newRun
         *            新创建的的文本节点
         * @param templateRun
         *            模板文本节点
         *
         */
        private void CopyRun(XWPFRun newRun, XWPFRun templateRun) {
            newRun.getCTR().setRPr(templateRun.getCTR().getRPr());
            // 设置文本
            newRun.setText(templateRun.text());
    
    
        }
    
    
    
    
        /**
         * 根据参数parametersMap对表格的一行进行标签的替换
         *
         * @author Juveniless
         * @date 2017年11月23日 下午2:09:24
         * @param tableRow
         *            表格行
         * @param parametersMap
         *            参数map
         *
         */
        public void replaceTableRow(XWPFTableRow tableRow, Map<String, Object> parametersMap) {
    
            List<XWPFTableCell> tableCells = tableRow.getTableCells();
            for (XWPFTableCell xWPFTableCell : tableCells) {
                List<XWPFParagraph> paragraphs = xWPFTableCell.getParagraphs();
                for (XWPFParagraph xwpfParagraph : paragraphs) {
    
                    replaceParagraph(xwpfParagraph, parametersMap);
                }
            }
    
        }
    
    
    
    
    
        /**
         * 根据map替换表格中的{key}标签
         * @author Juveniless
         * @date 2017年12月4日 下午2:47:36
         * @param xwpfTable
         * @param parametersMap
         *
         */
        public void replaceTable(XWPFTable xwpfTable,Map<String, Object> parametersMap){
            List<XWPFTableRow> rows = xwpfTable.getRows();
            for (XWPFTableRow xWPFTableRow : rows ) {
                List<XWPFTableCell> tableCells = xWPFTableRow.getTableCells();
                for (XWPFTableCell xWPFTableCell : tableCells ) {
                    List<XWPFParagraph> paragraphs2 = xWPFTableCell.getParagraphs();
                    for (XWPFParagraph xWPFParagraph : paragraphs2) {
                        replaceParagraph(xWPFParagraph, parametersMap);
                    }
                }
            }
    
        }
    
    
    
        private String getValueBykey(String key, Map<String, Object> map) {
            String returnValue="";
            if (key != null) {
                try {
                    returnValue=map.get(key)!=null ? map.get(key).toString() : "";
                } catch (Exception e) {
                    // TODO: handle exception
                    System.out.println("key:"+key+"***"+e);
                    returnValue="";
                }
    
            }
            return returnValue;
        }
    
    
    
    
    
    
    
    
    }
    
    • 使用

    package com.hidata.tool;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class Test {
    
        public static void main(String[] args) throws IOException {
    
            Map<String, Object> wordDataMap = new HashMap<String, Object>();// 存储报表全部数据
            Map<String, Object> parametersMap = new HashMap<String, Object>();// 存储报表中不循环的数据
    
    
    
            List<Map<String, Object>> table1 = new ArrayList<Map<String, Object>>();
            Map<String, Object> map1=new HashMap<>();
            map1.put("name", "张三");
            map1.put("age", "23");
            map1.put("email", "12121@qq.com");
    
            Map<String, Object> map2=new HashMap<>();
            map2.put("name", "李四");
            map2.put("age", "45");
            map2.put("email", "45445@qq.com");
    
            Map<String, Object> map3=new HashMap<>();
            map3.put("name", "Tom");
            map3.put("age", "34");
            map3.put("email", "6767@qq.com");
    
            table1.add(map1);
            table1.add(map2);
            table1.add(map3);
    
    
    
    
            List<Map<String, Object>> table2 = new ArrayList<Map<String, Object>>();
            Map<String, Object> map4=new HashMap<>();
            map4.put("name", "tom");
            map4.put("number", "sd1234");
            map4.put("address", "上海");
    
            Map<String, Object> map5=new HashMap<>();
            map5.put("name", "seven");
            map5.put("number", "sd15678");
            map5.put("address", "北京");
    
            Map<String, Object> map6=new HashMap<>();
            map6.put("name", "lisa");
            map6.put("number", "sd9078");
            map6.put("address", "广州");
    
            table2.add(map4);
            table2.add(map5);
            table2.add(map6);
    
    
    
            parametersMap.put("userName", "JUVENILESS");
            parametersMap.put("time", "2018-03-24");
            parametersMap.put("sum", "3");
    
    
            wordDataMap.put("table1", table1);
            wordDataMap.put("table2", table2);
            wordDataMap.put("parametersMap", parametersMap);
            File file = new File("D:\\Workspaces\\Eclipse 2017\\wordTemplate\\doc\\模板.docx");//改成你本地文件所在目录
    
    
            // 读取word模板
            FileInputStream fileInputStream = new FileInputStream(file);
            WordTemplate template = new WordTemplate(fileInputStream);
    
            // 替换数据
            template.replaceDocument(wordDataMap);
    
    
            //生成文件
            File outputFile=new File("D:\\Workspaces\\Eclipse 2017\\wordTemplate\\doc\\输出.docx");//改成你本地文件所在目录
            FileOutputStream fos  = new FileOutputStream(outputFile);
            template.getDocument().write(fos);
    
        }
    
    }
    
    展开全文
  • java实现word模板导出

    2021-04-19 16:13:33
    java实现word模板导出 以下文档为例 方案 通过freemarker模板引擎 步骤 1.制作模板 使用freemark语法填充变量 另存为xml格式 使用记事本工具检查${}是否连贯,把中间的内容删除即可 在循环处增加<#list 集合名 ...

    java实现word模板导出

    以下文档为例
    在这里插入图片描述

    方案一 通过freemarker模板引擎

    步骤
    1.制作模板
    使用freemark语法填充变量
    在这里插入图片描述

    另存为xml格式
    在这里插入图片描述

    使用记事本工具检查${}是否连贯,把中间的内容删除即可
    在这里插入图片描述

    在循环处增加<#list 集合名 as 变量名></#list>
    在这里插入图片描述
    在这里插入图片描述

    将xml文件的后缀改为.ftl

    2.代码实现

    添加依赖

    <!--freemark模板引擎-->
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.28</version>
    </dependency>
    
    @RestController
    @RequestMapping("/word")
    public class WordExportController {
        @GetMapping("/export")
        public void wordExport(HttpServletResponse response) {
            Map<String, Object> data = new HashMap<>();
            data.put("name", "年终总结大会");
            data.put("place", "第一会议室");
            data.put("time", "2021年3月25日");
            data.put("sponsor", "张三");
            List<User> users = Lists.newArrayList(
                    new User("张三", "组织部", "10:00"),
                    new User("李四", "宣传部", "10:00"));
            data.put("userList", users);
            FreeMarkerUtil.createLocalDoc(data, response);
        }
    }
    
    public static void createLocalDoc(Map<String, Object> data, HttpServletResponse response) {
        try {
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/msword");
            response.setHeader("Content-disposition", "attachment;filename=" + new String("会议签到表".getBytes("utf-8"), "ISO8859-1"));
            Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
            configuration.setDefaultEncoding("UTF-8");
            configuration.setDirectoryForTemplateLoading(new File("C:\\Users\\luban\\Desktop"));
            Template template = configuration.getTemplate("test.ftl");
            OutputStreamWriter writer = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
            template.process(data, writer);
            writer.flush();
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
            log.info("生成word文档发生异常<{}>", e.getMessage());
        }
    }
    

    3.效果如下
    在这里插入图片描述

    4.补充
    以上方法导出的word文档直接用ms打开没什么问题,但是要再java中使用pdf转换还是不行,因为其本质上还是一个xml文件,所以需要结合zip文件将其转换为word对应格式
    另存为mht(包含富文本必须用此格式) 或者word xml
    使用这种方法对普通变量,少量图片处理基本没啥问题
    需要使用远程模板参考https://blog.csdn.net/MrSpirit/article/details/100770060
    word标签解析参考https://blog.csdn.net/renfufei/article/details/77481753

    方案二 Xdocreport和Freemaker生成docx

    只使用freemaker生成简单的word文档很容易,但是当word文档需要插入动态图片,带循环数据,且含有富文本时解决起来相对比较复杂,但是使用Xdocreport可以轻易解决。
    Xdocreport既可以实现文档填充也可以实现文档转换,此处只介绍其文档填充功能。
    源码地址;https://github.com/opensagres/xdocreport
    文档地址:https://github.com/opensagres/xdocreport/wiki/GettingStarted
    步骤:
    1.制作模板
    以以下文档为例
    在这里插入图片描述

    会议内容为一段富文本
    我们需要在变量替换的位置通过快捷键Ctrl+F9 或 工具栏“插入”->“文档部件或文本”->“域”
    在这里插入图片描述

    选择邮件合并,添加对应属性

    在这里插入图片描述
    在这里插入图片描述

    遇到需要循环的位置
    在第一列的里
    在这里插入图片描述

    “@before-row[#list userList as user]”
    @after-row[/#list]
    遇到图片,先插入一张图片,再为图片添加书签

    在这里插入图片描述
    在这里插入图片描述

    这样模板就制作完成,不需要保存为xml,ftl。直接使用doc或者docx后缀即可
    2.代码实现
    引入依赖

    <dependency>
        <groupId>fr.opensagres.xdocreport</groupId>
        <artifactId>xdocreport</artifactId>
        <version>2.0.2</version>
    </dependency>
    

    核心代码

    public static void createXdocreport() {
            try {
                //使用远程模板
    //            InputStream inputStream = new URL(templateUrl).openConnection().getInputStream();
                File inputPath = new File("C:\\Users\\luban\\Desktop\\summary.docx");
                FileInputStream inputStream = new FileInputStream(inputPath);
                File outputPath = new File("C:\\Users\\luban\\Desktop\\test.docx");
                FileOutputStream outputStream = new FileOutputStream(outputPath);
                IXDocReport report = XDocReportRegistry
                        .getRegistry()
                        .loadReport(inputStream, TemplateEngineKind.Freemarker);
                // 设置特殊字段
                FieldsMetadata metadata = report.createFieldsMetadata();
                metadata.addFieldAsTextStyling("content", SyntaxKind.Html);
                metadata.addFieldAsImage("avatar", "user.avatar", NullImageBehaviour.RemoveImageTemplate);
                report.setFieldsMetadata(metadata);
                // 创建内容-text为模版中对应都变量名称
                String content = "&#x3c;p&#x3e;我在这里放了一段富文本&#x3c;/p&#x3e;" +
                        "&#x3c;p&#x3e;我准备测试富文本的处理&#x3c;/p&#x3e;";
                content = HtmlUtils.htmlUnescape(content);
                IContext context = report.createContext();
                context.put("name", "年终总结大会");
                context.put("time", "2021年3月26日");
                context.put("place", "线上");
                context.put("sponsor", "张三");
                context.put("content", content);
                //图片这里放图片的输入流
                InputStream p1 = new FileInputStream(new File("C:\\Users\\luban\\Desktop\\图片1.png"));
                InputStream p2 = new FileInputStream(new File("C:\\Users\\luban\\Desktop\\图片2.jpg"));
                List<UserAvatar> users = Lists.newArrayList(
                        new UserAvatar("张三", "组织部", new ByteArrayImageProvider(p1)),
                        new UserAvatar("李四", "宣传部", new ByteArrayImageProvider(p2)));
                context.put("userList", users);
                // 生成文件
                report.process(context, outputStream);
                inputStream.close();
                outputStream.close();
            } catch (Exception e) {
                log.info("生成纪要文件发生异常:<{}>", e.getMessage());
            }
        }
    

    测试

    public static void main(String[] args) {
        createXdocreport();
    }
    

    效果如下
    在这里插入图片描述

    源码地址
    https://github.com/lubanjune/word-export.git
    参考博文
    https://blog.csdn.net/renfufei/article/details/53283320
    https://blog.csdn.net/weixin_44569204/article/details/86543711
    https://blog.csdn.net/erpenggg/article/details/106714402

    展开全文
  • /** * @program demo01 * @description 核心工具类 * @author: Sun Jinxin * @create: 2021/11/30 14:50 */ public class WorderToNewWordUtils { /** * 根据模板生成word文档 * * @param inputUrl 模板路径 * @...


    在这里插入图片描述



    核心依赖

            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi</artifactId>
                <version>3.9</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>3.7</version>
            </dependency>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml-schemas</artifactId>
                <version>3.9</version>
            </dependency>
    

    动态表格

    测试类

    package com.uncle.demo.poi;
    
    
    import java.io.FileOutputStream;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import static java.lang.System.out;
    
    /**
     * @program demo01
     * @description 测试工具类
     * @author: Sun Jinxin
     * @create: 2021/11/30 14:50
     */
    public class Test {
    
        public static void main(String[] args){
            //需要进行文本替换的信息
            Map<String, Object> data = new HashMap<String, Object>();
            data.put("name", "维维豆奶粉");
    
            //需要进行动态生成的信息
            Map<String,Object> mapList = new HashMap<String, Object>();
    
            //第一个动态生成的数据列表
            List<String[]> list01 = new ArrayList<String[]>();
            list01.add(new String[]{"1","维修服务","1","6100333","2020/8/4","1、更换鼠标 \n" + "2、更换头托垫\n","设备运行正常","1.鼠标"});
            list01.add(new String[]{"2","售后服务","2","6107986","2020/10/28","相关校正","设备运行正常","1.鼠标\n" + "2.头托垫\n"});
            list01.add(new String[]{"3","售后服务","2","6100922","2020/11/15","1、更换鼠标 \n" + "2、更换头托垫\n","设备运行正常","1.鼠标"});
            list01.add(new String[]{"4","回退服务","3","6100922","2020/11/15","1、更换鼠标 \n" + "2、更换头托垫\n","设备运行正常","1.鼠标"});
            list01.add(new String[]{"5","回退服务","3","6100922","2020/11/15","1、更换鼠标 \n" + "2、更换头托垫\n","设备运行正常","1.鼠标"});
            list01.add(new String[]{"6","回退服务","3","6100922","2020/11/15","1、更换鼠标 \n" + "2、更换头托垫\n","设备运行正常","1.鼠标"});
    
            mapList.put("list01", list01);
    
            CustomXWPFDocument doc = WorderToNewWordUtils.changWord("C:\\Users\\sunjinxin\\Downloads\\project-office-temp-tool\\project-office-temp-tool\\demo01\\src\\main\\resources\\templates\\test1.docx",data,mapList);
            try (FileOutputStream fopts = new FileOutputStream("D:/呵呵.docx")) {
    
                doc.write(fopts);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            out.println("成功!!!");
        }
    }
    
    

    工具类

    package com.uncle.demo.poi;
    
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;
    
    import org.apache.poi.POIXMLDocument;
    import org.apache.poi.xwpf.usermodel.XWPFParagraph;
    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 org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
    
    /**
     * @program demo01
     * @description 核心工具类
     * @author: Sun Jinxin
     * @create: 2021/11/30 14:50
     */
    public class WorderToNewWordUtils {
        /**
         * 根据模板生成word文档
         *
         * @param inputUrl 模板路径
         * @param textMap  需要替换的文本内容
         * @param mapList  需要动态生成的内容
         * @return
         */
        public static CustomXWPFDocument changWord(String inputUrl, Map<String, Object> textMap, Map<String, Object> mapList) {
            CustomXWPFDocument document = null;
            try {
                //获取docx解析对象
                document = new CustomXWPFDocument(POIXMLDocument.openPackage(inputUrl));
    
                //解析替换文本段落对象
                WorderToNewWordUtils.changeText(document, textMap);
    
                //解析替换表格对象
                WorderToNewWordUtils.changeTable(document, textMap, mapList);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return document;
        }
    
        /**
         * 替换段落文本
         *
         * @param document docx解析对象
         * @param textMap  需要替换的信息集合
         */
        public static void changeText(CustomXWPFDocument document, Map<String, Object> textMap) {
            //获取段落集合
            List<XWPFParagraph> paragraphs = document.getParagraphs();
    
            for (XWPFParagraph paragraph : paragraphs) {
    
                //判断此段落时候需要进行替换
                String text = paragraph.getText();
                System.out.println(text);
                if (checkText(text)) {
                    List<XWPFRun> runs = paragraph.getRuns();
                    for (XWPFRun run : runs) {
                        run.setFontSize(8);
                        //替换模板原来位置
                        Object ob = changeValue(run.toString(), textMap);
                        if (ob instanceof String) {
                            run.setText((String) ob, 0);
                        }
                    }
                }
            }
        }
    
        /**
         * 替换表格对象方法
         *
         * @param document docx解析对象
         * @param textMap  需要替换的信息集合
         * @param mapList  需要动态生成的内容
         */
        public static void changeTable(CustomXWPFDocument document, Map<String, Object> textMap, Map<String, Object> mapList) {
            //获取表格对象集合
            List<XWPFTable> tables = document.getTables();
    
            //循环所有需要进行替换的文本,进行替换
            for (int i = 0; i < tables.size(); i++) {
                XWPFTable table = tables.get(i);
                if (checkText(table.getText())) {
                    List<XWPFTableRow> rows = table.getRows();
                    //遍历表格,并替换模板
                    eachTable(document, rows, textMap);
                }
            }
    
            List<String[]> list01 = (List<String[]>) mapList.get("list01");
            //操作word中的表格
            for (int i = 0; i < tables.size(); i++) {
                //只处理行数大于等于2的表格,且不循环表头
                XWPFTable table = tables.get(i);
                //第二个表格使用daList,插入数据
                //TODO
                if (null != list01 && 0 < list01.size() && i == 0) {
                    //TODO 处理第几个表格
                    insertTable(table, null, list01, 2);
    
                    int initFlag = 1;
                    int mergeRowNum = initFlag;
                    //获取第一条数据
                    String s1 = list01.get(0)[1];
                    for (int j = 0; j < list01.size(); j++) {
    
                        String s2 = list01.get(j)[1];
                        if (s1.equals(s2)) {
                            mergeRowNum++;
                            s1 = s2;
                        } else {
                            s1 = s2;
                            mergeCellVertically(table, 1, initFlag + 1, mergeRowNum);
                            mergeCellVertically(table, 2, initFlag + 1, mergeRowNum);
                            initFlag = mergeRowNum;
                            mergeRowNum = initFlag + 1;
                        }
                        if (j == list01.size() - 1) {
                            mergeCellVertically(table, 1, initFlag + 1, mergeRowNum);
                            mergeCellVertically(table, 2, initFlag + 1, mergeRowNum);
                        }
    
    
                    }
    
                }
            }
    
        }
    
    
        /**
         * 遍历表格
         *
         * @param rows    表格行对象
         * @param textMap 需要替换的信息集合
         */
        public static void eachTable(CustomXWPFDocument document, List<XWPFTableRow> rows, Map<String, Object> textMap) {
            for (XWPFTableRow row : rows) {
                List<XWPFTableCell> cells = row.getTableCells();
                for (XWPFTableCell cell : cells) {
                    //判断单元格是否需要替换
                    if (checkText(cell.getText())) {
                        List<XWPFParagraph> paragraphs = cell.getParagraphs();
                        for (XWPFParagraph paragraph : paragraphs) {
                            List<XWPFRun> runs = paragraph.getRuns();
                            for (XWPFRun run : runs) {
    
                                Object ob = changeValue(run.toString(), textMap);
                                if (ob instanceof String) {
                                    run.setText((String) ob, 0);
                                } else if (ob instanceof Map) {
    
                                    run.setText("", 0);
                                    Map pic = (Map) ob;
                                    int width = Integer.parseInt(pic.get("width").toString());
                                    int height = Integer.parseInt(pic.get("height").toString());
                                    int picType = getPictureType(pic.get("type").toString());
                                    byte[] byteArray = (byte[]) pic.get("content");
                                    ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);
                                    try {
                                        int ind = document.addPicture(byteInputStream, picType);
                                        document.createPicture(ind, width, height, paragraph);
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    
        /**
         * 为表格插入数据,行数不够添加新行
         *
         * @param table     需要插入数据的表格
         * @param tableList 第四个表格的插入数据
         * @param daList    第二个表格的插入数据
         * @param type      表格类型:1-第一个表格 2-第二个表格 3-第三个表格 4-第四个表格
         */
        public static void insertTable(XWPFTable table, List<String> tableList, List<String[]> daList, Integer type) {
            if (2 == type) {
                //创建行和创建需要的列
                for (int i = 0; i < daList.size(); i++) {
                    //添加一个新行
                    XWPFTableRow row = table.insertNewTableRow(i+2);
    
                    for (int j = 0; j < daList.get(0).length; j++) {
                        row.createCell();//添加第一个列
    
                    }
    
                }
    
                //创建行,根据需要插入的数据添加新行,不处理表头
                for (int i = 0; i < daList.size(); i++) {
                    List<XWPFTableCell> cells = table.getRow(i + 2).getTableCells();
    
                    for (int j = 0; j < cells.size(); j++) {
                        XWPFTableCell cell02 = cells.get(j);
    
                        cell02.setText(daList.get(i)[j]);
                    }
                }
            } else if (4 == type) {
                //插入表头下面第一行的数据
                for (int i = 0; i < tableList.size(); i++) {
                    XWPFTableRow row = table.createRow();
                    List<XWPFTableCell> cells = row.getTableCells();
                    cells.get(0).setText(tableList.get(i));
                }
            }
        }
    
        /**
         * 判断文本中时候包含$
         *
         * @param text 文本
         * @return 包含返回true, 不包含返回false
         */
        public static boolean checkText(String text) {
            boolean check = false;
            if (text.indexOf("$") != -1) {
                check = true;
            }
            return check;
        }
    
        /**
         * 匹配传入信息集合与模板
         *
         * @param value   模板需要替换的区域
         * @param textMap 传入信息集合
         * @return 模板需要替换区域信息集合对应值
         */
        public static Object changeValue(String value, Map<String, Object> textMap) {
            Set<Entry<String, Object>> textSets = textMap.entrySet();
            Object valu = "";
            for (Entry<String, Object> textSet : textSets) {
                //匹配模板与替换值 格式${key}
                String key = textSet.getKey();
                if (value.indexOf(key) != -1) {
                    valu = textSet.getValue();
                }
            }
            return valu;
        }
    
        /**
         * 将输入流中的数据写入字节数组
         *
         * @param in
         * @return
         */
        public static byte[] inputStream2ByteArray(InputStream in, boolean isClose) {
            byte[] byteArray = null;
            try {
                int total = in.available();
                byteArray = new byte[total];
                in.read(byteArray);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (isClose) {
                    try {
                        in.close();
                    } catch (Exception e2) {
                        System.out.println("关闭流失败");
                    }
                }
            }
            return byteArray;
        }
    
        /**
         * 根据图片类型,取得对应的图片类型代码
         *
         * @param picType
         * @return int
         */
        private static int getPictureType(String picType) {
            int res = CustomXWPFDocument.PICTURE_TYPE_PICT;
            if (picType != null) {
                if (picType.equalsIgnoreCase("png")) {
                    res = CustomXWPFDocument.PICTURE_TYPE_PNG;
                } else if (picType.equalsIgnoreCase("dib")) {
                    res = CustomXWPFDocument.PICTURE_TYPE_DIB;
                } else if (picType.equalsIgnoreCase("emf")) {
                    res = CustomXWPFDocument.PICTURE_TYPE_EMF;
                } else if (picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")) {
                    res = CustomXWPFDocument.PICTURE_TYPE_JPEG;
                } else if (picType.equalsIgnoreCase("wmf")) {
                    res = CustomXWPFDocument.PICTURE_TYPE_WMF;
                }
            }
            return res;
        }
    
        /**
         * 合并行
         *
         * @param table
         * @param col     需要合并的列
         * @param fromRow 开始行
         * @param toRow   结束行
         */
        public static void mergeCellVertically(XWPFTable table, int col, int fromRow, int toRow) {
            for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
                CTVMerge vmerge = CTVMerge.Factory.newInstance();
                if (rowIndex == fromRow) {
                    vmerge.setVal(STMerge.RESTART);
                } else {
                    vmerge.setVal(STMerge.CONTINUE);
                }
                XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
                CTTcPr tcPr = cell.getCTTc().getTcPr();
                if (tcPr != null) {
                    tcPr.setVMerge(vmerge);
                } else {
                    tcPr = CTTcPr.Factory.newInstance();
                    tcPr.setVMerge(vmerge);
                    cell.getCTTc().setTcPr(tcPr);
                }
            }
        }
    
        //列合并  ,有点问题,用不了
        public static void mergeCellHorizontally(XWPFTable table, int row, int fromCol, int toCol) {
            for (int colIndex = fromCol; colIndex <= toCol; colIndex++) {
                CTHMerge hmerge = CTHMerge.Factory.newInstance();
                if (colIndex == fromCol) {
                    hmerge.setVal(STMerge.RESTART);
                } else {
                    hmerge.setVal(STMerge.CONTINUE);
                }
                XWPFTableCell cell = table.getRow(row).getCell(colIndex);
                CTTcPr tcPr = cell.getCTTc().getTcPr();
                if (tcPr != null) {
                    tcPr.setHMerge(hmerge);
                } else {
                    tcPr = CTTcPr.Factory.newInstance();
                    tcPr.setHMerge(hmerge);
                    cell.getCTTc().setTcPr(tcPr);
                }
            }
        }
    
        /**
         * 获取需要合并单元格的下标
         *
         * @return
         */
        public static List<Integer[]> startEnd(List<String[]> daList) {
            List<Integer[]> indexList = new ArrayList<Integer[]>();
    
            List<String> list = new ArrayList<String>();
            for (int i = 0; i < daList.size(); i++) {
                list.add(daList.get(i)[0]);
            }
            Map<Object, Integer> tm = new HashMap<Object, Integer>();
            for (int i = 0; i < daList.size(); i++) {
                if (!tm.containsKey(daList.get(i)[0])) {
                    tm.put(daList.get(i)[0], 1);
                } else {
                    int count = tm.get(daList.get(i)[0]) + 1;
                    tm.put(daList.get(i)[0], count);
                }
            }
            for (Map.Entry<Object, Integer> entry : tm.entrySet()) {
                String key = entry.getKey().toString();
                String value = entry.getValue().toString();
                if (list.indexOf(key) != (-1)) {
                    Integer[] index = new Integer[2];
                    index[0] = list.indexOf(key);
                    index[1] = list.lastIndexOf(key);
                    indexList.add(index);
                }
            }
            return indexList;
        }
    }
    
    package com.uncle.demo.poi;
    
    
    import java.io.IOException;
    import java.io.InputStream;
    import org.apache.poi.openxml4j.opc.OPCPackage;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.apache.poi.xwpf.usermodel.XWPFParagraph;
    import org.apache.xmlbeans.XmlException;
    import org.apache.xmlbeans.XmlToken;
    import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
    import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
    import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
    
    
    /**
     * @program demo01
     * @description 自定义 XWPFDocument,并重写 createPicture()方法
     * @author: Sun Jinxin
     * @create: 2021/11/30 14:50
     */
    public class CustomXWPFDocument extends XWPFDocument {
        public CustomXWPFDocument(InputStream in) throws IOException {
            super(in);
        }
    
        public CustomXWPFDocument() {
            super();
        }
    
        public CustomXWPFDocument(OPCPackage pkg) throws IOException {
            super(pkg);
        }
    
        /**
         * @param id
         * @param width 宽
         * @param height 高
         * @param paragraph  段落
         */
        public void createPicture(int id, int width, int height,XWPFParagraph paragraph) {
            final int EMU = 9525;
            width *= EMU;
            height *= EMU;
            String blipId = getAllPictures().get(id).getPackageRelationship().getId();
            CTInline inline = paragraph.createRun().getCTR().addNewDrawing().addNewInline();
    
            System.out.println(blipId+":"+inline);
    
            String picXml = ""
                    + "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
                    + "   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
                    + "      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
                    + "         <pic:nvPicPr>" + "            <pic:cNvPr id=\""
                    + id
                    + "\" name=\"Generated\"/>"
                    + "            <pic:cNvPicPr/>"
                    + "         </pic:nvPicPr>"
                    + "         <pic:blipFill>"
                    + "            <a:blip r:embed=\""
                    + blipId
                    + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
                    + "            <a:stretch>"
                    + "               <a:fillRect/>"
                    + "            </a:stretch>"
                    + "         </pic:blipFill>"
                    + "         <pic:spPr>"
                    + "            <a:xfrm>"
                    + "               <a:off x=\"0\" y=\"0\"/>"
                    + "               <a:ext cx=\""
                    + width
                    + "\" cy=\""
                    + height
                    + "\"/>"
                    + "            </a:xfrm>"
                    + "            <a:prstGeom prst=\"rect\">"
                    + "               <a:avLst/>"
                    + "            </a:prstGeom>"
                    + "         </pic:spPr>"
                    + "      </pic:pic>"
                    + "   </a:graphicData>" + "</a:graphic>";
    
            inline.addNewGraphic().addNewGraphicData();
            XmlToken xmlToken = null;
            try {
                xmlToken = XmlToken.Factory.parse(picXml);
            } catch (XmlException xe) {
                xe.printStackTrace();
            }
            inline.set(xmlToken);
    
            inline.setDistT(0);
            inline.setDistB(0);
            inline.setDistL(0);
            inline.setDistR(0);
    
            CTPositiveSize2D extent = inline.addNewExtent();
            extent.setCx(width);
            extent.setCy(height);
    
            CTNonVisualDrawingProps docPr = inline.addNewDocPr();
            docPr.setId(id);
            docPr.setName("图片" + id);
            docPr.setDescr("测试");
        }
    }
    

    动态数据

    测试类

    package com.hidata.tool;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class Test {
    
        public static void main(String[] args) throws IOException {
    
            // 存储报表全部数据
            Map<String, Object> wordDataMap = new HashMap<String, Object>();
            // 存储报表中不循环的数据
            Map<String, Object> parametersMap = new HashMap<String, Object>();
    
            
            List<Map<String, Object>> table1 = new ArrayList<Map<String, Object>>();
    
            Map<String, Object> map1=new HashMap();
            map1.put("name", "张三");
            map1.put("age", "23");
            map1.put("email", "12121@qq.com");
    
            Map<String, Object> map2=new HashMap();
            map2.put("name", "李四");
            map2.put("age", "45");
            map2.put("email", "45445@qq.com");
    
            Map<String, Object> map3=new HashMap();
            map3.put("name", "Tom");
            map3.put("age", "34");
            map3.put("email", "6767@qq.com");
    
            table1.add(map1);
            table1.add(map2);
            table1.add(map3);
    
    
    
    
            List<Map<String, Object>> table2 = new ArrayList<Map<String, Object>>();
            Map<String, Object> map4=new HashMap();
            map4.put("name", "tom");
            map4.put("number", "sd1234");
            map4.put("address", "上海");
    
            Map<String, Object> map5=new HashMap();
            map5.put("name", "seven");
            map5.put("number", "sd15678");
            map5.put("address", "北京");
    
            Map<String, Object> map6=new HashMap();
            map6.put("name", "lisa");
            map6.put("number", "sd9078");
            map6.put("address", "广州");
    
            table2.add(map4);
            table2.add(map5);
            table2.add(map6);
    
    
    
            parametersMap.put("userName", "JUVENILESS");
            parametersMap.put("time", "2018-03-24");
            parametersMap.put("sum", "3");
    
    
            wordDataMap.put("table1", table1);
            wordDataMap.put("table2", table2);
            wordDataMap.put("parametersMap", parametersMap);
            //改成你本地文件所在目录
            File file = new File("C:\\Users\\sunjinxin\\Desktop\\time.docx");
    
    
    
            // 读取word模板
            FileInputStream fileInputStream = new FileInputStream(file);
    
    
            WordTemplate template = new WordTemplate(fileInputStream);
    
            // 替换数据
            template.replaceDocument(wordDataMap);
    
    
            //生成文件
            //改成你本地文件所在目录
            File outputFile=new File("C:\\Users\\sunjinxin\\Desktop\\输出.docx");
            FileOutputStream fos  = new FileOutputStream(outputFile);
            template.getDocument().write(fos);
    
        }
    
    }
    
    

    工具类

    /**
     * @Title: WordTemplate2.java
     * @Package: com.highdata.templateTools
     * @Description: TODO
     * @author: Juveniless
     * @date: 2017年11月27日 下午3:23:13
     */
    package com.hidata.tool;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    import org.apache.poi.xwpf.usermodel.BodyElementType;
    import org.apache.poi.xwpf.usermodel.IBodyElement;
    import org.apache.poi.xwpf.usermodel.PositionInParagraph;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.apache.poi.xwpf.usermodel.XWPFParagraph;
    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;
    
    /**
     *
     * 对docx文件中的文本及表格中的内容进行替换 --模板仅支持对 {key} 标签的替换
     *
     * @ClassName: WordTemplate
     * @Description: TODO(!!!使用word2013 docx文件)
     * @author Juveniless
     * @date: 2017年11月27日 下午3:25:56
     * <br>(1)word模板注意页边距的问题,存在问题:比如页边距默认为3cm,画表格时,仍然可以通过
     * 拖拽,把表格边框拖动到看起来就像页边距只有1cm的样子,但是实际上此时页边距还是3cm,生成的
     * word报表的页边距还是会按照3cm来生成。解决办法,在word文件里,设置好页边距,如果需要表格
     * 两边页边距很窄,需要在word里设置页边距窄一点,而不是直接拖动表格边框来实现。
     *
     */
    
    public class WordTemplate {
    
        private XWPFDocument document;
    
        public XWPFDocument getDocument() {
            return document;
        }
    
        public void setDocument(XWPFDocument document) {
            this.document = document;
        }
    
        /**
         * 初始化模板内容
         *
         * @author Juveniless
         * @date 2017年11月27日 下午3:59:22
         * @param inputStream
         *            模板的读取流(docx文件)
         * @throws IOException
         *
         */
        public WordTemplate(InputStream inputStream) throws IOException {
            document = new XWPFDocument(inputStream);
        }
    
        /**
         * 将处理后的内容写入到输出流中
         *
         * @param outputStream
         * @throws IOException
         */
        public void write(OutputStream outputStream) throws IOException {
            document.write(outputStream);
        }
    
    
    
    
    
        /**
         * 根据dataMap对word文件中的标签进行替换; <br><br>
         * !!!!***需要注意dataMap的数据格式***!!!! <br><br>
         * 对于需要替换的普通标签数据标签(不需要循环)-----必须在dataMap中存储一个key为parametersMap的map,
         * 来存储这些不需要循环生成的数据,比如:表头信息,日期,制表人等。 <br><br>
         * 对于需要循环生成的表格数据------key自定义,value为 --ArrayList&lt;Map&lt;String, String>>
         * @author Juveniless
         * @date 2017年11月27日 下午3:29:27
         * @param dataMap
         *
         */
        public void replaceDocument(Map<String, Object> dataMap) {
    
            if (!dataMap.containsKey("parametersMap")) {
                System.out.println("数据源错误--数据源(parametersMap)缺失");
                return;
            }
            @SuppressWarnings("unchecked")
            Map<String, Object> parametersMap = (Map<String, Object>) dataMap
                    .get("parametersMap");
    
            List<IBodyElement> bodyElements = document.getBodyElements();// 所有对象(段落+表格)
            int templateBodySize = bodyElements.size();// 标记模板文件(段落+表格)总个数
    
            int curT = 0;// 当前操作表格对象的索引
            int curP = 0;// 当前操作段落对象的索引
            for (int a = 0; a < templateBodySize; a++) {
                IBodyElement body = bodyElements.get(a);
                if (BodyElementType.TABLE.equals(body.getElementType())) {// 处理表格
                    XWPFTable table = body.getBody().getTableArray(curT);
    
                    List<XWPFTable> tables = body.getBody().getTables();
                    table = tables.get(curT);
                    if (table != null) {
    
                        // 处理表格
                        List<XWPFTableCell> tableCells = table.getRows().get(0).getTableCells();
                        // 获取到模板表格第一行,用来判断表格类型
                        String tableText = table.getText();
                        // 表格中的所有文本
    
                        if (tableText.indexOf("##{foreach") > -1) {
                            // 查找到##{foreach标签,该表格需要处理循环
                            if (tableCells.size() != 2
                                    || tableCells.get(0).getText().indexOf("##{foreach") < 0
                                    || tableCells.get(0).getText().trim().length() == 0) {
                                System.out.println("文档中第"
                                                + (curT + 1)
                                                + "个表格模板错误,模板表格第一行需要设置2个单元格,"
                                                + "第一个单元格存储表格类型(##{foreachTable}## 或者 ##{foreachTableRow}##),第二个单元格定义数据源。");
                                return;
                            }
    
                            String tableType = tableCells.get(0).getText();
                            String dataSource = tableCells.get(1).getText();
                            System.out.println("读取到数据源:"+dataSource);
                            if (!dataMap.containsKey(dataSource)) {
                                System.out.println("文档中第" + (curT + 1) + "个表格模板数据源缺失");
                                return;
                            }
                            @SuppressWarnings("unchecked")
                            List<Map<String, Object>> tableDataList = (List<Map<String, Object>>) dataMap
                                    .get(dataSource);
                            if ("##{foreachTable}##".equals(tableType)) {
                                // System.out.println("循环生成表格");
                                addTableInDocFooter(table, tableDataList, parametersMap, 1);
    
                            } else if ("##{foreachTableRow}##".equals(tableType)) {
                                // System.out.println("循环生成表格内部的行");
                                addTableInDocFooter(table, tableDataList, parametersMap, 2);
                            }
    
                        } else if (tableText.indexOf("{") > -1) {
                            // 没有查找到##{foreach标签,查找到了普通替换数据的{}标签,该表格只需要简单替换
                            addTableInDocFooter(table, null, parametersMap, 3);
                        } else {
                            // 没有查找到任何标签,该表格是一个静态表格,仅需要复制一个即可。
                            addTableInDocFooter(table, null, null, 0);
                        }
                        curT++;
    
                    }
                } else if (BodyElementType.PARAGRAPH.equals(body.getElementType())) {// 处理段落
                    // System.out.println("获取到段落");
                    XWPFParagraph ph = body.getBody().getParagraphArray(curP);
                    if (ph != null) {
                        // htmlText = htmlText+readParagraphX(ph);
                        addParagraphInDocFooter(ph, null, parametersMap, 0);
    
                        curP++;
                    }
                }
    
            }
            // 处理完毕模板,删除文本中的模板内容
            for (int a = 0; a < templateBodySize; a++) {
                document.removeBodyElement(0);
            }
    
        }
    
    
    
    
    
    
    
    
        /**
         * 根据 模板表格 和 数据list 在word文档末尾生成表格
         * @author Juveniless
         * @date 2017年12月6日 上午10:12:05
         * @param templateTable 模板表格
         * @param list   循环数据集
         * @param parametersMap  不循环数据集
         * @param flag   (0为静态表格,1为表格整体循环,2为表格内部行循环,3为表格不循环仅简单替换标签即可)
         *
         */
        public void addTableInDocFooter(XWPFTable templateTable, List<Map<String, Object>> list,
                                        Map<String, Object> parametersMap, int flag) {
    
            if (flag == 1) {// 表格整体循环
                for (Map<String, Object> map : list) {
                    List<XWPFTableRow> templateTableRows = templateTable.getRows();// 获取模板表格所有行
                    XWPFTable newCreateTable = document.createTable();// 创建新表格,默认一行一列
                    for (int i = 1; i < templateTableRows.size(); i++) {
                        XWPFTableRow newCreateRow = newCreateTable.createRow();
                        CopyTableRow(newCreateRow, templateTableRows.get(i));// 复制模板行文本和样式到新行
                    }
                    newCreateTable.removeRow(0);// 移除多出来的第一行
                    document.createParagraph();// 添加回车换行
                    replaceTable(newCreateTable, map);//替换标签
                }
    
            } else if (flag == 2) {// 表格表格内部行循环
                XWPFTable newCreateTable = document.createTable();
                // 创建新表格,默认一行一列
                List<XWPFTableRow> TempTableRows = templateTable.getRows();
                // 获取模板表格所有行
                int tagRowsIndex = 0;// 标签行indexs
                for (int i = 0, size = TempTableRows.size(); i < size; i++) {
                    String rowText = TempTableRows.get(i).getCell(0).getText();
                    // 获取到表格行的第一个单元格
                    if (rowText.indexOf("##{foreachRows}##") > -1) {
                        tagRowsIndex = i;
                        break;
                    }
                }
    
                /* 复制模板行和标签行之前的行 */
                for (int i = 1; i < tagRowsIndex; i++) {
                    XWPFTableRow newCreateRow = newCreateTable.createRow();
                    CopyTableRow(newCreateRow, TempTableRows.get(i));
                    // 复制行
                    replaceTableRow(newCreateRow, parametersMap);
                    // 处理不循环标签的替换
                }
    
                /* 循环生成模板行 */
                XWPFTableRow tempRow = TempTableRows.get(tagRowsIndex + 1);
                // 获取到模板行
                for (int i = 0; i < list.size(); i++) {
                    XWPFTableRow newCreateRow = newCreateTable.createRow();
                    CopyTableRow(newCreateRow, tempRow);
                    // 复制模板行
                    replaceTableRow(newCreateRow, list.get(i));
                    // 处理标签替换
                }
    
                /* 复制模板行和标签行之后的行 */
                for (int i = tagRowsIndex + 2; i < TempTableRows.size(); i++) {
                    XWPFTableRow newCreateRow = newCreateTable.createRow();
                    CopyTableRow(newCreateRow, TempTableRows.get(i));
                    // 复制行
                    replaceTableRow(newCreateRow, parametersMap);
                    // 处理不循环标签的替换
                }
                newCreateTable.removeRow(0);
                // 移除多出来的第一行
                document.createParagraph();
                // 添加回车换行
    
            } else if (flag == 3) {
                //表格不循环仅简单替换标签
                List<XWPFTableRow> templateTableRows = templateTable.getRows();
                // 获取模板表格所有行
                XWPFTable newCreateTable = document.createTable();
                // 创建新表格,默认一行一列
                for (int i = 0; i < templateTableRows.size(); i++) {
                    XWPFTableRow newCreateRow = newCreateTable.createRow();
                    CopyTableRow(newCreateRow, templateTableRows.get(i));
                    // 复制模板行文本和样式到新行
                }
                newCreateTable.removeRow(0);
                // 移除多出来的第一行
                document.createParagraph();
                // 添加回车换行
                replaceTable(newCreateTable, parametersMap);
    
            } else if (flag == 0) {
                List<XWPFTableRow> templateTableRows = templateTable.getRows();
                // 获取模板表格所有行
                XWPFTable newCreateTable = document.createTable();
                // 创建新表格,默认一行一列
                for (int i = 0; i < templateTableRows.size(); i++) {
                    XWPFTableRow newCreateRow = newCreateTable.createRow();
                    CopyTableRow(newCreateRow, templateTableRows.get(i));
                    // 复制模板行文本和样式到新行
                }
                newCreateTable.removeRow(0);
                // 移除多出来的第一行
                document.createParagraph();
                // 添加回车换行
            }
    
        }
    
    
    
    
    
    
        /**
         * 根据 模板段落 和 数据 在文档末尾生成段落
         *
         * @author Juveniless
         * @date 2017年11月27日 上午11:49:42
         * @param templateParagraph
         *            模板段落
         * @param list
         *            循环数据集
         * @param parametersMap
         *            不循环数据集
         * @param flag
         *            (0为不循环替换,1为循环替换)
         *
         */
        public void addParagraphInDocFooter(XWPFParagraph templateParagraph,
                                            List<Map<String, String>> list, Map<String, Object> parametersMap, int flag) {
    
            if (flag == 0) {
                XWPFParagraph createParagraph = document.createParagraph();
                // 设置段落样式
                createParagraph.getCTP().setPPr(templateParagraph.getCTP().getPPr());
                // 移除原始内容
                for (int pos = 0; pos < createParagraph.getRuns().size(); pos++) {
                    createParagraph.removeRun(pos);
                }
                // 添加Run标签
                for (XWPFRun s : templateParagraph.getRuns()) {
                    XWPFRun targetrun = createParagraph.createRun();
                    CopyRun(targetrun, s);
                }
    
                replaceParagraph(createParagraph, parametersMap);
    
            } else if (flag == 1) {
                // 暂无实现
            }
    
        }
    
    
    
    
        /**
         * 根据map替换段落元素内的{**}标签
         * @author Juveniless
         * @date 2017年12月4日 下午3:09:00
         * @param xWPFParagraph
         * @param parametersMap
         *
         */
        public void replaceParagraph(XWPFParagraph xWPFParagraph, Map<String, Object> parametersMap) {
            List<XWPFRun> runs = xWPFParagraph.getRuns();
            String xWPFParagraphText = xWPFParagraph.getText();
            String regEx = "\\{.+?\\}";
            Pattern pattern = Pattern.compile(regEx);
            Matcher matcher = pattern.matcher(xWPFParagraphText);//正则匹配字符串{****}
    
            if (matcher.find()) {
                // 查找到有标签才执行替换
                int beginRunIndex = xWPFParagraph.searchText("{", new PositionInParagraph()).getBeginRun();// 标签开始run位置
                int endRunIndex = xWPFParagraph.searchText("}", new PositionInParagraph()).getEndRun();// 结束标签
                StringBuffer key = new StringBuffer();
    
                if (beginRunIndex == endRunIndex) {
                    // {**}在一个run标签内
                    XWPFRun beginRun = runs.get(beginRunIndex);
                    String beginRunText = beginRun.text();
    
                    int beginIndex = beginRunText.indexOf("{");
                    int endIndex = beginRunText.indexOf("}");
                    int length = beginRunText.length();
    
                    if (beginIndex == 0 && endIndex == length - 1) {
                        // 该run标签只有{**}
                        XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex);
                        insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr());
                        // 设置文本
                        key.append(beginRunText.substring(1, endIndex));
                        insertNewRun.setText(getValueBykey(key.toString(),parametersMap));
                        xWPFParagraph.removeRun(beginRunIndex + 1);
                    } else {
                        // 该run标签为**{**}** 或者 **{**} 或者{**}**,替换key后,还需要加上原始key前后的文本
                        XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex);
                        insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr());
                        // 设置文本
                        key.append(beginRunText.substring(beginRunText.indexOf("{")+1, beginRunText.indexOf("}")));
                        String textString=beginRunText.substring(0, beginIndex) + getValueBykey(key.toString(),parametersMap)
                                + beginRunText.substring(endIndex + 1);
                        insertNewRun.setText(textString);
                        xWPFParagraph.removeRun(beginRunIndex + 1);
                    }
    
                }else {
                    // {**}被分成多个run
    
                    //先处理起始run标签,取得第一个{key}值
                    XWPFRun beginRun = runs.get(beginRunIndex);
                    String beginRunText = beginRun.text();
                    int beginIndex = beginRunText.indexOf("{");
                    if (beginRunText.length()>1  ) {
                        key.append(beginRunText.substring(beginIndex+1));
                    }
                    ArrayList<Integer> removeRunList = new ArrayList();//需要移除的run
                    //处理中间的run
                    for (int i = beginRunIndex + 1; i < endRunIndex; i++) {
                        XWPFRun run = runs.get(i);
                        String runText = run.text();
                        key.append(runText);
                        removeRunList.add(i);
                    }
    
                    // 获取endRun中的key值
                    XWPFRun endRun = runs.get(endRunIndex);
                    String endRunText = endRun.text();
                    int endIndex = endRunText.indexOf("}");
                    //run中**}或者**}**
                    if (endRunText.length()>1 && endIndex!=0) {
                        key.append(endRunText.substring(0,endIndex));
                    }
    
    
    
                    //*******************************************************************
                    //取得key值后替换标签
    
                    //先处理开始标签
                    if (beginRunText.length()==2 ) {
                        // run标签内文本{
                        XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex);
                        insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr());
                        // 设置文本
                        insertNewRun.setText(getValueBykey(key.toString(),parametersMap));
                        xWPFParagraph.removeRun(beginRunIndex + 1);
                        //移除原始的run
                    }else {
                        // 该run标签为**{**或者 {** ,替换key后,还需要加上原始key前的文本
                        XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex);
                        insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr());
                        // 设置文本
                        String textString=beginRunText.substring(0,beginRunText.indexOf("{"))+getValueBykey(key.toString(),parametersMap);
                        insertNewRun.setText(textString);
                        xWPFParagraph.removeRun(beginRunIndex + 1);
                        //移除原始的run
                    }
    
                    //处理结束标签
                    if (endRunText.length()==1 ) {
                        // run标签内文本只有}
                        XWPFRun insertNewRun = xWPFParagraph.insertNewRun(endRunIndex);
                        insertNewRun.getCTR().setRPr(endRun.getCTR().getRPr());
                        // 设置文本
                        insertNewRun.setText("");
                        xWPFParagraph.removeRun(endRunIndex + 1);//移除原始的run
    
                    }else {
                        // 该run标签为**}**或者 }** 或者**},替换key后,还需要加上原始key后的文本
                        XWPFRun insertNewRun = xWPFParagraph.insertNewRun(endRunIndex);
                        insertNewRun.getCTR().setRPr(endRun.getCTR().getRPr());
                        // 设置文本
                        String textString=endRunText.substring(endRunText.indexOf("}")+1);
                        insertNewRun.setText(textString);
                        xWPFParagraph.removeRun(endRunIndex + 1);//移除原始的run
                    }
    
                    //处理中间的run标签
                    for (int i = 0; i < removeRunList.size(); i++) {
                        XWPFRun xWPFRun = runs.get(removeRunList.get(i));//原始run
                        XWPFRun insertNewRun = xWPFParagraph.insertNewRun(removeRunList.get(i));
                        insertNewRun.getCTR().setRPr(xWPFRun.getCTR().getRPr());
                        insertNewRun.setText("");
                        xWPFParagraph.removeRun(removeRunList.get(i) + 1);//移除原始的run
                    }
    
                }// 处理${**}被分成多个run
    
                replaceParagraph( xWPFParagraph, parametersMap);
    
            }//if 有标签
    
        }
    
    
    
    
    
    
    
    
        /**
         * 复制表格行XWPFTableRow格式
         *
         * @param target
         *            待修改格式的XWPFTableRow
         * @param source
         *            模板XWPFTableRow
         */
        private void CopyTableRow(XWPFTableRow target, XWPFTableRow source) {
    
            int tempRowCellsize = source.getTableCells().size();// 模板行的列数
            for (int i = 0; i < tempRowCellsize - 1; i++) {
                target.addNewTableCell();// 为新添加的行添加与模板表格对应行行相同个数的单元格
            }
            // 复制样式
            target.getCtRow().setTrPr(source.getCtRow().getTrPr());
            // 复制单元格
            for (int i = 0; i < target.getTableCells().size(); i++) {
                copyTableCell(target.getCell(i), source.getCell(i));
            }
        }
    
    
    
    
    
        /**
         * 复制单元格XWPFTableCell格式
         *
         * @author Juveniless
         * @date 2017年11月27日 下午3:41:02
         * @param newTableCell
         *            新创建的的单元格
         * @param templateTableCell
         *            模板单元格
         *
         */
        private void copyTableCell(XWPFTableCell newTableCell, XWPFTableCell templateTableCell) {
            // 列属性
            newTableCell.getCTTc().setTcPr(templateTableCell.getCTTc().getTcPr());
            // 删除目标 targetCell 所有文本段落
            for (int pos = 0; pos < newTableCell.getParagraphs().size(); pos++) {
                newTableCell.removeParagraph(pos);
            }
            // 添加新文本段落
            for (XWPFParagraph sp : templateTableCell.getParagraphs()) {
                XWPFParagraph targetP = newTableCell.addParagraph();
                copyParagraph(targetP, sp);
            }
        }
    
        /**
         * 复制文本段落XWPFParagraph格式
         *
         * @author Juveniless
         * @date 2017年11月27日 下午3:43:08
         * @param newParagraph
         *            新创建的的段落
         * @param templateParagraph
         *            模板段落
         *
         */
        private void copyParagraph(XWPFParagraph newParagraph, XWPFParagraph templateParagraph) {
            // 设置段落样式
            newParagraph.getCTP().setPPr(templateParagraph.getCTP().getPPr());
            // 添加Run标签
            for (int pos = 0; pos < newParagraph.getRuns().size(); pos++) {
                newParagraph.removeRun(pos);
    
            }
            for (XWPFRun s : templateParagraph.getRuns()) {
                XWPFRun targetrun = newParagraph.createRun();
                CopyRun(targetrun, s);
            }
    
        }
    
        /**
         * 复制文本节点run
         * @author Juveniless
         * @date 2017年11月27日 下午3:47:17
         * @param newRun
         *            新创建的的文本节点
         * @param templateRun
         *            模板文本节点
         *
         */
        private void CopyRun(XWPFRun newRun, XWPFRun templateRun) {
            newRun.getCTR().setRPr(templateRun.getCTR().getRPr());
            // 设置文本
            newRun.setText(templateRun.text());
    
    
        }
    
    
    
    
        /**
         * 根据参数parametersMap对表格的一行进行标签的替换
         *
         * @author Juveniless
         * @date 2017年11月23日 下午2:09:24
         * @param tableRow
         *            表格行
         * @param parametersMap
         *            参数map
         *
         */
        public void replaceTableRow(XWPFTableRow tableRow, Map<String, Object> parametersMap) {
    
            List<XWPFTableCell> tableCells = tableRow.getTableCells();
            for (XWPFTableCell xWPFTableCell : tableCells) {
                List<XWPFParagraph> paragraphs = xWPFTableCell.getParagraphs();
                for (XWPFParagraph xwpfParagraph : paragraphs) {
    
                    replaceParagraph(xwpfParagraph, parametersMap);
                }
            }
    
        }
    
        /**
         * 根据map替换表格中的{key}标签
         * @author Juveniless
         * @date 2017年12月4日 下午2:47:36
         * @param xwpfTable
         * @param parametersMap
         *
         */
        public void replaceTable(XWPFTable xwpfTable,Map<String, Object> parametersMap){
            List<XWPFTableRow> rows = xwpfTable.getRows();
            for (XWPFTableRow xWPFTableRow : rows ) {
                List<XWPFTableCell> tableCells = xWPFTableRow.getTableCells();
                for (XWPFTableCell xWPFTableCell : tableCells ) {
                    List<XWPFParagraph> paragraphs2 = xWPFTableCell.getParagraphs();
                    for (XWPFParagraph xWPFParagraph : paragraphs2) {
                        replaceParagraph(xWPFParagraph, parametersMap);
                    }
                }
            }
    
        }
    
        private String getValueBykey(String key, Map<String, Object> map) {
            String returnValue="";
            if (key != null) {
                try {
                    returnValue=map.get(key)!=null ? map.get(key).toString() : "";
                } catch (Exception e) {
                    // TODO: handle exception
                    System.out.println("key:"+key+"***"+e);
                    returnValue="";
                }
    
            }
            return returnValue;
        }
    }
    
    
    展开全文
  • 1.去掉目录前面的黑点 最近我也是临近毕业,在写毕业论文,在写的过程中呢,发现自动生成的目录前面会个小黑点。如下图 但我们学校这边的目录...然后我们选择这个分节符,按delete键,即可删除空白了!!! ...
  • 删除论文中word的最后一页空白页

    万次阅读 多人点赞 2014-06-04 19:09:55
    今天在写论文的时候,遇到了个很奇葩的问题。
  • 亲测有效! https://zhidao.baidu.com/question/277131717.html?qbl=relate_question_0&amp;word=����ģ������һҳɾ������ô��
  • 使用POI 导出word模板文件

    千次阅读 热门讨论 2019-03-21 11:29:32
    } } 文件导出工具类: public class POIWordUtil { /** * 根据模板生成新word文档 * 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入 * * @param inputUrl 模板存放地址 * @param outputUrl 新...
  •  string templatePath = HttpContext.Current.Server.MapPath(@"~/office/doc/模板.doc");  System.Data.DataTable dt = DbSqlHelper.GetDataSet("SELECT * FROM KJYJJRHLTHTS WHERE XHBH='" + XHBH + "' and ...
  • java poi实现病历数据的word导出(包括word模板的使用、复制表格、复制行、插入图片的使用) 1.实现的效果 实现病人基本信息、多条病历数据、多项检查项图片的动态插入(网络图片) [外链图片转存失败(img-xiVmRGdl...
  • Word邮件合并功能详解:合并后生成多个word文档,删除空白 最近在实习,干了很多打杂得工作,所以office软件用的很多很多,瞬间觉得自己可以去裸考计算机二级了哈哈哈哈哈哈。今天因为工作用到了邮件合并这个功能...
  • SpringBoot+Poi-tl根据Word模板动态生成含动态表格的word文档。 Poi-tl官方文档:http://deepoove.com/poi-tl/ 实现过程 1.添加必要依赖 <!-- word导出 --> <!-- poi-tl是基于Apache POI的Word模板引擎。...
  • 这个我来答,缓缓,我慢慢来保留原格式复制入、格式刷,可达到效果,但效率、效果皆差,且LOW分为3个步骤:1-模板论文B中设置样式集,2-将论文B中各样式导入本次论文A,3-论文A中对应设置各文本样式。以下截图均为...
  • 步骤如下:1、编写 Word 模板,并将模板中要用代码动态生成数据用 Freemarker 变量取代,即${变量名},如${username};2、把该 word 文档 另存为 xml 文件(格式选择 Word 2003 XML,注意是另存为,不是改扩展名为 ...
  • 在Qt中使用已有模板创建新Word文档

    千次阅读 2018-07-14 22:07:03
    本文主要介绍如何在Qt下操作Word
  • 之前在html页面已经实现了个点击按钮下载excel模板文件的功能,现在新增业务需求,需要再增加个按钮实现下载word模板文件,经过周的摸索,现在给出个简单实现的方案。为了实现该功能,改动的地方也挺多的 ...
  • 菜单小票模板word

    2021-06-17 11:26:47
    WORD编辑好的小票模版打印出来很小呢展开全部 这里介绍下用WPS表格做拼音田字格模板制作的过程: 1、打开WPS表格,选定全部单元格。然后单击“格式”→“行” →“行高”,在“行高”对话框中将行高设置为17;再...
  • word模板文件参考下面: Map<String, Object> params = new HashMap<String, Object>(); params.put("name", name);//公司名称 params.put("beginDate", beginDate);//开始时间 params.put(...
  • 原因很多,比如:①空白页上有回车符,但是该页未包含任何字符,让文档多占据一页;②空白页上有分页符;但是该页未包含任何字符;③页面中存在表格,由于多按了回车符,导致表格分割到空白页,但是空白页却没有任何...
  • Freemarker使用mht制作导出word模板 、制作word导出模板时,我们使用官方的Office Word编辑样式,编辑好之后,另存为mhtml格式,这样我们就可以看到源代码了。注意:创建word文档时,使用doc后缀,docx与doc的操作...
  • 1.整理需要填充到WORD模板中的数据 2.调用CCWordApp查找模板.dot 根据[书签]去填充(文本,数字,图片) 3.保存WORD(id标识+日期 防止文件重复.)然后供用户下载.(扩展,可以安装WORD转PDF组件 在服务端就可以找到...
  • 加载模板或加载项之后,它只在当前的 Word 会话中保持加载状态,相关精彩文章Word试题编辑提速 快速输入着重号!死机导致Word文件无法打开,怎么办卸载模板和加载项若要节省内存并提高 Word 的运行速度,卸载不常用的...
  • word模板运用

    千次阅读 2012-12-26 20:57:22
    大家知道,Word提供了各式各样的模板,在开始编辑Word文档尤其是专业性质的文档之前,先看看有没有现成的模板可用吧。...第部分 Word模板的基础应用  Word模板的分类及存放位置  Word中的模板分为两类:是系统
  • 今天处理word文档模板时,需要将文档尾部多于的空白页面删除。 起初网上找了跟多资料,无法很精准的行为到最后页面内容是否为空并删除。。后来就用了这个不算很好地办法,写下来留记录,也希望知道如何操作的大神给...
  • word里目录怎么做才方便呢?有没有文字最佳排版格式??Word里面的目录做起来很方便呀,做成自动生成的就好了呀。成目录等功能的前提是正确使用“样式”,工具栏最左边的小方框注意了吗,平时是“正文”,下拉箭头有...
  • 【推荐】关于Java static 的面试题和答案-word范文模板本文部分内容来自网络整理,本司不为其真实性负责,如有异议或侵权请及时联系,本司将立即删除!== 本文为word格式,下载后可方便编辑和修改! ==关于Java ...
  • word模板格式,将需要替换的位置用&amp;xx&amp;占位符填上,在后台找到跟数据相同的名称时替换 #region 带模板导出 public HttpResponseMessage ExportWordModel(dynamic obj) { long formId = obj.id; ...
  • 最近在用EasyPOI的word模板导出功能,遇到了这样的一个需求:在用指令fe:List遍历输出List时,要在中间进行表格的分隔。如果直接把一个表格分成2个,一是可能会影响后面的输出,二是这个表格的表头就不能出现在每...
  • * 功能描述: Word 导出 */ @GetMapping("/filmReview/download") public void exportTemplate(HttpServletRequest request, @RequestParam Integer filmId, @RequestParam Integer filmReviewId, ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,648
精华内容 7,459
关键字:

word模板删除一页