POI word (三)分栏 及分栏后页眉页脚的使用 - 哔哩哔哩

概述

这个问题是困扰了我好几天,走了很多弯路。但是这个问题解决后我对POI就有了新的认识。或者说对word结构有了新的认识。

分栏

一开始自己建了头部不分栏,内容分栏的文档。类似于下图这样。

分栏文档

将word文档另存为成XML文件如下图所示

分栏后的XML结构

分栏后此时word文档就拥有了两个 sectPr 标签组,sectPr这个标签组就是用来标识分栏结构了,从里面的一些属性也可以看出来。 单纯的分栏结构还是比较简单的,跟着文件,依葫芦画瓢。

public static void main(String[] args) throws Exception {

    XWPFDocument document = new XWPFDocument();
    splitColumn(document);
    document.write(new FileOutputStream("D:\\workspace\\demo\\src\\test\\resources\\CreateWordFormulaFromLaTeX.docx"));
}
/**
     * 分栏
     * @param document
     */
    private static void splitColumn(XWPFDocument document) {
        XWPFParagraph paragraph = document.createParagraph();
        paragraph.createRun().setText("4444444444444444444444444444444444444444444");
        document.createParagraph().createRun().setText("33333333333333333333333333333333333333333333333333");

        CTP ctp1 = document.createParagraph().getCTP();
        CTBorder bottom = ctp1.addNewPPr().addNewPBdr().addNewTop();
        bottom.setVal(STBorder.Enum.forInt(3));

        // 分栏
        CTBody body =  document.getDocument().getBody();
        CTSectPr ctSectPr1 = body.addNewP().addNewPPr().addNewSectPr();
        ctSectPr1.addNewCols().setNum(BigInteger.valueOf(1));


        XWPFRun run = document.createParagraph().createRun();
        run.setText("sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss");
        run.setTextHighlightColor("lightGray");
        CTSectPr ctSectPr = body.addNewSectPr();

        ctSectPr.addNewType().setVal(STSectionMark.Enum.forString("continuous"));
        CTColumns ctColumns = ctSectPr.addNewCols();
        ctColumns.setNum(BigInteger.valueOf(2));
        ctColumns.setSep(STOnOff.Enum.forInt(1));
    }

解决分栏后页眉页脚不可用的问题

分栏问题是解决,但是页眉,页脚,页边距这些设置全都不生效了。也就是加入示例二

中的代码。没办法还是得老老实实看源码结构。将上面文档改成如下图这样。

另存为XML文档

分栏后页眉页脚的word结构

POI生成的页眉页脚结构

看完word结构后 比对POI生成的代码, 可以看出来word第一个sectPr实在P(段落)标签里面的,POI生成的sectPr是直接在body下面的。知道了问题那就找解决问题的方法。

给分栏设置页边距还是比较简单的只要传入CTSectPr对象就可以了

private static void setDocumentMarginForSec(CTSectPr sectPr,String left,String top, String right, String bottom) {
       CTPageMar ctpagemar = sectPr.addNewPgMar();
       if (!org.springframework.util.StringUtils.isEmpty(left)) {
           ctpagemar.setLeft(new BigInteger(left));
       }
       if (!org.springframework.util.StringUtils.isEmpty(top)) {
           ctpagemar.setTop(new BigInteger(top));
       }
       if (!org.springframework.util.StringUtils.isEmpty(right)) {
           ctpagemar.setRight(new BigInteger(right));
       }
       if (!org.springframework.util.StringUtils.isEmpty(bottom)) {
           ctpagemar.setBottom(new BigInteger(bottom));
       }
       ctpagemar.setHeader(new BigInteger(top).divide(new BigInteger("2")));
       ctpagemar.setFooter(new BigInteger(bottom).divide(new BigInteger("2")));
   }

纠结了很久的问题在于页眉页脚的设置 ,因为它在sect上是一个ref并不是直接加上去了。就是找这个关系找了很久。

其实把代码往里看几层就能找到,但是当时就困扰了很久。学会页眉的构造方式。创建相应方法如下

private static void createHeaderForSec(XWPFDocument document, CTSectPr ctSectPr1, String text,boolean withSplitLine) {
     // 页眉文字
     CTP ctp = CTP.Factory.newInstance();
     XWPFParagraph paragraph = new XWPFParagraph(ctp, document);
     ctp.addNewR().addNewT().setStringValue(text);
     ctp.addNewR().addNewT().setSpace(SpaceAttribute.Space.PRESERVE);

     XWPFParagraph paragraph2 = null;
     if (withSplitLine){
         // 分割线
         CTP splitLine = CTP.Factory.newInstance();
         paragraph2 = new XWPFParagraph(splitLine, document);
         CTBorder bottom = splitLine.addNewPPr().addNewPBdr().addNewTop();
         bottom.setVal(STBorder.Enum.forInt(3));
     }

     HdrDocument hdrDoc = HdrDocument.Factory.newInstance();
     XWPFHeader header = (XWPFHeader) document.createRelationship(XWPFRelation.HEADER, XWPFFactory.getInstance(), 1);

     CTHdrFtr hdr = header._getHdrFtr();
     hdr.addNewP();
     hdr.setPArray(0,paragraph.getCTP());
     if (withSplitLine){
         hdr.addNewP();
         hdr.setPArray(1,paragraph2.getCTP());
     }

     CTHdrFtrRef ctHdrFtrRef = ctSectPr1.addNewHeaderReference();
     ctHdrFtrRef.setType(STHdrFtr.DEFAULT);
     ctHdrFtrRef.setId(document.getRelationId(header));

     header.setHeaderFooter(hdr);
     hdrDoc.setHdr(hdr);
     header.setXWPFDocument(document);

 }

页脚也是相同的原理

private static void createFooterForSec(XWPFDocument document, CTSectPr ctSectPr1) {
        CTP pageNo = CTP.Factory.newInstance();
        XWPFParagraph paragraph = new XWPFParagraph(pageNo, document);
        CTPPr begin = pageNo.addNewPPr();
        begin.addNewPStyle().setVal(STYLE_FOOTER);
        begin.addNewJc().setVal(STJc.CENTER);
        pageNo.addNewR().addNewFldChar().setFldCharType(STFldCharType.BEGIN);
        pageNo.addNewR().addNewInstrText().setStringValue("PAGE   \\* MERGEFORMAT");
        pageNo.addNewR().addNewFldChar().setFldCharType(STFldCharType.SEPARATE);
        org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR end = pageNo.addNewR();
        CTRPr endRPr = end.addNewRPr();
        endRPr.addNewNoProof();
        endRPr.addNewLang().setVal(LANG_ZH_CN);
        end.addNewFldChar().setFldCharType(STFldCharType.END);

        FtrDocument ftrDoc = org.openxmlformats.schemas.wordprocessingml.x2006.main.FtrDocument.Factory.newInstance();
        XWPFFooter footer = (XWPFFooter) document.createRelationship(XWPFRelation.FOOTER, XWPFFactory.getInstance(), 1);
        footer.setXWPFDocument(document);

        CTHdrFtr ftr = footer._getHdrFtr();
        ftr.addNewP();
        ftr.setPArray(0,paragraph.getCTP());

        CTHdrFtrRef ctHdrFtrRef = ctSectPr1.addNewFooterReference();
        ctHdrFtrRef.setType(STHdrFtr.DEFAULT);
        ctHdrFtrRef.setId(document.getRelationId(footer));

        footer.setHeaderFooter(ftr);
        ftrDoc.setFtr(ftr);
        footer.setXWPFDocument(document);
    }

感谢

整理不易 对你有用的话点个赞吧


原网址: 访问
创建于: 2023-06-05 17:03:38
目录: default
标签: 无

请先后发表评论
  • 最新评论
  • 总共0条评论