java使用apache poi操作word文档_apache arrow java
前言
产品期望实现【公文管理】其中发文拟文一块内容,用户上传正文(word),再选择不同套红模板,最后拼接为一个对外发文,的公文格式。
基于上次使用vue实现在线编辑功能,产品不太满意,重新学习java如何操作word文档,之前地址:(vue使用Tinymce富文本模拟在线word文档)juejin.cn/post/723665…
最终效果
有两个文件test1.docx (作为红头模板)和test2.docx(作为正文);期望实现效果:用户选择红头模板加上自己写的正文内容,最终生成可编辑的word文档。
create_table.docx 合并之后最终效果“
test1.docx 红头模板:
test2.docx 正文(用户撰写上传的内容):
准备阶段
技术选型
- docx4j:一个用 文档的 Java 库,具有良好的文档合并功能。
- JODConverter:一个不依赖于 OpenOffice/LibreOffice 的 Java 库,可以帮助开发者将 Office 文档转换成 PDF、HTML、XHTML、ODF 等格式,并支持合并 Word 文档。
- Aspose.Words for Java:一个商业级的文档处理库,支持多种文档格式的处理,包括 Word、PDF、HTML 等,并且支持合并 Word 文档。
- FreeMarker:一个模板引擎库,可以用于制作 Word 文档模板,然后使用 Java 代码生成文档。
- Apache POI: 是一个开源的 Java 库,可以用来读写 Microsoft Office 文档,包括 Word、Excel、PowerPoint 等各种格式。它是 Apache 软件基金会的一部分,最新版本是 5.0.0。
如标题所示,最终采用Apache POI来实现这个功能主要原因:
- 读取和创建 Microsoft Office 文档,包括 Word、Excel、PowerPoint 等多种格式。
- 支持访问和修改文档的所有元素,比如文本、样式、图表、格式等。
- 提供丰富的工具类和方法,可以方便地进行文档操作,比如把文本转换成 HTML、从 Excel 中读取数据、合并 Word 文档等。
- 支持不同版本的 Office 文档格式,包括旧版本和新版本。
- 支持批量处理大量文档,提高了文档处理的效率。
主要是对于我这种初学者来说是非常友好的,太复杂玩不转。Apache POI 的使用非常简单,只需添加它的 jar 包到项目中,并调用相应的 API 即可实现文档读写。同时,Apache POI 提供了丰富的文档和官方网站上的文档也很详细。
功能设计思路
- 创建一个空的 Word 文档作为合并后的文档。
- 读取要合并的 Word 文档(test1.doxc、test2.docx),并将它们的内容复制到合并后的文档中。可以使用 Apache POI 中的 XWPFDocument 类来读写 Word 文档。
- 保存合并后的文档。使用 XWPFDocument 类的 write(OutputStream out) 方法将文档保存到本地文件或输出流中。
功能实现
Apache POI,分别为 Word、Excel、PowerPoint 等各种格式提供不同的类方法,我们需要操作Word文档的功能,所以使用(Java API for Microsoft Documents)中的XWPFDocument类,实现文档合并功能。
整理不同格式文档操作类
- HSSF: MS-Excel 97-2003(.xls),基于BIFF8格式的JAVA接口。
- XSSF:MS-Excel 2007+(.xlsx),基于OOXML格式的JAVA接口。
- HWPF: MS-Word 97-2003(.doc),基于BIFF8格式的JAVA接口。只支持.doc文件简单的操作,读写能力有限。本API为POI项目早期开发,很不幸的 是主要负责HWPF模块开发的工程师-"Ryan Ackley"已经离开Apache组织,现在该模块没有人维护、更新、完善。
- XWPF:MS-Word 2007+(.docx),基于OOXML格式的JAVA接口。较HWPF功能完善。
注意:word文档目前有两种不同格式,一种是以doc结尾的,另一种以docx结尾,本次功能主要讲解docx格式文档操作,doc格式文档调用的类和函数HWPF开头。
两者区别:doc是Word2007及以下版的文件扩展名,而docx是Word2007及以上版本的文件扩展名,docx版本兼容性较高,而且比doc文件所占用空间更小。
引入依赖
在pom.xml文件中引入maven依赖,
org.apache.poi
poi-scratchpad
4.1.2
org.apache.poi
poi
4.1.2
org.apache.poi
poi-ooxml-schemas
4.1.2
org.apache.poi
poi-ooxml
4.1.2
示例代码
简化整体流程,创建两个word文件test1.docx和test2.docx。将下列file对应的文件路径换成自己创建的文件路径创,建单个java文件(带main),直接运行main方法输出creat_table.docx文件。 先上代码,再进行讲解:
package org.ssssssss.magicboot;
import org.apache.poi.xwpf.usermodel.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.List;
public class WordDocumentTest {
public static void main(String[] args) throws Exception
{
//获取文件转io流
File file1 = new File("D:/IDM/test1.docx");
File file2 = new File("D:/IDM/test2.docx");
FileInputStream fis1 = new FileInputStream(file1);
FileInputStream fis2 = new FileInputStream(file2);
//最终文件输出的路径
FileOutputStream out = new FileOutputStream(new File("D:/IDM/create_table.docx"));
//转为word文档元素
XWPFDocument dcx1 = new XWPFDocument(fis1);
XWPFDocument dcx2 = new XWPFDocument(fis2);
//创建一个新的文档
XWPFDocument document= new XWPFDocument();
//将第一个文档元素复制新创建的文档中;
document = dcx1;
//换行 document.createParagraph().createRun().addBreak();
//将第二个docx内容添加到新创建的文档中
mergeParagraphs(dcx2.getParagraphs(), document);
//结束关闭io流
document.write(out);
out.close();
fis1.close();
fis2.close();
System.out.println("create_table document written success.");
}
// 合并文本段落
private static void mergeParagraphs(List paragraphs, XWPFDocument outDoc) {
for (XWPFParagraph para : paragraphs) {
XWPFParagraph newPara = outDoc.createParagraph();
newPara.getCTP().setPPr(para.getCTP().getPPr());
//判断是否是文本、段落、图片 //.getRPr() para.tables !=null ,iruns 获取图片
for (XWPFRun run : para.getRuns()) {
XWPFRun newRun = newPara.createRun();
newRun.getCTR().setRPr(run.getCTR().getRPr());
newRun.setText(run.getText(0));
}
}
}
代码解释
实现流程主要看代码中的注释,包含以下几个步骤
- 获取文件转io流
- 将io流转为word文档元素(XWPFDocument)
- 创建一个新的文档
- 将第一个文档元素复制新创建的文档中
- 将第二个docx内容添加到新创建的文档中
- 输出新文档,关闭io流
核心重点将第二个docx内容添加到新创建的文档中封装mergeParagraphs方法,在这个方法中传入了两个参数(List paragraphs, XWPFDocument outDoc) 其中List
刚才对XWPFRun没有进行很好的解释,这里重新举例说明下,例如以下标红的段落
按照正常理解这一个段落内容应该是一个东西,其实在XWPF中会划分为不同的XWPFRun,使用idea打断点查看数据
可以看出它将一段文字划分为不同模块,为什么会这样,在一段文字中也存在不同的区别,例如文字的字体,像下图中“根据”“2023”属于不同的字体,所以会划分为不同的XWPFRun,理解这个概念后同理明白为什么一个段落会划分为29模块
相关函数
在前面其实已经实现第一个模块最终效果的docx文档合并的功能,所以在这个模块讲解在实现这个过程中记录有意思的内容。
XWPFRun(文本段落)
接着上面讲XWPFRun这个函数,XWPFRun用于在 Word 文档中添加或修改单个本 Run 或 Run 中的文字格式。它是文本段落(XWPFParagraph)中的最小单元,用于精细控制文本的格式和样式。可以使用 XWPFRun 类的各种方法来设置文本的字体、大小、颜色、加粗、斜体、下划线等格式。 下列是在使用过程中记录的一些属性,以及这些属性对应能够设置的格式注释。
XWPFRun run = firstParagraph.createRun();
XWPFRun tempRun = xwpfRuns.get(i);
//默认:宋体(wps)/等线(office2016) 5号 两端对齐 单倍间距
run.setText(tempRun.text());
//加粗
run.setBold(tempRun.isBold());
//我也不知道这个属性做啥的
run.setCapitalized(tempRun.isCapitalized());
//设置颜色--十六进制
run.setColor(tempRun.getColor());
//这个属性报错
run.setCharacterSpacing(tempRun.getCharacterSpacing());
//浮雕字体----效果和印记(悬浮阴影)类似
run.setEmbossed(tempRun.isEmbossed());
//双删除线
run.setDoubleStrikethrough(tempRun.isDoubleStrikeThrough());
run.setEmphasisMark(tempRun.getEmphasisMark().toString());
//字体,//字体,范围----效果不详
run.setFontFamily(tempRun.getFontFamily());
//字体大小,没有设置默认是-1,
if(tempRun.getFontSize() != -1){
run.setFontSize(tempRun.getFontSize());
}
//印迹(悬浮阴影)---效果和浮雕类似
run.setImprinted(tempRun.isImprinted());
//斜体(字体倾斜)
run.setItalic(tempRun.isItalic());
//字距调整----这个好像没有效果
run.setKerning(tempRun.getKerning());
//阴影---稍微有点效果(阴影不明显)
run.setShadow(tempRun.isShadowed());
//小型股------效果不清楚
run.setSmallCaps(tempRun.isSmallCaps());
//单删除线(废弃)
run.setStrike(tempRun.isStrike());
//单删除线(新的替换Strike)
run.setStrikeThrough(tempRun.isStrikeThrough());
//下标(吧当前这个run变成下标)---枚举
run.setSubscript(tempRun.getSubscript());
//设置两行之间的行间距
run.setTextPosition(tempRun.getTextPosition());
//各种类型的下划线(枚举)
run.setUnderline(tempRun.getUnderline());
run.setVerticalAlignment(tempRun.getVerticalAlignment().toString());
run.setVanish(tempRun.isVanish());
run.setUnderlineThemeColor(tempRun.getUnderlineColor());
run.setUnderlineColor(tempRun.getUnderlineColor());
run.setTextScale(tempRun.getTextScale());
run.setTextPosition(tempRun.getTextPosition());
run.setTextHighlightColor(tempRun.getTextHightlightColor().toString());
// run.setStyle(tempRun.gets); 没找到这个属性
run.setLang(tempRun.getLang());
XWPFParagraph(段落)
XWPFParagraph 是 Apache POI 库中 XWPF 模块的一部分,用于创建或修改 Word 文档中的段落。它可以添加不同的文本格式,并且可以添加图片、表格、超链接等内容。XWPFParagraph 类可以控制段落的样式和格式,包括字体、字号、行距、首行缩进、对齐方式等。可以使用 XWPFParagraph 类的各种方法来设置段落的格式和样式。
常用方法:
//创建一个新的 XWPFRun 对象,用于在段落中添加文本或修改文本格式。
createRun()
//设置段落的对齐方式,align 参数可以是 LEFT、CENTER、RIGHT、JUSTIFY 等值。
setAlignment(ParagraphAlignment align)
//设置段落的行距和行距规则,lineSpacing 参数是行距大小(以磅为单位),lineSpacingRule 参数可以是 EXACT、AT_LEAST、AUTO 等值。
setSpacingBetween(int lineSpacing, LineSpacingRule lineSpacingRule)
//设置段落的左缩进大小(以磅为单位)。
setIndentationLeft(int indentation)
//设置段落的右缩进大小(以磅为单位)。
setIndentationRight(int indentation)
//设置段落的编号 ID。
setNumID(BigInteger numId)
//设置段落的编号格式,numFmt 参数可以是 DECIMAL、LOWERCASE_LETTER、UPPERCASE_LETTER 等值。
setNumFmt(NumberFormat numFmt)
//在段落中添加图片,pictureType 参数是图片类型,filename 参数是图片文件名,width 和 height 参数是图片宽度和高度。
createPicture(XWPFRun run, int pictureType, String filename, int width, int height)
其他方法:
//指定应显示在左边页面指定段周围的边界。
setBorderBottom(Borders.APPLES);
//指定应显示在下边页面指定段周围的边界。
setBorderLeft(Borders.APPLES);
//指定应显示在右侧的页面指定段周围的边界。
setBorderRight(Borders.ARCHED_SCALLOPS);
//指定应显示上方一组有相同的一组段边界设置的段落的边界。这几个是对段落之间的格式的统一,相当于格式刷
setBorderTop(Borders.ARCHED_SCALLOPS);
//---正文宽度会稍微变窄
p1.setFirstLineIndent(99);
//---段落的对齐方式 1左 2中 3右 4往上 左 不可写0和负数
p1.setFontAlignment(1);
//---首行缩进,指定额外的缩进,应适用于父段的第一行。
p1.setIndentationFirstLine(400);
//---首行前进,指定的缩进量,应通过第一行回到开始的文本流的方向上移动缩进从父段的第一行中删除。
p1.setIndentationHanging(400);
//---整段右移
p1.setIndentFromLeft(400);
//--此方法提供了样式的段落,这非常有用。
p1.setStyle("");
//--此元素指定是否消费者应中断超过一行的文本范围,通过打破这个词 (打破人物等级) 的两行或通过移动到下一行 (在词汇层面上打破) 这个词的拉丁文字。
p1.setWordWrapped(true);
//---指定的文本的垂直对齐方式将应用于此段落中的文本
p1.setVerticalAlignment(TextAlignment.CENTER);
//--指定行之间的间距如何计算存储在行属性中。
p1.setSpacingLineRule(LineSpacingRule.AT_LEAST);
//--指定应添加在此线单位在文档中的段落的第一行之前的间距。
p1.setSpacingBeforeLines(6);
//--指定应添加上面这一段文档中绝对单位中的第一行的间距。
p1.setSpacingBefore(6);
//--指定应添加在此线单位在文档中的段落的最后一行之后的间距。
p1.setSpacingAfterLines(6);
//--指定应添加在文档中绝对单位这一段的最后一行之后的间距。
p1.setSpacingAfter(6);
//--指定当渲染此分页视图中的文档,这一段的内容都呈现在文档中的新页的开始。
p1.setPageBreak(true);
其他功能
刚在展示活动内容都是根据自身的需求写小demo,实际项目远远不止这些内容,其中还是存在不足之处,例如word中的表格、图片都是需要单独处理,表格有个专门类XWPFTable;图片也有XWPFPictureData、 XWPFPicture,
学习参考
Apache POI 官方网站提供了完整的 API 文档:
poi.apache.org/apidocs/dev…
Apache POI 的 GitHub 仓库中查看示例代码和文档:github.com/apache/poi
Java POI 生成Word文档:blog.csdn.net/qq_34755766…
Apache POI 中文版
download.csdn.net/download/qq…
作者:沐游虞
转自:
https://juejin.cn/post/7237487091554730021
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。