1.pom包
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.8.1</version>
</dependency>
2.合并word工具类
package cn.com.fesco.hpe.config;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.BreakType;
import org.apache.poi.xwpf.usermodel.Document;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 参数1:需要合并的word的文件对象list
* 参数2:合并之后word存储的全路径file对象
*/
public class MergeDocUtils {
public static void mergeDoc(List<File> fileList, File newFile) throws Exception {
OutputStream dest = new FileOutputStream(newFile);
ArrayList<XWPFDocument> documentList = new ArrayList<XWPFDocument>();
XWPFDocument doc = null;
for (int i = 0; i < fileList.size(); i++) {
FileInputStream in = new FileInputStream(fileList.get(i).getPath());
OPCPackage open = OPCPackage.open(in);
XWPFDocument document = new XWPFDocument(open);
documentList.add(document);
}
for (int i = 0; i < documentList.size(); i++) {
doc = documentList.get(0);
if (i != 0) {
//documentList.get(i).createParagraph().setPageBreak(true);//实现了分页效果。//但是会出现在首行为空的情况
documentList.get(i).createParagraph().createRun().addBreak(BreakType.PAGE);//现了分页效果。使用这种方式不会出现留白的情况
appendBody(doc, documentList.get(i));
}
}
doc.write(dest);//输出合并之后的文件
}
public static void appendBody(XWPFDocument src, XWPFDocument append) throws Exception {
CTBody src1Body = src.getDocument().getBody();
CTBody src2Body = append.getDocument().getBody();
List<XWPFPictureData> allPictures = append.getAllPictures();
// 记录图片合并前及合并后的ID
Map<String, String> map = new HashMap();
for (XWPFPictureData picture : allPictures) {
String before = append.getRelationId(picture);
//将原文档中的图片加入到目标文档中
String after = src.addPictureData(picture.getData(), Document.PICTURE_TYPE_PNG);
map.put(before, after);
}
appendBody(src1Body, src2Body, map);
}
private static void appendBody(CTBody src, CTBody append, Map<String, String> map) throws Exception {
XmlOptions optionsOuter = new XmlOptions();
optionsOuter.setSaveOuter();
String appendString = append.xmlText(optionsOuter);
//去掉追加word内容中的 w:sectPr 标签,确保合成的word中只有一个 w:sectPr 标签对
//避免合成的word文档打开之后会提示有些内容读不出来,导致文件损坏
String rgex = "<[\\s]*?w:sectPr[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?w:sectPr[\\s]*?>";
appendString = appendString.replaceAll(rgex, "");
String srcString = src.xmlText();
String regex = regex(srcString, "w:sectPr");
System.out.println(regex);
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("<"));
if (map != null && !map.isEmpty()) {
//对xml字符串中图片ID进行替换
for (Map.Entry<String, String> set : map.entrySet()) {
addPart = addPart.replace(set.getKey(), set.getValue());
}
}
//将两个文档的xml内容进行拼接
CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart + sufix);
src.set(makeBody);
}
/**
* 获取指定标签中的内容
*
* @param xml
* @param label
* @return
*/
public static String regex(String xml, String label) {
String context = "";
// 正则表达式
String rgex = "<" + label + "[^>]*>((?:(?!<\\/" + label + ">)[\\s\\S])*)<\\/" + label + ">";
Pattern pattern = Pattern.compile(rgex);// 匹配的模式
Matcher m = pattern.matcher(xml);
// 匹配的有多个
List<String> list = new ArrayList<String>();
while (m.find()) {
int i = 1;
list.add(m.group(i));
i++;
}
if (list.size() > 0) {
// 输出内容自己定义
context = String.valueOf(list.size());
}
return context;
}
}
3.代码实例
//new一个list 模拟要合并的word对象集合
List<File>docFileList = new ArrayList<>();
docFileList.add(new File("D:/pdfData/2022-06-23-2c3d300450884b19bb58585d2c4ae518.docx"));
docFileList.add(new File("D:/pdfData/2022-06-23-4a899305225e4fd8abc7ae154841124c.docx"));
//合并之后doc存储路径 此处读的配置文件的存储路径 D:/pdfData/
String docPath = fileUploadConfig.getDocPath();
//当前日期+UUID作为文件名防止重复
String fileName = LocalDate.now() + "-" + UUID.randomUUID().toString().replaceAll("-", "");
//合并之后doc存储路径
String mergeDocUrl = docPath+fileName+".docx";
//转成file对象
File mergeDocFile = new File(mergeDocUrl);
//合并doc
MergeDocUtils.mergeDoc(docFileList,mergeDocFile);
System.out.println("合并word成功");
4.分页问题,我直接读的word模板,填充的数据,下边动态生成的表格
word填充模板,动态生成表格可以看这条poi填充word,动态生成表格+LibreOffice转成pdf_ytqucheng的博客-CSDN博客_poi 动态生成word表格
直接在word模板上需要分页的地方添加分页标识符,
我这里直接在最后一行加的分页标识
下面上图片
5.效果图