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;
}
}