一、需求描述
我们知道,有时在word中需要同时存在不同的节,部分页面需要竖向、部分页面需要横向。本文就是用java调用apache poi来实现用代码生成上述效果。下图是本文实现的效果,供各位看官查阅,本文以一篇课文为例,共三页,插入了两个“下一页分节符”,其中第一页为纵向,第二页为横向,第三页为纵向。接下来请看具体实现思路和示例代码。本文示例代码仅供学习交流,切勿直接用于生产环境。
二、实现思路
1.Apache POI的分页符
关于分页符,首先想到的是XWPFRun类的addBreak方法,经查阅API文档,发现addBreak的入参BreakType枚举一共有三种类型的可以选择,分别是COLUMN(分栏)、PAGE(分页)、TEXT_WRAPPING(下一行)。由此可见,无法通过addBreak的方式添加“下一页分节符”。
2.关于Office Open XML
根据微软网站显示,“Open XML 是可由不同平台上的多个应用程序自由实现的字处理文档、演示文稿和电子表格的开放式标准。 Open XML 旨在如实表示用 Microsoft Office 应用程序定义的二进制格式进行编码的现有字处理文档、演示文稿和电子表格。”而Apache POI的jar包中poi-ooxml前缀的jar提供了通过Open XML的方式处理Word的方法。所以可以使用操作xml的方式生成“下一页分节符”。
在WPS office中插入下一页分节符后,将word另存为xml,通过xml编辑器\阅读器查看xml代码,可以初步得出控制“下一页分节符”的元素是sectPr,控制页面尺寸及方向的元素是pgSz。因此调用新增sectPr和pgSz的方法即可实现下一页分节符。
<w:body>
<w:p>
<w:pPr>
<w:sectPr>
<w:pgSz w:w="11906" w:h="16838"/>
<w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="851" w:footer="992" w:gutter="0"/>
<w:cols w:space="425" w:num="1"/>
<w:docGrid w:type="lines" w:linePitch="312" w:charSpace="0"/>
</w:sectPr>
</w:pPr>
<w:r>
<w:t>崇祯五年十二月,余住西湖。大雪三日,湖中人鸟声俱绝。是日更定矣,余挐一小舟,拥毳衣炉火,独往湖心亭看雪。雾凇沆砀,天与云与山与水,上下一白。湖上影子,惟长堤一痕、湖心亭一点、与余舟一芥、舟中人两三粒而已。</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t>到亭上,有两人铺毡对坐,一童子烧酒,炉正沸。见余大惊喜,曰:“湖中焉得更有此人?”拉余同饮。余强饮三大白而别。问其姓氏,是金陵人,客此。及下船,舟子喃喃曰:“莫说相公痴,更有痴似相公者!”</w:t>
</w:r>
<w:bookmarkStart w:id="0" w:name="_GoBack"/>
<w:bookmarkEnd w:id="0"/>
</w:p>
<w:sectPr>
<w:pgSz w:w="16838" w:h="11906" w:orient="landscape"/>
<w:pgMar w:top="1800" w:right="1440" w:bottom="1800" w:left="1440" w:header="851" w:footer="992" w:gutter="0"/>
<w:cols w:space="425" w:num="1"/>
<w:docGrid w:type="lines" w:linePitch="312" w:charSpace="0"/>
</w:sectPr>
</w:body>
3.插入下一页分节符的实现
以下是在Apache POI中简单地实现插入下一页分节符的一种方法。
CTBody body = document.getDocument().getBody();
CTPPr ctpPr1 = body.addNewP().addNewPPr();
CTSectPr ctSectPr1 = ctpPr1.addNewSectPr();
4.设置页面方向及尺寸的实现
以下是在Apache POI中设置页面尺寸的一种方法。宽高值的单位约为1/20磅。以下宽高值为横向A4纸的宽高值。
CTPageSz pageSize = ctSectPr.addNewPgSz();
pageSize.setOrient(STPageOrientation.LANDSCAPE);// 设置页面方向
pageSize.setW(BigInteger.valueOf(16838)); // 设置页面宽度
pageSize.setH(BigInteger.valueOf(11906)); // 设置页面高度
三、代码示例
代码中实现了,在一个空白文档中创建了三个段落,通过新增两个sectPr元素实现插入两个“下一页分节符”,新增了一个自定义的全局sectPr,控制第三页的尺寸方向,其中第一页和最后一页是纵向纸张,第二页是横向纸张。从呈现效果上来描述,第一页书写了课文的上半部分,第二页书写了课文的下半部分,并设置纸张横向,第三页书写了课文的译文,纸张纵向。
以下是代码示例,受限于个人编程水平,此代码仅能说明实现需求的代码,未对生产环境的种种情况加以考虑,各位看官切莫直接用于生产环境。如有错误,欢迎批评指正。
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;public class TestWord1 {public static void main(String[] args) {try {create("测试分页符号2.docx");} catch (IOException e) {e.printStackTrace();}}public static void create(String path) throws IOException {XWPFDocument document = new XWPFDocument();FileOutputStream out = new FileOutputStream(new File(path));// 创建第一段XWPFParagraph paragraph1 = document.createParagraph();XWPFRun run1 = paragraph1.createRun();run1.setText("崇祯五年十二月,余住西湖。大雪三日,湖中人鸟声俱绝。是日更定矣,余挐一小舟,拥毳衣炉火,独往湖心亭看雪。" +"雾凇沆砀,天与云与山与水,上下一白。湖上影子,惟长堤一痕、湖心亭一点、与余舟一芥、舟中人两三粒而已。");//创建CTSectionPr对象,第一个分节符CTBody body = document.getDocument().getBody();body.addNewP().addNewPPr().addNewSectPr();// 创建第二段XWPFParagraph paragraph2 = document.createParagraph();XWPFRun run2 = paragraph2.createRun();run2.setText("到亭上,有两人铺毡对坐,一童子烧酒,炉正沸。见余大惊喜,曰:“湖中焉得更有此人?”拉余同饮。余强饮三大白而别。问其姓氏," +"是金陵人,客此。及下船,舟子喃喃曰:“莫说相公痴,更有痴似相公者!");//创建一个空白段CTPPr ctpPr2 = body.addNewP().addNewPPr();// 创建CTSectionPr对象,第二个分节符CTSectPr ctSectPr2 = ctpPr2.addNewSectPr();// 创建页尺寸对象CTPageSz pageSize2 = ctSectPr2.addNewPgSz();// 设置页面方向和尺寸pageSize2.setOrient(STPageOrientation.LANDSCAPE);pageSize2.setW(BigInteger.valueOf(16838)); // 设置页面宽度pageSize2.setH(BigInteger.valueOf(11906)); // 设置页面高度// 创建第三段,最后一个分节符之后的内容XWPFParagraph paragraph3 = document.createParagraph();XWPFRun run3 = paragraph3.createRun();run3.setText("译文:译文译文译文译文译文译文译文译文译文译文译文译文译文译文译文" +"译文译文译文译文译文译文译文译文译文译文译文译文译文译文译文" +"译文译文译文译文译文译文译文译文译文译文译文译文译文译文译文" +"译文译文译文译文译文译文译文译文译文译文译文译文译文译文译文" +"译文译文译文译文译文译文译文译文译文译文译文译文译文译文译文");CTSectPr globalSectPr = body.addNewSectPr();CTPageSz globalPageSize = globalSectPr.addNewPgSz();globalPageSize.setOrient(STPageOrientation.PORTRAIT);body.setSectPr(globalSectPr);document.write(out);out.close();System.out.println(path + "成功生成!");}}
说明,经过实践,若需要最后一节末尾不带分节符,需要不在段落后新增sectPr,而是在body中新增,并在新增的sectPr上设置页面尺寸,并将该尺寸用于body的sectPr。