最近工作上需要实现对word上的一些操作,其中包含:替换段落内容,替换表格里面的变量,页脚插入图片,页眉的关键字替换,多个Word合并等多个功能,已经实现,特此记录。
替换段落内容,替换表格里面的变量,页脚插入图片,页眉的关键字替换,多个Word合并。
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poiartifactId>
<version>5.2.3version>
dependency>
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poi-ooxmlartifactId>
<version>5.2.3version>
dependency>
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poi-ooxml-schemasartifactId>
<version>4.1.2version>
dependency>
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poi-scratchpadartifactId>
<version>5.2.3version>
dependency>
<dependency>
<groupId>fr.opensagres.xdocreportgroupId>
<artifactId>org.apache.poi.xwpf.converter.pdfartifactId>
<version>1.0.6version>
dependency>
<dependency>
<groupId>fr.opensagres.xdocreportgroupId>
<artifactId>xdocreportartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>com.itextpdfgroupId>
<artifactId>itextpdfartifactId>
<version>5.5.13.1version>
dependency>
<dependency>
<groupId>com.itextpdfgroupId>
<artifactId>itext-asianartifactId>
<version>5.2.0version>
dependency>
<dependency>
<groupId>com.deepoovegroupId>
<artifactId>poi-tlartifactId>
<version>1.9.1version>
dependency>
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.Document;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFFooter;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
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.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
import org.springframework.stereotype.Component;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author wuk
* @description: word填充转换工具
* @menu word填充转换工具
* @date 2022/9/17 15:43
*/
@Component
@Log4j2
public class WordToPdfUtil {
/**
* 替换段落内容 (格式有要求:<> 为三个文本对象)
*/
public static XWPFDocument doParagraph(Map<String, String> dataMap, XWPFDocument xwpfDocument) {
if (dataMap != null && dataMap.size() > 0) {
List<XWPFParagraph> paragraphs = xwpfDocument.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
replaceInPara(paragraph, dataMap);
}
}
return xwpfDocument;
}
/**
* 替换表格里面的变量
*/
public static XWPFDocument replaceInTable(Map<String, String> params, XWPFDocument doc) {
Iterator<XWPFTable> iterator = doc.getTablesIterator();
XWPFTable table;
List<XWPFTableRow> rows;
List<XWPFTableCell> cells;
List<XWPFParagraph> paras;
while (iterator.hasNext()) {
table = iterator.next();
rows = table.getRows();
for (XWPFTableRow row : rows) {
cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
paras = cell.getParagraphs();
for (XWPFParagraph para : paras) {
replaceInPara(para, params);
}
}
}
}
return doc;
}
/**
* 页脚插入图片
*/
public static XWPFDocument insertImageInFoot(Map<String, String> dataMap, XWPFDocument doc) throws Exception {
List<XWPFFooter> footerList = doc.getFooterList();
InputStream in = new FileInputStream(dataMap.get("${image}"));
for (XWPFFooter xwpfFooter : footerList) {
List<XWPFParagraph> listParagraph = xwpfFooter.getListParagraph();
for (XWPFParagraph xwpfParagraph : listParagraph) {
List<XWPFRun> runs = xwpfParagraph.getRuns();
if (CollectionUtils.isNotEmpty(runs)) {
XWPFRun run = runs.get(0);
run.addPicture(in, Document.PICTURE_TYPE_PNG, "", Units.toEMU(50), Units.toEMU(50));
}
}
}
in.close();
return doc;
}
/**
* 页眉的关键字替换
*/
public static XWPFDocument doParagraphOfHead(Map<String, String> dataMap, XWPFDocument doc) {
List<XWPFHeader> headerList = doc.getHeaderList();
for (XWPFHeader xwpfHeader : headerList) {
List<XWPFParagraph> listParagraph = xwpfHeader.getListParagraph();
for (XWPFParagraph xwpfParagraph : listParagraph) {
replaceInPara(xwpfParagraph, dataMap);
}
}
return doc;
}
/**
* 替换段落里面的变量
*
* @param para 要替换的段落
* @param params 参数
*/
private static void replaceInPara(XWPFParagraph para, Map<String, String> params) {
Map<Integer, StringBuilder> strMap = new HashMap<>();
recursionGetStr(para, strMap, params);
}
private static void recursionGetStr(XWPFParagraph para, Map<Integer, StringBuilder> strMap,
Map<String, String> params) {
List<XWPFRun> runs;
String paragraphText = para.getParagraphText();
boolean bool = matcher(paragraphText);
if (bool) {
runs = para.getRuns();
int start = -1;
int end;
StringBuilder str = new StringBuilder();
for (int i = 0; i < runs.size(); i++) {
XWPFRun run = runs.get(i);
String runText = run.toString();
if (runText != null) {
if (StringUtils.isNotEmpty(runText.trim())) {
runText = runText.trim();
}
if ('<' == runText.charAt(0)) {
start = i;
}
if ((start != -1)) {
str.append(runText);
}
if ('>' == runText.charAt(runText.length() - 1)) {
if (start != -1) {
end = i;
String substring = paragraphText.replace(str, "");
if (matcher(substring)) {
for (int j = start; j <= end; j++) {
para.removeRun(j);
j--;
end--;
}
strMap.put(start, str);
recursionGetStr(para, strMap, params);
} else {
for (int j = start; j <= end; j++) {
para.removeRun(j);
j--;
end--;
}
strMap.put(start, str);
break;
}
}
}
}
}
setPara(strMap, para, params);
strMap.clear();
}
}
private static void setPara(Map<Integer, StringBuilder> strMap, XWPFParagraph para, Map<String, String> params) {
List<XWPFRun> runs = para.getRuns();
XWPFRun xwpfRun = null;
if (CollectionUtils.isNotEmpty(runs)) {
for (XWPFRun run : runs) {
if (ObjectUtils.isNotEmpty(run) &&
StringUtils.isNotEmpty(run.toString().trim())) {
xwpfRun = run;
break;
}
}
}
AtomicInteger i = new AtomicInteger();
XWPFRun finalXwpfRun = xwpfRun;
strMap.forEach((start, str) -> {
i.set(i.get() + 1);
String text = params.get(str.toString().trim());
if (StringUtils.isNotEmpty(text)) {
log.info("被填充的内容包含:{}", text);
if (i.get() > 1) {
start = start + i.get() - 1;
}
XWPFRun run = para.insertNewRun(start);
//设置样式
if (!ObjectUtils.isEmpty(finalXwpfRun)) {
run.setBold(finalXwpfRun.isBold());
if (ObjectUtils.isNotEmpty(finalXwpfRun.getColor())) {
run.setColor(finalXwpfRun.getColor());
}
if (ObjectUtils.isNotEmpty(finalXwpfRun.getFontFamily())) {
run.setFontFamily(finalXwpfRun.getFontFamily());
}
if (ObjectUtils.isNotEmpty(finalXwpfRun.getFontSizeAsDouble())) {
run.setFontSize(finalXwpfRun.getFontSizeAsDouble());
}
}
run.setText(text);
}
});
}
/**
* 正则匹配字符串
*/
private static boolean matcher(String str) {
Pattern pattern = Pattern.compile("\\<([\\u4e00-\\u9fa5]++)\\>", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);
boolean bool = matcher.find();
return bool;
}
/**
* 关闭输入流
*/
public static void close(InputStream is) {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 关闭输出流
*/
public static void close(OutputStream os) {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 多个文档合并
*/
public static void mergeDoc(List<XWPFDocument> list) throws Exception {
//默认获取第一个作为模板
XWPFDocument xmd = list.get(0);
for (int i = 0; i < list.size() - 1; i++) {
//相继合并
mergeWord(xmd, list.get(i + 1));
}
xmd.write(new FileOutputStream("F:\\test1.docx"));
}
private static XWPFDocument mergeWord(XWPFDocument document, XWPFDocument docDocument2) throws Exception {
XWPFParagraph p = document.createParagraph();
//设置分页符
p.setPageBreak(true);
CTBody src1Body = document.getDocument().getBody();
CTBody src2Body = docDocument2.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 document;
}
}