apache poi 插入“下一页分节符”并设置下一节纸张横向的一种方法

一、需求描述

我们知道,有时在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。

public static void exportToWord(List<EntityItem> records, String outputPath) throws Exception { try (XWPFDocument doc = new XWPFDocument()) { // ========== 1. 页面设置 ========== setupPageLayout(doc); // ========== 2. 分页处理 ========== int pageSizeLimit = 4; // 每页数据行数(不含表头) int currentPageRowCount = 0; XWPFTable currentTable = null; // 创建第一页表格 currentTable = doc.createTable(); setupTable(currentTable); createTableHeader(currentTable); currentPageRowCount = 0; // ========== 3. 处理数据行 ========== int num = 0; for (EntityItem record : records) { // 计算当前记录所需行数(考虑图片换行) int imageRows1 = (int) Math.ceil(record.getPropertyUri().size() / 3.0); int imageRows2 = (int) Math.ceil(record.getNameplateUri().size() / 3.0); int recordRows = Math.max(imageRows1, imageRows2); // +1为文本行 // 检查是否需要新建页面(当前页空间不足) if (currentPageRowCount + recordRows > pageSizeLimit) { // 创建新页 doc.createParagraph().setPageBreak(true); // 分页 currentTable = doc.createTable(); setupTable(currentTable); createTableHeader(currentTable); currentPageRowCount = 0; } // 添加数据行 XWPFTableRow row = currentTable.createRow(); row.setCantSplitRow(true); // 禁止行跨页 // 序号列 createCenteredCell(row, 0, String.valueOf(++num)); // 工装编号列 createCenteredCell(row, 1, record.getToolNumber()); // 资产名称列 createCenteredCell(row, 2, record.getToolName()); // 图片列处理 XWPFTableCell imageCell = row.getCell(3); addImagesToCell(imageCell, record.getPropertyUri(), "D:\\imageFile\\"); XWPFTableCell nameplateCell = row.getCell(4); addImagesToCell(nameplateCell, record.getNameplateUri(), "D:\\imageFile\\"); // 更新当前页行计数(包括图片换行产生的额外行) currentPageRowCount += recordRows; } // ========== 5. 保存文档 ========== try (FileOutputStream out = new FileOutputStream(outputPath)) { doc.write(out); } } } // 页面设置 private static void setupPageLayout(XWPFDocument doc) { CTSectPr sectPr = doc.getDocument().getBody().addNewSectPr(); CTPageSz pageSize = sectPr.addNewPgSz(); pageSize.setOrient(STPageOrientation.LANDSCAPE); pageSize.setW(BigInteger.valueOf(16840)); // A4横向宽度 pageSize.setH(BigInteger.valueOf(11900)); // A4横向高度 // 紧凑页边距(单位:twips) CTPageMar pageMar = sectPr.addNewPgMar(); pageMar.setLeft(BigInteger.valueOf(390)); // 1.5cm pageMar.setRight(BigInteger.valueOf(390)); // 1.5cm pageMar.setTop(BigInteger.valueOf(900)); // 2cm pageMar.setBottom(BigInteger.valueOf(900)); // 2cm pageMar.setFooter(BigInteger.valueOf(900)); // 页脚1.59cm } // 表格基础设置 private static void setupTable(XWPFTable table) { table.setWidth("100%"); int[] columnWidths = {500, 800, 1200, 5000, 5000}; CTTbl cttbl = table.getCTTbl(); CTTblGrid tblGrid = cttbl.addNewTblGrid(); for (int width : columnWidths) { tblGrid.addNewGridCol().setW(BigInteger.valueOf(width)); } } // 创建表头 private static void createTableHeader(XWPFTable table) { int[] columnWidths = {500, 800, 1200, 5000, 5000}; XWPFTableRow headerRow = table.getRow(0); for (int i = 0; i < columnWidths.length; i++) { XWPFTableCell cell = headerRow.getCell(i); if (cell == null) cell = headerRow.createCell(); // 设置列宽 cell.getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf(columnWidths[i])); // 创建段落 cell.removeParagraph(0); XWPFParagraph para = cell.addParagraph(); para.setAlignment(ParagraphAlignment.CENTER); // 设置标题样式 XWPFRun run = para.createRun(); run.setBold(true); run.setFontSize(12); run.setText(getHeaderText(i)); } } // 创建水平居中单元格 private static void createCenteredCell(XWPFTableRow row, int pos, String text) { XWPFTableCell cell = row.getCell(pos); if (cell == null) cell = row.createCell(); cell.removeParagraph(0); XWPFParagraph para = cell.addParagraph(); para.setAlignment(ParagraphAlignment.CENTER); XWPFRun run = para.createRun(); run.setText(text); } // 添加图片到单元格(含换行处理) private static void addImagesToCell(XWPFTableCell cell, List<String> imagePaths, String basePath) throws Exception { cell.removeParagraph(0); // 清除默认段落 // 如果没有图片,添加空段落占位 if (imagePaths == null || imagePaths.isEmpty()) { cell.addParagraph(); return; } XWPFParagraph currentPara = cell.addParagraph(); currentPara.setAlignment(ParagraphAlignment.LEFT); XWPFRun currentRun = currentPara.createRun(); int imageCount = 0; for (String imagePath : imagePaths) { try (InputStream is = new FileInputStream(basePath + imagePath)) { // 添加图片(100x100 EMU) currentRun.addPicture(is, XWPFDocument.PICTURE_TYPE_PNG, imagePath, Units.toEMU(100), Units.toEMU(100)); imageCount++; // 每3张图片换行(且不是最后一张) if (imageCount % 3 == 0 && imageCount < imagePaths.size()) { currentPara = cell.addParagraph(); // 新建段落实现换行 currentPara.setAlignment(ParagraphAlignment.LEFT); currentRun = currentPara.createRun(); } } } } // 表头文本 private static String getHeaderText(int colIndex) { String[] headers = {"序号", "工装编号", "资产名称", "关联图片", "铭牌"}; return headers[colIndex]; } 增加页码,第几页共几页
最新发布
07-05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我一时想不起

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值