因项目需要把多个word文档合并,所以上网查了很多资料,最终用docx4j实现,docx4j 是一个基于 Java 的 Java 的开源库,专门用于处理 Microsoft Word 的 DOCX 格式文件。它允许开发者在 Java 应用中创建、读取、修改和生成符合 Office Open XML(OOXML)规范的 Word 文档(.docx 格式),无需依赖 Microsoft Office 软件。
话不多说,直接开始
一、导入依赖
因为项目本身就有slf4j,所以这里就屏蔽
<!-- https://mvnrepository.com/artifact/org.docx4j/docx4j -->
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j</artifactId>
<version>6.1.2</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
二、编写代码
1、根据文件路径合并转成word文档
通过文件路径进行合并,然后通过响应流返回,或者放开代码里面的注释,使用保存文件的方式,想必各位大佬都会吧,不用我再教你们如何创建文件的Output流了吧
// OutputStream outputStream = new FileOutputStream(outputPath); // targetPackage.save(outputStream);
/**
* 合并多个 DOCX 文件(文件路径)
* @param files 待合并的 DOCX 文件路径列表
* @param response HTTP 响应对象(输出合并后的文件)
*/
public static void mergeDocxFiles(List<String> files, HttpServletResponse response) throws Exception {
if (files == null || files.size() < 1) {
return;
}
// 1. 加载第一个文档作为目标文档(样式基准)
WordprocessingMLPackage targetPackage = WordprocessingMLPackage.load(new File(files.get(0)));
MainDocumentPart targetMainPart = targetPackage.getMainDocumentPart();
// 2. 遍历剩余文档,先合并样式,再复制内容
for (int i = 1; i < files.size(); i++) {
File sourceFile = new File(files.get(i));
if (!sourceFile.exists()) {
throw new IllegalArgumentException("文件不存在:" + sourceFile.getAbsolutePath());
}
try (InputStream sourceStream = new FileInputStream(sourceFile)) {
// 加载源文档
WordprocessingMLPackage sourcePackage = WordprocessingMLPackage.load(sourceStream);
MainDocumentPart sourceMainPart = sourcePackage.getMainDocumentPart();
// 关键步骤1:合并源文档的样式到目标文档(避免样式丢失)
mergeStyles(targetPackage, sourcePackage);
// 关键步骤2:添加分页符分隔不同文档(可选,根据需求调整)
// addPageBreak(targetMainPart);
// 关键步骤3:逐段复制源文档内容(替代 AltChunk,解决格式混乱)
copyContent(sourceMainPart, targetMainPart);
}
}
// 使用文件流的方式
// OutputStream outputStream = new FileOutputStream(outputPath);
// targetPackage.save(outputStream);
targetPackage.save(response.getOutputStream());
}
/**
* 合并源文档的样式到目标文档(避免样式冲突)
*/
private static void mergeStyles(WordprocessingMLPackage target, WordprocessingMLPackage source) throws Exception {
// 获取目标文档和源文档的样式部分
Styles targetStyles = target.getMainDocumentPart().getStyleDefinitionsPart().getJaxbElement();
Styles sourceStyles = source.getMainDocumentPart().getStyleDefinitionsPart().getJaxbElement();
// 复制源文档中目标文档没有的样式
for (Style sourceStyle : sourceStyles.getStyle()) {
boolean styleExists = targetStyles.getStyle().stream()
.anyMatch(targetStyle -> targetStyle.getStyleId().equals(sourceStyle.getStyleId()));
if (!styleExists) {
targetStyles.getStyle().add(sourceStyle); // 添加新样式
}
}
}
/**
* 复制源文档的内容(段落、表格等)到目标文档
*/
private static void copyContent(MainDocumentPart sourcePart, MainDocumentPart targetPart) {
// 获取源文档的所有内容
List<Object> sourceContent = sourcePart.getJaxbElement().getBody().getContent();
// 获取目标文档的主体
Body targetBody = targetPart.getJaxbElement().getBody();
for (Object content : sourceContent) {
// 不过滤空段落,确保所有内容都被复制
targetBody.getContent().add(content);
}
}
2、根据文件流集合转成word文档
/**
* 合并多个 DOCX 文件(流)
* @param sourceStreams
* @param response
* @throws Exception
*/
public static void mergeDocxFilesStreams(List<InputStream> sourceStreams, HttpServletResponse response) throws Exception {
if (sourceStreams == null || sourceStreams.size() < 1) {
return;
}
// 1. 加载第一个文档作为目标文档(样式基准)
WordprocessingMLPackage targetPackage = WordprocessingMLPackage.load(sourceStreams.get(0));
MainDocumentPart targetMainPart = targetPackage.getMainDocumentPart();
try {
for (InputStream sourceStream : sourceStreams) {
// 加载源文档
WordprocessingMLPackage sourcePackage = WordprocessingMLPackage.load(sourceStream);
MainDocumentPart sourceMainPart = sourcePackage.getMainDocumentPart();
// 关键步骤1:合并源文档的样式到目标文档(避免样式丢失)
mergeStyles(targetPackage, sourcePackage);
// 关键步骤2:添加分页符分隔不同文档(可选,根据需求调整)
// addPageBreak(targetMainPart);
// 关键步骤3:逐段复制源文档内容(替代 AltChunk,解决格式混乱)
copyContent(sourceMainPart, targetMainPart);
}
}catch (Exception e){
e.printStackTrace();
}
targetPackage.save(response.getOutputStream());
}
3、把xml文档转成word文档
springboot 利用freemarker模板生成word文档_freemarker html片段转docx-优快云博客
利用freemarker模板生成word文档,是xml格式,手机是不能直接打开的,需要使用工具才能打开,这很不方便,这个也是我们客户发现的,哈哈哈哈哈,所以我就突然想到是不是可以使用这篇文章的方式实现文件转换,没想到还真的可以,下面是示例代码。
public class WordUtil {
/**
* 生成 word 文件
*
* @param dataMap 待填充数据
* @param templateName 模板文件名称
* @param filePath 模板文件路径
* @param fileName 生成的 word 文件名称
* @param response 响应流
*/
public static void createWord(Map dataMap, String templateName, String filePath, String fileName, HttpServletResponse response){
// 创建配置实例
Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
// 设置编码
configuration.setDefaultEncoding(StandardCharsets.UTF_8.name());
// ftl模板文件
configuration.setClassForTemplateLoading(WordUtil.class, filePath);
try {
// 创建临时文件
File tempFile = File.createTempFile("temp", ".doc");
Template template = configuration.getTemplate(templateName);
// 保存为临时文件
FileOutputStream outputStream = new FileOutputStream(tempFile);
Writer out = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
template.process(dataMap, out);
// 关键修改:输出为docx格式
response.setHeader("Content-disposition",
"inline;filename=" + URLEncoder.encode(fileName + ".doc", StandardCharsets.UTF_8.name()));
// 修改MIME类型为docx
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
// 把响应流转成input流
DocxMerger.mergeDocxFilesStream(new FileInputStream(tempFile), response);
out.flush();
out.close();
tempFile.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 把流中的DOCX文件转成doc文件
* @param sourceStream
* @param response
* @throws Exception
*/
public static void mergeDocxFilesStream(InputStream sourceStream, HttpServletResponse response) throws Exception {
// 1. 加载第一个文档作为目标文档(样式基准)
WordprocessingMLPackage targetPackage = WordprocessingMLPackage.load(sourceStream);
MainDocumentPart targetMainPart = targetPackage.getMainDocumentPart();
try {
// 加载源文档
WordprocessingMLPackage sourcePackage = WordprocessingMLPackage.load(sourceStream);
MainDocumentPart sourceMainPart = sourcePackage.getMainDocumentPart();
// 关键步骤1:合并源文档的样式到目标文档(避免样式丢失)
mergeStyles(targetPackage, sourcePackage);
// 关键步骤2:添加分页符分隔不同文档(可选,根据需求调整)
// addPageBreak(targetMainPart);
// 关键步骤3:逐段复制源文档内容(替代 AltChunk,解决格式混乱)
copyContent(sourceMainPart, targetMainPart);
}catch (Exception e){
e.printStackTrace();
}
targetPackage.save(response.getOutputStream());
}
总结
所有事物都具有通用性和适应性,工具或功能的设计往往不局限于单一场景。通过简单的调整或重新配置,它们可以匹配不同的应用环境或需求,其价值在于灵活运用。稍加修改或重新组合,就能适应新的场景或解决不同的问题。这种灵活性是高效解决问题的关键。
1008

被折叠的 条评论
为什么被折叠?



