方案一:通过poi实现word文字插入,并把多个word合并(实现套红发文功能)

1. 先创建红头模板

注意${num} ${user} 参数位置
在这里插入图片描述

2. 公文的文件地址

在这里插入图片描述

3. 方法


import org.apache.commons.io.IOUtils;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * word合成工具类
 *
 * @author 7788
 * @version 1.0
 * @date 2021/1/5 下午 4:46
 * @location wuhan
 */
@Deprecated
public class POIMergeDocUtil {


    public static void main(String[] args) throws Exception {

		//红头模板位置
        String model = "d:\\360Downloads\\模板.docx";
        //模板存放项目里的话
        URL resource = POIMergeDocUtil.class.getClassLoader().getResource("files/official_doc_model.docx");
        if (null != resource){
            model =  resource.getPath();
        }
        //公文位置
        String content = "d:\\360Downloads\\公文.docx";

        Map<String, String> param = new HashMap<>(2);
        param.put("num", "2021-002");
        param.put("user", "王");

		//套红保存后的文件地址
        String destDocx = "d:\\360Downloads\\test.docx";

        exportWordUtils(model, content, param, destDocx);
        System.out.println("执行成功");
    }

    /**
     * 对多个word模板填充数据,并合并成一个word输出
     *
     * @param model    模板文件地址
     * @param content  公文文件地址
     * @param param    需要填写的参数
     * @param destDocx 合成后的文件地址
     */
    public static void exportWordUtils(String model, String content, Map<String, String> param, String destDocx) throws Exception {
        //向模板word填充参数
        XWPFDocument xwpf = generateWord(param, model);
        XWPFDocument xwpf1 = new XWPFDocument(POIXMLDocument.openPackage(content));
        //合并word 多个word需要合并的话 自行改成遍历合并即可
        XWPFDocument xwpfDocument = mergeWord(xwpf, xwpf1);
        //输出word
        OutputStream dest = new FileOutputStream(destDocx);
        xwpfDocument.write(dest);
        //关闭
        IOUtils.closeQuietly(dest);
    }

    /**
     * 替换word占位符的内容
     */
    public static XWPFDocument generateWord(Map<String, String> param, String filePath) {
        XWPFDocument doc = null;
        try {
            doc = new XWPFDocument(POIXMLDocument.openPackage(filePath));
            if (param != null && param.size() > 0) {
                //处理段落
                replaceInPara(doc, param);
                //替换表格里面的变量
                replaceInTable(doc, param);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return doc;
    }

    /**
     * 遍历word段落信息
     *
     * @param doc    要替换的文档
     * @param params 参数
     */
    private static void replaceInPara(XWPFDocument doc, Map<String, String> params) {
        Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
        XWPFParagraph para;
        while (iterator.hasNext()) {
            para = iterator.next();
            replaceInPara(para, params);
        }
    }

    /**
     * 替换段落里面的变量
     *
     * @param para 要替换的段落
     */
    private static void replaceInPara(XWPFParagraph para, Map<String, String> param) {
        List<XWPFRun> runs;
        String tempString = "";
        char lastChar = ' ';
        if (matcher(para.getParagraphText()).find()) {
            runs = para.getRuns();
            Set<XWPFRun> runSet = new HashSet<>();
            for (XWPFRun run : runs) {
                String text = run.getText(0);
                if (text == null) {
                    continue;
                }
                text = replaceText(text, param);
                run.setText("", 0);
                run.setText(text, 0);

                for (int i = 0; i < text.length(); i++) {
                    char ch = text.charAt(i);
                    if (ch == '$') {
                        runSet = new HashSet<>();
                        runSet.add(run);
                        tempString = text;
                    } else if (ch == '{') {
                        if (lastChar == '$') {
                            if (runSet.contains(run)) {

                            } else {
                                runSet.add(run);
                                tempString = tempString + text;
                            }
                        } else {
                            runSet = new HashSet<>();
                            tempString = "";
                        }
                    } else if (ch == '}') {
                        if (tempString != null && tempString.indexOf("${") >= 0) {
                            if (runSet.contains(run)) {

                            } else {
                                runSet.add(run);
                                tempString = tempString + text;
                            }
                        } else {
                            runSet = new HashSet<>();
                            tempString = "";
                        }
                        if (runSet.size() > 0) {
                            String replaceText = replaceText(tempString, param);
                            if (!replaceText.equals(tempString)) {
                                int index = 0;
                                XWPFRun aRun = null;
                                for (XWPFRun tempRun : runSet) {
                                    tempRun.setText("", 0);
                                    if (index == 0) {
                                        aRun = tempRun;
                                    }
                                    index++;
                                }
                                aRun.setText(replaceText, 0);
                            }
                            runSet = new HashSet<>();
                            tempString = "";
                        }
                    } else {
                        if (runSet.size() <= 0) {
                            continue;
                        }
                        if (runSet.contains(run)) {
                            continue;
                        }
                        runSet.add(run);
                        tempString = tempString + text;
                    }
                    lastChar = ch;
                }
            }

            //这种方法会导致占位符被拆开解析,不能识别替换掉
				/*for (int i = 0; i < runs.size(); i++) {
					XWPFRun run = runs.get(i);
					String runText = run.toString();
					matcher = this.matcher(runText);
					if (matcher.find()) {
						while ((matcher = this.matcher(runText)).find()) {
							runText = matcher.replaceFirst(String.valueOf(param.get(matcher.group(1))));
						}
						// 直接调用XWPFRun的setText()方法设置文本时,在底层会重新创建一个XWPFRun,把文本附加在当前文本后面,
						// 所以我们不能直接设值,需要先删除当前run,然后再自己手动插入一个新的run。
						para.removeRun(i);
						if(runText.equals("null")){
							runText="";
						}
						para.insertNewRun(i).setText(runText);
					}
				}*/
        }
    }

    /**
     * 替换表格里面的变量
     *
     * @param doc    要替换的文档
     * @param params 参数
     */
    private static void replaceInTable(XWPFDocument doc, Map<String, String> params) {
        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) {

                    //这种方法会导致表格中的格式丢失
						/*String cellTextString = cell.getText();
	                    for (Entry<String, Object> e : params.entrySet()) {
	                        if (cellTextString.contains("${"+e.getKey()+"}"))
	                            cellTextString = cellTextString.replace("${"+e.getKey()+"}", e.getValue().toString());
	                    }
	                    cell.removeParagraph(0);
	                    if(cellTextString.contains("${") && cellTextString.contains("}")){
	                    	cellTextString = "";
	                    }
	                    cell.setText(cellTextString);*/

                    //调用段落替换占位符的方式
                    paras = cell.getParagraphs();
                    for (XWPFParagraph para : paras) {
                        replaceInPara(para, params);
                    }

                }
            }
        }
    }

    /**
     * 替换占位符
     *
     * @param text
     * @param map
     * @return
     */
    private static String replaceText(String text, Map<String, String> map) {
        if (text != null) {
				/*for (Entry<String, String> entry : map.entrySet()) {
					if (text.contains("${"+entry.getKey()+"}")){
						text = text.replace("${"+entry.getKey()+"}", entry.getValue().toString());
					}
				}*/

            Matcher matcher = matcher(text);
            if (matcher.find()) {
                while ((matcher = matcher(text)).find()) {
                    text = matcher.replaceFirst(String.valueOf(map.get(matcher.group(1))));
                }
                if (text.equals("null")) {
                    text = "";
                }
            }
        }
        return text;
    }

    /**
     * 正则匹配字符串
     */
    private static Matcher matcher(String str) {
        return Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE).matcher(str);
    }

    /**
     * 两个对象进行追加
     */
    public static XWPFDocument mergeWord(XWPFDocument document1, XWPFDocument document2) throws Exception {
        //设置分页符---当刚好一页数据时,会导致出现空白页,后面出现分页符导致格式有一点差异
        //解决方法是,在模板头上增加分页符
        //XWPFParagraph p = document2.createParagraph();
        //p.setPageBreak(true);
        CTBody src1Body = document1.getDocument().getBody();
        CTBody src2Body = document2.getDocument().getBody();
        XmlOptions optionsOuter = new XmlOptions();
        optionsOuter.setSaveOuter();
        String appendString = src2Body.xmlText(optionsOuter);
        String srcString = src1Body.xmlText();
        String prefix = srcString.substring(0, srcString.indexOf(">") + 1);
        String mainPart = srcString.substring(srcString.indexOf(">") + 1, srcString.lastIndexOf("<"));
        String sufix = srcString.substring(srcString.lastIndexOf("<"));
        String addPart = appendString.substring(appendString.indexOf(">") + 1, appendString.lastIndexOf("<"));
        CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart + sufix);
        src1Body.set(makeBody);
        return document1;
    }
}

4. 效果 (基本功能实现,公文样式丢失)

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值